反射
反射是java中提供的一种机制,它允许我们在程序运行的时候,动态获取一个类中的基本信息,并且可以调用类中的属性,方法,构造器.
public class Student{
private String name;
int age;
public static int num;
public Student(){}
public Student(String name,int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String sayHello(String name){
return "hello! "+name;
}
}
我们除了使用眼睛看到这个类中的属性方法构造器之外,在代码运行的时候,也可以通过反射机制获取到这个类中的属性,方法,构造器,已经调用构造器和方法.
Class c = Class.forName("com.briup.demo.Student");
Field[] fields = c.getDeclaredFields();
for(Field f : fields){
System.out.println("属性的修饰符:"+Modifier.toString(f.getModifiers()));
System.out.println("属性的类型:"+f.getType().getName());
System.out.println("属性的名称:"+f.getName());
System.out.println("---------------------");
}
Class类型
java.lang.Class 是API中提供的一个类,它可以表示java中所有的类型,包括基本类型和引用类型.
getClass方法的返回类型就是Class,所以obj.getClass();这句代码的含义就是,返回obj引用在运行时所指向对象的实际类型.
Class类型可以表示基本类型,数组类型,接口类型,类类型,每种类型加载到内存之后,都会在内存中生成一个Class类型对象,这个对象就代表这个具体的java类型,并且保存这个类型中的基本信息.
注意:java中的每种类型都有且只有唯一的一个Class类型对象与之对应!并且在类加载的时候自动生成
获取基本类型的Class对象
只有一种: Class c = int.class;
获取接口类型的Class对象有两种方法
-
Class c1 = Action.class;
-
Class c2 = Class.forName(“com.briup.demo.Action”);
获取数组类的Class对象有两种方法
- Class c1 = int[].class; int[] arr = new int[4];
- Class c2 = arr.getClass();
获取类类型的Class对象有三种方法
- Class c1 = Student.class;
- Class c2 = Class.forName(“com.briup.demo.Student”);
- Student stu = new Student(); Class c3 = stu.getClass();
可以看出,获取一个类型Class对象的途径一般有三种
- 使用类型名称直接获取
- -使用Class类中的静态方法forName获取
- 使用对象调用getClass方法获取
获取类中声明的属性
- 获取类中public修饰的属性,也包括从父类中继承的public属性
-
Field[] getFields()
-
Field getFiled(String name)
- 获取类中声明的属性(包含私有的),但是不能获取从父类中继承过来的属性
- Field[] getDeclaredFields()
- Field getDeclaredField(String name)
java.lang.reflect.Field 表示类中的属性
获取类中的方法
- 获取当前类中的public方法,包含从父类中继承的public方法
- Method[] getMethods()
- Method getMethod(String name,Class<?>… parameterTypes)
- 获取当前类中声明的方法(包含私有的),但是不能获取从父类中继承过来的方法
- Method[] getDeclaredMethods();
- Method getDeclaredMethods(String name,Class<?>… parameterTypes);
获取类中声明的构造器
- 获取当前类中的public构造器
-
public Constructor[] getConstructors()
-
public Constructor getConstructor(Class… parameterTypes)
- 获取当前类中的所有构造器,包含私有
-
public Constructor[] getDeclaredConstructors()
-
public Constructor getDeclaredConstructor(Class… parameterTypes)
反射访问属性
public static void main(String[] args)throws Exception {
Student stu = new Student();
Class c = stu.getClass();
//获取类中名字叫name的属性
Field f1 = c.getDeclaredField("name");
//设置私有属性可以被访问,否则报错
f1.setAccessible(true);
//用反射的方式,给指定对象的name属性赋值
//相当于之前的stu.name = "tom";
f1.set(stu,"tom");
//用反射的方式,获取这个属性的值
//相当于之前的stu.name
System.out.println(f1.get(stu));
System.out.println("----------------------");
//获取类中名字叫age的属性
Field f2 = c.getDeclaredField("age");
//用反射的方式,给指定对象的age属性赋值
//相当于之前的stu.age = 20;
f2.set(stu,20);
//用反射的方式,获取这个属性的值
//相当于之前的stu.age
System.out.println(f2.get(stu));
System.out.println("----------------------");
//获取类中名字叫num的属性
//4.6 反射调用方法
//注意, public Object invoke(Object obj, Object... args)
//obj,表示要调用哪个对象的方法,如果是静态方法,可以传null
//args,可变参数,表示要调用的方法的参数列表
m.invoke(obj,null) 中的m,就是通过Class对象获取到的类中的某一个指定的方法
//4.7 反射创建对象
//使用反射的方式可以创建对象,也就是需要反射调用构造器。
Field f3 = c.getDeclaredField("num");
//用反射的方式,给静态属性num赋值,不需要对象
//相当于之前的Student.num = 99;
f3.set(null,99);
//用反射的方式,获取这个静态属性的值,不需要对象
//相当于之前的Student.num
System.out.println(f3.get(null));
}
反射调用方法
public static void main(String[] args)throws Exception {
Student stu = new Student();
Class c = stu.getClass();
//获取类中的toString方法,没有参数,这是从父类继承的方法
Method m1 = c.getMethod("toString", null);
//反射的方式,调用stu对象中的这个方法,没有参数,并接收执行结果
//相当于之前的:Object result = stu.toString();
Object result = m1.invoke(stu,null);
//输出执行结果
System.out.println(result);
System.out.println("-------------------");
//获取类中的sayHello方法,需要一个String类型的参数,这是自己定义的方法
Method m2 = c.getMethod("sayHello", String.class);
//反射的方式,调用stu对象中的这个方法,参数是"tom",并接收执行结果
//相当于之前的:Object result = stu.sayHello("tom");
result = m2.invoke(stu,"tom");
//输出执行结果
System.out.println(result);
}
反射调用构造器
- 无参构造器
public static void main(String[] args)throws Exception {
Class c = Student.class;
//默认调用类中的无参构造器来创建对象
//相当于之前的:Object obj = new Student();
Object obj = c.newInstance();
System.out.println(obj);
}
- 有参构造器
public static void main(String[] args)throws Exception {
Class c = Student.class;
//获取类中的俩参构造器
Constructor constructor = c.getConstructor(String.class, int.class);
//调用有参构造器创建对象,并传入对应的参数值
//相当于之前的:Object obj = new Student("tom",20);
Object obj = constructor.newInstance("tom",20);
System.out.println(obj);
}