反射就是对类中的成员变量、成员方法和构造方法进行编程访问。
要想使用反射,必须先获取class对象。
1、如何获取class对象呢?
Class这个类描述字节码文件的。
可通过以下3种方式获取:
①Class.forName("全类名")
②类名.class
③对象.getClass()
全类名就是包名+类名,这个不用自己写,IDEA中Copy Reference粘贴在括号里就是全类名
代码演示:
public class Demo1 {
public static void main(String[] args) throws ClassNotFoundException {
//第一种方式
//这个是最经常使用的
Class clazz1 = Class.forName("com.liu.Student");
//第二种方式
//这种一般是作为参数使用,比如作为锁
Class clazz2 = Student.class;
//第三种方式
Student student = new Student();
Class clazz3 = student.getClass();
}
}
2、如何获取构造方法呢?
Java中万物皆对象,对于构造方法有Constructor类去描述。
(1)常用方法
规则:
①get表示获取
②Declared表示所有
③最后的s表示所有,复数形式
④如果当前获取到的是私有的,必须要临时修改访问权限,否则无法使用
方法名 | 说明 |
---|---|
Constructor<?>[] getConstructors() | 获得public修饰所有的构造 |
Constructor<?>[] getDeclaredConstructors() | 获得类中所有的构造 |
Constructor<T> getConstructor(Class<?>... parameterTypes) | 获取指定构造,只能是public修饰的 |
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) | 获取指定构造,可以是类中所有的 |
Student类中有4个构造方法:
下面尝试使用一下获取构造方法:
a.第二个方法:获取类中所有的构造方法
for (Constructor constructor : clazz1.getDeclaredConstructors()) {
System.out.println(constructor);
}
输出结果:
b.第4种方法:获取指定的构造方法,如何指定呢?传递的是类中构造方法的形参变量的类型.class。
比如想获取类中两个参数的构造方法,参数类型分别是String和int,则在getDeclaredConstructor方法中传递的应该是String.class和int.class。代码如下:
运行结果报错,因为这个private的构造方法只能让你看到,并不能让你用,想用的话可以临时修改访问权限:con.setAccessible(true); 。
3、如何使用构造方法?
获取到了构造方法之后就可以拆分构造方法的各部分内容了,比如修饰符、名字、形参等等,也可以创建对象。
(1)获取构造方法的修饰符
int modifiers = constructor.getModifiers();
System.out.println(modifiers);
输出结果是以整数的形式进行返回的。
这个整数有什么含义,可以查API帮助文档。
(2)获取构造方法的名字
通过getName()方法获取。
(3)获取构造方法的形参
for (Parameter p : constructor.getParameters()) {
System.out.println(p);
}
输出结果如下:
(4)还可以使用newInstance()方法创建对象
constructor.setAccessible(true);
Object o = constructor.newInstance("zhangsan", 20);
System.out.println((Student)o);
4、如何获取成员变量?
(1)常用方法
使用与获取构造方法类似。
方法名 | 说明 |
---|---|
Field[] getFields() | 获得public修饰所有的成员变量 |
Field[] getDeclaredFields() | 获得类中所有的成员变量 |
Field getField(String name) | 获取指定成员变量,只能是public修饰的 |
Field getDeclaredField(String name) | 获取指定成员变量,可以是类中所有的 |
对于后2个方法,需要指定具体的变量名,以字符串形式给出,代码演示如下:
//获得单个成员变量对象
//如果获取的属性是不存在的,那么会报异常
//Field field3 = clazz.getField("aaa");
//System.out.println(field3);//NoSuchFieldException
Field field4 = clazz.getField("gender");
System.out.println(field4);
System.out.println("===============================");
//获取单个成员变量(私有)
Field field5 = clazz.getDeclaredField("name");
System.out.println(field5);
5、如何使用成员变量?
获取到了成员变量之后就可以拆分成员变量的各部分内容了,比如修饰符、名字、类型等等,也可以获取或者赋值。
(1)获取成员变量的修饰符
//获取成员变量的修饰符
int modifiers = name.getModifiers();
System.out.println(modifiers);
(2)获取成员变量的名字
//获取成员变量的名字
String s = name.getName();
System.out.println(s);
(3)获取成员变量的类型
//获取成员变量的类型
Class<?> type = name.getType();
System.out.println(type);
(4)获取成员变量的值
获取某个对象的某个成员变量的值,所以首先肯定要有一个对象,通过get(Object o)方法获取,代码如下:
//获取成员变量的值
Student student = new Student("zhangsan");
Object o = name.get(student);
System.out.println((String)o);
(5)给成员变量赋值
可以看到set方法有2个形参,分别是obj和value,要指定将哪个对象的name字段修改为何值。
//给成员变量赋值
name.set(student,"liu");
Object o1 = name.get(student);
System.out.println((String)o1);
运行结果如下:
6、如何获取成员方法?
(1)常用方法
方法名 | 说明 |
---|---|
Method[] getMethods() | 获得public修饰所有的成员方法 |
Method[] getDeclaredMethods() | 获得类中所有的成员方法 |
Method getMethod(String name, Class<?>... parameterTypes) | 获取指定成员方法,只能是public修饰的 |
Method getDeclaredMethod(String name, Class<?>... parameterTypes) | 获取指定成员方法,可以是类中所有的 |
关于方法1和2有一点细节需要注意。
getMethods()方法会返回父类中的public方法。
而getDeclaredMethods()方法只会返回子类中的所有方法,不涉及到父类。
方法3获取指定的成员方法,指定的有方法名,还有方法中形参类型.class,如果没有参数就不写。
7、如何使用成员方法?
获取修饰符,名字,形参就不细说了,和构造方法的步骤差不多,重要的是invoke方法。
Object invoke(Object obj, Object... args) :运行方法
参数一:用obj对象调用该方法
参数二:调用方法的传递的参数(如果没有就不写)
返回值:方法的返回值(如果没有就不写)
代码:
Student student = new Student(20);
Object o = setAge.invoke(student, 30);
System.out.println((String) o);
setAge方法:
运行结果: