原创文章,转载请注明: 转载自工学1号馆
在Java运行时环境中,对于任意一个类,能否知道这个类有哪些属性和方法?对于任意一个对象,能否调用它的任意一个方法?答案是肯定的。这种动态获取类的信息以及动态调用对象的方法的功能来自于Java 语言的反射机制。
Java的反射机制
Java 反射机制主要提供了以下功能:
在运行时判断任意一个对象所属的类。
在运行时构造任意一个类的对象。
在运行时判断任意一个类所具有的成员变量和方法。
在运行时调用任意一个对象的方法
Reflection 是Java被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运行时透过Reflection API取得任何一个已知名称的class的内部信息,包括其modifiers(诸如public, static 等等)、superclass(例如Object)、实现之interfaces(例如Serializable),也包括fields和methods的所有信息,并可于运行时改变fields内容或调用methods
在JDK中,主要由以下类来实现Java反射机制,这些类都位于java.lang.reflect包中:
Class类:代表一个类。
Field 类:代表类的成员变量(成员变量也称为类的属性)。
Method类:代表类的方法。
Constructor 类:代表类的构造方法。
Array类:提供了动态创建数组,以及访问数组的元素的静态方法
Proxy类以及InvocationHandler接口:提供了动态生成代理类以及实例的方法
其中,Class类是Reflection API 中的核心类,它有以下方法:
- getName():获得类的完整名字
- getFields():获得类的public类型的属性
- getDeclaredFields():获得类的所有属性
- getMethods():获得类的public类型的方法
- getDeclaredMethods():获得类的所有方法
- getMethod(String name, Class[] parameterTypes):获得类的特定方法,name参数指定方法的名字,parameterTypes 参数指定方法的参数类型
- getConstructors():获得类的public类型的构造方法
- getConstructor(Class[] parameterTypes):获得类的特定构造方法,parameterTypes 指定构造方法的参数类型
- newInstance():通过类的不带参数的构造方法创建这个类的一个对象
每当一個类被载入时,JVM就自动为其生成一个Class对象,通过操作class对象,我们可以得到该对象的所有成员并操作它们,举个例子:
package javatest;
import java.util.*;
class Student {
private String name;
private int age;
private int ID;
public Student() {
}
public Student(String name, int age, int ID) {
this.name = name;
this.age = age;
this.ID = ID;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class javatest {
public static void main(String[] args) {
Student s1 = new Student("java", 20, 123);
Class ss = s1.getClass();
System.out.println("getName: " + ss.getName());
System.out.println("getFields: " + ss.getFields());
System.out.println("getDeclaredFields: " + ss.getDeclaredFields());
System.out.println("getMethods: " + ss.getMethods());
System.out.println("isInterface: " + ss.isInterface());
System.out.println("isPrimitive: " + ss.isPrimitive());
System.out.println("isArray: " + ss.isArray());
System.out.println("SuperClass: " + ss.getSuperclass().getName());
}
}
运行结果如下:
getName: javatest.Student
getFields: [Ljava.lang.reflect.Field;@4e25154f
getDeclaredFields: [Ljava.lang.reflect.Field;@70dea4e
getMethods: [Ljava.lang.reflect.Method;@5c647e05
isInterface: false
isPrimitive: false
isArray: false
SuperClass: java.lang.Object
通过反射得到类对象:
| 获取方式 | 说明 | 示例 |
| object.getClass()每个对象都有此方法 | 获取指定实例对象的Class | List list = new ArrayList();Class listClass = list.getClass(); |
| class. getSuperclass() | 获取当前Class的继承类Class | List list = new ArrayList();Class listClass = list.getClass();Class superClass = listClass. getSuperclass(); |
| Object.class | .class直接获取 | Class listClass = ArrayList.class; |
| Class.forName(类名) | 用Class的静态方法,传入类的全称即可 | try {Class c = Class.forName(“java.util.ArrayList”);} catch (ClassNotFoundException e) {e.printStackTrace();} |
| Primitive.TYPE | 基本数据类型的封装类获取Class的方式 | Class longClass = Long.TYPE;Class integerClass = Integer.TYPE;Class voidClass = Void.TYPE; |
平常情况我们通过new Object来生成一个类的实例,但有时候我们没法直接new,只能通过反射动态生成。
通过反射实例化对象:
实例化无参构造函数的对象,两种方式:
① Class. newInstance();
② Class. getConstructor (new Class[]{}).newInstance(new Object[]{})
实例化带参构造函数的对象:
class.getConstructor(Class<?>… parameterTypes) . newInstance(Object… initargs)
接下来举个例子实战一下:
package javatest;
import java.util.*;
class BaseUser {
public int baseId;
public int getBaseId() {
return baseId;
}
public void setBaseId(int baseId) {
this.baseId = baseId;
}
}
class User extends BaseUser {
private int id;
public String name;
public User(){}
public User(String name) {
this.name = name;
}
private int getId() {
return id;
}
private void serId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class javatest {
public static void main(String[] args) {
Class<?> userClass = User.class;
try {
User user = (User)userClass.newInstance();
System.out.println("1.反射实例化(无参): " + user);
User user2 = (User)userClass.getConstructor(new Class[]{}).newInstance(new Object[]{});
System.out.println("2.反射实例化(无参): " + user2);
User user3 = (User)userClass.getConstructor(new Class[]{String.class}).newInstance(new Object[]{"test"});
System.out.println("反射实例化(带参): " + user3 + " 属性Name的值: " + user3.getName());
User user4 = new User();
System.out.println("正常实例化: " + user4);
} catch(Exception e) {
e.printStackTrace();
}
}
}
运行结果如下:
1.反射实例化(无参): javatest.User@7852e922
2.反射实例化(无参): javatest.User@4e25154f
反射实例化(带参): javatest.User@70dea4e 属性Name的值: test
正常实例化: javatest.User@5c647e05
通过反射调用Method(方法):
获得当前类以及超类的public Method:
Method[] arrMethods = classType.getMethods();
获得当前类申明的所有Method:
Method[] arrMethods = classType.getDeclaredMethods();
获得当前类以及超类指定的public Method:
Method method = classType.getMethod(String name, Class<?>… parameterTypes);
获得当前类申明的指定的Method:
Method method = classType.getDeclaredMethod(String name, Class<?>… parameterTypes)
通过反射动态运行指定Method:
Object obj = method.invoke(Object obj, Object… args)
例:动态操纵Method,改变一下上面的例子的主函数:
public class reflectMethodDemo {
public static void main(String[] args) {
User user = new User();
Class<?> userClass = User.class;
Method[] publicMethod = userClass.getMethods();
for(Method method : publicMethod) {
System.out.println("获得当前类以及超类的所有publicMethod: " + method);
}
Method[] currentMethod = userClass.getDeclaredMethods();
for(Method method : currentMethod) {
System.out.println("获得当前类自己声明的所有的Method: " + method);
}
try {
Method setBaseIdMethod = userClass.getMethod("setBaseId", new Class[]{int.class});
System.out.println("获得当前类或超类的public Method setBaseId: " + setBaseIdMethod);
Method setIdMethod = userClass.getDeclaredMethod("setId", new Class[]{int.class});
System.out.println("获得当前类的Method setId: " + setIdMethod);
setIdMethod.setAccessible(true);
setIdMethod.invoke(user, new Object[]{110});
Method getIdMethod = userClass.getDeclaredMethod("getId", new Class[]{});
getIdMethod.setAccessible(true);
Integer getId = (Integer)getIdMethod.invoke(user, new Object[]{});
System.out.println("调用getId方法获得: " + getId);
} catch(Exception e) {
e.printStackTrace();
}
}
}
通过反射调用Field(变量):
获得当前类以及超类的public Field:
Field[] arrFields = classType.getFields();
获得当前类申明的所有Field:
Field[] arrFields = classType.getDeclaredFields();
获得当前类以及超类指定的public Field:
Field field = classType.getField(String name);
获得当前类申明的指定的Field:
Field field = classType.getDeclaredField(String name);
通过反射动态设定Field的值:
fieldType.set(Object obj, Object value);
通过反射动态获取Field的值:
Object obj = fieldType.get(Object obj) ;
例:动态操纵Field,改变一下上面的例子的主函数:
public class reflectFieldDemo {
public static void main(String[] args) {
User1 user = new User1();
Class<?> userClass = user.getClass();
Field[] publicField = userClass.getFields();
for(Field field : publicField) {
System.out.println("获得该类及超类所有public Field: " + field);
}
Field[] currentField = userClass.getDeclaredFields();
for(Field field : currentField) {
System.out.println("获得该类自己声明的所有Field: " + field);
}
try {
Field baseIdField = userClass.getField("baseId");
System.out.println("获得该类或超类名为baseId的public Field: " + baseIdField);
Field idField = userClass.getDeclaredField("id");
System.out.println("获得该类自己声明的名为id的Field: " + idField);
idField.setAccessible(true);
idField.set(user, 110);
Integer id = (Integer)idField.get(user);
System.out.println("id的值为: " + id);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Java反射总结:
1、只要用到反射,先获得Class Object
2、没有方法能获得当前类的超类的private方法和属性,你必须通过getSuperclass()找到超类以后再去尝试获得
3、通常情况即使是当前类,private属性或方法也是不能访问的,你需要设置压制权限setAccessible(true)来取得private的访问权。但说实话,这已经破坏了面向对象的规则,所以除非万不得已,请尽量少用。

Comments