Java反射——Class和ClassLoader

概述

当你准备招待客人时,如果你知道你的客人是谁,那么直接去迎合他的喜好就好了。
但如果你还并不清楚具体客人是谁,那你需要注意了,你所做的准备,要适合所有的客人。

类是对对象的抽象,类的属性、方法、继承关系,其对象都同样拥有。同理,在很多场景下,我们需要对不同的类做一定的归类、合并和统一处理。这样,我们就需要对不同的类做一定的抽象,才能达到我们的目的。也就是说,在编译阶段,我们并不知道具体的类是谁,而真正的类是动态赋予的,由此,引出反射系列。

API

反射相关的类主要在java.lang 和 java.lang.reflect包下。
其中,java.lang下主要有以下两个。

1、Class

类是对象的抽象,Class就是所有类的抽象。
也可以说,Class表示类的类类型。

public final class Class<T> implements java.io.Serializable,
                              GenericDeclaration,
                              Type,
                              AnnotatedElement {
                              }
 

私有构造方法,仅JVM能创建Class对象。

   private Class(ClassLoader loader) {
       // Initialize final field for classLoader.  The initialization value of non-null
       // prevents future JIT optimizations from assuming this final field is null.
       classLoader = loader;
   }

重要方法:
a.创建类型的方法
newInstance()
创建类的新的实例-通过类类型可以创建类的实例对象(需要有无参构造方法)

b.查询类型的方法

forName()
根据给定的string 类名、类加载器(可选)返回相对应的Class对象

public static Class<?> forName(String className)
            throws ClassNotFoundException {
    Class<?> caller = Reflection.getCallerClass();
    return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}


public static Class<?> forName(String name, boolean initialize,
                                   ClassLoader loader)
        throws ClassNotFoundException
    {
        Class<?> caller = null;
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            // Reflective call to get caller class is only needed if a security manager
            // is present.  Avoid the overhead of making this call otherwise.
            caller = Reflection.getCallerClass();
            if (sun.misc.VM.isSystemDomainLoader(loader)) {
                ClassLoader ccl = ClassLoader.getClassLoader(caller);
                if (!sun.misc.VM.isSystemDomainLoader(ccl)) {
                    sm.checkPermission(
                        SecurityConstants.GET_CLASSLOADER_PERMISSION);
                }
            }
        }
        return forName0(name, initialize, loader, caller);
    }

    /** Called after security check for system loader access checks have been made. */
    private static native Class<?> forName0(String name, boolean initialize,
                                            ClassLoader loader,
                                            Class<?> caller)
        throws ClassNotFoundException;

可以看到,forName()重载方法,最终都调用了native方法forName0()。其中,forName(String className)方法中设置initialize为true。

注意:
a.指定的类加载器是用于加载类或者接口的。
b.若该方法中,未给出指定的加载器,会通过bootstrap类加载来加载相应的类。
c.当参数中的initialize为true,并且该类之前未被初始化过,才会对类进行初始化。

补充:其他获取Class的方式
类名为A

  • A.class (class是类的隐含的静态成员变量)
  • new A().getClass() (Object的方法getClass)

涉及到类加载机制的部分,下一篇详细说明。

其他查询方法:
getName()
getClassLoader()
getField()
getMethod()
getConstructors()

2、ClassLoader

public abstract class ClassLoader {
}

默认类加载器

先看几个简单的例子:

ps:注释为打印结果,其中,由于Bootstrap ClassLoader为C++语言编写,在java下无法打印,因此得到的打印结果为null。

        System.out.println(ClassTest.class.getClassLoader());//AppClassLoader 
        System.out.println(ClassTest.class.getClassLoader().getParent());//ExtClassLoader加载器
        System.out.println(ClassTest.class.getClassLoader().getParent().getParent());//Bootstrap加载器,打印结果为null

由上可知,类加载器有三种默认类型:Bootstrap ClassLoader、ExtClassLoader、AppClassLoader。那这三个有什么分别呢?

  • Bootstrap ClassLoader:Java中最顶层的类加载器,负责加载JDK中的核心类库,如:rt.jar、resources.jar、charsets.jar等。
  • ExtClassLoader:主要负责加载Java的扩展类库,负责加载JDK中的扩展类库。其父类加载器为Bootstrap ClassLoader。
  • AppClassLoader:应用类加载器(系统类加载器),负责加载classpath路径下的jar包。其父类加载器为ExtClassLoader。

除了这三个默认类加载器,当然用户可以自定义类加载器,但自定义类加载器的父类是AppClassLoader。关系如下:
在这里插入图片描述
那么一个类到底是如何加载的呢?这几个默认类加载器之间是如何工作的呢?

双亲委派

首先,明确下类加载亲在jvm内存模型中的位置。
在这里插入图片描述
什么是双亲委派?
若一个类加载器要加载一个类,先看其父类是否能加载,以此类推,直到最顶层的Bootstrap ClassLoader,若顶层类加载器可以加载即进行加载,若无法加载,才有最初的类加载器进行加载。

通俗的说,儿子接到活之后,一律不自己做,先给了爸爸,爸爸给了爷爷,爷爷如果可以做就做,不能做,再由儿子一层一层检查是否可以做。

为什么要用这种实现方式?

  • 安全
    若用户自定义了核心或扩展类库中的同名类,则不会被成功加载,因为这些系统默认类已由默认类加载器加载。

  • 避免重复加载
    类加载器之间有了层次优先级关系,就避免了类的重复加载。

java.lang.reflect包下的主要类有:
1、Field
该类提供了动态访问、设置类或接口的字段功能。

public final
class Field extends AccessibleObject implements Member {
}

2、Method
3、Constructor
4、Array

小结

本篇介绍了反射中的常用的相关类,Class和ClassLoader,介绍了Class抽象的思维,以及类加载机制的“双亲委派”机制。下篇我们重点介绍本文中说明的reflect包的代理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值