#Java 类加载 反射

什么是类加载机制
一般JVM使用 Java 类的流程为:先将.java文件编译成.class文件,然后类加载器会读取这个 .class 文件,并转换成 java.lang.Class 的实例。
Java类加载器
针对.class文件的不同类型,Java提供了至少四种ClassLoader 来加载。

  1. BootstrapClassLoader:被称为根加载器,主要用来加载Java核心类,即$JAVA_HOME/jre/lib 里的核心 jar 文件。如 java.lang、java.math、java.io 等 package 内部的这些Java 运行的基础类。同时,该类比较特殊,不继承Java提供的ClassLoader,而是由JVM内部实现。
  2. ExtClassLoader:被称为拓展加载器,主要用来加载Java核心拓展类。即 $JAVA_HOME/jre/lib/ext 目录下的 jar 文件。
  3. AppClassLoader:被称为系统加载类,主要用来加载用户在项目中自己编写的类。
  4. 另外一种是如果要想远程加载一个类,就必须定义实现一个ClassLoader,并实现其中的findClass()。

那么这几种加载类到底是如何工作的呢?
在Java中采用双亲委托的机制来加载,简单来说每次需要加载一个类,先获取一个AppClassLoader的实例,然后向上级层层请求,由最上级优先去加载,如果上级加载不了,在有各子级去自行加载。
验证代码如下:

     public class ClassLoaderTest {
    public static void main(String[] args) throws ClassNotFoundException
    {
            Class<?> clazz = Class.forName("com.neu.liuxi.Person");
            ClassLoader classLoader = clazz.getClassLoader();
            System.out.println("ClassLoader is "+classLoader.getClass().getSimpleName());
            while(classLoader.getParent()!=null){
                classLoader = classLoader.getParent();
                System.out.println("Parent ClassLoader is "+classLoader.getClass().getSimpleName());
            }
    }
}

打印结果:
ClassLoader is AppClassLoader
Parent ClassLoader is ExtClassLoader
由此说明,的确是按照双亲委托机制进行加载。因为BootstrapClassLoader较为特殊,不继承子ClassLoader,所以看不到。但是源码实现中有体现。

源码分析
下面看一下该机制的实现代码,加深理解。

protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // 首先,检查是否已经被加载
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    if (parent != null) {
                        // 让 parent 加载器去加载
                        c = parent.loadClass(name, false);
                    } else {
                        //如无 parent,说明当前是BootstrapClassLoader,调用 本地方法去 JVM 加载
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }

                if (c == null) {
                   // 如果 parent 均没有加载到目标class,调用自身的 findClass() 方法去搜索
                    // to find the class.
                    long t1 = System.nanoTime();
                    //找到class文件并把字节码加载到内存中
                    c = findClass(name);

                    // this is the defining class loader; record the stats
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
            //加载完字节码后,会根据需要进行验证、解析。由子类实现
                resolveClass(c);
            }
            return c;
        }
    }

反射
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。注意:反射是在运行的时候进行的,不是在编译的时候运行的。
Java反射机制主要提供了以下功能:

1在运行时判断任意一个对象所属的类。
2在运行时构造任意一个类的对象。
3在运行时判断任意一个类所具有的成员变量和方法。
4在运行时调用任意一个对象的方法,生成动态代理。

获取Java对象

//调用某个类的class属性来获取该类对应的class对象
Class<?> person2 = Person.class;
//使用Class类的forName(String className)静态方法。
Class<?> person = Class.forName("com.neu.liuxi.Person");
//调用某个对象的getClass方法。
 Person person = new Person(null, 0);  
 Class<?> class3 = person.getClass();
  • Class类提供了四个public方法,用于获取某个类的构造方法。
Constructor getConstructor(Class[] params)     根据构造函数的参数,返回一个具体的具有public属性的构造函数
Constructor getConstructors()     返回所有具有public属性的构造函数数组
Constructor getDeclaredConstructor(Class[] params)     根据构造函数的参数,返回一个具体的构造函数(不分public和非public属性)
Constructor getDeclaredConstructors()    返回该类中所有的构造函数数组(不分public和非public属性)
  • 四种获取成员方法的方法
Method getMethod(String name, Class[] params)   
   根据方法名和参数,返回一个具体的具有public属性的方法 Method[] getMethods()   
   返回所有具有public属性的方法数组 Method getDeclaredMethod(String name, Class[]
   params)    根据方法名和参数,返回一个具体的方法(不分public和非public属性) Method[]
   getDeclaredMethods()    返回该类中的所有的方法数组(不分public和非public属性)
  • 四种获取成员属性的方法
Field getField(String name)    根据变量名,返回一个具体的具有public属性的成员变量
Field[] getFields()    返回具有public属性的成员变量的数组
Field getDeclaredField(String name)    根据变量名,返回一个成员变量(不分public和非public属性)
Field[] getDelcaredField()    返回所有成员变量组成的数组(不分public和非public属性)

反射实例涉及代码地址

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值