标签:
林炳文Evankaka原创作品。转载请注明出处http://blog.csdn.net/evankakay
摘要:本文详细深入讲解是Java中反射的机制,并介绍了如何通过反射来生成对象、调用函数、取得字段、设置字段的方法。最后,给出了一些反射常用到的实例。
一、反射
(1)概念
反射含义:可以获取正在运行的Java对象。
(2)功能
1)在运行时判断任意一个对象所属的类
2)在运行时构造任意一个类的对象
3) 在运行时判断任意一个类所具有的成员变量和方法
4)在运行时调用任意一个对象的方法
(3)实现Java反射的类
1)Class:它表示正在运行的Java应用程序中的类和接口
2)Field:提供有关类或接口的属性信息,以及对它的动态访问权限
3)Constructor:提供关于类的单个构造方法的信息以及对它的访问权限
4)Method:提供关于类或接口中某个方法信息
注意:Class类是Java反射中最重要的一个功能类,所有获取对象的信息(包括:方法/属性/构造方法/访问权限)都需要它来实现
(4)取得class的三种方法
Dog dog = new Dog(); Class<?> dogClass = dog.getClass(); Class<?> dogClass1 = Dog.class; Class<?> dogClass2 = Class.forName("com.lin.Dog");//注意要添加异常抛出
(5)关键方法
方法关键字 | 含义 |
getDeclaredMethods() | 获取所有的方法 |
getReturnType() | 获得方法的放回类型 |
getParameterTypes() | 获得方法的传入参数类型 |
getDeclaredMethod("方法名",参数类型.class,……) | 获得特定的方法 |
|
|
构造方法关键字 | 含义 |
getDeclaredConstructors() | 获取所有的构造方法 |
getDeclaredConstructor(参数类型.class,……) | 获取特定的构造方法 |
|
|
父类和父接口 | 含义 |
getSuperclass() | 获取某类的父类 |
getInterfaces() | 获取某类实现的接口 |
(6)一些区别函数
public Method[] getMethods()返回某个类的所有公用(public)方法包括其继承类的公用方法,当然也包括它所实现接口的方法。
public Method[] getDeclaredMethods()对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。当然也包括它所实现接口的方法。
getFields()获得某个类的所有的公共(public)的字段,包括父类。
getDeclaredFields()获得某个类的所有申明的字段,即包括public、private和proteced,
但是不包括父类的申明字段。
下面来看一个例子说明:
动物接口
package com.lin; public interface Aminal { public String eat(String obj); public int run(int obj); }
来看看各自的调用:package com.lin; import java.util.jar.Attributes.Name; public class Dog implements Aminal { private String name; private int age; public Dog() { // TODO 自动生成的构造函数存根 } public Dog(String name,int age) { this.name = name; this.age = age; } public Dog(String name) { this.name = name; this.age = 10; } private void sleep(int x) { System.out.println(name + "睡觉" + x + "分钟"); } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String eat(String obj) { System.out.println(name + "吃"+ obj); return null; } @Override public int run(int obj) { System.out.println("跑,速度:"+ obj); return 0; } @Override public String toString() { return "狗名:" + name + " 狗的年纪:" + age; } private static void play() { System.out.println("狗狗自己玩啊玩"); } }
package com.lin; import java.lang.reflect.Method; public class ReflectLearning { public static void main(String[] args) throws ClassNotFoundException { Dog dog = new Dog(); System.out.println(dog.getClass()); System.out.println(dog.getClass().getName()); Class<?> dogClass = dog.getClass(); Class<?> dogClass1 = Dog.class; Class<?> dogClass2 = Class.forName("com.lin.Dog"); Method[] methods1 = dogClass.getMethods(); System.out.println("====================通过getMethods取得方法开始===================="); for (Method method : methods1) { System.out.println(method); } System.out.println("====================通过getMethods取得方法结束===================="); Method[] methods2 = dogClass.getDeclaredMethods(); System.out.println("====================通过getDeclaredMethods取得方法开始===================="); for (Method method : methods2) { System.out.println(method); } System.out.println("====================通过getDeclaredMethods取得方法结束===================="); } }
getMethods方法
getDeclareMethos方法:
从上面可以看出getMethods()返回某个类的所有公用(public)方法包括其继承类的公用方法,当然也包括它所实现接口的方法。getDeclaredMethods()对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。当然也包括它所实现接口的方法。
二、通过反射调用构造函数
(1)、列出所有的构造函数:
Constructor<?>[] constructors = dogClass.getConstructors(); System.out.println("====================列出所有的构造函数结束===================="); for (Constructor<?> constructor : constructors) { System.out.println(constructor); } System.out.println("====================列出所有的构造函数结束====================");输出结果:
(2)、通过反射生成对象
System.out.println("====================通过newInstance()来生成对象,一定在有默认构造函数===================="); Dog dog1 = (Dog) dogClass.newInstance(); dog1.setName("狗狗1号"); dog1.setAge(7); System.out.println(dog1); System.out.println("====================通过newInstance(参数)方法一来生成对象===================="); Dog dog2 = (Dog)constructors[0].newInstance("狗狗2号"); System.out.println(dog2); System.out.println("====================通过newInstance(参数)方法二来生成对象===================="); Constructor con1 = dogClass.getConstructor(new Class[]{String.class,int.class}); //主要就是这句了 Dog dog3 = (Dog) con1.newInstance(new Object[]{"狗狗3号",14}); System.out.println(dog3);输出结果:
从上面可以看出,先通过getConstructor(new Class[]{xxxx.class,yyy.class}),再通过con1.newInstance(new Object[]{"xxxxx",...});的方式是最灵活的,可以自动根据输入的参数类型和个数,找到对应的构造函数来调用。第二种方法需要得到构造函数的数组,并且需要知道对应哪一个构造函数。第一种就只能调用无参构造函数。
三、通过反射调用普通函数、静态函数
(1)取得函数的一些基本信息
Class<?> dogClass = Dog.class; Method[] methods = dogClass.getDeclaredMethods(); for (Method method : methods) { System.out.println("函数名:"+method.getName() +" 函数类型:"+ method.getModifiers() + " 函数返回: "+ method.getReturnType() + " 函数参数个数:" + method.getParameterCount()); }输出结果:
其中函数类型对应表如下:
PUBLIC: 1
PRIVATE: 2
PROTECTED: 4
STATIC: 8
FINAL: 16
SYNCHRONIZED: 32
VOLATILE: 64
TRANSIENT: 128
NATIVE: 256
INTERFACE: 512
ABSTRACT: 1024
STRICT: 2048
(2)方法调用
这是当前狗类的方法:
package com.lin; import java.util.jar.Attributes.Name; public class Dog implements Aminal { private String name; private int age; public Dog() { // TODO 自动生成的构造函数存根 } public Dog(String name,int age) { this.name = name; this.age = age; } public Dog(String name) { this.name = name; this.age = 10; } private void sleep(int x) { System.out.println(name + "睡觉" + x + "分钟"); } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String eat(String obj) { System.out.println(name + "吃"+ obj); return null; } @Override public int run(int obj) { System.out.println("跑,速度:"+ obj); return 0; } @Override public String toString() { return "狗名:" + name + " 狗的年纪:" + age; } private static void play() { System.out.println("狗狗自己玩啊玩"); } }
//调用私有方法 Method method1 = dogClass.getDeclaredMethod("sleep", int.class);//不要用getMethod,它只能取到public方法 Dog dog1 = (Dog) dogClass.getConstructor(new Class[] {String.class}).newInstance(new Object[]{"狗狗1号"}); method1.setAccessible(true);//私有方法一定要加这句 method1.invoke(dog1, 12); //调用私有静态方法 Method method2 = dogClass.getDeclaredMethod("play");//不要用getMethod,它只能取到public方法 method2.setAccessible(true);//私有方法一定要加这句 method2.invoke(dogClass.newInstance()); //调用公共方法 Method method3 = dogClass.getMethod("eat", String.class);//这里也可以用getDeclaredMethod Dog dog3 = new Dog("狗狗3号", 45); method3.invoke(dog3, "苹果~");
方法调用这里一定要记住getMethod和getDeclaredMethod的区别,并且在调用私有的方法之前一定要加setAccessible(true)这一句,要不会报错!
四、通过反射取得字段、设置字段值
(1)怎么通过反射获取类的属性
a)Class.getDeclaredField(String name);
返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段。
b)Class.getDeclaredFields();
返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段。
c)Class.getField(String name);
返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。
d)Class.getField();
返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段。
(2)进行属性获取更改
Dog dog1 = new Dog("狗狗1号", 12); System.out.println(dog1); Class<?> dogClass = dog1.getClass(); Field field1 = dogClass.getDeclaredField("name");//注意,getField只能取得public的字段 field1.setAccessible(true);//私有变量必须先设置Accessible为true System.out.println("原本狗名:" + field1.get(dog1)); field1.set(dog1,"狗狗2号"); System.out.println(dog1);
值得注意的是获取私有属性的时候必须先设置Accessible为true,然后才能获取。
五、反射常用工具类
(1)bean复制工具
这里可以使用commons-beanutils中的copyProperties()方法,自己写是为了加深对反射的理解。
1、toString的基类
package com.lin; import java.lang.reflect.Field; import java.text.SimpleDateFormat; import java.util.Date; /** * bean基類 * @author lin * */ public class BaseBean { public String toString() { StringBuffer sb = new StringBuffer(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Class<?> cls = this.getClass(); Field[] fields = cls.getDeclaredFields(); sb.append(cls.getName() + "{"); for (Field field : fields) { try { field.setAccessible(true); sb.append(field.getName()); sb.append("="); sb.append(field.get(this)); sb.append(" "); } catch (Exception e) { e.printStackTrace(); } } sb.append("}"); return sb.toString(); } }
package com.lin; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * 将一个JavaBean风格对象的属性值拷贝到另一个对象的同名属性中 (如果不存在同名属性的就不拷贝) **/ public class BeanCopy { private static String GET = "get"; private static String SET = "set"; /** * * @param source * @param target * @throws Exception */ public static void copy(Object source,Object target){ Class<?> sourceClz = source.getClass(); Class<?> targetClz = target.getClass(); // 得到Class对象所表征的类的所有属性(包括私有属性) Field[] sourceFields = sourceClz.getDeclaredFields(); if (sourceFields.length == 0) { sourceFields = sourceClz.getSuperclass().getDeclaredFields(); } int len = sourceFields.length; for (int i = 0; i < len; i++) { String fieldName = sourceFields[i].getName(); Field targetField = null; // 得到targetClz对象所表征的类的名为fieldName的属性,不存在就进入下次循环 try { targetField = targetClz.getDeclaredField(fieldName); } catch (NoSuchFieldException e) { try { targetField = targetClz.getSuperclass().getDeclaredField(fieldName); } catch (NoSuchFieldException e1) { e1.printStackTrace(); } catch (SecurityException e1) { e1.printStackTrace(); } } if (targetField == null) { continue; } // 判断sourceClz字段类型和targetClz同名字段类型是否相同 if (sourceFields[i].getType() == targetField.getType()) { // 由属性名字得到对应get和set方法的名字 String getMethodName = GET + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1); String setMethodName = SET + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1); // 由方法的名字得到get和set方法的Method对象 Method getMethod; Method setMethod; try { try { getMethod = sourceClz.getDeclaredMethod(getMethodName,new Class[] {});//get方法入參為空 } catch (NoSuchMethodException e) { getMethod = sourceClz.getSuperclass().getDeclaredMethod(getMethodName,new Class[] {}); } try { setMethod = targetClz.getDeclaredMethod(setMethodName,sourceFields[i].getType());//set方法入參不為空 } catch (NoSuchMethodException e) { setMethod = targetClz.getSuperclass().getDeclaredMethod(setMethodName,sourceFields[i].getType()); } // 调用source对象的getMethod方法 Object result = getMethod.invoke(source, new Object[] {}); // 调用target对象的setMethod方法 setMethod.invoke(target, result); } catch (SecurityException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } else { continue; } } } }使用:
新建两个类:
package com.lin; import java.util.Date; public class Car extends BaseBean{ private String name; private String id; private Boolean sellFlag; private int age; private double maxSpeed; private double minSpeed; private int driverPeople; private Date date; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getId() { return id; } public void setId(String id) { this.id = id; } public Boolean getSellFlag() { return sellFlag; } public void setSellFlag(Boolean sellFlag) { this.sellFlag = sellFlag; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public double getMaxSpeed() { return maxSpeed; } public void setMaxSpeed(double maxSpeed) { this.maxSpeed = maxSpeed; } public double getMinSpeed() { return minSpeed; } public void setMinSpeed(double minSpeed) { this.minSpeed = minSpeed; } public int getDriverPeople() { return driverPeople; } public void setDriverPeople(int driverPeople) { this.driverPeople = driverPeople; } public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } }
package com.lin; import java.util.Date; public class Bus extends BaseBean{ private String name; private String id; private Boolean sellFlag; private int age; private double maxSpeed; private double minSpeed; private long driverPeople;//和car類型不同 private int driverYear;//car沒有這個 private Date date; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getId() { return id; } public void setId(String id) { this.id = id; } public Boolean getSellFlag() { return sellFlag; } public void setSellFlag(Boolean sellFlag) { this.sellFlag = sellFlag; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public double getMaxSpeed() { return maxSpeed; } public void setMaxSpeed(double maxSpeed) { this.maxSpeed = maxSpeed; } public double getMinSpeed() { return minSpeed; } public void setMinSpeed(double minSpeed) { this.minSpeed = minSpeed; } public long getDriverPeople() { return driverPeople; } public void setDriverPeople(long driverPeople) { this.driverPeople = driverPeople; } public int getDriverYear() { return driverYear; } public void setDriverYear(int driverYear) { this.driverYear = driverYear; } public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } }
public static void test5() { Car car = new Car(); car.setAge(12); car.setDriverPeople(4); car.setId("YU1234"); car.setMaxSpeed(13.66); car.setMinSpeed(1.09); car.setName("小车"); car.setSellFlag(false); car.setDate(new Date()); Bus bus = new Bus(); BeanCopy.copy(car,bus); System.out.println(car); System.out.println(bus); }
标签:
原文地址:http://blog.csdn.net/evankaka/article/details/49978481