1.在无继承的结构中,实例化时执行顺序为静态、构造代码块、构造、普通方法,如下代码可知:
class HelloA {
{//构造代码块:对象一实例化就执行,每实例化一次执行一次;
System.out.println("父类A的构造代码块");
}
public HelloA() {//与类同名且没有返回值,用来初始化类属性,分为有参和无参构造
System.out.println("父类A的构造方法");
}
static {//静态代码块:对象实例化就执行,无论new 多少个对象,仅执行一次;
System.out.println("父类A的静态方法");
}
public void run() {//普通方法
System.out.println("run A普通方法...");
}
public static void main(String[] args) {
new HelloA().run();//实例类对象并调用普通方法
}
}
输出结果为:
2.当存在继承时,执行顺序如下(继续上方的代码):
public class HelloB extends HelloA{
{
System.out.println("子类B的构造代码块");
}
public HelloB()
{
System.out.println("子类B的构造");
}
static{
System.out.println("子类B的静态");
}
public static void main (String[] args){
new HelloB();//直接实例化时
HelloA ha=new HelloB();//存在转型问题时
}
}
结果为:
也可以参照这两个样题:
样题1:http://m.nowcoder.com/questions?uuid=439c7f3f930f4db288061d870bdbdd92
样题2:http://m.nowcoder.com/questions?uuid=444f3115c9214d8080816f56a6e51583
样题3:http://m.nowcoder.com/questions?uuid=c2bfb1512dfa4a7eab773a5871a52402
分析:转型问题,先看代码
public class Base
{
private String baseName = "base";
public Base()
{
callName();
}
public void callName()
{
System. out. println(baseName);
}
static class Sub extends Base
{
private String baseName = "sub";
public void callName()
{
System. out. println (baseName) ;
}
}
public static void main(String[] args)
{
Base b = new Sub();
}
}
输出
这里记忆下类加载顺序:
1.父类静态代码块(静态初始化块、静态属性,但不包括静态方法)
2.子类静态代码块(静态初始化块,静态属性,但不包括静态方法)
3.父类非静态代码块(包括非静态初始化块非、非静态属性)
4.父类构造函数
5.子类非静态代码块(包括非静态初始化块、非静态属性)
6.子类构造函数
Base b = new Sub();它为多态的一种表现形式,声明是Base,实现是Sub类, 理解为 b 编译时表现为Base类特性,运行时表现为Sub类特性。当子类覆盖了父类的方法后,意思是父类的方法已经被重写,题中父类初始化调用的方法为子类实现的方法,子类实现的方法中调用的baseName为子类中的私有属性。由1.可知,此时只执行到步骤4.,子类非静态代码块和初始化步骤还没有到,子类中的baseName还没有被初始化。所以此时 baseName为空。 所以为null。
样题参考:
public class B
{
public static B t1 = new B();
public static B t2 = new B();
{
System.out.println("构造块");
}
static
{
System.out.println("静态块");
}
public static void main(String[] args)
{
B t = new B();
}
}
结果为:构造快 构造快 静态块 构造快
解释:开始时JVM加载B.class,对所有的静态成员进行声明,t1 t2被初始化为默认值,为null,又因为t1 t2需要被显式初始化,所以对t1进行显式初始化,初始化代码块→构造函数(没有就是调用默认的构造函数),咦!静态代码块咋不初始化?因为在开始时已经对static部分进行了初始化,虽然只对static变量进行了初始化,但在初始化t1时也不会再执行static块了,因为JVM认为这是第二次加载类B了,所以static会在t1初始化时被忽略掉,所以直接初始化非static部分,也就是构造块部分(输出''构造块'')接着构造函数(无输出)。接着对t2进行初始化过程同t1相同(输出'构造块'),此时就对所有的static变量都完成了初始化,接着就执行static块部分(输出'静态块'),接着执行,main方法,同样也,new了对象,调用构造函数输出('构造块')。
3.特殊例子(类内部实现实例对象,多用于单例的懒汉式和饿汉式设计模式),看代码:
public class testSingleton {
// 内部实例化对象
public static testSingleton t1 = new testSingleton();
{// 构造代码块
System.out.println("构造块输出...");
}
static {// 静态块
System.out.println("静态块输出...");
}
public testSingleton() {//构造方法
System.out.println("构造方法输出");
}
public static void main(String[] args) {
// TODO Auto-generated method stub
testSingleton t2 = new testSingleton();
}
}
结果为:
解释:此处代码是参照此样题:
链接1:http://m.nowcoder.com/questions?uuid=3910188b1259470a9bb7109885ed48c8
链接2:http://m.nowcoder.com/questions?uuid=ab6eb06face84c4e81ab5bc6f0f7f258
分析过程没什么变化,只是给自己个印象