林炳文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的三种方法

  1. Dog dog = new Dog();
  2. Class<?> dogClass = dog.getClass();
  3. Class<?> dogClass1 = Dog.class;
  4. 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,
但是不包括父类的申明字段。

下面来看一个例子说明:

动物接口

  1. package com.lin;
  2. public interface Aminal {
  3. public String eat(String obj);
  4. public int run(int obj);
  5. }

实现类:

  1. <pre name="code" class="java">package com.lin;
  2. import java.util.jar.Attributes.Name;
  3. public class Dog implements Aminal {
  4. private String name;
  5. private int age;
  6. public Dog() {
  7. // TODO 自动生成的构造函数存根
  8. }
  9. public Dog(String name,int age) {
  10. this.name = name;
  11. this.age = age;
  12. }
  13. public Dog(String name) {
  14. this.name = name;
  15. this.age = 10;
  16. }
  17. private void sleep(int x) {
  18. System.out.println(name + "睡觉" + x + "分钟");
  19. }
  20. public String getName() {
  21. return name;
  22. }
  23. public void setName(String name) {
  24. this.name = name;
  25. }
  26. public int getAge() {
  27. return age;
  28. }
  29. public void setAge(int age) {
  30. this.age = age;
  31. }
  32. @Override
  33. public String eat(String obj) {
  34. System.out.println(name + "吃"+ obj);
  35. return null;
  36. }
  37. @Override
  38. public int run(int obj) {
  39. System.out.println("跑,速度:"+ obj);
  40. return 0;
  41. }
  42. @Override
  43. public String toString() {
  44. return "狗名:" + name + "  狗的年纪:" + age;
  45. }
  46. private static void play() {
  47. System.out.println("狗狗自己玩啊玩");
  48. }
  49. }
  50. </pre><br>

来看看各自的调用:

  1. package com.lin;
  2. import java.lang.reflect.Method;
  3. public class ReflectLearning {
  4. public static void main(String[] args) throws ClassNotFoundException {
  5. Dog dog = new Dog();
  6. System.out.println(dog.getClass());
  7. System.out.println(dog.getClass().getName());
  8. Class<?> dogClass = dog.getClass();
  9. Class<?> dogClass1 = Dog.class;
  10. Class<?> dogClass2 = Class.forName("com.lin.Dog");
  11. Method[] methods1 = dogClass.getMethods();
  12. System.out.println("====================通过getMethods取得方法开始====================");
  13. for (Method method : methods1) {
  14. System.out.println(method);
  15. }
  16. System.out.println("====================通过getMethods取得方法结束====================");
  17. Method[] methods2 = dogClass.getDeclaredMethods();
  18. System.out.println("====================通过getDeclaredMethods取得方法开始====================");
  19. for (Method method : methods2) {
  20. System.out.println(method);
  21. }
  22. System.out.println("====================通过getDeclaredMethods取得方法结束====================");
  23. }
  24. }

来看下结果:

getMethods方法

getDeclareMethos方法:

从上面可以看出getMethods()返回某个类的所有公用(public)方法包括其继承类的公用方法,当然也包括它所实现接口的方法。getDeclaredMethods()对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。当然也包括它所实现接口的方法。

二、通过反射调用构造函数

(1)、列出所有的构造函数:

  1. Constructor<?>[] constructors = dogClass.getConstructors();
  2. System.out.println("====================列出所有的构造函数结束====================");
  3. for (Constructor<?> constructor : constructors) {
  4. System.out.println(constructor);
  5. }
  6. System.out.println("====================列出所有的构造函数结束====================");

输出结果:

(2)、通过反射生成对象

  1. System.out.println("====================通过newInstance()来生成对象,一定在有默认构造函数====================");
  2. Dog dog1 = (Dog) dogClass.newInstance();
  3. dog1.setName("狗狗1号");
  4. dog1.setAge(7);
  5. System.out.println(dog1);
  6. System.out.println("====================通过newInstance(参数)方法一来生成对象====================");
  7. Dog dog2 = (Dog)constructors[0].newInstance("狗狗2号");
  8. System.out.println(dog2);
  9. System.out.println("====================通过newInstance(参数)方法二来生成对象====================");
  10. Constructor con1 = dogClass.getConstructor(new  Class[]{String.class,int.class});     //主要就是这句了
  11. Dog dog3 = (Dog) con1.newInstance(new Object[]{"狗狗3号",14});
  12. System.out.println(dog3);

