构造块和静态的执行顺序(笔试)

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张图片

也可以参照这两个样题:

样题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();
	}

}

结果为:

构造块和静态的执行顺序(笔试)_第2张图片

解释:此处代码是参照此样题:

链接1:http://m.nowcoder.com/questions?uuid=3910188b1259470a9bb7109885ed48c8

链接2:http://m.nowcoder.com/questions?uuid=ab6eb06face84c4e81ab5bc6f0f7f258

分析过程没什么变化,只是给自己个印象


你可能感兴趣的:(java笔试面试基础)