概述
Reflection(反射) 是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说“自审”,也有称作“自省”。反射非常强大,它甚至能直接操作程序的私有属性。我们前面学习都有一个概念,private的只能类内部访问,外部是不行的,但这个规定被反射赤裸裸的打破了。
反射就像一面镜子,它可以在运行时获取一个类的所有信息,可以获取到任何定义的信息(包括成员变量,成员方法,构造器等),并且可以操纵类的字段、方法、构造器等部分。
反射运用基础
基础测试类
package com.cy;
import java.util.Objects;
public class Shop {
public final Integer NUMBER = 10;
public final String BRAND = "BRAND";
private String name;
private Integer price;
private Integer sales;
public Shop() {
System.out.println("-----我是公有无参构造方法-----");
}
private Shop(String name, Integer price) {
System.out.println("-----我是私有有参构造方法-----");
this.name = name;
this.price = price;
}
public Shop(String name, Integer price, Integer sales) {
System.out.println("-----我是公有有参构造方法-----");
this.name = name;
this.price = price;
this.sales = sales;
}
private void priMethod() {
System.out.println("-----我是私有方法-----");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getPrice() {
return price;
}
public void setPrice(Integer price) {
this.price = price;
}
public Integer getSales() {
return sales;
}
public void setSales(Integer sales) {
this.sales = sales;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Shop shop = (Shop) o;
return name.equals(shop.name) &&
price.equals(shop.price) &&
sales.equals(shop.sales);
}
@Override
public int hashCode() {
return Objects.hash(name, price, sales);
}
@Override
public String toString() {
return "Shop{" +
"name='" + name + '\'' +
", price=" + price +
", sales=" + sales +
'}';
}
}
获取类对象属性
Class.forName(“类路径”) – 获取类对象
getPackage().getName() – 获取包名
getName() – 获取完整类名
getSimpleName() – 类名,不含包名
测试:
@Test
public void test1() throws Exception{
Class c = Class.forName("com.cy.Shop");
String packageName = c.getPackage().getName();
String className = c.getName();
String simpleName = c.getSimpleName();
System.out.println("packageName: " + packageName);
System.out.println("className: " + className);
System.out.println("simpleName: " + simpleName);
}
运行结果:
获取成员变量定义信息
getFields() – 获得所有公开的成员变量,包括继承的变量
getDeclaredFields() – 获得本类定义的成员变量,包括私有,不包括继承的变量
getField(变量名) – 获取指定成员变量
getDeclaredField(变量名) – 获得指定本类定义的成员变量
测试:
@Test
public void test2() throws Exception{
Shop shop = new Shop();
Class c = shop.getClass();
Field[] fields = c.getFields();
for (Field field : fields) {
System.out.println(field.toString());
}
System.out.println("-----------------------------");
Field[] declaredFields = c.getDeclaredFields();
for (Field field : declaredFields) {
System.out.println(field.toString());
}
System.out.println("-----------------------------");
Field field = c.getField("NUMBER");
Field declaredField = c.getDeclaredField("name");
System.out.println(field.toString());
System.out.println(declaredField.toString());
}
运行结果:
获取方法定义信息
getMethods() – 获得所有可见的方法,包括继承的方法
getDeclaredMethods() – 获得本类定义的方法,包括私有,不包括继承的方法
getMethod(方法名,参数类型列表) – 获得指定可见的方法
getDeclaredMethod(方法名, 参数类型列表) – 获得本类指定的方法,包括私有,不包括继承的方法
测试:
@Test
public void test3() throws Exception{
Class c = Class.forName("com.cy.Shop");
Method[] methods = c.getMethods();
for (Method method : methods) {
System.out.println(method.toString());
}
System.out.println("----------------------------");
Method[] declaredMethods = c.getDeclaredMethods();
for (Method method : declaredMethods) {
System.out.println(method.toString());
}
System.out.println("----------------------------");
Method method = c.getMethod("setName", String.class);
System.out.println(method.toString());
Method declaredMethod = c.getDeclaredMethod("priMethod");
System.out.println(declaredMethod.toString());
}
运行结果:
获取构造方法定义信息
getConstructors() – 获得所有公开的构造方法
getDeclaredConstructors() – 获得所有构造方法,包括私有
getConstructor(参数类型列表) – 获得指定公开的构造方法
getDeclaredConstructor(int.class, String.class) – 获得指定构造方法,包括私有
测试:
@Test
public void test4() throws Exception{
Class c = Class.forName("com.cy.Shop");
Constructor[] constructors = c.getConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor.toString());
}
System.out.println("---------------------------------------");
Constructor[] declaredConstructors = c.getDeclaredConstructors();
for (Constructor constructor : declaredConstructors) {
System.out.println(constructor.toString());
}
System.out.println("---------------------------------------");
Constructor constructor = c.getConstructor();
System.out.println(constructor.toString());
Constructor declaredConstructor = c.getDeclaredConstructor(String.class, Integer.class);
System.out.println(declaredConstructor.toString());
}
反射访问类的属性
反射新建实例
— 新建实例时,执行无参构造
Object obj = 类(Class).newInstance();
— 获取构造方法
Constructor t = 类(Class).getConstructor(参数类型列表);
— 新建实例,并执行该构造方法
Object obj = t.newInstance(参数数据列表);
反射调用成员变量
— 获取变量
Field field = 类(Class).getDeclaredField(变量名);
— 使私有成员允许访问
field.setAccessible(true);
— 反射给变量赋值
field.set(实例, 值);
— 反射访问变量的值
Object v = field.get(实例);
反射调用成员方法
获取方法
Method m = 类(Class).getDeclaredMethod(方法名, 参数类型列表);
使私有方法允许被调用
m.setAccessible(true)
反射让指定的实例来执行该方法
Object returnValue = m.invoke(实例, 参数数据)
测试:
@Test
public void test5() throws Exception{
Class c = Class.forName("com.cy.Shop");
Constructor declaredConstructor = c.getDeclaredConstructor(String.class, Integer.class);
// 反射使私有构造方法允许访问
declaredConstructor.setAccessible(true);
// 反射调用私有构造方法创建实例
Shop shop = (Shop)declaredConstructor.newInstance("苹果", 10);
System.out.println(shop.toString());
System.out.println("-----------------------------------------");
Constructor constructor = c.getConstructor();
// 反射调用公有构造方法创建实例
Shop shop1 = (Shop)constructor.newInstance();
System.out.println(shop1.toString());
System.out.println("-----------------------------------------");
Field field = c.getDeclaredField("name");
// 反射使成员变量允许访问
field.setAccessible(true);
// 反射给成员变量赋值
field.set(shop1, "香蕉");
// 反射访问成员变量
String name = (String)field.get(shop1);
System.out.println(shop1.toString());
System.out.println(name);
System.out.println("-----------------------------------------");
Method method = c.getDeclaredMethod("priMethod");
// 反射使私有方法允许访问
method.setAccessible(true);
// 反射指定实例调用该私有方法
method.invoke(shop1);
}
运行结果: