详解Java反射机制实例

开发 后端
在 Java 运行时环境中,对于任意一个类,能否知道这个类有哪些属性和方法?对于任意一个对象,能否调用它的任意一个方法?答案是肯定的。这种动态获取类的信息,以及动态调用对象的方法的功能来自于Java 语言的反(Reflection)机制。

在 Java 运行时环境中,对于任意一个类,能否知道这个类有哪些属性和方法?对于任意

一个对象,能否调用它的任意一个方法?答案是肯定的。这种动态获取类的信息,以及动态

调用对象的方法的功能来自于Java 语言的反射(Reflection)机制。Java 反射机制主要提供

了以下功能:

在运行时判断任意一个对象所属的类;

在运行时构造任意一个类的对象;

在运行时判断任意一个类所具有的成员变量和方法;

在运行时调用任意一个对象的方法;

生成动态代理。

在 JDK 中,主要由以下类来实现Java 反射机制,这些类都位于java.lang.reflect

包中。

Class类:代表一个类。

Field类:代表类的成员变量(成员变量也称为类的属性)。

Method类:代表类的方法。

Constructor 类:代表类的构造方法。

Array类:提供了动态创建数组,以及访问数组元素的静态方法。

如例程1所示DumpMethods 类演示了Reflection API的基本作用,它读取命令

行参数指定的类名,然后打印这个类所具有的方法信息:

例程1:DumpMethods.java

Java代码

 

 

  1. import java.lang.reflect.*;     
  2.     
  3. public class DumpMethods {     
  4.     public static void main(String args[]) throws Exception {     
  5.         // 加载并初始化命令行参数指定的类     
  6.         Class classType = Class.forName(args[0]);     
  7.         // 获得类的所有方法     
  8.         Method methods[] = classType.getDeclaredMethods();     
  9.         for (int i = 0; i < methods.length; i++)     
  10.             System.out.println(methods[i].toString());     
  11.     }     
  12. }    

 

运行命令“java DumpMethods java.util.Stack”,就会显示java.util.Stack类所具有的方法,程序的打印结果如下:

 

  1. public synchronized java.lang.Object java.util.Stack.pop()  
  2.  
  3. public java.lang.Object java.util.Stack.push(java.lang.Object)  
  4.  
  5. public boolean java.util.Stack.empty()  
  6.  
  7. public synchronized java.lang.Object java.util.Stack.peek()  
  8.  
  9. public synchronized int java.util.Stack.search(java.lang.Object)  

如例程2 所示ReflectTester 类进一步演示了Reflection API 的基本使用方法。

ReflectTester 类有一个copy(Object object)方法,这个方法能够创建一个和参数object同样类型的对象,然后把object对象中的所有属性复制到新建的对象中,并将它返回。这个例子只能复制简单的JavaBean,假定JavaBean的每个属性都有public类型的

getXXX()和setXXX()方法。

例程2 ReflectTester.java

