关键字: java 面试题 初始化
作者:臧圩人(zangweiren)
网址:http://zangweiren.iteye.com
>>>转载请注明出处!
<<<
大家在去参加面试的时候,经常会遇到这样的考题:给你两个类的代码,它们之间是继承的关系,每个类里只有构造器方法和一些变量,构造器里可能还有
一段代码对变量值进行了某种运算,另外还有一些将变量值输出到控制台的代码,然后让我们判断输出的结果。这实际上是在考查我们对于继承情况下类的初始化顺
序的了解。
我们大家都知道,对于静态变量、静态初始化块、变量、初始化块、构造器,它们的初始化顺序依次是(静态变量、静态初始化块)>(变量、初始化块)>构造器。我们也可以通过下面的测试代码来验证这一点:
- 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();
- }
- }
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();
}
}
运行以上代码,我们会得到如下的输出结果:
- 静态变量
- 静态初始化块
- 变量
- 初始化块
- 构造器
这与上文中说的完全符合。那么对于继承情况下又会怎样呢?我们仍然以一段测试代码来获取最终结果:
- 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();
- }
- }
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();
}
}
- 运行一下上面的代码,结果马上呈现在我们的眼前:
- 父类--静态变量
- 父类--静态初始化块
- 子类--静态变量
- 子类--静态初始化块
- 父类--变量
- 父类--初始化块
- 父类--构造器
- 子类--变量
- 子类--初始化块
- 子类--构造器
静态代码为什么先于非静态代码这是因为静态代码是在类加载完毕后执行的,而加载类的顺序是先父类后子类,所以静态代码的执行是先执行父类的,然后执行子类
的。对于非静态变量以及实例初始化块都是在构造函数里的代码执行前执行。所以静态代码是在类加载后执行,而实例代码是在构造函数执行前执行。但是当我们显
示控制类加载的时候情况有点变化,显示加载可以有关两种方法:
第一种:利用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. **super()与 this()的区别** `super()`用于调用父类的构造器,确保子类实例化时父类的初始化;`this()`则...
数据类型、变量与运算符:理解Java中的基本数据类型、变量声明与初始化,以及常用的运算符和表达式。 控制流语句:熟悉if-else、switch、for、while等控制流语句的用法。 面向对象编程:深入理解Java中的类、对象、...
在面试中,面试官可能会通过这种类型的题目来评估应聘者对Java内存模型的理解,以及他们在编写代码时是否能考虑到这些初始化规则,从而避免潜在的陷阱。因此,掌握类的初始化顺序是每个Java开发者必备的知识点。
以上是对“JAVA面试题2019”中提及的一些核心知识点的总结,涵盖了项目介绍、Java基础知识、并发编程、Spring框架、Netty框架以及分布式系统等方面的知识点。这些知识点不仅对于准备Java面试至关重要,同时也是Java...
- 确保所有成员变量在构造方法中被初始化后就不会再被修改。 2. **重载(Overload)与重写(Override)的区别:** - **重载**:在同一类中,方法名相同但参数列表不同(参数个数、类型或顺序不同)。 - **重写**...
Java 面试题大全 Java 是一种广泛使用的编程语言,本文总结了 Java 面试中常见的知识点,涵盖了 Java 基础、字符串操作、数据类型、运算符、抽象类等方面的知识。 Java 基础 1. JDK 和 JRE 的区别:JDK(Java ...
【中兴软创Java面试题】是一份2018年的面试资料,涵盖了针对Java开发者在中兴软创面试过程中可能会遇到的问题。这份资源对于准备Java面试,特别是中兴软创公司的面试者来说,是非常宝贵的参考资料。以下是根据这份...
JVM类加载机制指的是JVM如何加载Java类的过程,它包括加载、验证、准备、解析、初始化等几个阶段。类加载器负责加载类文件,包括启动类加载器、扩展类加载器和应用程序类加载器。双亲委派模型是类加载机制中的一种...
Java面试题超详细解答 Java作为一门广泛应用的编程语言,其面试题目涵盖了众多知识点,从基础语法到高级特性,从理论概念到实际应用。这里我们将深入探讨这些面试题所涉及的Java技术要点。 1. **Java基础** - **...
`final`关键字在JAVA中有多种用途,它可以用来声明常量,表示该变量的值一旦初始化后就不能改变。同时,final也可以用来防止类的继承或方法的重写,从而保证代码的稳定性和安全性。 ### 7. Heap与Stack的区别 堆...
【JAVA面试题】Java语言是IT领域广泛应用的编程语言,面试中经常涉及到其核心概念和技术。以下是基于给定内容的一些详细知识点: 1. **面向对象的特征**:面向对象编程的四大特征是抽象、继承、封装和多态。 - ...
### 深圳各公司Java面试题精要解析 #### 中联宏达 - Struts面试题解析 **1. 如何定义FormBean?** FormBean是Struts框架中用于封装表单数据的类,通常继承自`org.apache.struts.action.ActionForm`。定义FormBean...
Java面试题是每个Java开发者在求职过程中必须面对的挑战,涵盖的范围广泛,涉及语言基础、数据库、并发编程、设计模式等多个领域。这份"java面试题总结资料"应该包含了作者精心整理的各类常见问题和解答,旨在帮助...
《JAVA面试题解惑系列合集》这篇文章详细地讨论了Java面试中常见的一些知识点和问题。它包括了从类的初始化顺序、String对象的创建数量、变量的覆盖、final关键字、传值和传引用的区别、字符串的处理、日期和时间的...
**1.1 JAVA面试题解惑系列(一)——类的初始化顺序** - **知识点**:类的初始化顺序涉及静态变量、静态初始化块、实例变量、实例初始化块及构造器的执行顺序。在继承关系中,父类的初始化先于子类进行,且静态部分...
Java和Android面试题涵盖了许多核心概念,以下是这些知识点的详细说明: 1. **面向对象** (Object-Oriented Analysis and Design Principle, OOADP): 面向对象编程是Java和Android开发的基础,它涉及类、对象、继承...
### JavaSE面试题知识点梳理 #### 一、Java 跨平台原理 Java 语言的核心优势之一在于其跨平台性,即“一次编写,到处运行”(Write Once, Run Anywhere)。这种特性主要得益于 Java 字节码(Bytecode)及其运行...
Java 面试题大全 2023 版 Java 是一种广泛使用的编程语言,面试中经常会出现各种问题,本文档总结了 Java 面试题大全 2023 版,其中涵盖了 Java 基础、Java 集合、Java 多线程、Java 网络编程等方面的知识点。 一...
### 2024年Java基础面试题及解析 #### 1. 什么是 Java? **答案解析:** Java 是一种广泛使用的高级编程语言,由 Sun Microsystems 在 1995 年开发并发布。它的主要特点包括面向对象、平台独立性、安全性、可移植...