「这是我参与11月更文挑战的第10天,活动详情查看:2021最后一次更文挑战」
什么是反射
对于运行阶段的一个类,可以动态的获取这个类的所有属性、方法和构造方法等信息。对于运行阶段的一个对象,也可以动态的获取这个对象的属性、方法、构造方法等信息的机制,称之为反射机制。 反射就是在运行时才知道要操作的类是什么,并且可以在运行时获取类的完整构造,并调用对应的方法。
Java反射机制主要提供了以下功能:
- 在运行时构造任意一个类的对象
- 在运行时获取任意一个类所具有的成员变量和方法
- 在运行时调用任意一个对象的方法(属性)
- 生成动态代理
Class类
主要方法
getName():获得类的完整名字。
getFields():获得类的public类型的属性。
getDeclaredFields():获得类的所有属性。包括private 声明的和继承类
getMethods():获得类的public类型的方法。
getDeclaredMethods():获得类的所有方法。包括private 声明的和继承类
getMethod(String name, Class[] parameterTypes):获得类的特定方法,name参数指定方法的名字,parameterTypes 参数指定方法的参数类型。
getConstructors():获得类的public类型的构造方法。
getConstructor(Class[] parameterTypes):获得类的特定构造方法,parameterTypes 参数指定构造方法的参数类型。
newInstance():通过类的构造方法创建这个类的一个对象。
class获取示例
public class Apple {
private int price;
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public static void main(String[] args) throws Exception{
//正常的调用
Apple apple = new Apple();
apple.setPrice(5);
System.out.println("Apple Price:" + apple.getPrice());
//通过.class方式调用
Class class1 = Apple.class;
//使用class对象的forName方法调用
Class clz = Class.forName("com.demo.api.Apple");
Method setPriceMethod = clz.getMethod("setPrice", int.class);
Constructor appleConstructor = clz.getConstructor();
Object appleObj = appleConstructor.newInstance();
setPriceMethod.invoke(appleObj, 14);
Method getPriceMethod = clz.getMethod("getPrice");
System.out.println("Apple Price:" + getPriceMethod.invoke(appleObj));
}
}
从这个简单的例子可以看出,一般情况下我们使用反射获取一个对象的步骤:
- 获取类的 Class 对象实例
Class clz = Class.forName("com.demo.api.Apple");
- 根据 Class 对象实例获取 Constructor 对象
Constructor appleConstructor = clz.getConstructor();
- 使用 Constructor 对象的 newInstance 方法获取反射类对象
Object appleObj = appleConstructor.newInstance();
而如果要调用某一个方法,则需要经过下面的步骤:
- 获取方法的 Method 对象
Method setPriceMethod = clz.getMethod("setPrice", int.class);
- 利用 invoke 方法调用方法
setPriceMethod.invoke(appleObj, 14);
Class能实现的功能
1判断对象属于哪个类
Person person = new Person();
Class class2= person.getClass();
System.out.println("class2:"+class2);
输出:class2:class reflect.Person
2获取类信息
Class class1 = Person.class;
Method[] methods = class1.getMethods();
Method[] declaredMethods = class1.getDeclaredMethods();
Field[] declaredFields = class1.getDeclaredFields();
3构建对象
Person person = new Person();
Class class2= person.getClass();
Object o = class2.newInstance();
//强转前先用instanceof判断
if(o instanceof Person){undefined
((Person) o).workIng();
}
4动态执行方法
Class class1 = Class.forName("reflect.Person");
Method work = class1.getDeclaredMethod("work");
Person person = new Person();
work.invoke(person);
5动态操作属性
Class class1 = Class.forName("reflect.Person");
Person person = new Person();
Field field = class1.getDeclaredField("username");
field.set(person,"pine");
代码示例
public class Consumer {
private long id;//私有的
public String name;//共有的
/*没参数构造体*/
public Consumer() {
}
/*有参数构造体*/
public Consumer(long id, String name) {
this.id = id;
this.name = name;
}
/*getter setter*/
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
/*私有的无参buy方法*/
private static void buy() {
System.out.println("私有的无参buy方法");
}
/*共有的有参有返回值consume方法*/
public String consume(String giftName) {
System.out.println("买了一件礼物: " + giftName);
return giftName;
}
}
public class TestReflect {
public static void getProperty() throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
try {
/* 获取对象类型 */
Class<?> clazz = Class.forName("com.Dan.Consumer");
Object object = clazz.newInstance();
/* 获取到所有属性 */
Field[] field = clazz.getDeclaredFields();
for (Field f:field) {
//String fieldName = f.getName();// 取到属性名字
//System.out.println(fieldName);
System.out.println(f);
}
/* 获取到所有的方法,包括私有的,但不包括父类的 */
Method[] methods = clazz.getDeclaredMethods();
for (Method m:methods){
//String methodName = m.getName();
//System.out.println(methodName);
System.out.println(m);
}
/* 所有的构造体 */
Constructor[] constructors = clazz.getDeclaredConstructors();
for (Constructor c:constructors){
System.out.println(c);
}
// 调用方法
Method method = clazz.getMethod("info", String.class, long.class);//获取方法
method.invoke(object, "隔壁老王",2017032009);
//得到属性
Field aField = clazz.getDeclaredField("name"); //因为name变量是private的,所以不能用getField方法
aField.setAccessible(true);
aField.set(object,"二大爷");
Object obj = aField.get(object);
System.out.println(obj);
// 得到构造器
Constructor constructor = clazz.getDeclaredConstructor(long.class, String.class);
constructor.newInstance(2016040221, "王小二");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException,
InstantiationException, IllegalAccessException, NoSuchFieldException {
getProperty();
}
}
总结
- 在运行期间,如果我们要产生某个类的对象,Java虚拟机(JVM)会检查该类型的Class对象是否已被加载。如果没有被加载,JVM会根据类的名称找到.class文件并加载它。一旦某个类型的Class对象已被加载到内存,就可以用它来产生该类型的所有对象,虚拟机只会产生一份字节码, 用这份字节码可以产生多个实例对象。
- 一个Java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等等信息也用一个个的Java类来表示,就像汽车是一个类,汽车中的发动机,变速箱等等也是一个个的类。表示Java类的Class类显示要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,它们是Field、Method、Contructor、Package等等。
\