输出结果:

从上面可以看出,先通过getConstructor(new  Class[]{xxxx.class,yyy.class}),再通过con1.newInstance(new Object[]{"xxxxx",...});的方式是最灵活的,可以自动根据输入的参数类型和个数,找到对应的构造函数来调用。第二种方法需要得到构造函数的数组,并且需要知道对应哪一个构造函数。第一种就只能调用无参构造函数。

三、通过反射调用普通函数、静态函数

(1)取得函数的一些基本信息

  1. Class<?> dogClass = Dog.class;
  2. Method[] methods = dogClass.getDeclaredMethods();
  3. for (Method method : methods) {
  4. System.out.println("函数名:"+method.getName() +"        函数类型:"+ method.getModifiers() + "         函数返回: "+ method.getReturnType() + "        函数参数个数:" + method.getParameterCount());
  5. }

输出结果:

其中函数类型对应表如下:
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)方法调用

这是当前狗类的方法:

  1. package com.lin;
  2. import java.util.jar.Attributes.Name;
  3. public class Dog implements Aminal {
  4. private String name;
  5. private int age;
  6. public Dog() {
  7. // TODO 自动生成的构造函数存根
  8. }
  9. public Dog(String name,int age) {
  10. this.name = name;
  11. this.age = age;
  12. }
  13. public Dog(String name) {
  14. this.name = name;
  15. this.age = 10;
  16. }
  17. private void sleep(int x) {
  18. System.out.println(name + "睡觉" + x + "分钟");
  19. }
  20. public String getName() {
  21. return name;
  22. }
  23. public void setName(String name) {
  24. this.name = name;
  25. }
  26. public int getAge() {
  27. return age;
  28. }
  29. public void setAge(int age) {
  30. this.age = age;
  31. }
  32. @Override
  33. public String eat(String obj) {
  34. System.out.println(name + "吃"+ obj);
  35. return null;
  36. }
  37. @Override
  38. public int run(int obj) {
  39. System.out.println("跑,速度:"+ obj);
  40. return 0;
  41. }
  42. @Override
  43. public String toString() {
  44. return "狗名:" + name + "  狗的年纪:" + age;
  45. }
  46. private static void play() {
  47. System.out.println("狗狗自己玩啊玩");
  48. }
  49. }

不同方法的调用过程:

  1. //调用私有方法
  2. Method method1 = dogClass.getDeclaredMethod("sleep", int.class);//不要用getMethod,它只能取到public方法
  3. Dog dog1 = (Dog) dogClass.getConstructor(new Class[] {String.class}).newInstance(new Object[]{"狗狗1号"});
  4. method1.setAccessible(true);//私有方法一定要加这句
  5. method1.invoke(dog1, 12);
  6. //调用私有静态方法
  7. Method method2 = dogClass.getDeclaredMethod("play");//不要用getMethod,它只能取到public方法
  8. method2.setAccessible(true);//私有方法一定要加这句
  9. method2.invoke(dogClass.newInstance());
  10. //调用公共方法
  11. Method method3 = dogClass.getMethod("eat", String.class);//这里也可以用getDeclaredMethod
  12. Dog dog3 = new Dog("狗狗3号", 45);
  13. 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)进行属性获取更改

  1. Dog dog1 = new Dog("狗狗1号", 12);
  2. System.out.println(dog1);
  3. Class<?> dogClass = dog1.getClass();
  4. Field field1 = dogClass.getDeclaredField("name");//注意,getField只能取得public的字段
  5. field1.setAccessible(true);//私有变量必须先设置Accessible为true
  6. System.out.println("原本狗名:" + field1.get(dog1));
  7. field1.set(dog1,"狗狗2号");
  8. System.out.println(dog1);

输出结果:

值得注意的是获取私有属性的时候必须先设置Accessible为true,然后才能获取。

五、反射常用工具类

(1)bean复制工具

这里可以使用commons-beanutils中的copyProperties()方法,自己写是为了加深对反射的理解。

