《疯狂java讲义》读书笔记(九):类加载机制与反射

《疯狂java讲义》读书笔记(九):类加载机制与反射

像使用反射生成JDK动态代理以及AOP、反射和泛型的内容在笔记中没有涉及。后面想单独写博客巩固下,暂时写个前言mark着!

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

​ 同一个JVM的所有线程、所有变量都处于同一个进程里,都使用该JVM进程的内存区,当以下情况发生的时候,JVM进程就会被终止。

  • 程序运行到最后正常结束

  • 程序运行到使用System.exit()Runtime.getRuntime().exit()代码处结束程序

  • 程序执行过程中遇到未捕获的异常或错误而结束

  • 程序所在平台强制结束了JVM进程

    当Java程序运行结束之后,JVM进程结束,该进程在内存中的状态将会丢失。

​ 类加载或者类初始化指的是加载、连接、初始化这三个步骤。将类的class文件读入内存,并为之创建一个java.lang.Class对象,由此我们就可以是由一个类了。

​ 类的加载由类加载器完成,类加载器通常由JVM提供,这些类加载器也是前面所有程序运行的基础。

1.1 类的加载

​ 类加载器不需要等到首次使用某个类的时候才加载该类,Java虚拟机规范允许系统预先加载某些类。通过使用不同的类加载器,可以从不同来源加载类的二进制数据,一般有以下来源:

​ 1)从本地文件系统加载class文件,可以从不同来源加载类的二进制数据。

​ 2)从JAR包加载class文件。

​ 3)通过网络加载class文件

​ 4)把一个Java源文件动态编译,并执行加载。

1.2 类的连接

​ 当类被加载之后,就会生成对应的Class对象,连接阶段主要是把类的二进制数据合并到JRE中。该阶段又可以细分为验证准备解析

​ 验证主要是用于检验被加载的类是否有正确的内部结构,并和其他类协调一致,准备阶段负责为类的类变量分配内存并且设置默认初始值,解析阶段是将类的二进制数据中的符号引用替换成直接引用。

1.3 类的初始化

​ 主要是对类变量进行初始化。如果程序首次通过下面6种方式去使用某个接口或者类的话,系统就会初始化该类或接口。

  • 创建类的实例:new、反射、反序列化
  • 调用某个类的类方法
  • 访问某个类或接口的类变量,或为给类变量赋值
  • 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
  • 初始化某个类的子类
  • 直接使用java.exe命令运行某个主类

​ 需要说明的是,对于一个final型类变量,如果在编译的时候就可以确定它的值,那么它就会被当成一个宏变量,在编译的时候直接把这个类变量出现的地方替换成它的值,也就不会导致该类的初始化。使用loadClass()方法只是加载一个类,并不会初始化。

2.类加载器

​ 类加载器是将.class文件加载到内存里,然后生成对应的java.lang.Class对象。

2.1 类加载器介绍

​ 一个类被载入JVM,同一个类就不会被再次载入了。在Java里,一个类用包名+类名作为标识,但是在JVM里除了用包名+类名外,还得用类加载器作为标识,去界定是否为同一个类。

​ 当JVM启动时,会形成由三各类加载器组成的初始类加载器层次结构。Bootstrap ClassLoader:根加载器(负责加载Java的核心类,不是java.lang.ClassLoader的子类,而是JVM自身实现的)Extension ClassLoader:扩展类加载器System ClassLoader:系统类加载器

2.2 类加载机制

​ 类加载机制主要有下面三种:

1)全盘负责:当一个类加载器负责加载某个Class时,该Class所依赖的和引用的其它Class也将由该类加载器负责载入,除非显示使用另外一个类加载器来载入

2)父类委托:先让父类加载器试图加载该Class,只有在父类加载器无法加载该类时才尝试从自己的类路径中加载该类【父子关系不是继承上的含义,而是类加载器实例之间的关系,根加载器<-扩展类加载器<-系统类加载器<-用户类加载器】

3)缓存机制:保证所有加载过的Class都会被缓存,当程序中需要使用某个Class时,类加载器先从缓存区中搜索该Class,只有当缓存区不存在的时候,系统才会读取该类对应的二进制数据然后转换成Class对象,存入缓存区。所以修改了Class,必须重启JVM,程序所做的修改才会生效。

3.使用反射生成并操作对象

3.1 创建对象

​ 通过反射生成对象有2种方式:使用Class对象的newInstance()方法来创建该Class对象对应类的实例,这种方式要求改Class对象的对应类有默认构造器。执行newInstance()方法时实际是利用默认构造器来创建该类的实例。

​ 先使用Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建该Class对象对应类的实例。

3.2 调用方法

​ 当获得某个类对应的Class对象后,就可以通过该Class对象的getMethods()方法或者getMethod()方法来获取全部方法或者指定方法,返回值一个是Method数组一个是Method对象。

3.3 访问成员变量值

​ 通过Class对象的getFields()或getField()方法可以获取该类所包括的全部成员变量或指定成员变量。

3.4 操作数组

​ java.lang.reflect包下面提供了一个Array类,这个Array可以代表所有的数组,程序可以通过使用Array来动态创建数组,操作数组元素。通过Array.newInstance()可以创建数组,通过Array.set()和Array.get()可以设置参数和获取参数

发布了58 篇原创文章 · 获赞 5 · 访问量 6267

猜你喜欢

转载自blog.csdn.net/weixin_40992982/article/details/104011231
今日推荐