您的位置:首页 > 编程语言 > Java开发

[2014-09-11]JAVA笔记_反射(Reflection)

2014-09-11 13:06 543 查看
一、简介

       JAVA 的反射机制可以在java运行时动态获取类的信息以及动态调用对象的方法。

二、功能

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

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

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

       · 在运行是调用任意一个对象的方法。

三、 在JDK中,主要由一下类来实现Java反射机制,这些类都位于 java.lang.reflec 包中

        · Class 类: 代表一个类。(特殊:位于java.lang包下。每个类都会有与之关联的Class)

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

        · Methoud 类: 代表类的方法。

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

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

四、 使用反射调用类的方法

        · Java 中,无论生成某个类的多少个对象,这些对象都会对应于同一个 Class 对象。

/**
* 读取命令行参数指定的类名,然后打印这个类所具有的方法
*/
package com.bob.reflection;

import java.lang.reflect.Method;

public class DumpMethods {

public static void main(String[] args) throws Exception {

//使用反射第一步首先获你想操作类的对应的Class对象
Class<?> classType = Class.forName("java.lang.String");    //通过Class的静态方法获取类名

Method[] methodType = classType.getDeclaredMethods();	//获得所有声明的方法

for(Method method : methodType){
System.out.println(method);
}
}

}


例子:使用反射调用某个类中的某个方法
package com.bob.reflection;

import java.lang.reflect.Method;

public class InvokeTest {

public int add(int param1, int param2){
return param1 + param2;
}
public String echo(String message){
return "Hello:" + message;
}

public static void main(String[] args) throws Exception {

//		InvokeTest test = new InvokeTest();
//		System.out.println(test.add(1, 2));
//		System.out.println(test.echo("Bob"));

//使用反射完成功能

//第一步还是获取类所对应的Class对象
Class<?> classType = InvokeTest.class;		//通过类名.class语法方式获得类的Class对象

//使用newInstance()方法生成invokeTest实例
Object invokeTest = classType.newInstance();

//获取类中的指定方法。参数1:方法名; 参数2:方法参数对应的Class对象所构成的Class类型数组
Method addMethod = classType.getMethod("add", new Class[]{int.class, int.class} );	//addMethod方法会对应上add方法

//使用Method类中的invoke()方法调用目标方法。
//参数1:调用哪个对象的方法; 参数2:方法实际接受的参数
Object result = addMethod.invoke(invokeTest, new Object[]{1, 2});	//调用invokeTest对象的addMethod()方法,传递参数

System.out.println((Integer)result);    //可以不加Integer,默认返回的是对象

System.out.println("-----------------------------");

//获得类中的指定方法。调用方法前先获得Method对象
Method echoMethod = classType.getDeclaredMethod("echo", new Class[]{String.class});

//调用对应的目标方法
Object result2 = echoMethod.invoke(invokeTest, new Object[]{"Tom"});	//调用invokeTest对象的echoMethod方法,传入参数

System.out.println((String)result2);     //可省略强制转换。invoke()方法的返回值总是对象,如果实际是基本类型会自动转换。

}

}


总结: 想要使用反射机制调用某个类中的方法,大致步骤如下:
            1. 获得类对应的Class对象。

            2. 可以使用 newInstance() 方法生成类的实例。 

            3. 获得 Method 对象。使用Class对象的 getMethod() 方法。参数1:需要获得方法的名称; 参数2: 这个方法接受哪些参数,把这些参数所对应的Class对象以数组或者离散的方式传入进去。

            4. Method 对象获得后使用 invoke() 方法实现真正的调用。参数1: 你所需要调用的是哪个对象的方法; 参数2: 方法接受的参数。

            备注:步骤3和4中的参数2,是对应关系。可以把第一个看成描述参数,第二个是实际参数。

五、 获取某个类或某个对象所对应的 Class 对象的常用的3中方式:

        1. 使用 Class 类的静态方法 forName(): Class.forName("java.lang.String");

        2. 使用类的.class 语法:String.class;

        3. 使用对象的 getClass() 方法:String s = "aaa"; Class<?> class = s.getClass();

六、通过类的构造方法来生成对象

   若想通过类的不带参数的构造方法来生成对象,我们有两种方式:

          1)  先获得 Class 对象,然后通过该 Class 对象的 newInstance()方法直接生成即可:

                      Class<?> classType = String.class; 

                      Object obj = classType.newInstance();

          2)  先获得 Class 对象,然后通过该对象获得对应的 Constructor 对象,再通过该 Constructor对象的 newInstance()方法生成:

                     Class<?> classType = Customer.class; 

                     Constructor cons = classType.getConstructor(new Class[]{}); 

                     Object obj = cons.newInstance(new Object[]{});

   若想通过类的带参数的构造方法生成对象,只能使用下面这一种方式:

                    Class<?> classType = Customer.class; 

                    Constructor cons = classType.getConstructor(new Class[]{String.class, int.class}); 

                    Object obj = cons.newInstance(new Object[]{“hello” , 3});

package com.bob.reflection;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class ReflectionTester {

//实现对Customer对象的拷贝
public Object copy(Object object) throws Exception{

Class<?> classType = object.getClass();		//返回调用getClass()方法运行期的Class对象
//		System.out.println(classType.getName());

//要实现将原有的对象拷贝到新的对象首先创建一个新的对象,然后将属性拷贝到新对象

Constructor cons = classType.getConstructor(new Class[]{});		//{}里面代表构造方法的参数
Object objectCopy = cons.newInstance(new Object[]{});		//通过构造方法生成对象
//以上两行代码等价于下面一行。(无参时)
//Object objectCopy = classType.newInstance();

//获得对象的所有成员变量
Field[] fields = classType.getDeclaredFields();

for(Field field : fields){

String name = field.getName();	//获得所有属性的名字

//要调用方法需要首先获得Method对象,Method对象的第一个参数是方法的名称。
//方法名规律是属性的首字母大写+前缀
String firstLetter = name.substring(0, 1).toUpperCase();	//将属性的值从第0个开始拷贝到第0个(首字母),然后转换为大写

String getMethodName = "get" + firstLetter + name.substring(1);		//获得方法的名称
String setMethodName = "set" + firstLetter + name.substring(1, name.length());	//从第1个开始,到最后一个

//转向Method对象。描述方法
Method getMethod = classType.getMethod(getMethodName, new Class[]{});
Method setMethod = classType.getMethod(setMethodName, new Class[]{field.getType()});	//获取属性的类型

//调用方法
Object value = getMethod.invoke(object, new Object[]{});	//在目标对象上调用目标对象的方法
setMethod.invoke(objectCopy, new Object[]{value});		//将值拷贝到指定对象

}
return objectCopy;
}

public static void main(String[] args) throws Exception {

Customer customer = new Customer("Tom", 20);
customer.setId(new Long(10010));
ReflectionTester reflectionTester = new ReflectionTester();

Customer obj2 = (Customer)reflectionTester.copy(customer);
//		Object obj =reflectionTester.copy(customer);
//		Customer obj2 = (Customer)obj;
System.out.println(obj2.getId() + ", " + obj2.getName() + ", " + obj2.getAge());

}

}

class Customer{
private Long id;	//使用包装类型
private String name;
private int age;

public Customer(){

}
public Customer(String name, int age){
this.name = name;
this.age = age;
}

public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
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;
}

}

七、常用方法

   ·Class类是Reflectoin API 中的核心类,它有以下方法:

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

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

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

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

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

        - getMehod(String name, Class[] parameterTypes): 获得类的特定方法,name参数指定方法的名字,parameterTypes参数指定方法的参数类型。

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

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

        - newInstance():通过类的不带参数的构造方法创建这个类的一个对象。

八、 Array类

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

一维数组

package com.bob.reflection;

import java.lang.reflect.Array;

public class ArrayTester1 {

public static void main(String[] args) throws Exception {

Class<?> classType = Class.forName("java.lang.String");		//获得字符串类的Class对象

Object array = Array.newInstance(classType, 10);	//参数1:数组当中的每个元素的类型

Array.set(array, 5, "hello");		//设置array数组的第5个索引的值

String str = (String)Array.get(array, 5);	//获取array数组的第5个元素

System.out.println(str);

}

}


二维数组:
      Integer.TYPE 返回的是int, 而Integer.class返回的是 Integer 类所对应的 Class 对象。

package com.bob.reflection;

import java.lang.reflect.Array;

public class ArrayTester2 {

public static void main(String[] args) {

int[] dims = new int[]{5, 10, 15};

Object array = Array.newInstance(Integer.TYPE, dims);	//数组的维度由dims决定

Object arrayObj = Array.get(array, 3);

//		Class<?> clasType = arrayObj.getClass().getComponentType();

arrayObj = Array.get(arrayObj, 5);

Array.setInt(arrayObj, 10, 37);

int[][][] arrayCase = (int[][][]) array;

System.out.println(arrayCase[3][5][10]);

}
}


九、使用反射访问私有成员变量、方法

package com.bob.reflection;

public class Private {

private String sayHello(String name){      //私有方法

return "Hello: " + name;
}
}


package com.bob.reflection;

import java.lang.reflect.Method;

public class PrivateTest {

public static void main(String[] args) throws Exception {

Class<?> classType = Class.forName("com.bob.reflection.Private");

//通过构造方法创建对象
Object pri = classType.getConstructor(new Class[]{}).newInstance(new Object[]{});

//使用getDeclaredMethod()方法获得声明的方法。getMethod()方法只能获得public权限的方法
Method myMethod = classType.getDeclaredMethod("sayHello", new Class[]{String.class});

//AccessibleObject类提供了一个标志控制是否执行java访问控制检查
myMethod.setAccessible(true);	//压制java语言的访问控制检查。Method类继承自AccessibleObject类

String str = (String)myMethod.invoke(pri, new Object[]{"Bob"});

System.out.println(str);

}
}

java访问私有成员变量

package com.bob.reflection;

public class PrivateMember {

private String name = "zhangsan";
private String name2 = "lisi";

public String getName(){
return name;
}

}

package com.bob.reflection;

import java.lang.reflect.Field;

public class PrivateMemberTest {

public static void main(String[] args) throws Exception{

//		Class<?> classType = Class.forName("com.bob.reflection.PrivateMember");
Class<?> classType = PrivateMember.class;

Object obj = classType.getConstructor(new Class[]{}).
newInstance(new Object[]{});

Field member = classType.getDeclaredField("name");		//获得私有属性名称
Field member2 = classType.getDeclaredField("name2");

member.setAccessible(true);		//压制java语言默认访问控制检查
member2.setAccessible(true);	//压制java对第二个属性的访问修饰检查

member.set(obj, "Bob");

member2.set(obj, "Tom");

Object obj2 = classType.getMethod("getName", new Class[]{})
.invoke(obj, new Object[]{});
System.out.println((String)obj2);

System.out.println(member2.get(obj));	//直接是用Field的get()

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Reflection 反射