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

一、简介

       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()
		
	}

}
















评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值