首页 > 试题广场 >

运行代码,输出的结果是()

[单选题]
运行代码,输出的结果是()
public class P {
    public static int abc = 123;
    static{
        System.out.println("P is init");
    }
}
public class S extends P {
    static{
        System.out.println("S is init");
    }
}
public class Test {
    public static void main(String[] args) {
        System.out.println(S.abc);
    }
}


  • P is init<br />123
  • S is init<br />P is init<br />123
  • P is init<br />S is init<br />123
  • S is init<br />123
不会初始化子类的几种
1. 调用的是父类的static方法或者字段
2.调用的是父类的final方法或者字段
3. 通过数组来引用

发表于 2019-10-28 11:11:48 回复(37)
属于被动引用不会出发子类初始化 
 1.子类引用父类的静态字段,只会触发子类的加载、父类的初始化,不会导致子类初始化 
 2.通过数组定义来引用类,不会触发此类的初始化 
 3.常量在编译阶段会进行常量优化,将常量存入调用类的常量池中, 本质上并没有直接引用到定义常量的类,因此不会触发定义常量的类的初始化。 
 参考:《深入理解Java虚拟机》
这里有类主动引用和被动引用的demo:https://www.jianshu.com/p/3afa5d24bf71
编辑于 2019-08-22 10:21:35 回复(17)

虚拟机规范严格规定了有且只有五种情况必须立即对类进行“初始化”:

1.      使用new关键字实例化对象的时候、读取或设置一个类的静态字段的时候,已经调用一个类的静态方法的时候。

2.      使用java.lang.reflect包的方法对类进行反射调用的时候,如果类没有初始化,则需要先触发其初始化。

3.      当初始化一个类的时候,如果发现其父类没有被初始化就会先初始化它的父类。

4.      当虚拟机启动的时候,用户需要指定一个要执行的主类(就是包含main()方法的那个类),虚拟机会先初始化这个类;

5.      使用Jdk1.7动态语言支持的时候的一些情况。

 

除了这五种之外,其他的所有引用类的方式都不会触发初始化,称为被动引用。下面是被动引用的三个例子:

1.      通过子类引用父类的的静态字段,不会导致子类初始化。

2.      通过数组定义来引用类,不会触发此类的初始化。

public class NotInitialization { 

    public static void main(String[] args) { 

        SuperClass[] sca = new SuperClass[10]; 

    }   

}

3.      常量在编译阶段会存入调用类的常量池中,本质上没有直接引用到定义常量的类,因此不会触发定义常量的类的初始化。

public class ConstClass { 

    static { 

        System.out.println("ConstClass init!"); 

    } 

    public static final int value = 123; 

public class NotInitialization{ 

    public static void main(String[] args) { 

        int x = ConstClass.value; 

    } 

上述代码运行之后,也没有输出“ConstClass init!”,这是因为虽然在Java源码中引用了ConstClass类中的常量HELLOWORLD,但其实在编译阶段通过常量传播优化,已经将此常量的值“hello world”存储到了NotInitialization类的常量池中,以后NotInitialization对常量ConstClass.HELLOWORLD的引用实际都被转化为NotInitialization类对自身常量池的引用了。也就是说,实际上NotInitialization的Class文件之中并没有ConstClass类的符号引用入口,这两个类在编译成Class之后就不存在任何联系了。参考资料:https://blog.csdn.net/qq_22771739/article/details/86348962

发表于 2019-01-12 10:26:24 回复(10)
子类引用父类的静态字段,只会触发子类的加载、父类的初始化,不会导致子类初始化 
而静态代码块在类初始化的时候执行!!

发表于 2019-09-04 16:00:57 回复(5)
经过代码测试:
当直接new 子类  创建时的执行顺序为:父类静态块、子类静态块、父类构造方法、子类构造方法。
当new创建子类数组时,不加载任何东西
当用父类名调用父类静态变量、方法时:加载父类静态块
当用子类名调用父类静态变量、方法是:加载父类静态块
当用子类名调用子类特有静态变量、方法是:加载父类静态块、加载子类静态块
发表于 2020-05-08 20:37:15 回复(9)
Test()中的System.out.println(S.abc); 调用的是父类的静态字段abc,初始化的是父类,而不会初始化子类,如果是new S(),则父类和子类都要初始化
发表于 2019-12-30 18:57:21 回复(1)
这题主要考的是ClassLoader隐式加载方式。 当一个类被使用了,那么应用程序类加载器就会将类加载入方法区。 被使用的含义: 1:类的成员被使用了:类名.属性,类名.方法名,表示调用静态成员 2:类实例被创建了,new 对象。我们再来看题目本身 System.out.print(s.abc) 注意到此时abc是属于类P的,所以当S去调用abc的时候,S本身并不会被隐式加载。而P的静态属性被调用了,所以P被加载了。 加载包含:创建类的Class对象,加载静态属性,静态块(两者顺序只取决于在源码中的顺序),而后解析方法 所以此时打印P的静态块 主方法输出abc的值 ================================== 拓展:如果属性是静态final修饰的话,会被认为是一个常量,会直接将常量加载入方法区使用。不会去加载类 所以如果此时abc是静态final的,那么连P的静态块也不执行了。直接打印abc的值。 显示加载方式: Class.forName(包名.类名)
编辑于 2020-12-07 05:48:35 回复(1)
这题考查的是在JVM类加载过程的初始化阶段,被动引用不会触发类初始化。考查的是其中一种情况,即调用父类静态成员时,只会触发父类初始化, 不会触发子类初始化
发表于 2022-01-17 21:59:27 回复(0)
main方法中S类并没有用到,并不会被加载,所以Sisinit不会被打印,选A
发表于 2019-08-21 12:36:02 回复(1)
不谈答案,我在想,不能同时存在这么多的public类,再找有没有编译错误的答案,然后直接交白卷,这种题做的没意思。
发表于 2022-05-15 23:25:09 回复(0)
类初始化时机:只有当对类的主动使用的时候才会导致类的初始化,类的主动使用包括以下六种:
– 创建类的实例,也就是new的方式
– 访问某个类或接口的静态变量,或者对该静态变量赋值
– 调用类的静态方法
– 反射(如Class.forName(“com.xxx.Test”))
– 初始化某个类的子类,则其父类也会被初始化
– Java虚拟机启动时被标明为启动类的类(Java Test),直接使用java.exe命令来运行某个主类。
发表于 2022-02-03 11:06:40 回复(0)
 1.子类引用父类的静态字段,只会触发子类的加载、父类的初始化,不会导致子类初始化 
 2.通过数组定义来引用类,不会触发此类的初始化 
3,常量在编译阶段会存入调用类的常量池中,本质上没有直接引用到定义常量的类,因此不会触发定义常量的类的初始化。
发表于 2022-01-17 12:15:41 回复(0)
弱弱的问一句,static代码块不应该是class P和S加载的时候就先执行了吗?不应该是C吗?
发表于 2020-09-04 11:44:14 回复(2)
触发类初始化:
  • 访问类的静态元素(包括静态成员变量,静态方法,构造函数)
  • 子类初始化时会优先为父类初始化
发表于 2020-08-11 09:43:17 回复(0)
在 Java 虚拟机中,对一个类型的引用必须对类进行初始化的引用称为主动引用,《Java 虚拟机规范》严格规定了六种情况为主动引用。
对一个类型的引用不需要对类进行初始化的引用称为被动引用,除了《Java 虚拟机规范》规定的那六种之外,其余的全部为被动引用,主要有以下三种:
1. 通过子类引用父类的静态字段,不会导致子类初始化,也是本题中的情况。
2. 通过数组定义来引用类,不会触发此类的初始化。
3. 常量在编译阶段会存入调用类的常量池中,本质上没有直接引用到定义常量的类,因此不会触发定义常量的类的初始化。
发表于 2020-07-12 19:53:58 回复(0)

这道题有问题啊,程序会把报错的,在一个java文件里只能有一个public修饰的类好吧?main方法在Text类里,只能这个类被public修饰
编辑于 2019-12-08 20:02:44 回复(2)

1.子类引用父类的静态字段,只会触发子类的加载、父类的初始化,不会导致子类初始化

2.通过数组定义来引用类,不会触发此类的初始化

3.常量在编译阶段会进行常量优化,将常量存入调用类的常量池中, 本质上并没有直接引用到定义常量的类,因此不会触发定义常量的类的初始化。

发表于 2022-05-20 15:29:12 回复(0)
没有初始化子类,所以A才是正确的;
本题调用的是父类的static字段,是不会初始化子类的。
编辑于 2022-04-13 10:53:03 回复(0)
只要记住,加载跟初始化不是一回事就好了,使用类的时候,不管怎样,这个类必须已经加载到内存当中了,然而初始化没有,就不好说了。被动引用不会触发初始化,也就不会触发static{}代码块。
发表于 2020-08-30 16:40:16 回复(0)
不会初始化子类的情况: 1. 调用的是父类的static方法或者字段 2. 调用的是父类的final方法或者字段 3. 子类通过数组引用
发表于 2020-03-30 18:20:56 回复(0)