Java基础-类加载机制与反射

类加载机制与反射

Java基础第四篇-类加载机制与反射

1.类的加载、连接和初始化

JVM和类

一个Java程序启动一个Java虚拟机进程,当系统被终结时,JVM进程也会被终止。

有以下几种情况:

程序运行到最后正常结束

程序使用System.exit()结束程序

程序遇到未捕获的异常或者错误而结束

程序平台强制结束了JVM进程

类的加载

首先将类的class文件读入内存,创建一个java.lang.class对象。

类的连接

当类被加载之后,系统会生成一个对应的Class对象,接着把类的二进制数据合并到JRE中

类的初始化

虚拟机对类进行初始化,主要是静态Field进行初始化

2.类加载器

类加载器负责将.class文件加载到内存中,并生成java.lang.class对象。

类加载机制

全盘负责:当一个雷加载器负责加载某个Class时,该Class所依赖的和引用的其他Class也将由此类加载器负责载入

父类委托:先让parent类加载器试图加载该Class

缓存机制:缓存机制会保证所有加载过的Class都会被缓存,当程序需要使用某个Class时,类加载器先从缓存区找,当缓存区不存在该Class对象,系统才会读取该类对应的二进制数据,转换成Class对象,存入缓存区。这也就是为什么修改了Class,不许重新启动JVM,程序新修改才会生效。

这个例子可以获取根类加载器的核心类库:

public class ClassLoaderPropTest {

    public static void main(String[] args) throws IOException {

        ClassLoader systemLoader = ClassLoader.getSystemClassLoader();

        System.out.println("系统类加载器:" + systemLoader);

        Enumeration<URL> eml = systemLoader.getResources("");

        while (eml.hasMoreElements())
        {
            System.out.println(eml.nextElement());
        }
        ClassLoader extensionLoader = systemLoader.getParent();

        System.out.println("拓展类加载器:" + extensionLoader);

        System.out.println("拓展类加载器的加载路径" + System.getProperty("java.ext.dirs"));

        System.out.println("拓展类加载器的Parent:" + extensionLoader.getParent());
    }
}

打印结果:

系统类加载器:sun.misc.Launcher$AppClassLoader@18b4aac2
file:/IdeaProject/out/production/IdeaProject/
拓展类加载器:sun.misc.Launcher$ExtClassLoader@60e53b93
拓展类加载器的加载路径/Users/blue/Library/Java/Extensions:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/ext:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java
拓展类加载器的Parent:null

Extension Classloader被称为扩展类加载器,负责加载JRE的拓展目录中JAR包的类

从上面结果可以看出,系统类加载器的家在路径是当前程序运行路径,拓展类加载器的加载路径是jdk路径,但是拓展类加载器的父加载器是null,说明并不是根类加载器。

最后总结一下类加载器加载Class的步骤

  1. 检测Class是否再如果,如果有-> step 8
  2. 如果父类加载器不存在-> step 4,如果父类加载器存在-> step 3
  3. 请求使用父类加载器去载入Class,成功-> step 8,失败-> step 5
  4. 请求使用跟雷加载器载入Class,成功-> step 8,失败-> step 5
  5. 当前类加载器尝试寻找Class文件,找到-> step 6,失败-> step 7
  6. 从文件中载入Class,成功-> step 8
  7. 抛出ClassNotFound异常
  8. 返回java.lang.class对象

3.通过反射查看类信息

获得Class对象

由于每个类被加载后,系统都会生成一个对应的Class对象,通过该Class对象就可以访问到JVM中的这个类,获得Class对象的方式如下:

  • 使用Class类的forName(String clazzName)方法,参数是某个类的全限定类名
  • 使用某个类的class属性获取对应的Class对象,例如:Person.class
  • 使用某个对象的getClass(0方法

从Class中获取信息

大致包含了以下几个方法:

  • Constructor getConstructor(Class

4.利用反射生成并操作对象

创建对象

通过反射来生成对象有以下两种方式:

  • 使用Class对象的newInstance()方法
  • 先使用Class对象获取指定的Constructor对象,在调用Constructor对象的newInstance()方法。

举个例子:

private Object createObject(String className) throws ClassNotFoundException, IllegalAccessException, InstantiationException {

    Class<?> clazz = Class.forName(className);
    return clazz.newInstance();
}

调用方法

生成对象后,就可以通过getMethod()方法或者getMethods()方法来获取方法。

再通过invoke()方法来执行

访问属性值

通过getFields()或者getField()方法可以获取Class对象的Field。可以用以下两组方法来读取或者设置Field值

  • getXxx(Object obj):获取Field的属性值
  • setXxx(Object obj, Xxx val):将obj对象的Field设置成val值
发布了55 篇原创文章 · 获赞 37 · 访问量 14万+

猜你喜欢

转载自blog.csdn.net/blue_zy/article/details/80582055