1、toString的基类

  1. package com.lin;
  2. import java.lang.reflect.Field;
  3. import java.text.SimpleDateFormat;
  4. import java.util.Date;
  5. /**
  6. * bean基類
  7. * @author lin
  8. *
  9. */
  10. public class BaseBean {
  11. public String toString() {
  12. StringBuffer sb = new StringBuffer();
  13. SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  14. Class<?> cls = this.getClass();
  15. Field[] fields = cls.getDeclaredFields();
  16. sb.append(cls.getName() + "{");
  17. for (Field field : fields) {
  18. try {
  19. field.setAccessible(true);
  20. sb.append(field.getName());
  21. sb.append("=");
  22. sb.append(field.get(this));
  23. sb.append(" ");
  24. } catch (Exception e) {
  25. e.printStackTrace();
  26. }
  27. }
  28. sb.append("}");
  29. return sb.toString();
  30. }
  31. }

2、bean复制工具

  1. package com.lin;
  2. import java.lang.reflect.Field;
  3. import java.lang.reflect.InvocationTargetException;
  4. import java.lang.reflect.Method;
  5. /**
  6. * 将一个JavaBean风格对象的属性值拷贝到另一个对象的同名属性中 (如果不存在同名属性的就不拷贝)
  7. **/
  8. public class BeanCopy {
  9. private static String GET = "get";
  10. private static String SET = "set";
  11. /**
  12. *
  13. * @param source
  14. * @param target
  15. * @throws Exception
  16. */
  17. public static void copy(Object source,Object target){
  18. Class<?> sourceClz = source.getClass();
  19. Class<?> targetClz = target.getClass();
  20. // 得到Class对象所表征的类的所有属性(包括私有属性)
  21. Field[] sourceFields = sourceClz.getDeclaredFields();
  22. if (sourceFields.length == 0) {
  23. sourceFields = sourceClz.getSuperclass().getDeclaredFields();
  24. }
  25. int len = sourceFields.length;
  26. for (int i = 0; i < len; i++) {
  27. String fieldName = sourceFields[i].getName();
  28. Field targetField = null;
  29. // 得到targetClz对象所表征的类的名为fieldName的属性,不存在就进入下次循环
  30. try {
  31. targetField = targetClz.getDeclaredField(fieldName);
  32. } catch (NoSuchFieldException e) {
  33. try {
  34. targetField = targetClz.getSuperclass().getDeclaredField(fieldName);
  35. } catch (NoSuchFieldException e1) {
  36. e1.printStackTrace();
  37. } catch (SecurityException e1) {
  38. e1.printStackTrace();
  39. }
  40. }
  41. if (targetField == null) {
  42. continue;
  43. }
  44. // 判断sourceClz字段类型和targetClz同名字段类型是否相同
  45. if (sourceFields[i].getType() == targetField.getType()) {
  46. // 由属性名字得到对应get和set方法的名字
  47. String getMethodName = GET + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
  48. String setMethodName = SET + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
  49. // 由方法的名字得到get和set方法的Method对象
  50. Method getMethod;
  51. Method setMethod;
  52. try {
  53. try {
  54. getMethod = sourceClz.getDeclaredMethod(getMethodName,new Class[] {});//get方法入參為空
  55. } catch (NoSuchMethodException e) {
  56. getMethod = sourceClz.getSuperclass().getDeclaredMethod(getMethodName,new Class[] {});
  57. }
  58. try {
  59. setMethod = targetClz.getDeclaredMethod(setMethodName,sourceFields[i].getType());//set方法入參不為空
  60. } catch (NoSuchMethodException e) {
  61. setMethod = targetClz.getSuperclass().getDeclaredMethod(setMethodName,sourceFields[i].getType());
  62. }
  63. // 调用source对象的getMethod方法
  64. Object result = getMethod.invoke(source, new Object[] {});
  65. // 调用target对象的setMethod方法
  66. setMethod.invoke(target, result);
  67. } catch (SecurityException e) {
  68. e.printStackTrace();
  69. } catch (NoSuchMethodException e) {
  70. e.printStackTrace();
  71. } catch (IllegalArgumentException e) {
  72. e.printStackTrace();
  73. } catch (IllegalAccessException e) {
  74. e.printStackTrace();
  75. } catch (InvocationTargetException e) {
  76. e.printStackTrace();
  77. }
  78. } else {
  79. continue;
  80. }
  81. }
  82. }
  83. }

使用:

