一、类的初始化
1、类的初始化如何触发
a、new一个类的实例对象之前,需要进行类加载和初始化;
b、访问类的静态变量或者对类的静态变量进行赋值;
c、类的静态方法的调用;
d、使用反射机制进行上面1、2、3的操作;
e、main()方法所在的类需要先加载和初始化;
f、子类进行加载和初始化之前需要对父类进行加载和初始化;
g、jdk1.7中的动态语言执行过程。
如下情况不会触发类的初始化:
a、子类调用父类的静态变量,不会触发子类的初始化;
b、定义对象数组,不会触发该类的初始化;
c、调用类中已经确定值的常量,不会触发该类的初始化。若常量是在运行时才确定值的,则会触发该类的初始化;
d、通过类名,获取该类对应的Class对象;
e、通过 Class.forName 加载指定类时,如果指定参数 initialize 为 false 时,也不会触发类初始化;
f、ClassLoader 默认的 loadClass 方法,也不会触发初始化动作。
2、类的初始化过程
a、类的初始化其实就是对<clinit>方法的执行
b、<clinit>由类的静态变量显示赋值代码(静态方法的调用)和静态代码块组成,按顺序执行
c、<clinit>方法在类的初始化过程中只执行一次
3、类的初始代码演示
a、父类代码
public class Father {
private int i = test();
private static int j = method();
static {
System.out.println("Father 1");
}
public Father() {
System.out.println("Father 2");
}
{
System.out.println("Father 3");
}
public int test(){
System.out.println("Father 4");
return 1;
}
public static int method(){
System.out.println("Father 5");
return 1;
}
}
b、子类代码
public class Son extends Father {
private int i = test();
private static int j = method();
static {
System.out.println("Son 6");
}
public Son() {
System.out.println("Son 7");
}
{
System.out.println("Son 8");
}
public int test(){
System.out.println("Son 9");
return 1;
}
public static int method(){
System.out.println("Son 10");
return 1;
}
public static void main(String[] args) {
}
}
c、子类Son中的main方法直接调用运行,子类的初始化之前要先执行父类的初始化
①、Father类初始化【执行Father类中的静态变量显示赋值代码及静态代码块】
②、子类初始化【执行Son类中的静态变量显示赋值代码及静态代码块】
d、执行结果如下
Father 5
Father 1
Son 10
Son 6
二、对象的实例化
1、对象的实例化方式
①、new关键字创建对象;
②、工厂方法返回对象:String str = String.valueOf(23);
③、通过反射方法创建对象,Clazz.newInstance();
④、通过对象的clone()方法克隆,对象实例中的成员变量为引用类型时为浅拷贝;
⑤、通过I/O流创建对象,如运用反序列化手段,调用java.io.ObjectInputStream对象的 readObject()方法。
2、对象的实例化过程
①、对象的实例化过程,其实就是<init>()方法的执行,类中有多少个构造器,就有多少个<init>()方法的重载;
②、<init>由非静态成员变量的显示赋值代码、非静态代码块、构造函数组成,按从上到下的顺序执行,其中构造函数最后执行
③、<init>()的方法首行是super()或者super(参数),即父类的<init>()方法;
④、每创建一个对象就会调用一次<init>方法;
3、this关键字的特殊性
遇到this关键字(也就是构造函数调用自身其他的构造函数时)不插入构造代码块(构造代码块的出现就是为了提取构造函数的共同量,减少各个构造函数的代码而产生的);
子类中对父类方法进行了重写,进行子类对象实例创建的时候,非静态方法的默认对象是this(即正在创建的子类对象实例),所以在父类非静态成员变量的显示赋值代码中调用的是子类重写之后的方法。如下运行结果所示:Son 9打印了两次。
4、对象的实例化过程代码演示
public static void main(String[] args) throws Exception {
Son son1 = new Son();
System.out.println("---------");
Son son2 = new Son();
}
代码执行结果:
Father 5
Father 1
Son 10
Son 6
Son 9
Father 3
Father 2
Son 9
Son 8
Son 7
---------
Son 9
Father 3
Father 2
Son 9
Son 8
Son 7
三、方法的重写
final、private、static修饰的方法不可被子类重写;
对象的多态性:子类重写父类方法,子类对象调用的是子类重写后的方法。
四、方法的重载
同一个类中,方法名相同,但是方法的参数列表不一致(参数类型、参数个数、参数排列顺序),与方法的返回值无关。