一、概述
(一)什么是反射: 反射指的是任何一个Class类,在“运行时”都可以直接得到全部成分。
(二)动态可获取的对象: 构造器对象——Constructor,成员变量对象——Field,成员方法对象——Method。
(三)反射关键: 第一步都是得到编译后的Class对象,然后可以获得Class全部成分。
二、反射相关对象的获取
(一)获取Class对象
//过程:Hello.java -> javac -> Hello.class
Class c = Hello.class;
1、Object.forName(String className) -> 源码阶段获取
2、Object.class -> 内存阶段获取
3、Object.class() -> 实例化阶段获取
public class getClassInfoDemo {
public static void main(String[] args) {
try {
/*forName(类全名)*/
Class c = Class.forName("com.zengoo.reflected.Student");
System.out.println(c);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
/*类获取*/
System.out.println(Student.class);
/*对象获取*/
System.out.println(new Student().getClass());
}
}
class Student{
private String id;
private String name;
public Student() {
}
public Student(String id, String name) {
this.id = id;
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
'}';
}
}
/*打印输出*/
class com.zengoo.reflected.Student
class com.zengoo.reflected.Student
class com.zengoo.reflected.Student
(二)获取构造器
1、相关API
方法 | 说明 |
---|---|
Constructor>[] getConstructors() | 获取public修饰的所有构造器对象 |
Constructor>[] getDecalaredConstructors() | 获取所有构造器对象 |
Constructor> getConstructor(Class |
根据参数类型返回单个public构造器 |
Constructor> getDecalaredConstructor(Class |
根据参数类型获取单个构造器对象 |
2、获取构造器示例
public class getClassConstructorDemo {
public static void main(String[] args) {
Class c = Student.class;
//获取所有public构造器
Constructor[] c1 = c.getConstructors();
System.out.println("=============获取所有public构造器=============");
for (Constructor constructor :c1) {
System.out.println(constructor.getName() + "===>" + constructor.getParameterCount());
}
//获取所有构造器
System.out.println("=============获取所有构造器=============");
Constructor[] c2 = c.getDeclaredConstructors();
for (Constructor constructor :c2) {
System.out.println(constructor.getName() + "===>" + constructor.getParameterCount());
}
//获取单个public构造器对象
System.out.println("=============获取单个public构造器对象=============");
try {
Constructor c3 = c.getConstructor();
System.out.println(c3.getName() + "===>" + c3.getParameterCount());
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
//获取单个构造器对象
System.out.println("=============获取单个构造器对象=============");
try {
Constructor c4 = c.getDeclaredConstructor(String.class,String.class);
System.out.println(c4.getName() + "===>" + c4.getParameterCount());
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
}
/*打印输出*/
=============获取所有public构造器=============
com.zengoo.reflected.Student===>0
com.zengoo.reflected.Student===>2
=============获取所有构造器=============
com.zengoo.reflected.Student===>0
com.zengoo.reflected.Student===>2
=============获取单个public构造器对象=============
com.zengoo.reflected.Student===>0
=============获取单个构造器对象=============
com.zengoo.reflected.Student===>2
3、获取构造器并调用
(1)作用: 获取构造器的作用是为了初始化一个对象返回。
(2)相关API
方法 | 说明 |
---|---|
T newInstance(Object initargs) | 根据指定构造器创建对象 |
void setAccessible(boolean flag) | 设置true表示无视访问限制,暴力反射 |
(3)使用示例
class useConstructor{
public static void main(String[] args) throws Exception {
Constructor constructor = Student.class.getConstructor(String.class,String.class);
constructor.setAccessible(true); //暴力破解私有权限,若构造器为公开权限,则不需要
Student student = (Student) constructor.newInstance(UUID.randomUUID().toString(),"金牙齿");
System.out.println(student);
}
}
/*打印输出*/
Student{id='77430b37-a65f-4379-b181-437dc5544032', name='金牙齿'}
(三)获取成员变量
1、相关API
方法 | 说明 |
---|---|
Field>[] getFields() | 获取public修饰的所有成员变量 |
Field>[] getDeclaredFields() | 获取所有成员变量 |
Field> getField(String name) | 根据参数名称返回单个public成员变量 |
Field> getDecalaredField(String name) | 根据参数名称返回单个成员变量 |
void set(Object obj,Object value) | 给对象注入某个成员变量数据 |
Object get(Object obj) | 根据参数名称返回单个成员变量 |
void setAccessible(boolean b) | 暴力开权限 |
Class getType() | 获取属性的类型,返回Class对象 |
String getName() | 获取属性名称 |
2、使用示例
public class getClassFieldDemo {
public static void main(String[] args) throws NoSuchFieldException {
Class c = Student.class;
//获取所有public成员变量
Field[] fields = c.getFields();
for (Field f :fields) {
System.out.println(f.getType() + " " + f.getName());
}
//获取所有成员变量
Field[] fields1 = c.getDeclaredFields();
for (Field f :fields1) {
System.out.println(f.getType() + " " + f.getName());
}
//获取单个public成员变量
Field field = c.getDeclaredField("name");
System.out.println(field.getType() + " " + field.getName());
//获取单个成员变量
Field field1 = c.getDeclaredField("id");
System.out.println(field1.getType() + " " + field1.getName());
}
}
/*打印变量*/
class java.lang.String id
class java.lang.String name
class java.lang.String name
class java.lang.String id
class useField{
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
Class c = Student.class;
Field id = c.getDeclaredField("id");
Field name = c.getDeclaredField("name");
id.setAccessible(true);
name.setAccessible(true);
Student s = new Student();
id.set(s, UUID.randomUUID().toString());
name.set(s, "金钟罩");
System.out.println(id.getType() + " " + id.get(s));
System.out.println(name.getType() + " " + name.get(s));
}
}
/*打印输出*/
class java.lang.String d368bc5c-76c9-413a-ad2d-565729b7afe9
class java.lang.String 金钟罩
(四)获取成员方法
1、相关API
方法 | 说明 |
---|---|
Method[] getMethods() | 返回所有public修饰的成员方法对象的数组 |
Method[] getDeclaredMethods() | 返回所有成员方法对象的数组 |
Method getMethod(String name,Class>… parameterTypes) | 根据方法名,参数列表属性,返回单个public修饰的成员方法对象 |
Method getDecalaredField(String name,Class>… parameterTypes) | 根据方法名,参数列表属性,返回单个修饰的成员方法对象 |
void setAccessible(boolean b) | 暴力开权限 |
2、使用示例
public class getClassMethodDemo {
public static void main(String[] args) throws NoSuchMethodException {
Class c = Student.class;
//获取所有public成员方法
Method[] methods = c.getMethods();
for (Method method :methods) {
System.out.println(method.getGenericParameterTypes().toString() + " " + method.getName());
}
//获取所有成员方法
Method[] methods1 = c.getDeclaredMethods();
for (Method method :methods1) {
System.out.println(method.getGenericParameterTypes().toString() + " " + method.getName());
}
//获取单个public成员变量
Method method = c.getMethod("getName");
System.out.println(method.getGenericParameterTypes().toString() + " " + method.getName());
//获取单个成员变量
Method method1 = c.getMethod("setId", String.class);
System.out.println(method1.getGenericParameterTypes().toString() + " " + method1.getName());
}
}
/*打印输出*/
[Ljava.lang.Class;@67b64c45 getName
[Ljava.lang.Class;@68837a77 toString
[Ljava.lang.Class;@6be46e8f setName
[Ljava.lang.Class;@3567135c getId
[Ljava.lang.Class;@327471b5 setId
[Ljava.lang.Class;@4157f54e wait
[Ljava.lang.Class;@90f6bfd wait
[Ljava.lang.Class;@47f6473 wait
[Ljava.lang.Class;@15975490 equals
[Ljava.lang.Class;@6b143ee9 hashCode
[Ljava.lang.reflect.Type;@9f70c54 getClass
[Ljava.lang.Class;@234bef66 notify
[Ljava.lang.Class;@737996a0 notifyAll
[Ljava.lang.Class;@61dc03ce getName
[Ljava.lang.Class;@50f8360d toString
[Ljava.lang.Class;@2cb4c3ab setName
[Ljava.lang.Class;@13c78c0b getId
[Ljava.lang.Class;@12843fce setId
[Ljava.lang.Class;@3dd3bcd getName
[Ljava.lang.Class;@97e1986 setId
3、方法调用
class useMethod{
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
Class c = Student.class;
Constructor constructor = c.getConstructor(String.class,String.class);
constructor.setAccessible(true);
Student student = (Student) constructor.newInstance(UUID.randomUUID().toString(),"金环法");
System.out.println(student);
Method method = c.getMethod("setName", String.class);
method.setAccessible(true);
method.invoke(student,"新名称");
System.out.println(student);
}
}
/*打印输出*/
Student{id='d001810b-88e7-468d-bb8c-bc4129970191', name='金环法'}
Student{id='d001810b-88e7-468d-bb8c-bc4129970191', name='新名称'}
三、反射的作用
(一)绕过编译阶段为集合添加数据(原理是泛型擦除,即强制执行)
class useClassDemo{
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
List<Integer> list1 = new ArrayList<>();
List<Integer> list2 = new ArrayList<>();
list1.add(1);
list1.add(2);
list1.add(3);
list2.add(1);
list2.add(2);
list2.add(3);
System.out.println(list1.getClass());
System.out.println(list2.getClass());
System.out.println(list1.getClass() == list2.getClass());
System.out.println("===========================");
Class c = list2.getClass();
Method method = c.getMethod("add", Object.class);
method.invoke(list2,"字符串");
System.out.println(list1.getClass() == list2.getClass());
System.out.println(list1);
System.out.println(list2);
}
}
/*打印输出*/
class java.util.ArrayList
class java.util.ArrayList
true
===========================
true
[1, 2, 3]
[1, 2, 3, 字符串]
(二)通用框架的底层原理(重点)
用反射做通用框架示例
/**
* 需求:给定任意对象,在不清楚对象字段的情况下,将对象的字段名和对应值存储到文件中去。
*/
public class useReflectedToFrame {
public static void main(String[] args) {
Shop shop = new Shop(UUID.randomUUID().toString(),"店名","xxx市xxx区xxx街道xxx");
Goods goods = new Goods(UUID.randomUUID().toString(),"商品名",28.5);
String parentPath = "D:\\JavaBase\\JavaSEpro\\src\\com\\zengoo\\outDir\\";
TestUtil.save(shop,parentPath+"shop.txt");
TestUtil.save(goods,parentPath+"goods.txt");
System.out.println("打印完毕");
}
}
/*自定义通用框架*/
class TestUtil{
public static void save(Object obj,String pathname) {
try(PrintStream printStream = new PrintStream(new FileOutputStream(pathname))){
//1、提取对象的所有成员变量
Class c = obj.getClass();
Field[] fields = c.getDeclaredFields();
for (Field field:fields) {
field.setAccessible(true);
//2、获取变量名
String name = field.getName();
//3、获取变量名对应的值
String value = " = " + field.get(obj);
printStream.println(name + value);
}
} catch (IllegalAccessException | FileNotFoundException e) {
throw new RuntimeException(e);
}
}
}
class Shop{
private String id;
private String shopName;
private String address;
public Shop() {
}
public Shop(String id, String shopName, String address) {
this.id = id;
this.shopName = shopName;
this.address = address;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getShopName() {
return shopName;
}
public void setShopName(String shopName) {
this.shopName = shopName;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "Shop{" +
"id='" + id + '\'' +
", shopName='" + shopName + '\'' +
", address='" + address + '\'' +
'}';
}
}
class Goods{
private String id;
private String goodsName;
private double price;
public Goods() {
}
public Goods(String id, String goodsName, double price) {
this.id = id;
this.goodsName = goodsName;
this.price = price;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getGoodsName() {
return goodsName;
}
public void setGoodsName(String goodsName) {
this.goodsName = goodsName;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString() {
return "Goods{" +
"id='" + id + '\'' +
", goodsName='" + goodsName + '\'' +
", price=" + price +
'}';
}
}
shop.txt
id = cd23f6eb-91c3-4f19-adf5-654ef4602b2e
shopName = 店名
address = xxx市xxx区xxx街道xxx
goods.txt
id = 77d46cea-04ec-45dd-b806-f39179bfa37e
goodsName = 商品名
price = 28.5