java.lang.reflect包中有三个类,Field,Method,Constructor,这三个类都有一个叫getName()的方法来返回项目名称。其中他们都有对指定成员/方法,赋值和修改的工具,含declared的表示他们多了一个访问私有域的权限,否则只有访问和操作公有域的权限;可以选择使用哪个构造器,传入参数构造构造器的实例。
Field: 获取成员变量的信息
field 和 field[]类型只能获取public的成员变量,包括父类
getDeclaredFields方法可以获取所有成员变量,不能获取到父类
field 的 getField方法和getDeclaredField 方法都是对指定名称成员变量去获取的
field[] 的 getFields 方法和 getDeclaredFields 方法是获取成员的集合
虽然 getDeclaredField 可以访问 private 成员变量,但是不具有操作它的能力
想要操作它就必须加入一个setAccessible(true)来忽略访问权限
field 中 的 getDeclaredField 中有暴力反射法,可忽略访问权限,调用 setAccessible(true);
//打印类中的公共的成员变量,包括他继承了的父类的成员变量
Field[] field = Student.class.getFields();//
for (Field f : field) {
System.out.println("公有成员:" + f.getName());
}
System.out.println("----------------------");
//打印类中的所有的成员变量,不包括他继承了的父类的成员变量
Field[] field4 = Student.class.getDeclaredFields();
for (Field f : field4) {
System.out.println("所有成员:" + f.getName());
}
System.out.println("----------------------");
Field field2 = Student.class.getField("TeacherName");
//TeacherName是私有成员,所以要忽略访问权限
field2.setAccessible(true);
Student st = new Student();
//get方法获取成员值
Object oj = field2.get(st);
System.out.println(oj);
//set方法修改成员值
field2.set(st, "Teacher");
Object oj2 = field2.get(st);
System.out.println(oj2);
System.out.println("----------------------");
Field field3 = Student.class.getField("publicPersonName");
//publicPersonName是父类的公有成员
Student st1 = new Student();
Person ps1 = new Person();
// set方法设定对象参数是因为有一些成员是继承得到的,下面进行演示
field3.set(st1, "student");
field3.set(ps1, "Person");
//子类的
Object oj3 = field3.get(st1);
//父类的
Object oj4 = field3.get(ps1);
//输出
System.out.println(oj3);
System.out.println(oj4);
System.out.println("----------------------");
Method:获取成员方法的信息(使用方法和Field的几乎一样)
publlic Object invoke(Object implicitParameter,Object[ ] explicitparamenters)
invoke 的参数和返回值必须是Object类型的,在使用包装器传递基本类型时,基本类型的返回值必须是未包装的。
下面是一个例子:
Method method4 = studentClass.getMethod("getSalary", int.class);
int a = (Integer) method4.invoke(st0, 50);
System.out.println(a);
method4.invoke(st0, 50);调用了
public int getSalary(int salary) {
return salary * 2;
}
返回对象是Object类,实际接收的是Integer类,因此 int a 不能直接接收到这个对象,只要把这个对象向下造型成Integer,就会触发自动拆箱
这就意味着必须进行多次类型转换,这样会使编译器错过检查代码的机会,因此等待测试阶段才会发现这些错误,找到并改正将会很困难。不仅如此,使用反射获得方法指针的代码要比仅仅直接调用方法显得慢一些。
所以,建议仅在必要的时候才使用Method对象,而最好使用接口以及lambda表达式。
特别要重申:建议Java开发者不要使用Method对象的回调功能。使用接口进行回调会使得代码的执行速度更快,更易于维护
Class<Student> studentClass = Student.class;
//打印类中的公共的成员方法,包括它的继承到的父类的公共成员方法,返回一个数组
Method[] methods = studentClass.getMethods();
for (Method method : methods) {
System.out.println(method);
}
System.out.println("-------------------------------");
打印类中的所有的成员方法,不包括它的继承到的父类的公共成员方法,返回一个数组
Method[] methods2 = studentClass.getDeclaredMethods();
for (Method method : methods2) {
System.out.println(method);
}
System.out.println("-------------------------------");
// getMethod(String name,Class <?> ... parameterTypes)
// parameterTypes是形参的意思,没有参数就不用输入
// Java调用方法看的是方法名和参数列表
// 所以在使用getMethod创建指定方法对象时要加入方法名和参数列表
Method method0 = studentClass.getMethod("read");// 这里会抛出异常
System.out.println(method0);
System.out.println("-------------------------------");
// 演示暴力反射和有参数的举例
Method method1 = studentClass.getDeclaredMethod("privateMethod");
//privateMethod是私有的成员方法
method1.setAccessible(true);
Student st0 = new Student();
// 调用invoke方法使用这个privateMethod方法
method1.invoke(st0);
// invoke()方法有两个参数,前者是对象,(如果是继承的方法)是用在父类的身上呢还是自己身上呢,后面是privateMethod方法的参数
//如果没有参数需要传递,就不需要写东西
System.out.println("-------------------------------");
Method method2 = studentClass.getDeclaredMethod("privateMethod", String.class);
method2.setAccessible(true);
method2.invoke(st0, "hahahahaha");// 需要传递参数
System.out.println("-------------------------------");
Method method3 = studentClass.getMethod("publicStaticMethod", String.class);
//publicStaticMethod是Student类的静态方法
// invoke使用静态方法时第一个参数可以忽略,但是不能不填,可以用null代替,比如原来是这样的
// method3.invoke("st0", "still use args");
// 现在可以这样写
method3.invoke(null, "still use args");
Constructor:获取构造器的信息
getConstructors,返回全部公有构造方法
getConstructor,返回公有指定的构造方法
getDeclaredConstructors,返回全部构造方法
getDeclaredConstructor,返回指定的构造方法(部分公共和私有)
Constructor<Student> constructor = Student.class.getDeclaredConstructor(String.class);
System.out.println(constructor);
System.out.println("-------------------------");
// 尽管此方法返回一个 Constructor<T>对象数组(即此类的构造函数数组)
// 但此方法的返回类型是 Constructor<?>[],并非 Constructor<T>[]预期的那样
// Type safety: Unchecked cast from Constructor<?>[] to Constructor<Student>[]
// 安全性问题,不检查<?>,<?>意思时不确定类型
//下面这个不使用泛型可以,但是会有一个小警告,就好像Class不使用泛型那样
Constructor[] constructor1 = Student.class.getDeclaredConstructors();
for (Constructor c : constructor1) {
System.out.println(c);
}
System.out.println("-------------------------");
Constructor<?>[] construstor2 = Student.class.getConstructors();
for (Constructor<?> c : construstor2) {
System.out.println(c);
}
System.out.println("-------------------------");
constructor.setAccessible(true);// 暴力反射
//constructor.newInstance(Object[] args)构造一个构造器所属类的新实例,返回一个Object对象,args是提供给构造器的参数
Object obj = constructor.newInstance("zhangsan");
//打印这个实例,就是打印使用过构造器后的成员变量
System.out.println(obj);
System.out.println("-------------------------");
// 同理,构造空参,但是这个操作有点麻烦,class类有专门构造空参的方法,也是newInstance(),这是一个老方法了
Constructor<Student> constructor3 = Student.class.getConstructor();
Object obj2 = constructor3.newInstance();
System.out.println(obj2);
System.out.println("-------------------------");
// class类的newInstance使用构造空参
// class类是<T>的,这个类下面有class<?>的方法
Class<Student> clazz = Student.class;
Object obj3 = clazz.newInstance();
System.out.println(obj3);
这三个类有一个方法叫做 getModifiers
int getModifiers() 返回一个用于描述构造器,方法或域的修饰符的整数值,划重点:一个
使用Modifier类中的 isPublic,isPrivate,isFinal 判断它是否是 public,private 还是 final
使用Modifier类的静态方法 Modifier.toString(调用getModifiers后返回的数值);可以翻译出这个修饰符是什么
Class studentClass = Student.class;
int modifier = studentClass.getModifiers();
String modifierString = Modifier.toString(modifier);
System.out.println(modifier + " is " + modifierString);
int field = studentClass.getDeclaredField("teacherName").getModifiers();
// 不能使用getField("teacherName"),因为它没有访问私有域的权限
System.out.println("成员\"teacherName\" is " + Modifier.toString(field));
int method = studentClass.getDeclaredMethod("privateMethod", String.class).getModifiers();
System.out.println("方法\"privateMethod\" is " + Modifier.toString(method));
int constructor = studentClass.getDeclaredConstructor(String.class).getModifiers();
System.out.println("构造方法 is " + Modifier.toString(constructor));