新建两个类:

  1. package com.lin;
  2. import java.util.Date;
  3. public class Car extends BaseBean{
  4. private String name;
  5. private String id;
  6. private Boolean sellFlag;
  7. private int age;
  8. private double maxSpeed;
  9. private double minSpeed;
  10. private int driverPeople;
  11. private Date date;
  12. public String getName() {
  13. return name;
  14. }
  15. public void setName(String name) {
  16. this.name = name;
  17. }
  18. public String getId() {
  19. return id;
  20. }
  21. public void setId(String id) {
  22. this.id = id;
  23. }
  24. public Boolean getSellFlag() {
  25. return sellFlag;
  26. }
  27. public void setSellFlag(Boolean sellFlag) {
  28. this.sellFlag = sellFlag;
  29. }
  30. public int getAge() {
  31. return age;
  32. }
  33. public void setAge(int age) {
  34. this.age = age;
  35. }
  36. public double getMaxSpeed() {
  37. return maxSpeed;
  38. }
  39. public void setMaxSpeed(double maxSpeed) {
  40. this.maxSpeed = maxSpeed;
  41. }
  42. public double getMinSpeed() {
  43. return minSpeed;
  44. }
  45. public void setMinSpeed(double minSpeed) {
  46. this.minSpeed = minSpeed;
  47. }
  48. public int getDriverPeople() {
  49. return driverPeople;
  50. }
  51. public void setDriverPeople(int driverPeople) {
  52. this.driverPeople = driverPeople;
  53. }
  54. public Date getDate() {
  55. return date;
  56. }
  57. public void setDate(Date date) {
  58. this.date = date;
  59. }
  60. }

另一个:

  1. package com.lin;
  2. import java.util.Date;
  3. public class Bus extends BaseBean{
  4. private String name;
  5. private String id;
  6. private Boolean sellFlag;
  7. private int age;
  8. private double maxSpeed;
  9. private double minSpeed;
  10. private long driverPeople;//和car類型不同
  11. private int driverYear;//car沒有這個
  12. private Date date;
  13. public String getName() {
  14. return name;
  15. }
  16. public void setName(String name) {
  17. this.name = name;
  18. }
  19. public String getId() {
  20. return id;
  21. }
  22. public void setId(String id) {
  23. this.id = id;
  24. }
  25. public Boolean getSellFlag() {
  26. return sellFlag;
  27. }
  28. public void setSellFlag(Boolean sellFlag) {
  29. this.sellFlag = sellFlag;
  30. }
  31. public int getAge() {
  32. return age;
  33. }
  34. public void setAge(int age) {
  35. this.age = age;
  36. }
  37. public double getMaxSpeed() {
  38. return maxSpeed;
  39. }
  40. public void setMaxSpeed(double maxSpeed) {
  41. this.maxSpeed = maxSpeed;
  42. }
  43. public double getMinSpeed() {
  44. return minSpeed;
  45. }
  46. public void setMinSpeed(double minSpeed) {
  47. this.minSpeed = minSpeed;
  48. }
  49. public long getDriverPeople() {
  50. return driverPeople;
  51. }
  52. public void setDriverPeople(long driverPeople) {
  53. this.driverPeople = driverPeople;
  54. }
  55. public int getDriverYear() {
  56. return driverYear;
  57. }
  58. public void setDriverYear(int driverYear) {
  59. this.driverYear = driverYear;
  60. }
  61. public Date getDate() {
  62. return date;
  63. }
  64. public void setDate(Date date) {
  65. this.date = date;
  66. }
  67. }

调用:

  1. public static void test5() {
  2. Car car = new Car();
  3. car.setAge(12);
  4. car.setDriverPeople(4);
  5. car.setId("YU1234");
  6. car.setMaxSpeed(13.66);
  7. car.setMinSpeed(1.09);
  8. car.setName("小车");
  9. car.setSellFlag(false);
  10. car.setDate(new Date());
  11. Bus bus = new Bus();
  12. BeanCopy.copy(car,bus);
  13. System.out.println(car);
  14. System.out.println(bus);
  15. }
除了两个不同的字段外,其它的都复制过去了,这在DTO、VO、DOMAIN对象转换时经常用到。

http://blog.csdn.net/evankaka/article/details/49978481

