虚拟机类加载机制

1、概述

 2、类加载的时机

类的生命周期

 

/**
 * @author ljy
 * @version V1.0
 * @Package PACKAGE_NAME
 * @Description:
 * 被动使用类字段演示一
 * 通过子类引用父类的静态字段,不会导子类初始化
 * @date 2018/10/26 13:20
 */

class SuperClass{

    static {
        System.out.println("SuperClass init!");
    }

    public static int value = 123;
}

class SubClass extends SuperClass{
    static {
        System.out.println("SubClass init!");
    }
}

/**
 * 非主动使用类字段演示
 */
public class NoInitialization {

    public static void main(String[] args) {
        System.out.println(SubClass.value);
    }
}

 运行

 

 

/**
 * @author ljy
 * @version V1.0
 * @Package PACKAGE_NAME
 * @Description:
 * 被动使用类字段演示二
 * 通过数组定义引用类,不会触发此类的初始化
 * @date 2018/10/26 13:20
 */

class SuperClass{

    static {
        System.out.println("SuperClass init!");
    }

    public static int value = 123;
}

class SubClass extends SuperClass{
    static {
        System.out.println("SubClass init!");
    }
}

/**
 * 非主动使用类字段演示
 */
public class NoInitialization {

    public static void main(String[] args) {
        SuperClass[] sca = new SuperClass[10];
    }
}

运行

可以看出没有触发SuperClass的初始化

 

 

/**
 * @author ljy
 * @version V1.0
 * @Package PACKAGE_NAME
 * @Description:
 * 被动使用类字段演示三
 *     常量在编译阶段会存入调用类的常量池,本质上并没有直接引用到定义常量的类,
 * 因此不会触发定义常量的类的初始化
 * @date 2018/10/26 13:20
 */
/**
 * 非主动使用类字段演示
 */

class ConstClass{
    static {
        System.out.println("ConstClass init !");
    }
    public static final String HELLOWORLD = "hello world !";
}

public class NoInitialization {

    public static void main(String[] args) {
        System.out.println(ConstClass.HELLOWORLD);
    }
}

运行后

 

 3、类加载过程

3.1、加载

 

3.2、验证 

 3.3、准备

 3.4、解析

 

 

public class FieldResolution  {

    interface interface0{
        int A=0;
    }
    interface interface1 extends  interface0{
        int A=1;
    }

    interface  interface2{
        int A=2;
    }

    static class Parent implements interface1{
        public static  int A = 3;
    }

    static class Sub extends  Parent implements  interface2{
        public static  int A = 4;
    }

    public static void main(String[] args) {
        System.out.println(Sub.A);
    }
}

jdk8下我可以正常运行

关于解析 就到这了

3.5、初始化

public class Test {

    static {
        i=0;//给变量赋值可以正常通过
        System.out.println(i);//这句编译会提示“非法引用向前”
    }
    static int i =1;

    public static void main(String[] args) {

    }
}

 运行

 

public class Test {
    //父类的client方法优先执行
    static class Parent{
        public static int A=1;
        static {
            A=2;
        }

    }
    static class Sub extends Parent{
        public static int B=A;
    }

    public static void main(String[] args) {
        System.out.println(Sub.A);
    }
}
运行

 4、类加载器

 4.1、类与类加载器

 

 

import java.io.InputStream;

/**
 * 类加载器与instanceof关键字演示
 */
public class ClassLoaderTest {

    public static void main(String[] args)throws Exception {
        ClassLoader myLoader = new ClassLoader(){
            public Class<?> loadClass(String name) throws ClassNotFoundException{
                try{
                    String fileName = name.substring(name.lastIndexOf(".") + 1) + ".class";
                    InputStream is = getClass().getResourceAsStream(fileName);
                    if(is == null){
                        return super.loadClass(name);
                    }
                    byte [] b = new byte[is.available()];
                    is.read(b);
                    return defineClass(name, b, 0,b.length);
                }catch(Exception e){
                    throw new ClassNotFoundException(name);
                }
            }
        };
        Object obj = myLoader.loadClass("ClassLoaderTest").newInstance();
        System.out.println(obj.getClass());
        System.out.println(obj instanceof ClassLoaderTest);
    }

}

运行

4.2、双亲委派模型

          从Java虚拟机的角度来说,只存在两种不同的类加载器:一种是启动类加载器(Bootstrap ClassLoader),这个类加载器使用C++语言实现(HotSpot虚拟机中),是虚拟机自身的一部分;另一种就是所有其他的类加载器,这些类加载器都有Java语言实现,独立于虚拟机外部,并且全部继承自java.lang.ClassLoader。

从开发者的角度,类加载器可以细分为:

启动(Bootstrap)类加载器:负责将 Java_Home/lib下面的类库加载到内存中(比如rt.jar)。由于引导类加载器涉及到虚拟机本地实现细节,开发者无法直接获取到启动类加载器的引用,所以不允许直接通过引用进行操作。

标准扩展(Extension)类加载器:是由 Sun 的 ExtClassLoader(sun.misc.Launcher$ExtClassLoader)实现的。它负责将Java_Home /lib/ext或者由系统变量 java.ext.dir指定位置中的类库加载到内存中。开发者可以直接使用标准扩展类加载器。

应用程序(Application)类加载器:是由 Sun 的 AppClassLoader(sun.misc.Launcher$AppClassLoader)实现的。它负责将系统类路径(CLASSPATH)中指定的类库加载到内存中。开发者可以直接使用系统类加载器。由于这个类加载器是ClassLoader中的getSystemClassLoader()方法的返回值,因此一般称为系统(System)加载器。

除此之外,还有自定义的类加载器它们之间的层次关系被称为类加载器的双亲委派模型。该模型要求除了顶层的启动类加载器外,其余的类加载器都应该有自己的父类加载器,而这种父子关系一般通过组合(Composition)关系来实现,而不是通过继承(Inheritance)。

 

 

 4.3 、破坏双亲委派模型

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值