多态性,对象转换类型

父类不能强转成子类

关键字static

static关键字表示静态,可以修饰成员变量、方法和代码块。

static修饰成员变量:

1、被static修饰的属性所用对象共享同一个值

2、被static修饰的属性值会被保存在内存的方法区中

3、当该类的所有对象共享一个资源时,将这个资源设置为静态能够节省内存

4、静态属性使用类名调用

5、静态属性也称类属性

public class Main {
public static void main(String[] args)
{
Cat cat01=new Cat();
Cat cat02=new Cat();
cat01.name="小黄";
cat01.eat("面包");
Cat.eat("鱼");

Cat.name="小白";
Cat.eat("鱼");
cat01.eat("面包");
cat02.eat("饺子");


cat02.name="小黑";
cat02.eat("饺子");
cat01.eat("面包");


}
}
public class Cat
{
public static String name;
public static void eat(String food)
{
System.out.println(name+"吃"+food);
}
}

static修饰方法:

1、被static修饰的方法称之为静态方法、类方法

2、静态方法可以直接使用类名无需实例化对象

3、静态方法中无法调用普通(实例)属性和方法,因为静态方法中没有this

4、如果一个不需要访问当前类中的实例成员就可以定义称静态的

5、静态方法不能被重写

abstract关键字

abstract表示抽象的,可以修饰类和方法。

方法重写规则与包装类型

重写方法规则一:

方法名和形式参数必须具有完全相同的签名,返回类型也必须一致。方法可以改变返回类型,但子类的返回类型必须时父类返回类型的子类型。例如,如果父类的方法返回一个Object,子类的重写方法可以返回一个String,但重写方法不能返回Integer,因为String不是Integer的子类型

子类重写的方法可以改变其访问权限,比如将父类中的Protected方法重写为public方法

子类重写的方法不能抛出比父类中被重写的方法更广泛的异常

重写方法规则二:

如果一个类声明了一个带有final关键字,表明此方法为不可变的,不能被重写

子类可以重写父类中被声明为static的方法,但必须保持方法的签名(方法名和参数列表)完全一致

子类重写的方法可以调用父类中被重写的方法,而且可以使用super关键字在子类中直接调用父类中被重写的方法

包装类型

public class Main
{
public static void main(String[] args)
{
int age=18;
Integer age2=Integer.valueOf(19);
System.out.println("age "+age);
System.out.println("age2 "+age2.intValue());
System.out.println("age2 "+age2.toString());
System.out.println("age2 "+age2);
System.out.println("age2 "+age2.byteValue());//取位数最低的一字节
Boolean isObj=Boolean.valueOf(age2 instanceof Object);
System.out.println("isObj:"+isObj.toString());
}
}

接口的定义和实现

接口的关键字:interface

在定义一个接口时,我们需要把public class xxx 中的class改成interface,即public interface xxx ,这就是定义了一个接口。

接口中的定义的方法与常量

在定义方法时,例如我们定义一个run方法与go方法,我们可以写成public abstract void run();和 public abstract void go();但是因为在接口的定义中都是public abstract,因此我们只需要写:void run();和void go();即可。即直接写:方法类型+方法名(参数 类型)即可。

在定义常量时,因为接口中所有的常量都是public static void final, 而final类是无法被继承的,所以我们不经常在接口中定义常量

接口及其实现类,implements关键字

由于接口仅仅能给我们定义一个方法,无法让我们去实例化(即实现它),因此我们需要再写一个实现类来实现它,而这个实现类的名字就是接口名+Impl

Impl就是implements,而想要实现接口中的类,就需要重写接口中的所有方法

接口与继承的不同

接口为多继承,而extend是单继承,例如我们在这里再定义一个TimerServi的接口,我们可以再UserService实现类中再继承一个TimeService,只要重写TimeService中的方法即可

public class UserServiceImpl implents UserService, TimeService{}

Main函数

