反射定义
反射允许程序在运行期通过reflection API操作对象。因为每个对象加载后都会产生一个Class对象,可以通过这个对象获取该类的结构(方法、属性、注解…),这个对象像一面镜子一样,看到它就好像看到了该类,所以称之为反射。
反射原理
反射api
反射的优缺点
优点:可以动态的创建和使用对象(也是框架底层核心),使用灵活,没有反射机制,框架技术就失 去了底层支撑。
缺点:基本上是解释执行,效率比较低,可以通过取消边界检查提高一定效率。
Class类对象
1、Class也是类,因此也继承Object类、
2、Class类对象不是new出来的,而是系统创建的
进入方法中:
首先先获取类加载器
获取到类加载器返回Class对象
3、对于某个类的Class类对象,在内存中只有一份,因此类只加载一次
4、每个类的实例都会记得自己是由那个Class实例所生成
5、通过Class对象可以完整地得到一个类的完整结构,通过一系列API
6、Class对象是存放在堆的
7、类的字节码二进制数据,是放在方法区的,有的地方称之为类的元数据(包括方法代码、变量名、方法区、访问权限等等)
Class类方法
//1、获取Class对象的方式(6种)
//(1)通过Class.forName();
String classAllPath="com.st.reflection.Cat";//一般通过配置文件获取
Class<?> cls1 = Class.forName(classAllPath);
//(2)通过类名.class
Class<Cat> cls2 = Cat.class;
//(3)通过对象获取
Cat cat = new Cat();
Class cls3 = cat.getClass();
//(4)通过类加载器获取
ClassLoader classLoader = cat.getClass().getClassLoader();//获取类加载器
Class<?> cls4 = classLoader.loadClass(classAllPath);
//(5)基本数据类型通过类型.class获取
Class<Integer> intCls = int.class;
//(6)包装类型通过类型.TYPE获取
Class<Integer> integerCls = Integer.TYPE;
哪些类型有Class对象
1、外部类,成员内部类,静态内部类,局部内部类,匿名内部类
2、interface:接口
3、数组
4、enum:枚举
5、annotation:注解
6、基本数据类型
7、void
类加载
静态加载:编译时加载相关的类,如果没有则报错,依赖性太强。
动态加载:运行时加载需要的类,如果运行时不用该类,则不报错,降低了依赖性。
1、加载loading:JVM在该阶段的主要目的是将字节码从不同的数据源(可能是class文件、也可能是jar包,甚至是网络)转化为二进制字节流加载到内存中,并生成一个代表该类的java.lang. Class对象
2、连接阶段-验证:目的是为了确保Class文件的字节流包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。包括:文件格式验证(是否以魔数oxcafebabe开头)、元数据验证、字节码验证和符号引用印证。可以考虑使用-Xverify:none参数来关闭大部分的类验证措施,缩短虚拟机类加载的时间。
3、连接阶段-准备:JVN会在该阶段对静态变量,分配内存并默认初始化。这些变量所使用的内存都将在方法区中进行分配。这里只是针对静态变量,对于静态常量则直接赋常量值。
4、连接阶段-解析:JVM将常量池内的符号引用替换为直接引用的过程。
5、初始化:到初始化阶段,才真正开始执行类中定义的Java程序代码,此阶段是执行()方法的过程。()方法是由编译器按语句在源文件中出现的顺序自动收集类中的所有静态变量的赋值动作和静态代码块中的语句,并进行合并。JVM会保证一个类的()方法在多线程环境中被正确地加锁、同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的()方法,其他线程都需要阻塞等待,直到活动线程执行()方法完毕。
反射创建对象、设置属性测试代码
package com.st.reflection;
public class B {
public String id="001";
private static String desc="B类描述";
private String name="张三";
private int age=12;
public B(){
}
public B(String name){
this.name=name;
}
private B(String name,int age){
this.name=name;
this.age=age;
}
@Override
public String toString() {
return "B{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", age=" + age +"desc:"+desc+
'}';
}
}
public static void m2() throws Exception{
//获取Class对象
Class bCls = B.class;
Object o = bCls.newInstance();
System.out.println(o);
Constructor constructor = bCls.getConstructor(String.class);
Object o2 = constructor.newInstance("李四");
System.out.println(o2);
Constructor constructor1 = bCls.getDeclaredConstructor(String.class, Integer.TYPE);
//反射爆破,可以访问私有的构造器
constructor1.setAccessible(true);
Object o3 = constructor1.newInstance("李四", 20);
System.out.println(o3);
}
public static void m3() throws Exception{
Class<B> bCls = B.class;
Object o = bCls.newInstance();
//public String id="001";公有属性赋值
Field id = bCls.getField("id");
id.set(o, "002");
System.out.println(o);
//private static String desc="B类描述";静态私有属性赋值
Field desc = bCls.getDeclaredField("desc");
desc.setAccessible(true);
desc.set(null, "B类描述重新赋值");
System.out.println(o);
}