Java反射探索研究(转)的更多相关文章

  1. 第28章 java反射机制

    java反射机制 1.类加载机制 1.1.jvm和类 运行Java程序:java 带有main方法的类名 之后java会启动jvm,并加载字节码(字节码就是一个类在内存空间的状态) 当调用java命令 ...

  2. Java反射机制

    Java反射机制 一:什么事反射机制 简单地说,就是程序运行时能够通过反射的到类的所有信息,只需要获得类名,方法名,属性名. 二:为什么要用反射:     静态编译:在编译时确定类型,绑定对象,即通过 ...

  3. java反射(基础了解)

    package cn.itcast_01; /** *Person类 */ public class Person {    /** 姓名 */    private String name;     ...

  4. java基础知识(十一)java反射机制(上)

    java.lang.Class类详解 java Class类详解 一.class类 Class类是java语言定义的特定类的实现,在java中每个类都有一个相应的Class对象,以便java程序运行时 ...

  5. java基础知识(十一)java反射机制(下)

    1.什么是反射机制? java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象都能够调用他的属性和方法,这种动态获取属性和方法的功能称为java的反射机制. ...

  6. java反射学习之二万能EXCEL导出

    一.EXCEL导出的实现过程 假设有一个对象的集合,现在需要将此集合内的所有对象导出到EXCEL中,对象有N个属性:那么我们实现的方式是这样的: 循环这个集合,在循环集合中某个对象的所有属性,将这个对 ...

  7. java反射学习之一反射机制概述

    一.反射机制背景概述 1.反射(reflection)是java被视为动态语言的一个关键性质 2.反射机制指的是程序在运行时能获取任何类的内部所有信息 二.反射机制实现功能概述 1.只要给定类的全名, ...

  8. java反射 之 反射基础

    一.反射 反射:JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为 ...

  9. java反射 cglib asm相关资料

    有篇文章对java反射的调用的效率做了测试,写的比较好.猛击下面地址 http://www.blogjava.net/stone2083/archive/2010/09/15/332065.html ...

随机推荐

  1. Keywords Search (ac 自己主动机)

    Keywords Search Problem Description In the modern time, Search engine came into the life of everybod ...

  2. poj 1743 男人八题之后缀数组求最长不可重叠最长重复子串

    Musical Theme Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 14874   Accepted: 5118 De ...

  3. 验证码 Captcha 之大插件

    验证码 Captcha 之大插件小用 不知何年何月才能完成OADemo啊,总之还是一步一步来吧,这段时间开始着手了,先做登陆.  前段时间研究了一下在CentOS7下安装Mysql和Memcached ...

  4. 慕尼黑大学公开课 Competitive Strategy(竞争策略)总结

    第一章博弈 同时的博弈:双方同时定制策略 如果有显著的次优策略总是不如另一个,则剔除它. 如果一个策略组合中没有一方可以单独改变其策略以提高回报,则称为Nash均衡.一个游戏可能没有也可能有多个Nas ...

  5. freemark换行输出

    <!--附件图片-->              <#if attatList? exists>       <#if (attatList?size>0)> ...

  6. 分布式发布订阅消息系统Kafka

    高吞吐量的分布式发布订阅消息系统Kafka--安装及测试   一.Kafka概述 Kafka是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者规模的网站中的所有动作流数据. 这种动作(网页浏览, ...

  7. 解决NGINX的WORDPRESS伪静态规则失效的问题

    解决NGINX的WORDPRESS伪静态规则失效的问题 前两天搬到了EMSVPS的PR线路上,用上了最新的WDCP2.0管理面板,支持多用户管理(我们几个合租的VPS,最需要这个功能了),感觉很不错, ...

  8. 使用jQuery实现tag便签去重效果

    话不多说直接看代码 jsp页面的核心代码 <head> <script type="text/javascript" src="js/jQuery.js ...

  9. 番外:android模拟器连不上网

    1.删除你PC端得备用DNS,只留一个即可.确保能够上网. 注意:这个虽然不是必须的,出错点也不一定在他,但是我建议这样做,因为我们不确定到底模拟器和我们的PC是否使用的是一个DNS,不是的话,就会造 ...

  10. 备份恢复与CRM集成的sharepoint站点

    在部署CRM与Sharepoint2010集成文档管理之后,一直担心如果需要在新服务器上重新部署CRM, 那么之前与CRM集成的Sharepoint2010文档内容,是否可以重新正确映射到相应的文档位 ...