学习了反射机制之后,在这里总结一下如何使用,以顾自己复习。
与反射相关的几个类:
Java.lang.Class;//Class类
Java.lang.reflect.Constructor;//构造方法类
Java.lang.reflect.Field;//对象中的属性类
Java.lang.reflect.Method;//对象中的方法类
Java.lang.reflect.Modifier;//属性/方法的修饰符
目录
获取Class的三种方法:
- 数据类型.class,如int.class,String.class,任何数据类型都有.class,可以直接调用
- 对象.getClass(),如String str=new Stirng(); Class c=str.getClass();
- Class.forName("完整类名")
//第一种
Class string = Class.forName("java.lang.String");
//第二种
String str="abc";
Class aClass = str.getClass();
//第三种
Class stringClass = String.class;
获取类的属性:
- 先获取整个类的class
- 由类得到Field数组,因为属性可能有多个,所以返回值是数组。Fleld[] fields=cls.getDeclaredFields();
- 一个Field包括修饰符、数据类型、字段名。
- 获取字段名的方法是:fs.getName();
- 获取字段名类型的方法是:fs.getType();
- 获取字段名修饰符的方法是:fs.getModifiers();//返回值是修饰符的字符串,所以使用Modifier.toString()转化为修饰符
Field[] stuFileds = fileds.getDeclaredFields();
for (Field fs:fileds){
//获取字段名
String name = fs.getName();
//获取字段名数据类型
Class type = fs.getType();
String typeName = type.getSimpleName();
//获取字段名修饰符
int modifiers = fs.getModifiers();//返回值是修饰符的代号
String str = Modifier.toString(modifiers);//将代号转化为字符串
}
修改属性的值:
在不使用反射机制之前,我们如何修改属性的值?
public class Student {
public int no;//整体是一个Filed对象
private String name;
protected int age;
boolean sex;
public Student() {
}
public Student(int no) {
this.no = no;
}
public static void m(String s,int b){
}
}
应该是这样的先创建对象:Student stu=new Student();
然后修改属性的值: stu.no=1;
必须有三个要素:对象,属性,值
反射机制要素需要这三个要素:
//先获取整个类的Class
Class studentClass = Class.forName("bean.Student");
//获取Student对象
Student obj = (Student)studentClass.newInstance();
//获取no属性,通过属性名获取Field
Field noFiled = studentClass.getDeclaredField("no");
//给obj对象的no属性赋值
noFiled.set(obj,111);//包含三要素:对象,no属性,值
//获取属性的值,通过get()方法
System.out.println(noFiled.get(obj));//两要素:对象,属性名
//给私有属性赋值,反射机制访问私有属性
Field nameField = studentClass.getDeclaredField("name");
//需要是要setAccessible()方法打破封装才能修改值
nameField.setAccessible(true);
nameField.set(obj,"jack");
通过反射机制获取方法以及调用方法:
与方法相关的类java.lang.reflect.Method
与获取属性名类似,可以使用method.getDeclaredMethods()获取所有的方法。
Class cls=Class.forName("bean.Student");
Method[] methods = cls.getDeclaredMethods();
for (Method method:methods){
//获取修饰符列表,与获取属性修饰符一样
System.out.println(Modifier.toString(method.getModifiers()));
//获取方法的返回值类型,getReturnType()返回的是一个Class,获取Class的简类名
System.out.println(method.getReturnType().getSimpleName());
//获取方法名
System.out.println(method.getName());
//获取参数类型,参数类型可能多个。返回值是一个Class数组
Class[] parameterTypes = method.getParameterTypes();
for (Class parameterType:parameterTypes){
System.out.println(parameterType.getSimpleName());
}
}
也可以通过方法名加参数类型定位特定的方法,不能只使用方法名特定方法,因为Java中存在方法重载机制。
调用方法需要四要素:对象、方法名、实参、返回值
注意:getDeclaredMethod()方法是获得指定的方法,第一个参数是方法名,后面的参数是参数类型,使用相应类型的Class,可以有多个,这是一个可变形参。
invoke()中填写对象名,实参。返回值是一个Object对象
//获取方法
Class cls = Class.forName("bean.Student");
//创建对象
Object obj = cls.newInstance();
//得到指定的方法
Method method = cls.getDeclaredMethod("m", String.class, int.class);
//调用对象四要素 对象,方法名,参数,返回值
Object retValue = method.invoke(obj, "123", 1);
使用构造方法创建对象
只需要指定构造方法的类型就可以找到指定的构造方法,不需要写构造方法名。
Class cls = Class.forName("bean.Student");
//获取构造方法,区分构造方法只看参数就可以了
Constructor constructor =
cls.getDeclaredConstructor(int.class,String.class,int.class,boolean.class);
Object o = constructor.newInstance(1,"刘哥",22,true);
也可以这样,直接通过获取整个Class,然后cls.newInstance(),但是这个方法自Java9之后不建议使用
Class cla=Class.forName("bean.Student");
//newInstance()会调用无参构造方法,所以要有无参
Object obj=cla.newInstance();
通过反射获取父类以及实现的接口
//获取String的父类
Class cls = Class.forName("java.lang.String");
Class superclass = cls.getSuperclass();
System.out.println(superclass.getSimpleName());
//获取String类实现的所有接口
Class[] interfaces = cls.getInterfaces();
for (Class in:interfaces){
System.out.println(in.getName());
}