Java类加载器 除了根类加载器之外,其他类加载器都是用Java语言书写的.
Java.lang.reflect 包下的借口和类:
Class(类) Method(方法) Filed(成员变量) Constructor(构造器) Array(数组)
Type(Class实现的接口) ParameteriaedType (带泛型参数的类型)
Proxy InvocationHandler (创建JDK动态代理和AOP之间的内在关系)
1.1.JVM 和 类
JVM进程结束:
1.程序正常结束
2.运行到使用System.exit()或者Runtime.getRuntime().exit()代码处结束程序.
3.遇到未捕获的异常或错误结束.
4.强制结束JVM进程.
1.2当程序主动使用某个类时,如果该类还未被加到内存中,则系统会通过,加载,连接,初始化三个操作进行初始化.
类加载:将类的class文件读入到内存,并为之创建一个Java.lang.Class对象.====当程序使用任何类时候,系统都会为之建立一个java.lang.Class对象.
系统中所有的类实际上也是实例, 他们都是java.lang Class 的实例.
1.3类的加载由类加载器完成,类加载器通常由JVM提供 JVM提供的这些类加载器 通常被称为系统类加载器,
开发者可以通过继承ClasssLoader 基类来创建自己的类加载器.
1.4有不同的来源加载类的二进制数据:
1.从本地系统
2.JAR包加载class文件
3.网络
4.把一个Java源文件动态编译,并执行.
1.5类加载器通常无需等到“”首次使用“”该类才加载该类,Java虚拟机规范允许系统余下你贾安琪加载一些类.
1.6 类的连接:
当类被加载后,系统为之生成一个Class对象, 接着将会进入连接阶段,连接状态负责吧类的二进制数据合并到JRE中.
类的连接:
1. 验证:是否有正确的内部结构
2. 准备:为类的类变量分配内存,设置默认值
3. 解析 : 将类的二进制数据中符号引用替换成直接引用.
1.7 类的初始化:
虚拟机负责对类进行初始化, 主要是对类变量进行初始化,在Java类中, 对类变量指定初始值有两种方式:
1.声明变量时候指定初始值
2.使用静态初始化快为类变量指定初始值.
JVM初始化步骤:
1. 程序先加载并连接该类
2. 先初始化其直接父类
3. 依次执行这些初始化语句.
类初始化的时机:
1 . 创建类的实例 (使用new操作符来创建实例)(通过反射来创建实例)(通过反序列的方法)
2. 调用某个类的类方法(静态方法)
3. 访问某个类或接口的类变量,或者为该类变量赋值
4. 使用反射方式来强制创建某个类或接口对应的 java.lang.Class 对象.(Class.forName("Person"),如果系统还未初始化Person类,则这行代码会导致Person类被初始化 ,并返回Person类对应的 java.lang.Class 对象.)
5. 初始化某个类的子类
6. 直接使用java.exe 命令来运行某个类的主类.
2.不会初始化情况
1.对于一个final型的类变量, 如果该类变量在编译时候就可以确定下来,那么这个类变量相当于“”宏变量“”.Java 编译器会在编译时直接把这个类变量出现的地方替换成它的值,因此即使程序使用该静态类变量,也不会导致该类的初始化.
2.使用ClassLoader 类的loadClass()v方法来加载某个类时候。
3. 使用Class 的forName( )静态方法才会导致强制初始化该类.
类加载器:
将 .class 文件加载到内存中,并为之生成对应的java.lang.Class 对象.
类加载器加载所有的类,系统会为之分配唯一的标识.
Java中 一个类用其全限定类名(包名和类名)作为标识;
JVM 中一个类用其全限定类名和类加载器作为全限定类名. 例如: 类名 包名 实例名
java类加载器就是在运行时候JVM中动态加载所需要的类.
-----------Java类加载器三个机制:
1. 委托:
2. 可见
3. 单一
把classpath下的那些.class文件加载进内存 , 处理后称为字节码 , 这些工作是类加载器做的.
-----------------自定义类加载器原理:
模板方法设计模式
父类:
loadClass
(类加载的流程,模板)findClass
供子类覆盖的、被loadClass
方法调用的类加载逻辑defineClass
得到class文件转换成字节码子类:覆盖findClass
方法
当JVM启动时:会形成三个类加载器组成的初始类加载器层次结构.
1. Bootstrap ClassLoader: 根类加载器 (加载Java的核心类,他并不是Java.lang.ClassLoader的子类,而是由JVM自身实现的)
2. Extension ClassLoader:扩展类加载器 (加载JRE的扩展目录(%JAVA_HOME%/jre/lib/ext或者由java.ext,dirs 系统属性指定的目录中的JAR包的类) 就可以为Java扩展核心类以外的新功能,只要把自己开发的类打包成JAR 文件,放入JAVA_HOME/jre/lib/ext 路径即可)
3. System ClassLoader : 系统类加载器 (应用类加载器 负责加载来自Java命令的-classpath选项 通过 ClassLoader.getSystemClassLoader() 来获取系统类加载器.)
JVM 的类加载机制有三种:
1. 全盘负责:当一个类加载器负责加载某个Class时,该Class 所依赖的和引用的其他Class 也将有该类加载器 负责载入,除非显示使用另外一个类加载器来载入.
2. 父类委托 : 先让Parent类加载该Class
3. 缓存机制 : 保证所有加载过得Class都会被缓存.当程序需要某个Class时类加载器加载器先从缓存区查找该Class,只有当找不到时候,才会读取该类对应的二进制数据,并转换成Class对象.
通过反射查看类信息:
在Java程序中获得Class对象通常有如下三种方式:
1.Class.forName()静态方法
2.类名.class
3.getClass()
第一种第二种都是直接根据类来取得该类的Class对象:
第二种优势:(1)代码更安全(在编译阶段就可以检查Class对象是否存在),(2) 程序性能更好(无需调用方法)
如果程序只能获得一个字符串,例如 "java.lang.String",只能使用第一种方式,使用forName()会抛异常.
Java8 在java.lang.reflect 包下新增一个 Executable抽象基类,派生出Constructor Method两个子类.
isModifiers() 方法来获取该方法或构造器的修饰符,
提供了两个方法获取该方法或参数的形参个数及形参名。
int getParameterCount(); 获取该构造器或方法的形参个数
edg: Method
Method replace =clazz.getMethod("replace",String.class,List.class); // 获取指定方法的参数个数
System.out.println("replace方法参数个数"+replace.getParameterCount());
Parameter[] getParameters(); 获取该构造器或方法的形参个数。
Parameter [] parameter = replace.getParameteres();
Class 对象 获得该类的方法(Method) 构造器(Constructor) 成员变量(Filed) 这三个类都位于java.lang.reflect 包下
--------------创建对象
1. 使用Class对象的newInstance() 方法来创建该Class对象对应类的实例,(有默认构造器)
2. 先获取指定Constructor对象。在调用Constructor对象的newInstance()方法
如果不想利用默认的构造器来创建Java对象,而利用指定的构造器来创建Java对象,则需要利用Constructor 对象.
1.获取该类的Class对象
2.利用Class对象的getConstructor() 方法来获取指定的构造器.
3.调用Constructor 的newInstance() 方法来创建java 对象.
--------------调用方法
当获得某个类对应的Class对象后, 就可以通过该对象的 getMethods() 方法 或者getMethod()方法来获取全部方法
或者指定方法 .Method 里面包含一个invoke() 方法.
---------------访问成员变量
通过Class对象的getFields() 或getField() 方法
----------------使用反射生成JDK动态代理
在java.lang.reflect 包下提供了一个Proxy 类 和一个 InvocationHandler 接口.
--------------------反射和泛型
Class类增加了泛型功能,允许使用泛型来限制Class类.