您的位置:首页 > 编程语言 > Java开发

深入理解Java(一)类加载原理

2016-03-14 09:27 375 查看
本文转载自http://colinwang.cn/2014/12/12/UnderstandingTheJavaClassLoadingPrinciple/

感觉作者写的很好,就转载了。

Java类加载机制这个词相信对于任何一个使用过Java的人都不会陌生,但是并不是每一个写Java程序的人都十分清楚Java类是什么时候被加载的,是什么时候被初始化的,下面我们就来分析一下吧。

类的加载

  首先要清楚,类的加载和类的初始化是不同的。类的加载是由类加载器完成的,类加载器也是一个程序,如ClassLoader类就是一个类加载器,它也是用Java语言写的,可以通过继承并重写它的方法来实现自己的类加载方式。常见的类加载方式是当用到这个类的时候,系统才加载这个类。一个JVM中可以有多个类加载器,如下图


Java类加载器的树状结构

类的初始化

  而类的初始化发生在类加载完成之后,这时会把类的静态属性初始化。当类发生以下情况时也会初始化这个类:

通过使用new关键字创建实例

使用Class.forName()反射创建实例(有可能导致ClassNotFoundException)

类的静态方法被调用

类的静态域被赋值

类的静态域被访问,而且它不是常量(没有final修饰,被final关键字修饰的常量为编译时常量,不会触发类的初始化)

在顶层类中执行assert语句

类的初始化步骤

类按照代码从上到下的顺序初始化,所以声明在顶部的字段初始化早于底部的字段

超类的初始化早于子类和衍生类

如果类的初始化是由于访问静态域而触发,那么只有该声明静态域的类被初始化,而不会触发超类或者子类的初始化,即使该类的静态域被子类或子接口或者它的实现类所引用

列表内容

接口初始化不会导致父接口的初始化

静态域的初始化在类的静态初始化期间,非静态域的初始化时在类的实例创建期间,这意味这静态域初始化在非静态域之前

非静态域通过构造器初始化,子类在做任何初始化之前构造器会隐含地调用父类的构造器

示例代码

定义父类

package org.colin.classinit;
public class SuperClass {
static {
System.out.println("SuperClass:Static block of Super class is initialized!");
}
{
System.out.println("SuperClass:Non static block of Super class is initialized!");
}
}


定义子类

package org.colin.classinit;
public class SubClass extends SuperClass {
static {
System.out.println("SubClass:Static block of Sub class is initialized!");
}
{
System.out.println("SubClass:Non static blocks of Sub class is initialized!");
}
}


定义一个不被使用的类

package org.colin.classinit;
public class NotUsedClass {
static {
System.out.println("NotUsedClass:NotUsedClass has been initialized!");
}
}


测试类

package org.colin.classinit;
public class ClassInitializationTest {
public static void main(String[] args) {
NotUsedClass notUsedClass = null;
SubClass subClass = new SubClass();
System.out.println((Object) notUsedClass == (Object) subClass);
}
}


输出结果为:

SuperClass:Static block of Super class is initialized!
SubClass:Static block of Sub class is initialized!
SuperClass:Non static block of Super class is initialized!
SubClass:Non static blocks of Sub class is initialized!
false


由此可见:

超类初始化早于子类

静态变量或代码块初始化早于非静态块和域

没使用的类根本不会被初始化,因为他没有被使用

总结

  Java类在第一次被用到的时候,被类加载器加载,接着初始化静态部分(被final关键字修饰的常量不会被初始化,因为它在编译的时候就已经确定了),如果有父类,会先进行父类的初始化(Java需要保证父类的成员初始化早于子类的成员初始化,否则,在子类中使用父类的成员变量就会出现问题)。当这个类被实例化的时候,会初始化类的非静态部分。因为静态部分是属于类本身的,类初始化就要初始化它。而非静态部分是属于具体实例的,所以在类被实例化时初始化。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息