Java类中各部件加载顺序,面试必问!!!

xiaoxiao2021-02-28  33

    面试或者笔试中经常会遇到的一道题目就是Java类中各部件加载的顺序,通常会给你一段代码让你写出输入的结果,一般包含:静态块、静态变量、普通代码块、构造器、子类重写父类的方法等等。下面我们来看一段代码:

Father类代码:

package com.extend; public class Father { public static int Father_A = getA(); int Father_C = getC(); { System.out.println("我是Father的第一个普通代码块"); } static{ System.out.println("我是Father的第一个静态块"); } { System.out.println("我是Father的第二个普通代码块"); } static{ System.out.println("我是Father的第二个静态块"); } public static boolean Father_B = getB(); public static int getA(){ System.out.println("我是Father获取静态变量A的方法"); return 100; } public static boolean getB(){ System.out.println("我是Father获取静态变量B的方法"); return true; } public int getC(){ System.out.println("我是Father获取变量C的方法"); return 100; } public Father(){ System.out.println("我是Father的构造器"); } public void hello(){ System.out.println("Hello!我是Father"); } }

Son类代码:

package com.extend; public class Son extends Father { public static int Son_A = getA(); int Son_C = getC(); { System.out.println("我是Son的第一个普通代码块"); } static{ System.out.println("我是Son的第一个静态块"); } { System.out.println("我是Son的第二个普通代码块"); } static{ System.out.println("我是Son的第二个静态块"); } public static boolean Son_B = getB(); public static int getA(){ System.out.println("我是Son获取静态变量A的方法"); return 100; } public static boolean getB(){ System.out.println("我是Son获取静态变量B的方法"); return true; } public Son(){ System.out.println("我是Son的构造器"); } public void hello(){ System.out.println("Hello!我是Son"); }  }

接下来在看main方法(main方法在Son类中)如何执行:

public static void main(String[] args) { System.out.println("main start"); System.out.println("-------分隔符--------"); Father s = new Son(); System.out.println("-------分隔符--------"); s.hello(); System.out.println("-------分隔符--------"); Father f = new Father(); System.out.println("-------分隔符--------"); f.hello(); System.out.println("-------分隔符--------"); }

想清楚后来看答案,是否和预想的一致呢?

输出结果:

我是Father获取静态变量A的方法 我是Father的第一个静态块 我是Father的第二个静态块 我是Father获取静态变量B的方法 我是Son获取静态变量A的方法 我是Son的第一个静态块 我是Son的第二个静态块 我是Son获取静态变量B的方法 main start -------分隔符-------- 我是Father获取变量C的方法 我是Father的第一个普通代码块 我是Father的第二个普通代码块 我是Father的构造器 我是Father获取变量C的方法 我是Son的第一个普通代码块 我是Son的第二个普通代码块 我是Son的构造器 -------分隔符-------- Hello!我是Son -------分隔符-------- 我是Father获取变量C的方法 我是Father的第一个普通代码块 我是Father的第二个普通代码块 我是Father的构造器 -------分隔符-------- Hello!我是Father -------分隔符--------

       到这里可能很多同学要问了,为什么“main start”不是第一行输出呢?这是因为main方法虽然是主进程的入口方法,但是它也需要在类加载完之后才会执行main方法,所以main方法的第一行输出是在所有的静态变量、静态块加载之后执行。这里还有一个容易搞混的地方,在第二次实例化Father类的时候并不会输出Father类静态变量以及静态块中的内容,也就是说静态变量以及静态块只是在第一次实例化时会被加载。

单一类加载顺序:

静态变量、静态块先执行,如果存在多个则顺序执行;只会加载一次如果main方法第一行有输出,则输出第一行内容接下来加载普通变量、普通代码块,如果存在多个则顺序执行;每实例化一次就会加载一次接下来是调用该类的构造方法;每实例化一次就会加载一次

继承类之间的加载顺序:

先加载父类的静态变量、静态块,如果存在多个则顺序执行;只会加载一次再加载子类的静态变量、静态块,如果存在多个则顺序执行;只会加载一次如果main方法第一行有输出,则输出第一行内容接下来是加载父类的普通变量、普通代码块,如果存在多个则顺序执行;每实例化一次就回加载一次接下来是调用父类的构造器;每实例化一次就会加载一次接下来是加载子类的普通变量、普通代码块,如果存在多个则顺序执行;每实例化一次就会加载一次接下来是调用子类的子类的构造器;每实例化一次就会加载一次

总之实例化的时候先加载静态相关信息,再加载普通相关信息,再加载构造器

    静态块,静态变量  >  普通变量,普通代码块  >  构造器

       在写这些代码的时候发现一个比较疑惑的问题,我在Father类中定义了一个普通变量father_C对应了一个getC()的方法,无论这个方法是静态方法还是普通方法,编译器都不会报错并且执行也不受影响。代码如下:

int Father_C = getC(); int Father_D = new Father().getD(); int Father_E = getD(); public static int getC(){ System.out.println("我是Father获取变量C的方法"); return 100; } public int getD(){ System.out.println("我是Father获取变量C的方法"); return 100; } 这是编译器在编译阶段会优化还是什么原因呢?欢迎大家在留言区进行讨论。
转载请注明原文地址: https://www.6miu.com/read-2622263.html

最新回复(0)