一、类加载
类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构。类的加载的最终产品是位于堆区中的Class对象实例。Class对象封装了类在方法区内的数据结构,并且向Java程序提供了访问方法区内的数据结构的方法
类加载并不需要等到某个类被“首次主动使用”时再加载它,JVM规范允许类加载器在预料某个类将要被使用时就预先加载它,如果在预先加载的过程中遇到了.class文件缺失或存在错误,类加载器必须在程序首次主动使用该类时才报告错误(LinkageError错误)如果这个类一直没有被程序主动使用,那么累加载器就不会报告错误
- 类加载的几个阶段
加载: 查找并加载类的二进制数据。(把类的.class文件的二进制数据读入内存,存放在运行时数据区的方法区;类加载的最终结果是产生 堆区中描述对应类的Class对象);
连接: 包括验证、准备和解析三个子阶段;
☞☞☞验证:确保补加载类的正确性;
☞☞☞准备:为类的静态变量分配内存,并设定默认值;
☞☞☞解析:把类中的符号引用转换为直接引用;
初始化: 给类中的静态变量赋予正确的初始值;
- 类加载器
Java虚拟机自带以下几种加载器:
☞☞☞启动(Bootstrap)类加载器: 没有父类加载器。负责加载虚拟机核心类,sun.boot.class.path路径下类库,java.lang.*; 实现依赖于底层操作系统,没有继承java.lang.ClassLoader;(系统提供的)
☞☞☞扩展(Extension)类加载器: 父加载器为根加载器;加载java.ext.dirs下的类库 和 JDK目录下jre/lib/ext目录下类库;继承于java.lang.ClassLoader;
☞☞☞应用程序(Application)类加载器: 也称应用类加载器,父加载器为扩展类加载器;加载classpath路径下指定的类库;继承于java.lang.ClassLoader,也是自定义加载器的默认父类;(自己写的类) - 反射—获取字节码文件对象的三种方式
一个类的组成部分 - 构造方法
- 成员方法
- 成员变量
想要通过一个字节码文件获取里面的上述成员,必须先将字节码文件转换成字节码文件对象
获取字节码文件对象的三种方式: - Class clazz = Person.class
- Person p = new Person(); Class clazz2 = p.getClass()
- Class clazz3 = Class.forName(“类路径”);(开发中最常用)
代码实现:
package cn.edu360;
public class ReflectDemo {
public static void main(String[] args) throws Exception {
//①
Class clazz = Person.class;
//②
Person p = new Person();
Class clazz2 = p.getClass();
//③
Class clazz3 = Class.forName("cn.edu360.Person");
System.out.println(clazz == clazz2);//true
System.out.println(clazz == clazz3);//true
}
}
Person.java
package cn.edu360;
public class Person{
private String name;
private int age;
private String address;
private char sex;
public Person() {
}
Person(String name, int age){
this.name = name;
this.age = age;
}
private Person(String name,char sex){
this.name = name;
this.sex = sex;
}
public void show(){
System.out.println("show");
}
protected void test(String msg){
System.out.println(msg);
}
int getNum(int a, int b){
return a+b;
}
}
- 获取构造方法并创建对象
访问所有的构造方法,方法比较多,开发中最常用的就一个 - public Constructor getDeclaredConstructors(相应参数)
- public void setAccessible(boolean flag)值为true则取消java语法检查
注意事项:构造方法对象一般是用来创建对象的
代码实现:
package cn.edu360;
import java.lang.reflect.Constructor;
public class ReflectConstructor {
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("cn.edu360.Person");
Constructor c = clazz.getDeclaredConstructor(String.class, char.class);
c.setAccessible(true);//暴力反射
Object object = c.newInstance("王五",'男');
System.out.println(object);
}
}
Person.java
package cn.edu360;
public class Person{
private String name;
private int age;
private String address;
private char sex;
public Person() {
}
Person(String name, int age){
this.name = name;
this.age = age;
}
private Person(String name,char sex){
this.name = name;
this.sex = sex;
}
public void show(){
System.out.println("show");
}
protected void test(String msg){
System.out.println(msg);
}
int getNum(int a, int b){
return a+b;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", address=" + address
+ ", sex=" + sex + "]";
}
}
- 获取成员方法对象并使用
- public Object invoke(Object obj, Object … args)该方法对象想在obj对象上面调用,参数为args
obj-------从中调用底层方法的对象
args-----用于方法调用的参数
案例展示:
package cn.edu360;
import java.lang.reflect.Method;
public class ReflectConstructor {
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("cn.edu360.Person");
Method method = clazz.getDeclaredMethod("show2", String.class);
method.setAccessible(true);//暴力反射,取消java语法检查
Object result = method.invoke(clazz.newInstance(), "我是结果");
System.out.println(result);
}
}
- 注册与登录图解说明