1. 什么反射 (What is reflect)
-
当实例化类的时候,jvm都会寻得.class文件,加载进代码区,为它创建一个Class对象(这个对象是jvm自动创建的,每个.class文件只创建一个Class对象)
-
通过Class对象获得Constructor Method Field 对象,然后就可以使用.class里面的所有内容
2.反射的各种操作 (How to use)
欲用之,必先有对象
-
获得.class文件的对象
//方式一:(推荐的方式,优点语法简介,使用灵活)
Class classFileObj1 = Class.forName(完整的类名);<下面步骤中都有使用>
//完整的类名 = 包名 + 类名
//方式二:(缺点要导入包,灵活性较低)
Class classFileObj2 = 类名.class;
//所有的类都有一个class的静态属性
//方式三:
类类型 标识符 = new 类类型();
//这个中规中矩,没啥好说的
- 这里可能有个疑问,为什么是加类名,而不是加.java的文件名:
- 有这个疑问的原因是不清楚,jvm的解释机制
- 当还是.java文件的时候可能会在一个文件里面储存多各类
- jvm在把.java文件解释成字节码文件的时候会为每个class生成一个.class文件
- 所以就能解释完整的类名 = 包名 + 类名,而不是加.java的文件名
-
获得类的构造函数
类类型 标识符 = new 类类型();
常规的实例化类就是通过new调用类的构造方法
//第一步获得.class的对象
Class classFileObj = Class.forName("完整的类名");
//第二步 获得Constructor 有四种方式:
//方式一:(获得所有public修饰的构造方法)
Constructor[] consObj1 = classFileObj.getConstructors();
//方式二:(获得所有** 修饰符 **修饰的构造方法)
Constructor[] consObj2 = classFileObj.getDeclaredConstructors();
//方式三:(通过指定parameter列表获取public修饰的构造方法)
Constructor consObj3 = classFileObj.getConstructor(Class.. parameter);
//方式四:(通过指定parameter列表获取** 所有修饰符 **修饰的构造方法)
Constructor consObj4 = classFileObj.getDeclaredConstruct(Class.. parameter);
//第三步:
//通过获得的构造函数实例化一个一个对象
Object obj = consObje3.newInstance(parameter); <后面使用了它>
//第四步:
//使用它 use it
-
获得类的方法
//方式一:(获得所有public修饰的方法,包括父类的方法)
Method[] method1 = classFileObj1.getMethods();
//方式二:(获得所有** 标识符 **修饰的方式,不包括父类的方法)
Method[] method2 = classFileObj1.getDeclaredMethods();
//方式三:(通过指定方法名和parameter列表获取方法)
Method method3 = classFileObj1.getMethod(methodName,parameter);
//方式四:(通过指定方法名和parameter列表获取** 所有修饰符修饰的方法)
Method method4 = classFileObj1.getDeclaredMethod(MethodName,parameter);
//使用获得的方法
method4.invoke(方法所属的对象,方法所需的参数)
//如果是私有方法
method4.setAccessible(true);//暴力使用
method4.invoke(方法所属的对象,方法所需的参数)
-
获得类的字段
//方式一:(获得所有public修饰的字段)
Field[] field1 = classFileObj1.getFields();
//方式二:(获得所有** 标识符 **修饰的Field)
Field[] field2 = classFileObj1.getDeclaredFields();
//方式三:(通过指定Field名获取方法)
Field field3 = classFileObj1.getField(FieldName);
//方式四:(通过指定Field名获取** 所有修饰符修饰的字段)
Field field4 = classFileObj1.getDeclaredField(FieldName);
//使用设置获得的字段
field4.set(字段所属对象,要设置的值);
//如果是私有字段
field4.setAccessible(true);//暴力使用
field4.set(字段所属的对象,要设置的值)
3.反射的简单使用
//创建一个反射要使用的类
package com.person;
class Person{
//私有Field
private int age;
private String name;
private int weight;
//public Field
public int height = 170;
//private Constructor
private Person(){
this.age = 10;
this.weight = 20;
}
//public Constructot
public Person(String name){
this();
this.name = name;
}
//public Method
public void getPersonName(){
System.out.println("我的名字是:"+this.name);
}
//private Method
private void privateGetAge(){
System.out.println("我的年龄是:"+this.age);
}
//protected Method
protected void getHeight(){
System.out.println("我的身高是"+this.height);
}
}
import java.lang.reflect.*;
try{
//通过完整的类名,获取Class对象
Class cls = Class.forName("com.person.Person");
//获得其中一个构造方法
Constructor oneOfCons = cls.getConstructor(String.class);
//创建对象
Person obj = (Person)oneOfCons.newInstance("小明");
//获得方法
Method oneOfMethod = cls.getDeclaredMethod("getPersonName");
//使用它
oneOfMethod.invoke(obj,null);
//获得字段
Field name = cls.getDeclaredField("name");
//使用它,因为是私有字段所以必须暴力使用
name.setAccessible(true);
name.set(obj,"呼啸");
//查看是否改变
oneOfMethod.invoke(obj,null);
}catch(Exception e){
e.printStackTrace();
}
//结果
我的名字是:小明
我的名字是:呼啸