1.反射的作用
首先用一段很简单易懂的话来说明反射的作用,一个类,如果里面没有get,set方法,那么我们即使有实例对象,也无法获取到里面的属性。如果里面还有私有的构造器以及私有的成员函数,我们同样无法通过实例对象去调用这些构造器和方法,但是反射机制就可以帮我们做到,可以仅仅通过一个类名,就去获取这个类的所有域,构造器和方法并进行调用和修改。
反射作用具体表现在:
- 在运行时分析类的能力
- 在运行时查看对象。例如可以编写一个toString方法供所有类使用
- 实现通用的数组操作代码
- 利用Method对象,这个对象很像C++中的函数指针
2.反射中的主要组成
- 1)Class类:泛型类 和类名有关
- 2)Field类:和类中的域有关
- 3)Method类:和类中的成员方法有关
- 4)Constructor类:和类中的构造器有关
3.反射获取类属性:
定义实体类:
这个类中有私有,共有的属性,构造器和方法,但是没有get,set方法
public class Animal {
public Integer age;
private String type;
private String name;
private Animal(String type) {
this.type = type;
}
public Animal(){}
public Animal(String type, String name) {
this.type = type;
this.name = name;
}
public Animal(Integer age, String type, String name) {
this.age = age;
this.type = type;
this.name = name;
}
private void hello(String msg){
System.out.println(msg);
}
@Override
public String toString() {
return "Animal{" +
"age='" + age + '\'' +
", type='" + type + '\'' +
", name='" + name + '\'' +
'}';
}
}
获取Class类的三种方法:
- getClass():
- forName(className):
Animal animal1 = new Animal("猫科","熊猫");
//获取Class类对象第一种方式
Class c1 = animal1.getClass();
System.out.println(c1.getName());//test.Animal
//获取Class类对象第二种方式
String className = "java.util.Random";
Class c2 = Class.forName(className);
System.out.println(c2.getName());//java.util.Random
//获取Class类对象第三种方式
Class cl1 = Random.class;
Class cl2 = int.class;
Class cl3 = Double[].class;
System.out.println(cl1.getName());
System.out.println(cl2.getName());
System.out.println(cl3.getName());
//输出
java.util.Random
int
[Ljava.lang.Double;
获取类中的域属性:Field
- getFields():返回所有的public域
- getDeclaredFields():返回所有级别的域
- getDeclaredField(“xxx”):返回指定域名的域
```java
//获取域
Animal animal3 = new Animal("猫科","熊猫");
Class cx3 = animal3.getClass();
Field[] fields = cx3.getFields(); //返回public域
for(Field field: fields){
System.out.println(field.getName());
}
Field[] declaredFields = cx3.getDeclaredFields();//返回所有域
for(Field field: declaredFields){
System.out.println(field.getName());
}
Field field1 = cx3.getDeclaredField("name");//返回指定域
System.out.println(field1.getType().getName());//这里的getType方法是获取类型
//输出
age
age
type
name
java.lang.String
获取构造器:Constructor
- getConstructors():获取所有public级别的构造器
- getDeclaredConstructors():获取所有级别的构造器
- getDeclaredConstructor(String.class):获取指定构造器 传入参数类型列表
//获取构造器
Animal animal4 = new Animal("猫科","熊猫");
Class cx4 = animal4.getClass();
Constructor[] constructors = cx4.getConstructors();//获取public构造器
for(Constructor constructor:constructors){
System.out.println(constructor.getName());
}
Constructor[] constructors1 = cx4.getDeclaredConstructors();//获取所有构造器
for(Constructor constructor:constructors1){
System.out.println(constructor.getName());
}
Constructor constructor2 = cx4.getDeclaredConstructor(String.class);//获取指定构造器 传入参数类型列表
//constructor2.getModifiers()返回的是一个整形数值 用于判断修饰级别
System.out.println(Modifier.toString(constructor2.getModifiers()));
//输出
test.Animal
test.Animal
test.Animal
test.Animal
test.Animal
test.Animal
test.Animal
private
这里上面输出三个说明有一个private构造器没有获取到,后面是四个,最后一个输出了获取构造器的修饰级别
获取成员函数:Method
- getMethods():获取所有public成员函数 包括了父类的方法
- getDeclaredMethods():获取所有级别的成员函数
- getDeclaredMethod(“functionName”, String.class):获取指定成员函数 前面是函数名后面是参数类型列表
//获取成员函数
Animal animal5 = new Animal("猫科","熊猫");
Class cx5 = animal5.getClass();
Method[] methods = cx5.getMethods();//获取所有public成员函数 包括了父类的方法
for(Method method: methods){
System.out.println(method.getName());
}
System.out.println();
Method[] declaredMethods = cx5.getDeclaredMethods();//获取所有级别的成员函数
for (Method method: declaredMethods){
System.out.println(method.getName());
}
System.out.println();
//获取指定成员函数 前面是函数名 后面是参数类型列表
Method method = cx5.getDeclaredMethod("hello", String.class);
System.out.println(method.getName());
System.out.println();
4.反射调用和访问类
上一部分仅仅是说了如何获取到类的属性,但是并没有进行访问和调用,现在来开始调用。
1)反射获取对象的私有域和公有域并进行修改
用get和set方法进行获取和修改,这里要注意实体类中并没有set和get方法
还有就是访问私有域的时候要用setAccessible()方法添加权限才可以
//通过反射获取某个对象的域值 并进行修改
Animal animal6 = new Animal(20,"猫科","熊猫");
Class cx6 = animal6.getClass();
Field age = cx6.getDeclaredField("age");//获取公有属性age
Object o = age.get(animal6);//获取animal6实例的age属性的值
System.out.println("animal6的age: "+o);
age.set(animal6,56);//修改该对象age的值为56
Object o2 = age.get(animal6);
System.out.println("animal6的age: "+o2);//56
Field type = cx6.getDeclaredField("type");//获取私有属性
type.setAccessible(true);//这里要设置权限
Object o1 = type.get(animal6);
System.out.println("animal6的type: "+o1);
type.set(animal6,"虎类");
Object o3 = type.get(animal6);
System.out.println("animal6的type: "+o3);//虎类
2)通过反射调用私有和公有成员函数
用invoke方法来调用,第一个参数是对象名,第二个是方法参数列表
//通过反射调用方法 用invoke方法调用获取的方法 第一个参数是对象 之后是参数列表
Animal animal7 = new Animal(20,"猫科","熊猫");
Class cx7 = animal7.getClass();
Method hello = cx7.getDeclaredMethod("hello", String.class);
hello.setAccessible(true);//这个方法是私有的 所以要加权限
hello.invoke(animal7,"11111");
3)通过反射调用私有公有构造器构造实例
获取构造器后用newInstance方法实例化!
//通过反射调用构造函数构造实例
Animal animal8 = new Animal(20,"猫科","熊猫");
Class cx8 = animal8.getClass();
Constructor constructor = cx8.getDeclaredConstructor(String.class);
constructor.setAccessible(true);
Object o4 = constructor.newInstance("狗类");
System.out.println(o4);