Effective Java(Java的反射机制)

在第三条用私有构造器或者枚举类型强化Singleton属性中提到了反射机制可以调用类的私有化构造器,于是便查了一些关于反射机制的资料,以求能够最后实现通过反射来调用私有化构造器

基础知识

定义:

Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这照片那个动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制


Java反射机制主要提供了以下功能:

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

<2>在运行时构造任意一个类的对象

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

<4>在运行时调用任意一个对象的方法


Java Reflection API简介

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

Class类:代表一个类,位于java.lang包下

Field类:代表类的成员变量

Method类:代表类的方法

Constructor类:代表类的构造方法

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


获取Class对象的3中方式

<1>使用Class类的静态方法

Class.forName("包名");     例:Class.forName("java.lang.String");

<2>使用类的.class语法

类名.class          例:String.class

<3>使用对象的getClass()方法

例:

String str="aa";

Class<?> classType=str.getClass();


通过Class类获取成员变量,成员方法,接口,超类,构造方法等

在java.lang.Object类中定义了getClass()方法,因此对于任意一个Java对象,都可以通过此方法获得对象的类型。

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

getName():获得类的完整名字。
getFields():获得类的public类型的属性。
getDeclaredFields():获得类的所有属性。
getMethods():获得类的public类型的方法。
getDeclaredMethods():获得类的所有方法。
getMethod(String name, Class[] parameterTypes):获得类的特定方法,name参数指定方法的名字,parameterTypes 参数指定方法的参数类型。
getConstructors():获得类的public类型的构造方法。
getConstructor(Class[] parameterTypes):获得类的特定构造方法,parameterTypes 参数指定构造方法的参数类型。
newInstance():通过类的不带参数的构造方法创建这个类的一个对象。


下面举个例子,实现获取String对象的所有方法

import java.lang.reflect.Method;

public class DumpMethods {

	public static void main(String[] args) throws Exception {
		
		//获取字符串类
		Class<?> classType=Class.forName("java.lang.String");
		
		//返回字符串类中的所有方法的数组
		Method[] methods=classType.getDeclaredMethods();
		
		//遍历输出
		for(Method method:methods){
			System.out.println(method);
		}
		
	}
	
}

通过反射使用类中的方法

import java.lang.reflect.Method;

public class InvokeTester {

	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 {
		
		//获取Class对象
		Class<?> classType=InvokeTester.class;
		
		//用newInstance()方法生成新的对象,并判断是否是InvokeTester对象
		Object invokeTester=classType.newInstance();
		System.out.println(invokeTester instanceof InvokeTester);
		
		//首先需要获得与该方法对应的Method对象,第一个参数时方法名;第二个参数是一个Class数组,用来装置参数类
		Method addMethod=classType.getMethod("add", new Class[]{int.class,int.class});
		//调用目标方法,第一个参数是类的对象,第二个参数是方法参数对象集合
		Object result=addMethod.invoke(invokeTester, new Object[]{1,2});
		System.out.println(result);
		
		//同理
		Method echoMethod=classType.getDeclaredMethod("echo", new Class[]{String.class});
		Object result2=echoMethod.invoke(invokeTester, new Object[]{"Tom"});
		System.out.println(result2);
		
	}
}

下面基本上可以实现利用反射调用私有方法,访问私有对象

(注意,以Method为例,getMethod()方法返回的是public的Method对象,而getDeclaredMethod()返回的Method对象可以是非public的)

访问私有属性和方法,在使用前要通过AccessibleObject类中的setAccessible()方法来抑制Java访问权限的检查

代码如下:

public class PrivateClass {

	private String sayHello(String name){
		return "Hello:"+name;
	}
}
下面的代码实现访问上面类的私有方法

import java.lang.reflect.Method;

public class TestPrivate {

	public static void main(String[] args) throws Exception {
		PrivateClass p=new PrivateClass();
		Class<?>classType=p.getClass();
		
		Method method=classType.getDeclaredMethod("sayHello", new Class[]{String.class});
		method.setAccessible(true);
		String string=(String)method.invoke(p, new Object[]{"zhangsan"});
		System.out.println(string);
	}
	
}

利用反射实现私有化构造方法的类的实例化

public class PrivateClass2 {

	private PrivateClass2(){
		//
	}
	
	public void sendMsg(){
		System.out.println("私有化对象实例化成功");
	}
}

反射实现代码

import java.lang.reflect.Constructor;

public class TestPrivate2 {

	public static void main(String[] args) throws Exception{
		//类的获取
		Class<?> classType=PrivateClass2.class;
		
		//获取无参构造函数,
		Constructor constructor=classType.getDeclaredConstructor();
		//抑制Java访问控制检查
		constructor.setAccessible(true);
		
		//这个newInstance之前一直见到的是类去新建一个对象,现在是直接用构造器来新建对象
		PrivateClass2 privateClass2=(PrivateClass2)constructor.newInstance();
		//调用公有方法
		privateClass2.sendMsg();
	}
}


参考:

http://www.cnblogs.com/mengdd/archive/2013/01/26/2877972.html

http://gaoquanyang.iteye.com/blog/1160561

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值