反射机制
Java反射是Java语言的一个很重要的特征,它使得Java具有了“动态性”。
一般而言,开发者社群说到动态语言,大致认同的一个定义 是:“程序运行时,允许改变程序结构或者变量类型,这种语言称为动态语言”。从这个观点看,Perl,Python,Ruby是动态语言,C++,Java,C#不是动态语言。
Reflection是java被视为动态(或准动态)语言的一个关键性质。
Java反射机制主要提供了一下功能:
1、在运行时判断任意一个对象所属的类。
2、在运行时构造任意一个类的对象。
3、在运行时判断任意一个类所具有的成员变量和方法。
4、在运行时调用任意一个对象的方法。
在JDK中,主要由一下类来实现Java反射机制,这些类都位于java.lang.reflect包中:
1、Class类:代表一个类
2、Field类:代表类的成员变量(成员变量也称为类的属性)
3、Method类:代表类的方法
4、Constructor类:代表类的构造方法。
5、Array类:提供了动态创建数组,以及访问数组的元素的静态方法。
一、通过Class类获取成员变量、成员方法、接口,超类,构造方法等。
在java.lang.Object类中定义了getClass()方法,因此对于任意一个Java对象,都可以通过此方法获得对象的类型。Class类是ReflectionAPI中核心的类,它有以下方法
getName():获得类的完整名字
getFields():获得类的public类型的属性
getDeclaredFields():获得类的所有属性
getMethods():获得类的public类型的方法
getDeclaredMethods():获得类的所有方法
getMethod(String name,Class[] parameterTypes):获得类的特定方法,name参数指定方法的名字,parameterType参数指定方法的参数类型。
getConstructors():获得类的public类型的构造方法。
getConstructor(Class[] parameterTypes):获得类的特定构造方法,parameterType参数指定构造方法的参数类型
newInstance():通过类的不带参数的构造方法创建这个类的一个对象。
二、运行时复制对象
1 package reflection; 2 import java.lang.reflect.Field; 3 import java.lang.reflect.Method; 4 public class ReflectTester { 5 public Object copy(Object object) throws Exception { 6 // 获得对象的类型 7 Class<?> classType = object.getClass(); 8 System.out.println("Class:" + classType.getName()); 9 // 通过默认构造方法创建一个新的对象 10 System.out.println("该类的构造方法有:"+classType.getConstructors()[0]); 11 Object objectCopy = classType.getConstructor() 12 .newInstance(); 13 // 获得对象的所有属性 14 Field[] fields = classType.getDeclaredFields(); 15 for (int i = 0; i < fields.length; i++) { 16 Field field = fields[i]; 17 String fieldName = field.getName(); 18 System.out.println("fieldName:"+fieldName); 19 String firstLetter = fieldName.substring(0, 1).toUpperCase(); 20 // 获得和属性对应的getXXX()方法的名字 21 String getMethodName = "get" + firstLetter + fieldName.substring(1); 22 // 获得和属性对应的setXXX()方法的名字 23 String setMethodName = "set" + firstLetter + fieldName.substring(1); 24 // 获得和属性对应的getXXX()方法 25 Method getMethod = classType.getMethod(getMethodName, 26 new Class[] {}); 27 // 获得和属性对应的setXXX()方法 28 Method setMethod = classType.getMethod(setMethodName, 29 new Class[] { field.getType() }); 30 // 调用原对象的getXXX()方法 31 Object value = getMethod.invoke(object); 32 System.out.println(fieldName + ":" + value); 33 // 调用拷贝对象的setXXX()方法 34 setMethod.invoke(objectCopy, new Object[] { value }); 35 } 36 return objectCopy; 37 } 38 public static void main(String[] a) throws Exception { 39 Customer customer = new Customer("Tom", 21); 40 customer.setId(new Long(1)); 41 Customer customerCopy = (Customer) new ReflectTester().copy(customer); 42 System.out.println(customerCopy==customer); 43 System.out.println(customerCopy.equals(customer)); 44 System.out.println("Copy information:" + customerCopy.getId() + "" 45 + customerCopy.getName() + "" + customerCopy.getAge()); 46 } 47 } 48 class Customer { 49 private Long id; 50 private String name; 51 private int age; 52 public Customer() { 53 } 54 public Customer(String name, int age) { 55 this.name = name; 56 this.age = age; 57 } 58 public Long getId() { 59 return id; 60 } 61 public String getName() { 62 return name; 63 } 64 public int getAge() { 65 return age; 66 } 67 public void setId(Long id) { 68 this.id = id; 69 } 70 public void setName(String name) { 71 this.name = name; 72 } 73 public void setAge(int age) { 74 this.age = age; 75 } 76 }
解说:ReflectTester类的copy(object,object)方法依次执行以下步骤
(1)获得对象的类型
Class classType=object.getClass();
System.out.println("Class:"+classType.getName());
(2)通过默认构造方法创建一个新对象:
Object objectCopy=classType.getConstructor().newInstance();
以上代码先调用Class类的getConstructor()方法获得一个Constructor对象,它代表默认的构造方法,然后调用Constructor对象的newInstance()方法构造一个实例。
(3)获得对象的所有属性:
Field[] fields=classType.getDeclaredFields();
Class类的getDeclaredFields()方法返回类的所有属性。
(4)获得每个属性对应的getXXX()和setXXX()然后执行这些方法,把原来的属性拷贝到新的对象中。
三、用反射机制调用对象的方法
1 package reflection; 2 import java.lang.reflect.InvocationTargetException; 3 import java.lang.reflect.Method; 4 public class InvokeTester { 5 public int add(int param1,int param2){ 6 return param1+param2; 7 } 8 9 public String echo(String msg){ 10 return "echo:"+msg; 11 } 12 13 public static void main(String[] args) throws InstantiationException, IllegalAccessException, SecurityException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException{ 14 Class<?> classType=InvokeTester.class; 15 Object invokeTester =classType.newInstance(); 16 17 //获取InvokeTester类的add()方法 18 Method addMethod=classType.getMethod("add", int.class,int.class); 19 //调用invokeTester对象上的add()方法 20 Object result=addMethod.invoke(invokeTester,100,200); 21 System.out.println((Integer)result); 22 23 //获取InvokeTester类的echo方法 24 Method echoMethod=classType.getMethod("echo", java.lang.String.class); 25 26 Object echoResult=echoMethod.invoke(invokeTester, "HelloWorld"); 27 System.out.println(echoResult); 28 29 } 30 }
四、动态创建和访问数组
创建简单的一维数组
1 import java.lang.reflect.Array; 2 public class ArrayTester1 { 3 public static void main(String[] args) throws ClassNotFoundException { 4 Class<?> classType=Class.forName("java.lang.String"); 5 //创建一个长度为10的字符串数组 6 Object array=Array.newInstance(classType, 10); 7 //把索引位置为5的元素设为“hello” 8 Array.set(array, 5, "hello"); 9 //获得索引位置为5的元素的值 10 String s=(String)Array.get(array, 5); 11 System.out.println(s); 12 } 13 }
创建多维数组
1 public class ArrayTester2 { 2 /** 3 * @param args 4 */ 5 public static void main(String[] args) { 6 7 //创建一个int类型的3维数组,维度分别是5,10,15 8 Object array=Array.newInstance(int.class, 5,10,15); 9 Object arrayObj=Array.get(array, 3); 10 Class<?> cls=arrayObj.getClass().getComponentType(); 11 System.out.println(array.getClass().getComponentType()); 12 System.out.println(cls); 13 14 arrayObj=Array.get(arrayObj, 5); 15 Array.setInt(arrayObj, 10, 37); 16 int[][][] arrarCast=(int[][][]) array; 17 System.out.println(arrarCast[3][5][10]); 18 } 19 }

浙公网安备 33010602011771号