原创文章,转载请注明: 转载自工学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