public class Main {
public static void main(String[] args)
{
Cat cat=new Cat();
cat.sleep();
cat.hunt();
cat.playwithme();
}
}

Animal接口

public interface Animal
{
void sleep();
}

Pet接口

public interface Pet
{
void playwithme();
}

Hunt接口

public interface Hunt
{
void hunt();
}

Cat类

public class Cat implements Animal,Hunt,Pet
{
@Override
public void sleep()
{
System.out.println("睡觉");
}

@Override
public void hunt()
{
System.out.println("打猎");

}

@Override
public void playwithme()
{
System.out.println("吃饭");

}
}

内部类与匿名类

Java中的类有两种重要的成员,即成员变量和方法。其实Java还允许类有一种成员,即在一个类中声明另一个类,这就是内部类,而包含内部类的类叫做外嵌类

内部类与外嵌类之间的关系如下:

内部类可以使用外嵌类的成员变量和方法

内部类中不可以声明类变量和类方法

外嵌类可以使用内部类声明对象作为外嵌类的成员

内部类仅供它的外嵌类使用,其他类不可以用某个类的内部类声明对象

Main

public class Main {
public static void main(String[] args)
{
Farm farm=new Farm("红星农场");
farm.cow.speak();
}
}

Farm类

public class Farm
{
private String farmName;
public Cow cow=new Cow(5,"hyq");
Farm(String pFarmName)
{
this.farmName=pFarmName;
}
class Cow
{
private String cowName;
int age;
Cow(int pAge,String pCowName)
{
this.age=pAge;
this.cowName=pCowName;
}
public void speak()
{
System.out.println("我是"+cowName+",年龄"+age+"我所在农场: "+farmName);
}
}

内部类可以被修饰为static内部类,类是一种数据类型,那么static内部类就是外嵌类中的一种静态数据类型,这样其他类就可以使用static内部类来声明创建对象了。(注意:static内部类不能操作外嵌类中的实例成员变量)

和类有关的匿名类

我们可以直接使用一个类的子类的类体创建一个对象。再创建子类对象时,使用的是父类的构造方法和类体,这个类体被认为是子类去掉类声明之后的类体,称作匿名类

Main

public class Main {
public static void main(String[] args)
{
Farm farm=new Farm("红星农场");
farm.cow.speak();
Speak speak=new Speak()
{
@Override
public void speakhello()
{
System.out.println("hello ! 一");
}
};
new Speak()
{
@Override
public void speakhello()
{
System.out.println("hello ! 二");
}
};
}
}

Speak类

abstract class Speak
{
Speak()
{
System.out.println("我是父类");
}
public abstract void speakhello();
}

匿名对象的引用可以传递给一个匹配的参数,匿名类常用的方式是向方法的参数传值

//Main中的代码片段      
A a=new A();
a.f(new Speak()
{
@Override
public void speakhello() {
System.out.println("hello ! 三");
}
});
}
}
//Speak类
abstract class Speak
{
Speak()
{
System.out.println("我是父类");
}
public abstract void speakhello();
}

和接口有关的匿名类

我们可以直接使用接口名和一个类体创建一个匿名对象,这个类体被称为是实现了这个接口的类去掉声明后的类体,称为匿名类。

如果某个方法的参数是接口类型,那么可以使用接口名和类体组合创建一个匿名对象传递给这个方法的参数,但类体必须重写接口中的所有方法

//Main中的代码片段 
//和接口有关的匿名类
Cubic cubic = new Cubic()
{
@Override
public double getCubic(double x) {
return x * x * x;
}
};
System.out.println(cubic.getCubic(3));

System.out.println(new Cubic()
{
@Override
public double getCubic(double x)
{
return x * x * x;
}
}.getCubic(4));
//Cubic类
public interface Cubic
{
double getCubic(double x);
}
//传参方法
B b=new B();
b.g(new Cubic() {
@Override
public double getCubic(double x) {
return x*x*x;
}
});

数组声明与定义区别

对于变量来说,Java 定义就是声明

例如:int[] a; 我们可说它是定义也可以说它是声明

定义初始化方法(见下方代码)

public class Main {
public static void main(String[] args)
{
//数组定义
int[] arr1 = {1,2,3};
int[] arr2 = new int [4];
int arr3_len=5;
int[] arr3=new int[arr3_len];
//错误演示
//int[] arr4;
//arr4={4,5,6}; 错误原因,定义和初始化必须在一起
//int[] arr4=new int[]{5,6,7,8} 错误原因,不可指定长度


//访问元素
int[] arr4=new int[]{5,6,7,8};
int one=arr4[0];
for(int i=0;i< arr4.length;i++)
{
System.out.println("arr4 下标"+i+":"+arr4[i]);
}
//数组的复制 拷贝

//浅拷贝
int[] arr5=arr4;


//深拷贝
int[] arr6= new int[arr4.length];
for(int j=0;j<arr4.length;j++)
{
arr6[j]=arr4[j];
}
for(int i:arr6)
{
System.out.println(i);
}
int[] arr7={1,1,1,1,1,1};
System.arraycopy(arr4,0,arr7,1,arr4.length);
//不规则数组
int[][] arr8=new int[4][];
arr8[0]=new int[3];
arr8[1]=new int[]{6,5,4,3};
arr8[2]=new int[]{1,1,1,1,1};
arr8[3]=new int[]{3,3,3,3,3,3,3};
for(int m=0;m<arr8.length;m++)
{
for(int n=0;n<arr8[m].length;n++)
{
System.out.println(arr8[m][n]+",");
}
}
}
}

字符串

Java.lang.String是java的字符串类. String是一个不可变的对象,所有对String修改的操作都需要构造新的String实例。

java.lang.StringBuffer与java.lang.StringBuilder是可变的字符串对象,StringBuilder较快但是线程不安全,在对线程安全没有要求时我们通常使用StringBuilder

public class Main {
public static void main(String[] args)
{
char[] data={'a','b','c','d'};
String s1= new String(data);
String s2= new String("efg");
String s3="hijk";
String s4="lmn";
String s5="";
StringBuffer sb=new StringBuffer(s3);
for(int i=0;i<10000;i++)
{
s5=s3+i;
sb.append(i);
System.out.println(s5);
System.out.println(sb.toString());
}
}

容器

集合与数组

容器的分类:

Collection:List、Set

Map:HashMap、HashTable、TreeMap、ConcurrHashMap

List 有序集合,允许重复的元素

Set无序集合,不允许重复的元素

HashMap:采用散列算法来实现,底层用哈希表来存储数据,因此要求键不能重复。线程不安全,HashMap在查找、删除、修改方面效率都非常高。允许key或value为null

//List
List myList=new ArrayList();
myList.add("A");
myList.add("B");
myList.add("C");
myList.add("D");
for (int i=0;i<myList.size();i++)
{
System.out.println(myList.get(i));
}
Iterator it=myList.iterator();
while(it.hasNext())
{
Object o=it.next();
System.out.println(o);
}
List<String> aList=new ArrayList<>();
aList.add("bbb");
//HashMap
Map<String,String>map=new HashMap<>();
map.put("张三","福建省");
map.put("王五","湖南省");
map.put("李四","海南省");
for(Map.Entry<String,String> entry:map.entrySet())
{
String key=entry.getKey();
String val=entry.getValue();
System.out.println("key"+key+","+"val"+val);
}
Iterator<Map.Entry<String,String>>entries=map.entrySet().iterator();
while(entries.hasNext())
{
Map.Entry<String,String>entry=entries.next();
String key= entry.getKey();
String val=entry.getValue();
System.out.println("key"+key+",val"+val);
}
for(String oneKey:map.keySet())
{

}
for(String oneVal:map.values())
{

}