`

java 面试题 初始化

阅读更多

关键字: java 面试题 初始化 作者:臧圩人(zangweiren)
网址:http://zangweiren.iteye.com

>>>转载请注明出处! <<<

大家在去参加面试的时候,经常会遇到这样的考题:给你两个类的代码,它们之间是继承的关系,每个类里只有构造器方法和一些变量,构造器里可能还有 一段代码对变量值进行了某种运算,另外还有一些将变量值输出到控制台的代码,然后让我们判断输出的结果。这实际上是在考查我们对于继承情况下类的初始化顺 序的了解。

我们大家都知道,对于静态变量、静态初始化块、变量、初始化块、构造器,它们的初始化顺序依次是(静态变量、静态初始化块)>(变量、初始化块)>构造器。我们也可以通过下面的测试代码来验证这一点:

Java代码 复制代码
  1. public   class  InitialOrderTest {  
  2.   
  3.     // 静态变量   
  4.     public   static  String staticField =  "静态变量" ;  
  5.     // 变量   
  6.     public  String field =  "变量" ;  
  7.   
  8.     // 静态初始化块   
  9.     static  {  
  10.         System.out.println(staticField);  
  11.         System.out.println("静态初始化块" );  
  12.     }  
  13.   
  14.     // 初始化块   
  15.     {  
  16.         System.out.println(field);  
  17.         System.out.println("初始化块" );  
  18.     }  
  19.   
  20.     // 构造器   
  21.     public  InitialOrderTest() {  
  22.         System.out.println("构造器" );  
  23.     }  
  24.   
  25.     public   static   void  main(String[] args) {  
  26.         new  InitialOrderTest();  
  27.     }  
  28. }  
public class InitialOrderTest {

	// 静态变量
	public static String staticField = "静态变量";
	// 变量
	public String field = "变量";

	// 静态初始化块
	static {
		System.out.println(staticField);
		System.out.println("静态初始化块");
	}

	// 初始化块
	{
		System.out.println(field);
		System.out.println("初始化块");
	}

	// 构造器
	public InitialOrderTest() {
		System.out.println("构造器");
	}

	public static void main(String[] args) {
		new InitialOrderTest();
	}
}


运行以上代码,我们会得到如下的输出结果:

  1. 静态变量
  2. 静态初始化块
  3. 变量
  4. 初始化块
  5. 构造器


这与上文中说的完全符合。那么对于继承情况下又会怎样呢?我们仍然以一段测试代码来获取最终结果:

Java代码 复制代码
  1. class  Parent {  
  2.     // 静态变量   
  3.     public   static  String p_StaticField =  "父类--静态变量" ;  
  4.     // 变量   
  5.     public  String p_Field =  "父类--变量" ;  
  6.   
  7.     // 静态初始化块   
  8.     static  {  
  9.         System.out.println(p_StaticField);  
  10.         System.out.println("父类--静态初始化块" );  
  11.     }  
  12.   
  13.     // 初始化块   
  14.     {  
  15.         System.out.println(p_Field);  
  16.         System.out.println("父类--初始化块" );  
  17.     }  
  18.   
  19.     // 构造器   
  20.     public  Parent() {  
  21.         System.out.println("父类--构造器" );  
  22.     }  
  23. }  
  24.   
  25. public   class  SubClass  extends  Parent {  
  26.     // 静态变量   
  27.     public   static  String s_StaticField =  "子类--静态变量" ;  
  28.     // 变量   
  29.     public  String s_Field =  "子类--变量" ;  
  30.     // 静态初始化块   
  31.     static  {  
  32.         System.out.println(s_StaticField);  
  33.         System.out.println("子类--静态初始化块" );  
  34.     }  
  35.     // 初始化块   
  36.     {  
  37.         System.out.println(s_Field);  
  38.         System.out.println("子类--初始化块" );  
  39.     }  
  40.   
  41.     // 构造器   
  42.     public  SubClass() {  
  43.         System.out.println("子类--构造器" );  
  44.     }  
  45.   
  46.     // 程序入口   
  47.     public   static   void  main(String[] args) {  
  48.         new  SubClass();  
  49.     }  
  50. }  
class Parent {
	// 静态变量
	public static String p_StaticField = "父类--静态变量";
	// 变量
	public String p_Field = "父类--变量";

	// 静态初始化块
	static {
		System.out.println(p_StaticField);
		System.out.println("父类--静态初始化块");
	}

	// 初始化块
	{
		System.out.println(p_Field);
		System.out.println("父类--初始化块");
	}

	// 构造器
	public Parent() {
		System.out.println("父类--构造器");
	}
}

public class SubClass extends Parent {
	// 静态变量
	public static String s_StaticField = "子类--静态变量";
	// 变量
	public String s_Field = "子类--变量";
	// 静态初始化块
	static {
		System.out.println(s_StaticField);
		System.out.println("子类--静态初始化块");
	}
	// 初始化块
	{
		System.out.println(s_Field);
		System.out.println("子类--初始化块");
	}

	// 构造器
	public SubClass() {
		System.out.println("子类--构造器");
	}

	// 程序入口
	public static void main(String[] args) {
		new SubClass();
	}
}

 

 

  1. 运行一下上面的代码,结果马上呈现在我们的眼前:
  2. 父类--静态变量
  3. 父类--静态初始化块
  4. 子类--静态变量
  5. 子类--静态初始化块
  6. 父类--变量
  7. 父类--初始化块
  8. 父类--构造器
  9. 子类--变量
  10. 子类--初始化块
  11. 子类--构造器

       静态代码为什么先于非静态代码这是因为静态代码是在类加载完毕后执行的,而加载类的顺序是先父类后子类,所以静态代码的执行是先执行父类的,然后执行子类 的。对于非静态变量以及实例初始化块都是在构造函数里的代码执行前执行。所以静态代码是在类加载后执行,而实例代码是在构造函数执行前执行。但是当我们显 示控制类加载的时候情况有点变化,显示加载可以有关两种方法:
第一种:利用forName方法
当我们查API文档就会发现forName方法有两种形式。分别如下:
public static Class<?> forName(String className)
throws ClassNotFoundException


public static Class<?> forName(String name,
boolean initialize,
ClassLoader loader)
throws ClassNotFoundException

第二个方法值得注意的就是第二个参数boolean initialize,如果我们把这个参数设置为false,那么当我们加载完类后就不会执行静态代码和静态的初始化动作。只有当我们new一个对象的时候才会初始化。而第三个参数是用来指明类的加载器的。
如果查看java.lang.Class类的源代码,上述两种方法最终都会调用Class类中的私有的native方法forName0(),此方法的声明如下:
private static native Class forName0(String name, boolean init , ClassLoader loader)
throws ClassNotFoundException;
所以当我们调用Class.forName(name )时,其实是在方法内部调用了:
forName0(name, true, ClassLoader.getCallerClassLoader());
当我们调用Class.forName(name, initialize, loader )的时候,实际上此方法内部调用了:
forName0(name, initialize, loader);

第二种:利用Class对象获取的ClassLoader装载。
此方法也是在实例化时才执行静态代码的执行。

综上所述可以总结如下:
1 对于隐式的加载(new一个对象和调用类的静态方法),静态代码是在类加载后立刻执行,而对于显示加载(第一种是用java.lang.Class的 forName(String str)方法,第二种是用java.lang.ClassLoader的loadClass())就如同我上面所说,加载过程是可以由我们来控制的。
2 实例化代码执行是载构造函数执行之前,涉及到继承时,父类的构造函数执行之前执行父类里的实例化代码,子类的构造函数执行之前执行子类的实例化代码。所以这样可以保证子类中用到的变量都是已经经过父类初始化的,从而保证了初始化的正确性。

分享到:
评论

相关推荐

    JAVA面试题解惑系列合集

    1.1 JAVA面试题解惑系列(一)——类的初始化顺序 1.2 JAVA面试题解惑系列(二)——到底创建了几个String对象? 1.3 JAVA面试题解惑系列(三)——变量(属性)的覆盖 1.4 JAVA面试题解惑系列(四)——final、...

    java面试题-类的初始化顺序.doc

    java面试题-类的初始化顺序.doc 大家在去参加面试的时候,经常会遇到这样的考题:给你两个类的代码,它们之间是继承的关系,每个类里只有构造器方法和一些变量,构造器里可能还有一段代码对变量值进行了某种运算,...

    2020最新Java面试题及答案(带完整目录).pdf

    这里所说的线程指程序执行过程中的一个线程实体。JVM 允许一个应用并发执行多个线程。 Hotspot JVM 中的 Java 线程与原生操作系统线程有直接的...当原生线程初始化完毕,就会调用 Java 线程的 run() 方法。当线程结束时

    JAVA面试题解惑系列类的初始化顺序JAVA程序员JAVA工程师面试必看.pdf

    JAVA面试题解惑系列类的初始化顺序JAVA程序员JAVA工程师面试必看.pdf

    JAVA面试题解惑系列——类的初始化顺序

    JAVA面试题解惑系列(一)——类的初始化顺序-JAVA程序员JAVA工程师面试必看

    Java面试题合集最新版2024.zip

    数据类型、变量与运算符:理解Java中的基本数据类型、变量声明与初始化,以及常用的运算符和表达式。 控制流语句:熟悉if-else、switch、for、while等控制流语句的用法。 面向对象编程:深入理解Java中的类、对象、...

    JAVA面试题解惑系列

    JAVA面试题解惑系列(一)——类的初始化顺序 大家在去参加面试的时候,经常会遇到这样的考题:给你两个类的代码,它们之间是继承的关系,每个类里只有构造器方法和一些变量,构造器里可能还有一段代码对变量值进行...

    JAVA面试题最全集

    60.JAVA语言国际化应用,Locale类,Unicode 61.描述反射机制的作用 62.如何读写一个文件? 63.在图形界面中,一个按钮如何处理鼠标点击事件? 64.在图形界面中,一个表格,如何实现编辑单元格时弹出下拉框? ...

    JAVA面试题解惑系列(一)——类的初始化顺序-JAVA程序员JAVA工程师面试必看.pdf

    JAVA面试题解惑系列(一)——类的初始化顺序-JAVA程序员JAVA工程师面试必看.pdf

    20个高级Java面试题汇总

    这是一个高级 Java面试系列题中的第一部分。这论述了可变参数,断言,垃圾回收初始化器令牌日期历等 Java核

    JAVA面试题解惑系列(一)——类的初始化顺序-JAVA程序员JAVA工程师面试必看.pdf,这是一份不错的文件

    JAVA面试题解惑系列(一)——类的初始化顺序-JAVA程序员JAVA工程师面试必看.pdf,这是一份不错的文件

    Java面试题解惑系列

    来自网络,主要包括以下内容:1、类初始化的顺序;2、到底创建了几个String对象;3、变量(属性)的覆盖;4、final,finally,finalize;5.传了值还是传了引用;6.String杂谈;7.日期与时间的处理;8.基本类型总结;9....

    2024年Java高工面试题 2024年Java高工面试题 2024年Java高工面试题

    2024年Java高工面试题 JVM虚拟机:堆、方法区(元空间)、栈(线程)、本地方法栈、程序计数器 栈帧:局部变理表、操作数栈、动态链接、方法出口 对象组成:对象头(Mark Word、KlassPointer类型指针、数组长度)、...

    java面试题静态加载顺序构造方法

    java面试题静态加载顺序构造方法 继承与static 面试题目如下:请写出程序执行完成之后的结果。 package extend; public class X { Y y=new Y(); static{ System.out.println("tttt"); } X(){ System....

    java面试题-附答案

    java面试题 1.JDK和JRE区别 JRE(Java Runtime Enviroment)是运行Java程序所必须环境的集合,包含JVM标准实现及 Java核心类库。它包括Java虚拟机、Java平台核心类和支持文件。它不包含开发工具(编译器、调试器等)。 ...

    java面试800题

    《java面试800题(包括java,数据库,前台等,绝对全面)》 Q0027 哪些SQL语句在执行时是自动提交的? 数据定义语言DDL是自动提交的。 Q0028 索引对数据库的影响? 提高查询速度 Q0029 主外键有什么关系? 外键是从...

    涵盖了90%以上的面试题

    java程序的初始化顺序 请说出作用域public,private,protected,以及不写时的区别 为什么java中有些接口没有任何方法 java中的clone方法有什么作用 面向对象有哪些特征 面向对象的开发方式有什么优点 组合和继承有...

Global site tag (gtag.js) - Google Analytics