SCJP中的一道题,大家来看看!

时间:2022-07-29 17:48:00
class X
{
Y b=new Y();
X()
{
System.out.print("X");
}
}
class Y
{
Y()
{
System.out.print("Y");
}
}
public class Z extends X
{
Y y=new Y();
Z()
{
System.out.print("Z");
}
   public static void main(String[] args)
    {
     new Z();
    }
}
两个问题请教大家:1.运行结果;2.分析结果.

8 个解决方案

#1


YXYZ   就是初始化顺序的问题
super()  成员变量初始化  构造器体

#2


YXYZ
这个题考得是子类初始化顺序以及属性和构造初始化顺序。
在new一个Z的时候,由于它有父类,因此先初始化父类X(这个很好理解,既然子类继承父类,那当然是父类给有东西才能继承,因此为了防止子类在初始化时用到父类的东西,自然给先把父类初始化出来。)于是到X的内部,它有一个属性还有一个构造,那么先初始化哪个呢?通常在构造里我们都会对类的属性进行一些操作(这点你可以看看现成代码,很多都这样),如果构造执行在先那么在操作属性时,属性还没初始化怎么行。所以要先初始化属性Y。于是又转到Y里,Y比较简单没属性,构造里输出“Y”即可,然后在执行X的构造输出“X”,这时候父类X初始化完了,再接着初始化Z,还是先初始化属性,那么输出“Y”,然后再输出构造里的“Z”。
实际上这道题是简化很多的。因为它没有考到静态属性(类属性)以及程序块及静态程序块。
我把这个题改一下,你运行一下对照结果,应该会有些收获的。
public class Z extends X{
    
    static{ //静态代码块
        System.out.println("我是子类的静态代码块,除了父类静态代码块和静态属性(类变量)我是最先执行的"); 
    }
    static C c= new C(); //静态属性
    
    Y2 y=new Y2();
    
    { System.out.println("我是子类初始化块,我的优先级和非静态属性一样,我们之间的顺序以代码顺序为准"); } //初始化块
    
    
    Z(){System.out.println("我是子类构造函数");}
    
    public static void main(String[] args){
        new Z();
    }   
}


class X{
    
    static{System.out.println("我是父类的静态代码块,我是最先执行的"); }  //静态代码块       
    
    static C2 c= new C2();  //静态属性     
    
    { System.out.println("我是父类初始化块,我的优先级和非静态属性一样,我们之间的顺序以代码顺序为准"); } //初始化块
    
    
    Y b=new Y();  //非静态属性

    X(){System.out.println("我是父类构造函数");}
}


class Y{
    Y(){System.out.println("我是父类非静态属性,和具体的类实例相关,我可能在初始化块前执行也可能在其后");}
}

class Y2{
    Y2(){System.out.println("我是子类非静态属性,和具体的类实例相关,我可能在初始化块前执行也可能在其后");}
}

class C{
    C(){System.out.println("我是子类的一个静态属性(类变量),我和之前的初始化过程都是针对类的,与实例无关");}
}

class C2{
    C2(){System.out.println("我是父类一个静态属性(类变量),我比子类的静态代码块执行的还早");}
}

#3


YXYZ

“实例化”一个类时先去把父类实例话,然后把成员变量初始化,然后再构造函数。

所以new Z()时先去实例化Z的父类X。在实例化X时,X没有父类,所以初始化成员Y,这时打印第一个Y,然后调用X的构造函数,这时打印X,
Z的父类实例完后就实例化Z的成员变量,只有一个成员变量Y,这时打印第二个Y,然后最后调用Z的构造函数,这时打印Z

#4


谢谢各位,尤其是二楼的细心~~

#5


实例化一个类时,首先去实例化父类,再去实例化子类,类中的成员变量和构造函数,首先去初始化其成员变量,然后再执行构造函数。你可以做一下测试:
class X {
        String str = this.getStr();
Y b = new Y();
X() {
System.out.print("X ");
}
String getStr(){
System.out.println("我要初始化成员变量");
return "0000";
}
}

class Y {
Y() {
System.out.print("Y ");
}
}

