黑马程序员_java类加载复习四

---------android培训、java培训期待与您交流! ---------

1.       类在JVM中的工作原理

要想使用一个Java类为自己工作,必须经过以下几个过程

1):类加载load:从字节码二进制文件——.class文件将类加载到内存,从而达到类的从硬盘上到内存上的一个迁移,所有的程序必须加载到内存才能工作。将内存中的class放到运行时数据区的方法区内,之后在堆区建立一个java.lang.Class对象,用来封装方法区的数据结构。这个时候就体现出了万事万物皆对象了,干什么事情都得有个对象。就是到了最底层究竟是鸡生蛋,还是蛋生鸡呢?类加载的最终产物就是堆中的一个java.lang.Class对象。

2):连接:连接又分为以下小步骤

验证:出于安全性的考虑,验证内存中的字节码是否符合JVM的规范,类的结构规范、语义检查、字节码操作是否合法、这个是为了防止用户自己建立一个非法的XX.class文件就进行工作了,或者是JVM版本冲突的问题,比如在JDK6下面编译通过的class(其中包含注解特性的类),是不能在JDK1.4JVM下运行的。

准备:将类的静态变量进行分配内存空间、初始化默认值。(对象还没生成呢,所以这个时候没有实例变量什么事情)

解析:把类的符号引用转为直接引用(保留

3):类的初始化: 将类的静态变量赋予正确的初始值,这个初始值是开发者自己定义时赋予的初始值,而不是默认值。

2.       类的主动使用与被动使用

以下是视为主动使用一个类,其他情况均视为被动使用!

1):初学者最为常用的new一个类的实例对象(声明不叫主动使用)

2):对类的静态变量进行读取、赋值操作的。

3):直接调用类的静态方法。

4):反射调用一个类的方法。

5):初始化一个类的子类的时候,父类也相当于被程序主动调用了(如果调用子类的静态变量是从父类继承过来并没有复写的,那么也就相当于只用到了父类的东东,和子类无关,所以这个时候子类不需要进行类初始化)。

6):直接运行一个main函数入口的类。

所有的JVM实现(不同的厂商有不同的实现,有人就说IBM的实现比Sun的要好……)在首次主动调用类和接口的时候才会初始化他们。

 

 

1.       类的加载方式

1):本地编译好的class中直接加载

2):网络加载:java.net.URLClassLoader可以加载url指定的类

3):从jarzip等等压缩文件加载类,自动解析jar文件找到class文件去加载util

4):从java源代码文件动态编译成为class文件

2.       类加载器

JVM自带的默认加载器

1):根类加载器:bootstrap,由C++编写,所有Java程序无法获得。

2):扩展类加载器:由Java编写。

3):系统类、应用类加载器:由Java编写。

用户自定义的类加载器:java.lang.ClassLoader的子类,用户可以定制类的加载方式。每一个类都包含了加载他的ClassLoader的一个引用——getClass().getClassLoader()。如果返回的是null,证明加载他的ClassLoader是根加载器bootstrap

如下代码

 这里面的指针就是C++的指针。

1.       ClassLoader的剖析

ClassLoader的loadClass方法加载一个类不属于主动调用,不会导致类的初始化。如下代码块

public Class<?> loadClass(String name)throws ClassNotFoundException {

        return loadClass(name, false);

}

protectedsynchronized Class<?> loadClass(String name, boolean resolve)

            throws ClassNotFoundException {

        // 首先判断该类型是否已经被加载

        Class c = findLoadedClass(name);

        if (c == null) {

            //如果没有被加载,就委托给父类加载或者委派给启动类加载器加载

            try {

                if (parent != null) {

//如果存在父类加载器,就委派给父类加载器加载

                    c = parent.loadClass(name, false);

                } else {

//如果不存在父类加载器,就检查是否是由启动类加载器加载的类,通过调用本地方法native Class findBootstrapClass(String name)

                    c = findBootstrapClass0(name);

                }

            } catch (ClassNotFoundException e) {

        // 如果父类加载器和启动类加载器都不能完成加载任务,才调用自身的加载功能

                c = findClass(name);

            }

        }

        if (resolve) {

            resolveClass(c);

        }

        return c;

}

几点注意:

Java中,一个类用其完全匹配类名(fully qualified class name)作为标识,这里指的完全匹配类名包括包名和类名。但在JVM中一个类用其全名和一个加载类ClassLoader的实例作为唯一标识,不同类加载器加载的类将被置于不同的命名空间.我们可以用两个自定义类加载器去加载某自定义类型(注意,不要将自定义类型的字节码放置到系统路径或者扩展路径中,否则会被系统类加载器或扩展类加载器抢先加载),然后用获取到的两个Class实例进行java.lang.Object.equals)判断,将会得到不相等的结果。

  一般尽量不要覆写已有的loadClass)方法中的委派逻辑

一般在JDK 1.2之前的版本才这样做,而且事实证明,这样做极有可能引起系统默认的类加载器不能正常工作。JVM规范和JDK文档中(1.2或者以后版本中),都没有建议用户覆写loadClass(…)方法


  最后,当一个类被加载、连接、初始化后,它的生命周期就开始了,当代表该类的Class对象不再被引用、即已经不可触及的时候,Class对象的生命周期结束。那么该类的方法区内的数据也会被卸载,从而结束该类的生命周期。一个类的生命周期取决于它Class对象的生命周期。由Java虚拟机自带的默认加载器(根加载器、扩展加载器、系统加载器)所加载的类在JVM生命周期中始终不被卸载。所以这些类的Class对象(我称其为实例的模板对象)始终能被触及!而由用户自定义的类加载器所加载的类会被卸载掉!

---------android培训、java培训期待与您交流! ---------


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值