Java代码

 

 

  1. import java.lang.reflect.*;     
  2.     
  3. public class ReflectTester {     
  4.     public Object copy(Object object) throws Exception {     
  5.         // 获得对象的类型     
  6.         Class classType = object.getClass();     
  7.         System.out.println("Class:" + classType.getName());     
  8.         // 通过默认构造方法创建一个新的对象     
  9.         Object objectCopy = classType.getConstructor(new Class[] {})     
  10.                 .newInstance(new Object[] {});     
  11.         // 获得对象的所有属性     
  12.         Field fields[] = classType.getDeclaredFields();     
  13.         for (int i = 0; i < fields.length; i++) {     
  14.             Field field = fields[i];     
  15.             String fieldName = field.getName();     
  16.             String firstLetter = fieldName.substring(01).toUpperCase();     
  17.             // 获得和属性对应的getXXX()方法的名字     
  18.             String getMethodName = "get" + firstLetter + fieldName.substring(1);     
  19.             // 获得和属性对应的setXXX()方法的名字     
  20.             String setMethodName = "set" + firstLetter + fieldName.substring(1);     
  21.             // 获得和属性对应的getXXX()方法     
  22.             Method getMethod = classType.getMethod(getMethodName,     
  23.                     new Class[] {});     
  24.             // 获得和属性对应的setXXX()方法     
  25.             Method setMethod = classType.getMethod(setMethodName,     
  26.                     new Class[] { field.getType() });     
  27.             // 调用原对象的getXXX()方法     
  28.             Object value = getMethod.invoke(object, new Object[] {});     
  29.             System.out.println(fieldName + ":" + value);     
  30.             // 调用复制对象的setXXX()方法     
  31.             setMethod.invoke(objectCopy, new Object[] { value });     
  32.         }     
  33.         return objectCopy;     
  34.     }     
  35.     
  36.     public static void main(String[] args) throws Exception {     
  37.         Customer customer = new Customer("Tom"21);     
  38.         customer.setId(new Long(1));     
  39.         Customer customerCopy = (Customer) new ReflectTester().copy(customer);     
  40.         System.out.println("Copy information:" + customerCopy.getName() + " "    
  41.                 + customerCopy.getAge());     
  42.     }     
  43. }     
  44.     
  45. class Customer { // Customer类是一个JavaBean     
  46.     private Long id;     
  47.     private String name;     
  48.     private int age;     
  49.     
  50.     public Customer() {     
  51.     }     
  52.     
  53.     public Customer(String name, int age) {     
  54.         this.name = name;     
  55.         this.age = age;     
  56.     }     
  57.     
  58.     public Long getId() {     
  59.         return id;     
  60.     }     
  61.     
  62.     public void setId(Long id) {     
  63.         this.id = id;     
  64.     }     
  65.     
  66.     public String getName() {     
  67.         return name;     
  68.     }     
  69.     
  70.     public void setName(String name) {     
  71.         this.name = name;     
  72.     }     
  73.     
  74.     public int getAge() {     
  75.         return age;     
  76.     }     
  77.     
  78.     public void setAge(int age) {     
  79.         this.age = age;     
  80.     }     
  81. }   

 

执行结果:Class:Customer

id:1

name:Tom

age:21

Copy information:Tom 21

Class类是Reflection API中的核心类,它有以下方法。

getName():获得类的完整名字。

getFields():获得类的public类型的属性。

getDeclaredFields():获得类的所有属性。

getMethods():获得类的public类型的方法。

getDeclaredMethods():获得类的所有方法。

getMethod(String name, Class[] parameterTypes):获得类的特定方法,name 参

数指定方法的名字,parameterTypes参数指定方法的参数类型。

getConstrutors():获得类的public类型的构造方法。

getConstrutor(Class[] parameterTypes):获得类的特定构造方法,parameterTypes参数指定构造方法的参数类型。

如例程3 所示的InvokeTester 类的main()方法中,运用反射机制调用一个

InvokeTester 对象的add()和echo()方法。

例程3 InvokeTester.java

Java代码

 

 

  1. import java.lang.reflect.*;     
  2.     
  3. public class InvokeTester {     
  4.     public int add(int param1, int param2) {     
  5.         return param1 + param2;     
  6.     }     
  7.     
  8.     public String echo(String msg) {     
  9.         return "echo:" + msg;     
  10.     }     
  11.     
  12.     public static void main(String[] args) throws Exception {     
  13.         Class classType = InvokeTester.class;     
  14.         Object invokeTester = classType.newInstance();     
  15.         // 调用InvokeTester对象的add()方法     
  16.         Method addMethod = classType.getMethod("add"new Class[] { int.class,     
  17.                 int.class });     
  18.         Object result = addMethod.invoke(invokeTester, new Object[] {     
  19.                 new Integer(100), new Integer(200) });     
  20.         System.out.println((Integer) result);     
  21.         // 调用InvokeTester对象的echo()方法     
  22.         Method echoMethod = classType.getMethod("echo",     
  23.                 new Class[] { String.class });     
  24.         result = echoMethod.invoke(invokeTester, new Object[] { "Hello" });     
  25.         System.out.println((String) result);     
  26.     }     
  27. }    

 

执行结果:300

echo:Hello

add()方法的两个参数为int 类型,获得表示add()方法的Method对象的代码如下:

Method addMethod=classType.getMethod("add",new Class[]{int.class,int.class});

Method类的invoke(Object obj,Object args[])方法接收的参数必须为对象,如果参数为基本类型数据,必须转换为相应的包装类型的对象。invoke()方法的返回值总是对象,

如果实际被调用的方法的返回类型是基本类型数据,那么invoke()方法会把它转换为相

应的包装类型的对象,再将其返回。

在本例中,尽管InvokeTester 类的add()方法的两个参数及返回值都是int 类型,调

用addMethod对象的invoke()方法时,只能传递Integer 类型的参数,并且invoke()方法的返回类型也是Integer 类型,Integer 类是int 基本类型的包装类:

Object result=addMethod.invoke(invokeTester,

new Object[]{new Integer(100),new Integer(200)});

System.out.println((Integer)result); //result 为Integer类型

java.lang.Array 类提供了动态创建和访问数组元素的各种静态方法。如例程10-4

所示的ArrayTester1 类的main()方法创建了一个长度为10 的字符串数组,接着把索引

位置为5 的元素设为“hello”,然后再读取索引位置为5 的元素的值。

例程10-4 ArrayTester1.java

Java代码

 

 

  1. import java.lang.reflect.*;     
  2.     
  3. public class ArrayTester1 {     
  4.     public static void main(String args[]) throws Exception {     
  5.         Class classType = Class.forName("java.lang.String");     
  6.         // 创建一个长度为10 的字符串数组     
  7.         Object array = Array.newInstance(classType, 10);     
  8.         // 把索引位置为5 的元素设为"hello"     
  9.         Array.set(array, 5"hello");     
  10.         // 读取索引位置为5 的元素的值     
  11.         String s = (String) Array.get(array, 5);     
  12.         System.out.println(s); //输出hello     
  13.     }     
  14. }    

 

如例程10-5 所示的ArrayTester2 类的main()方法创建了一个5×10×15 的整型数

组,并把索引位置为[3][5][10]的元素的值为设37。

Java代码

 

 

  1. import java.lang.reflect.*;     
  2.     
  3. public class ArrayTester2 {     
  4.     public static void main(String args[]) {     
  5.         int dims[] = new int[] { 51015 };     
  6.         Object array = Array.newInstance(Integer.TYPE, dims);     
  7.         // 使arrayObj 引用array[3]     
  8.         Object arrayObj = Array.get(array, 3);     
  9.         Class cls = arrayObj.getClass().getComponentType();     
  10.         System.out.println(cls);     
  11.         // 使arrayObj 引用array[3][5]     
  12.         arrayObj = Array.get(arrayObj, 5);     
  13.         // 把元素array[3][5][10]设为37     
  14.         Array.setInt(arrayObj, 1037);     
  15.         int arrayCast[][][] = (int[][][]) array;     
  16.         System.out.println(arrayCast[3][5][10]);     
  17.     }     
  18. }    

 

输出:

class [I

37???

【编辑推荐】

  1. 深入剖析JAVA反射机制强大功能
  2. 关于Java反射机制的一个实例
  3. Java编译过程与c/c++编译过程有何不同
  4. Java虚拟机发展回顾 为跨平台而生
  5. Java虚拟机(JVM)中的内存设置详解
责任编辑:金贺 来源: JavaEye博客
相关推荐

2011-09-27 10:23:24

Java反射机制

2009-06-17 13:57:54

java实例Reflection

2011-04-01 14:50:56

Java的反射机制

2011-05-26 15:23:34

JavaReflection

2010-08-11 09:40:44

LINQ

2009-06-19 13:59:41

Java反射机制

2012-04-05 13:50:38

Java

2009-08-28 13:12:56

C#反射实例C#反射

2010-02-04 11:23:25

C++反射机制

2017-03-24 09:44:33

Java反射机制

2017-05-17 15:28:15

Java反射机制

2009-08-31 09:41:05

C#反射静态方法开发

2009-04-10 09:55:44

C#反射.NET

2010-09-17 13:02:11

JAVA反射机制

2022-10-21 14:12:06

2012-02-08 09:44:52

Java反射

2022-09-26 11:03:25

Java反射漏洞

2009-06-11 08:59:35

2023-11-01 13:48:00

反射java

2012-02-08 09:53:25

Java反射
点赞
收藏

51CTO技术栈公众号