类初始化和实例初始化
一个实例对象的创建包括:类初始化和实例初始化1. 一个类要创建实例需要先加载并初始化该类,main方法所在的类需要先加载和初始化2. 一个子类要初始化需要先初始化父类3. 一个类初始化就是执行<clinit>()方法<clinit>方法由静态变量显示赋值代码和静态代码块组成类静态变量显示赋值代码和静态代码块代码从上到下顺序执行<clinit>方法只执行一次4.实例初始化就是执行<init>方法<init>方法由非静态实例变量显示赋值代码和非静态代码块,对应构造器代码组成。非静态实例变量显示赋值代码和非静态代码块从上到下顺序执行,而对应构造器代码最后执行每次创建实例对象,调用对应的构造器,执行的就是对应的<init>方法<init>方法的首行是super()或super(实参列表),即对应父类的<init>方法
类加载过程
类加载过程(类初始化):1、类加载就是执行Java程序编译之后在字节码文件中生成的clinit()方法(称之为类构造器),clinit()方法由静态变量和静态代码块组成。2、子类的加载首先需要先加载父类,如果父类为接口。则不会调用父类的clinit方法。一个类中可以没有clinit方法。3、clinit方法中的执行顺序为:父类静态变量初始化,父类静态代码块,子类静态变量初始化,子类静态代码块。4、clinit()方法只执行一次。对象实例化过程(实例初始化):1、对象实例化过程就是执行Java程序编译之后在字节码文件中生成的init()方法(称之为实例构造器),init()方法由非静态变量、非静态代码块以及对应的构造器组成。2、init()方法可以重载多个,有几个构造器就有几个init()方法,每次创建实例,调用哪一个构造器,就会调用相应的init()方法。3、init()方法中的执行顺序为:父类变量初始化,父类代码块,父类构造器,子类变量初始化,子类代码块,子类构造器。clinit()方法优先于init()方法执行,所以整个顺序就是:父类静态变量初始化,父类静态代码块,子类静态变量初始化,子类静态代码块,父类非静态变量初始化,父类非静态代码块,父类构造器,子类非静态变量初始化,子类非静态代码块,子类构造器。类加载时只会加载静态代码块和静态变量。只有创建对象的实例时: 变量和初始化代码块和构造函数才会执行(创建对象实例会先触发类加载)类加载:执行<clinit>创建对象实例:执行<<init>,但是创建类实例之前会先类加载执行<clinit>。类初始化:执行<clinit>方法,<clinit>方法由静态变量显示赋值代码和静态代码块组成,<clinit>方法只执行一次实例初始化:执行<init>方法,<init>方法由非静态实例变量显示赋值代码和非静态代码块,对应构造器代码组成。触发类加载:1. 为一个类型创建一个新的对象实例时(比如new、反射、序列化)只有这个会触发 变量和初始化代码块和构造函数执行,这个是实例初始化,其他6个都是类初始化2. 调用一个类型的静态方法时(即在字节码中执行invokestatic指令)3. 调用一个类型或接口的静态字段,或者对这些静态字段执行赋值操作时(即在字节码中,执行getstatic或者putstatic指令),不过用final修饰的静态字段已经赋值了(String和基本类型,不包含包装类型)的除外,它被初始化为一个编译时常量表达式4. 调用JavaAPI中的反射方法时(比如调用java.lang.Class中的方法(Class.forName),或者java.lang.reflect包中其他类的方法)5. 初始化一个类的派生类时(Java虚拟机规范明确要求初始化一个类时,它的超类必须提前完成初始化操作,接口例外)6. JVM启动包含main方法的启动类时。7. 对于静态字段,只有直接定义这个字段的类才会被初始化,因此通过其子类来引用父类中定义的静态字段,只会触发父类的初始化而不会触发子类的初始化。加载顺序: 静态变量和静态初始化块是依照他们在类中的定义顺序进行初始化的。同样,变量和初始化块也遵循这个规律。1. 父类--静态变量2. 父类--静态初始化块3. 子类--静态变量4. 子类--静态初始化块5. 父类--变量6. 父类--初始化块7. 父类--构造器8. 子类--变量9. 子类--初始化块10. 子类--构造器
多态方法重写@Override哪些方法不可以被重写1、final方法2、静态方法3、private等子类中不可见的方法对象的多态性1、子类如果重写了父类的方法,通过子类对象调用的一定是子类重写过的代码2、非静态方法默认的调用对象是this3、this对象在构造器或者说<init>方法中就是正在创建的对象,所以通过子类实例化时触发的父类加载调用的非静态方法,调用对象this是子类对象,调用的方法是子类重写的方法。子类实例化时如果有父类,会触发父类加载 在初始化过程中如果父类方法被子类重写了,会调用子类的方法。通过父类的引用类型变量指向子类类型对象,访问成员变量时是访问的父类的成员变量。
示例代码
Public class TM {public static void main(String[] args) {
// System.out.println(TM.ccccccc);
// TM.ss();
// TM.ccccccc="333";
// System.out.println(TM.ccccccc);
// TM.sss();TM t = new TM();System.out.println("new 后 ccccccc = "+t.ccccccc);TM t2 = new TM();System.out.println("new 后 ccccccc = "+t2.ccccccc);}private static void sss() {System.out.println("初始化类块-静态值 ccccccc="+ccccccc);
}public TM(){System.out.println("构造器");
}static {System.out.println("初始化类块-静态");
}
public static void ss(){System.out.println("初始化类块-静态方法");
}
{System.out.println("初始化类块-非静态");
}
public static String ccccccc= "222";}