一、定义
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
二、作用
在日常的开发过程中,经常会遇到某个类的某个成员变量、方法或是属性是私有的或是只对系统应用开放,这时候就可以利用Java的反射机制通过反射来获取所需的私有成员或是方法。
三、反射机制相关类与方法
类名 | 作用 |
---|---|
Class类 | 代表类的实体,在运行的Java应用程序中表示类和接口 |
Field类 | 代表类的成员变量(成员变量也称为类的属性) |
Method类 | 代表类的方法 |
Constructor类 | 代表类的构造方法 |
Class类
Class代表类的实体,在运行的Java应用程序中表示类和接口。在这个类中提供了很多有用的方法,这里对他们简单的分类介绍。
- 获得类的相关方法
方法 | 作用 |
---|---|
asSubclass(Class clazz) | 把传递的类的对象转换成代表其子类的对象 |
Cast | 把对象转换成代表类或是接口的对象 |
getClassLoader() | 获得类的加载器 |
getClasses() | 返回一个数组,数组中包含该类中所有公共类和接口类的对象 |
getDeclaredClasses() | 返回一个数组,数组中包含该类中所有类和接口类的对象 |
getName() | 获得类的完整路径名字 |
forName(String className) | 根据类名返回类的对象 |
newInstance() | 创建类的实例 |
getPackage() | 获得类的包 |
getSimpleName() | 获得类的名字 |
getSuperclass() | 获得当前类继承的父类的名字 |
getInterfaces() | 获得当前类实现的类或是接口 |
1.常用获取Class对象实例的方法
a.已知具体类,如已知Person类,通过类的class属性获得,该方法最为安全可靠
Class clazz=Person.class;
b.已知某个类的实例,如person实例,调用该实例的getClass()方法获取Class对象
Class clazz= person.getClass();
c.已知某个类的全类名,且该类在类路径下,通过Class类的静态方法forName()获取,需抛出异常
Class clazz= Class.forName("com.ori.Person");
Type属性
基本类型都有type属性,可以得到这个基本类型的类型,比如:
Class c1 = Boolean.TYPE;
Class c2 = Byte.TYPE;
Class c3 = Float.TYPE;
Class c4 = Double.TYPE;
2.获取类的成员
设定一个测试类
public class Test {
private int age;
private String name;
private int testint;
public Test(int age) {
this.age = age;
}
public Test(int age, String name) {
this.age = age;
this.name = name;
}
private Test(String name) {
this.name = name;
}
public Test() {
}
2-1.获取类的所有构造方法
Test test = new Test();
Class c4 = test.getClass();
Constructor[] constructors = c4.getDeclaredConstructors();
- 通过getDeclaredConstructors可以返回类的所有构造方法,返回的是一个数组因为构造方法可能不止一个
- 通过getModifiers可以得到构造方法的类型
- getParameterTypes可以得到构造方法的所有参数,返回的是一个Class数组
- 通过getConstructors方法获取类中 所有的public类型的构造方法
for (int i = 0; i < constructors.length; i++) {
System.out.print(Modifier.toString(constructors[i].getModifiers()) + "参数:");
Class[] parametertypes = constructors[i].getParameterTypes();
for (int j = 0; j < parametertypes.length; j++) {
System.out.print(parametertypes[j].getName() + " ");
}
System.out.println("");
}
输出结果
2-2.调用构造方法
为了方便,对Test类中的构造器加上打印方法
public Test(int age, String name) {
this.age = age;
this.name = name;
System.out.println("hello" + name + "i am" + age);
}
private Test(String name) {
this.name = name;
System.out.println("My Name is" +
name);
}
借助于newInstance方法来得到类的实例
Class[] p = {int.class,String.class};
constructors = c4.getDeclaredConstructor(p);
constructors.newInstance(24,"HuangLinqing");
调用私有构造方法呢,和上面一样,只是我们要设置constructors.setAccessible(true);代码如下:
Class[] p = {String.class};
constructors = c4.getDeclaredConstructor(p);
constructors.setAccessible(true);
constructors.newInstance("HuangLinqing");
输出分别如下
2-3.调用类的私有方法
写一个私有方法在测试类里
private void welcome(String tips){
System.out.println(tips);
}
- 调用私有方法也需要得到类的实例,如之前的 c4
- 首先通过 getDeclaredMethod方法获取到这个私有方法,第一个参数是方法名,第二个参数是参数类型
- 然后通过invoke方法执行,invoke需要两个参数一个是类的实例,一个是方法参数
Class[] p4 = {String.class};
Method method = c4.getDeclaredMethod("welcome",p4);
method.setAccessible(true);
Object arg1s[] = {"My Name is HuangLinqing"};
method.invoke(test,arg1s);
输出
2-4. 获取类的私有字段并修改值
Field类常用方法
方法 | 用途 |
---|---|
equals(Object obj) | 属性与obj相等则返回true |
get(Object obj) | 获得obj中对应的属性值 |
set(Object obj, Object value) | 设置obj中对应属性值 |
在通过反射得到类的实例之后先获取字段:
Field field = c4.getDeclaredField("name");
field.setAccessible(true);
field.set(ref,"代码男人");
其中ref是通过反射构造方法获取的实例,打印field.get(ref).toString()的值如下: