1、概念
反射机制可以在程序运行期间获取类的信息(成员变量、构造器、成员方法等),并能操作对象的属性及方法。
类加载完成之后,在堆中产生了一个Class类型的对象(一个类中只有一个Class对象),这个对象包含了类的完整结构信息。通过这个对象得到类的结构,这个对象就像一面镜子,透过这个镜子看到类的结构,所以形象的称之为:反射
2、 Class类
- Class也是类,因此继承Object类
- Class类对象不是new出来的,而是系统创建的
- 对于某个类的Class类对象,在内存中只有一份,因为类只加载一次
- 每个类的实例都会记得自己是由那个Class实例所生成
- 通过Class可以完整的得到一个类的完整结构,通过一系列API
- Class对象是存放在堆中
- 类的字节码二进制数据,是放在方法区的(元数据),包括方法代码,变量名,方法名,访问权限等
2.1、Class类的常用方法
方法名 | 功能说明 |
Class forName(String name) | 返回指定类名name 的 Class对象 |
Object newInstance() | 调用缺省构造函数,返回该Class对象的一个实例 |
getName() | 返回此Class对象所表示的实体(类、接口、基本类型等)名称 |
Class[] getInterfaces() | 获取当前Class对象的接口 |
ClassLoader getClassLoader() | 返回该类的类加载器 |
Class getSuperClass() | 返回表示此Class所表示的实体类的超类的Class |
Constructor[] getConstructors() | 返回一个包含某些Constructor对象的数组 |
Field[] getDeclaredFields() | 返回Field对象的一个数组 |
Method getMethod(String name,Class ... paramTypes) | 返回一个Method对象,此对象的形参类型为paramType |
2.2、获取Class的几种方式
1、已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法Class.forName()来获取。多用于配置文件,读取类全路径,加载类
2、若已知具体的类,通过类的class获取,该方式最为安全可靠,程序性能最高。
例:Class clazz = Cat.class; 多用于参数传递,比如通过反射得到对应构造器对象
3、已知某个类的实例,调用该实例的getClass()方法获取Class对象。
例:Class clazz = 对象.getClass(); 多用于通过创建好的对象,获取Class对象
4、通过类加载器加载Class对象
ClassLoader cl = 对象.getClass().getClassLoader();
例:Class clazz = cl.loadClass("类的全类名")
5、基本数据类型获取Class对象
例:Class clazz = 基本数据类型.class
6、基本数据类型对应的包装类,可以通过.TYPE得到Class对象
例:Class clazz = 包装类.TYPE
2.3、获取Class类的结构信息
方法名 | 方法说明 |
getName | 获取全类名 |
getSimpleName | 获取简单类名 |
getFields | 获取所有public修饰的属性,包含本类及父类的 |
getDeclaredFields | 获取本类中所有属性 |
getMethods | 获取所有public修饰的方法,包含本类及父类的 |
getDeclaredMethods | 获取本类中所有方法 |
getConstructors | 获取本类所有public修饰的构造器 |
getDeclaredConstructors | 获取本类中所有的构造器 |
getPackage | 以Package形式返回包信息 |
getSuperClass | 以Class形式返回父类信息 |
getInterface | 以Class[] 形式返回接口信息 |
getAnnotations | 以Annotation[] 形式返回注解信息 |
3、实例
3.1、反射爆破创建实例对象
package com.tk.reflection;
import java.lang.reflect.Constructor;
/**
* 通过反射创建对象
*
* @author taoke
* @date 2022/6/1
*/
public class CreateInstance {
public static void main(String[] args) throws Exception {
//1、获取Cat类的Class对象
Class<?> clazz = Class.forName("com.tk.reflection.Cat");
//2、通过public的无参构造器创建实例
Object o = clazz.newInstance();
System.out.println(o);
//3.1 得到对应的构造器
Constructor<?> constructor = clazz.getConstructor(String.class);
//3.2 创建实例,并传入参数
Object instance = constructor.newInstance("taoke");
System.out.println("instance=" + instance);
//4.1、通过非public的有参构造创建实例
//爆破(暴力破解),使用反射可以访问private构造器/方法/属性,反射面前,都是纸老虎
Constructor<?> constructor1 = clazz.getDeclaredConstructor(String.class, int.class);
constructor1.setAccessible(true);
//4.2、创建实例
Object instance1 = constructor1.newInstance("taoke", 18);
System.out.println("instance1=" + instance1);
}
}
class Cat {
public String name;
private int age;
public Cat() {
}
public Cat(String name) {
this.name = name;
}
private Cat(String name, int age) {
this.name = name;
this.age = age;
}
public void hello() {
System.out.println("喵喵喵:" + name);
}
@Override
public String toString() {
return "Cat{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
3.2、反射爆破操作属性
package com.tk.reflection;
import java.lang.reflect.Field;
/**
* 通过反射创建对象
*
* @author taoke
* @date 2022/6/1
*/
public class CreateInstance {
public static void main(String[] args) throws Exception {
//1、获取Cat类的Class对象
Class<?> clazz = Class.forName("com.tk.reflection.Cat");
//2、通过public的无参构造器创建实例
Object o = clazz.newInstance();
System.out.println(o.getClass());
//使用反射获取name属性
Field nameField = clazz.getField("name");
//通过反射操作属性
nameField.set(o, "zhangsan");
System.out.println(o);
//使用反射操作age属性
Field ageField = clazz.getDeclaredField("age");
ageField.setAccessible(true);
ageField.set(o, 20);
System.out.println(o);
}
}
class Cat {
public String name;
private int age;
public Cat() {
}
public Cat(String name) {
this.name = name;
}
private Cat(String name, int age) {
this.name = name;
this.age = age;
}
public void hello() {
System.out.println("喵喵喵:" + name);
}
@Override
public String toString() {
return "Cat{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
3.3、反射爆破操作方法
package com.tk.reflection;
import java.lang.reflect.Method;
/**
* 通过反射创建对象
*
* @author taoke
* @date 2022/6/1
*/
public class CreateInstance {
public static void main(String[] args) throws Exception {
//1、获取Cat类的Class对象
Class<?> clazz = Class.forName("com.tk.reflection.Cat");
//2、通过public的无参构造器创建实例
Object o = clazz.newInstance();
System.out.println(o.getClass());
//3、得到hello方法
Method method = clazz.getMethod("hello", String.class);
//3.1 调用方法
method.invoke(o, "taoke");
//4、得到 hi方法
Method declaredMethod = clazz.getDeclaredMethod("hi", String.class);
//4.1、因为 hi() 是私有方法,所以需要爆破
declaredMethod.setAccessible(true);
//4.2 调用 hi()
declaredMethod.invoke(o, "taoke");
}
}
class Cat {
public String name;
private int age;
public Cat() {
}
public Cat(String name) {
this.name = name;
}
private Cat(String name, int age) {
this.name = name;
this.age = age;
}
public void hello(String name) {
System.out.println("喵喵喵~" + name);
}
private void hi(String name) {
System.out.println("hi~" + name);
}
@Override
public String toString() {
return "Cat{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}