public class Z extends X {
Y y = new Y();

Z() {
System.out.print("Z ");
}

public static void main(String[] args) {
System.out.println("---------");
new Z();
}
}

#6


不错,学习

#7


很好!

#8


恩,不错 ,仔细点分析还是能做对的。我为自己感到骄傲

#1


YXYZ   就是初始化顺序的问题
super()  成员变量初始化  构造器体

#2


YXYZ
这个题考得是子类初始化顺序以及属性和构造初始化顺序。
在new一个Z的时候,由于它有父类,因此先初始化父类X(这个很好理解,既然子类继承父类,那当然是父类给有东西才能继承,因此为了防止子类在初始化时用到父类的东西,自然给先把父类初始化出来。)于是到X的内部,它有一个属性还有一个构造,那么先初始化哪个呢?通常在构造里我们都会对类的属性进行一些操作(这点你可以看看现成代码,很多都这样),如果构造执行在先那么在操作属性时,属性还没初始化怎么行。所以要先初始化属性Y。于是又转到Y里,Y比较简单没属性,构造里输出“Y”即可,然后在执行X的构造输出“X”,这时候父类X初始化完了,再接着初始化Z,还是先初始化属性,那么输出“Y”,然后再输出构造里的“Z”。
实际上这道题是简化很多的。因为它没有考到静态属性(类属性)以及程序块及静态程序块。
我把这个题改一下,你运行一下对照结果,应该会有些收获的。
public class Z extends X{
    
    static{ //静态代码块
        System.out.println("我是子类的静态代码块,除了父类静态代码块和静态属性(类变量)我是最先执行的"); 
    }
    static C c= new C(); //静态属性
    
    Y2 y=new Y2();
    
    { System.out.println("我是子类初始化块,我的优先级和非静态属性一样,我们之间的顺序以代码顺序为准"); } //初始化块
    
    
    Z(){System.out.println("我是子类构造函数");}
    
    public static void main(String[] args){
        new Z();
    }   
}


class X{
    
    static{System.out.println("我是父类的静态代码块,我是最先执行的"); }  //静态代码块       
    
    static C2 c= new C2();  //静态属性     
    
    { System.out.println("我是父类初始化块,我的优先级和非静态属性一样,我们之间的顺序以代码顺序为准"); } //初始化块
    
    
    Y b=new Y();  //非静态属性

    X(){System.out.println("我是父类构造函数");}
}


class Y{
    Y(){System.out.println("我是父类非静态属性,和具体的类实例相关,我可能在初始化块前执行也可能在其后");}
}

class Y2{
    Y2(){System.out.println("我是子类非静态属性,和具体的类实例相关,我可能在初始化块前执行也可能在其后");}
}

class C{
    C(){System.out.println("我是子类的一个静态属性(类变量),我和之前的初始化过程都是针对类的,与实例无关");}
}

class C2{
    C2(){System.out.println("我是父类一个静态属性(类变量),我比子类的静态代码块执行的还早");}
}

#3


YXYZ

“实例化”一个类时先去把父类实例话,然后把成员变量初始化,然后再构造函数。

所以new Z()时先去实例化Z的父类X。在实例化X时,X没有父类,所以初始化成员Y,这时打印第一个Y,然后调用X的构造函数,这时打印X,
Z的父类实例完后就实例化Z的成员变量,只有一个成员变量Y,这时打印第二个Y,然后最后调用Z的构造函数,这时打印Z

#4


谢谢各位,尤其是二楼的细心~~

#5


实例化一个类时,首先去实例化父类,再去实例化子类,类中的成员变量和构造函数,首先去初始化其成员变量,然后再执行构造函数。你可以做一下测试:
class X {
        String str = this.getStr();
Y b = new Y();
X() {
System.out.print("X ");
}
String getStr(){
System.out.println("我要初始化成员变量");
return "0000";
}
}

class Y {
Y() {
System.out.print("Y ");
}
}

public class Z extends X {
Y y = new Y();

Z() {
System.out.print("Z ");
}

public static void main(String[] args) {
System.out.println("---------");
new Z();
}
}

#6


不错,学习

#7


很好!

#8


恩,不错 ,仔细点分析还是能做对的。我为自己感到骄傲