JAVA反射总结(2)

上一篇博文,主要回顾了利用反射,可以拿到类中的所有东西,不管是私有的,还是共有的,并且最后一个demo9,利用反射实例化了一个对象,上次最重要的还有怎么拿到三种反射入口对象Class。这里就不一一复述了。上篇是知道反射有什么用。本次主要是对反射的一些应用。

首先我们还是一如既往地准备好测试类,和接口。基本和上个一样,有一个小改动,后面会说到。

接口分别是myInterface1.java,myInterface2.java,代码如下:

package com.charles.reflectDemo;
 
public interface myInterface1
{
	public void myInterface1Method();
}
package com.charles.reflectDemo;
 
public interface myInterface2
{
	public void myInterface2Method();
}

再是实现类reflectDemo.java,我们在该测试类中再加入一个方法showMessage(String message),待会用来测试,再说一下,该类属性有2个私有,1个公有,以及所有get和set方法,三个构造,2个实现接口方法,一个私有无参方法,一个公有有参方法。

package com.charles.reflectDemo;
 
public class reflectDemo implements myInterface1,myInterface2{
	private String name;
	private int id;
	public String desc;
	public reflectDemo(String name, int id, String desc) {
		super();
		this.name = name;
		this.id = id;
		this.desc = desc;
	}
	public reflectDemo(String name, int id) {
		super();
		this.name = name;
		this.id = id;
	}
	public reflectDemo() {
		super();
	}
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getDesc() {
		return desc;
	}
	public void setDesc(String desc) {
		this.desc = desc;
	}
	@Override
	public void myInterface2Method() {
		System.out.println("method myInterface2Method");
	}
	@Override
	public void myInterface1Method() {
		System.out.println("method myInterface1Method");
		
	}
	public void sayHello()
	{
		System.out.println("method sayHello");
	}

    private void showMessage(String message)
    {
        System.out.println("Message is:"+message);
    }
}

准备工作完了,接下来编写测试类testDemo1.java,其中有如下方法:(为了方便测试与观察其主要代码,我们此处不处理异常)

demo1代码如下:(通过Class反射入口,然后通过反射实例化对象,并调用对象方法)

 //获取对象实例,并操作该对象。
	public static void demo1() throws ClassNotFoundException, InstantiationException, IllegalAccessException 
	{
		Class<?> reflectDemoClazz=Class.forName("com.charles.reflectDemo.reflectDemo");
		Object 	reflectDemoObj=reflectDemoClazz.newInstance();
		reflectDemo instance=(reflectDemo)reflectDemoObj;
		instance.setName("charles");
		instance.setId(123456);
		System.out.println(instance.getName()+" "+instance.getId());
	}

执行结果如图所示:(完成了对象的实例化,并且成功调用方法)通过Class对象的newInstance方法来得到一个Object对象,经过强转成为reflectDemo对象;用该对象调用该类成员方法即可!

 

demo2代码如下:(通过Class反射入口,调用getDeclaredField(String FieldName)方法,返回一个Field属性对象代表反射类中的一个属性,该方法的参数是一个属性名,比如reflectDemo 类中的name属性,通过参数就可以拿自己想要的属性。后面,同样和demo1类似,我们也产生一个reflectDemo 类对象待用。Field类对象调用set方法,即可为该数据成员赋值,set(Object obj,Object obj),该方法的参数都是object类型,第一个代表的是该类的一个对象,第二个代表给属性的赋值,相当于我们平常的想要为一个属性赋值就用: 对象.setXXX(参数类型 形参名)。此处是反射,我们拿到的是一个属性,其实就相当于顺序变了一下,此处是: 属性.set(对象,属性值)),先不多说,我们来观察执行结果!

	public static void demo2() throws ClassNotFoundException, NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException, InstantiationException
	{
		Class<?> reflectDemoClazz=Class.forName("com.charles.reflectDemo.reflectDemo");
		Object 	reflectDemoObj=reflectDemoClazz.newInstance();
		reflectDemo instance=(reflectDemo)reflectDemoObj;
		Field fieldName=reflectDemoClazz.getDeclaredField("name");
        //空白处
		//fieldName.setAccessible(true);
		fieldName.set(instance, "charles");
		System.out.println(instance.getName());
	}

执行结果:异常!

Exception in thread "main" java.lang.IllegalAccessException: Class com.charles.reflectDemo.testDemo1 can not access a member of class com.charles.reflectDemo.reflectDemo with modifiers "private"
    at sun.reflect.Reflection.ensureMemberAccess(Unknown Source)
    at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(Unknown Source)
    at java.lang.reflect.AccessibleObject.checkAccess(Unknown Source)
    at java.lang.reflect.Field.set(Unknown Source)
    at com.charles.reflectDemo.testDemo1.demo2(testDemo1.java:26)
    at com.charles.reflectDemo.testDemo1.main(testDemo1.java:63)

解释:我们拿的属性是reflectDemo中的私有属性 private String name,Java私有属性不能被外界访问,所以此处报异常。解决方法:

我们拿到了属性Field fieldName对象,代表一个属性,我们可以用该对象调用一个方法:setAccessible(true);即可将该私有属性设置为可以访问,现在我们将以下代码插入到上段代码注释的空白处

	fieldName.setAccessible(true);

,执行观察;如下;

我们通过反射,为该类对象的私有成员成功赋值,并且成功访问!

demo3代码如下:(demo2和demo3相似,都是拿属性,但是demo2拿的是私有属性,demo3拿的是公共属性,所以不用setAccessible(true)来设置其可以访问)

//获取reflectDemo类的public desc属性并赋值测试
	public static void demo3() throws ClassNotFoundException, NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException, InstantiationException
	{
		Class<?> reflectDemoClazz=Class.forName("com.charles.reflectDemo.reflectDemo");
		Object 	reflectDemoObj=reflectDemoClazz.newInstance();
		reflectDemo instance=(reflectDemo)reflectDemoObj;
		Field fieldName=reflectDemoClazz.getDeclaredField("desc");
		fieldName.set(instance, "this is public field");
		System.out.println(instance.getDesc());
	}

执行结果:没毛病

demo4代码如下:(和之前一样我么先拿Class反射入口,然后通过入口实例化一个对象,demo4主要是拿公有方法并执行,我们之前定义了一个sayHello方法,所以我们用此方法为例。我们先执行,再分析!)

	//获取reflectDemo类的public myInterface1Method方法并测试
	public static void demo4() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException
	{
		Class<?> reflectDemoClazz=Class.forName("com.charles.reflectDemo.reflectDemo");
		Object 	reflectDemoObj=reflectDemoClazz.newInstance();
		reflectDemo instance=(reflectDemo)reflectDemoObj;
		Method method=reflectDemoClazz.getDeclaredMethod("sayHello", null);
		method.invoke(instance,null);
	}

 

执行结果:执行成功,并且打印了该方法的输出语句;

分析:我们通过反射入口对象,调用该对象方法getDeclaredMethod("sayHello", null);返回一个Method类型对象,代表一个你想要拿到方法,注意,该方法有多个重载,第一个参数是你要反射拿的方法名,后面的参数是你想反射的方法的参数,因为我的这个例子中没有参数,所以为null,然后,我们通过Method类对象,就可以执行该方法,用invoke(instance,null);第一个参数是该类的对象,后面的参数是参数值因为该方法无参,所以为null,再来思考它是如何执行的;

我们拿到的是一个代表方法的对象,然后用该对象的invoke方法将对象和参数传进去就可以执行:

method.invoke(obj,para1,para2...),

思考我们平常的执行顺序,是对象.方法(参数1,参数2....)即:

obj.method(para1,para2....),,

不难理解,其实就是顺序的一些变化。

demo5代码如下:(demo4是拿的一个公有的方法,并且无参,demo5拿的是私有方法带参,循序渐进,先看代码执行结果再来分析!)

//获取reflectDemo类的private showMessage方法并测试
	public static void demo5() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException
	{
		Class<?> reflectDemoClazz=Class.forName("com.charles.reflectDemo.reflectDemo");
		Object 	reflectDemoObj=reflectDemoClazz.newInstance();
		reflectDemo instance=(reflectDemo)reflectDemoObj;
		Method method=reflectDemoClazz.getDeclaredMethod("showMessage", String.class);
		method.setAccessible(true);
		method.invoke(instance, "hello reflect method");
	}

执行结果:成功输出信息并打印!

理解:和demo4一样,先拿反射入口对象,通过该对象的方法拿到代表方法的对象,和该反射类实例对象,此处我们测试带一个String类型参数,所以我们的方法是.getDeclaredMethod("showMessage", String.class);和demo4一样,该方法第一个参数是传入一个想要通过反射获得的方法名,后面的参数是该方法列表的参数类型,而且也是Class类型。因为我们此处访问的是私有方法,所以直接访问依旧会报异常,回顾我们demo2,此处我们依旧需要设置一下,让该方法让外外界可以访问,一样也用setAccessible(true);方法即可,最后,用代表该方法的对象执行method.invoke(instance, "hello reflect method");就完成了方法的反射执行,第一个参数和demo4一样,是该反射类的实例对象,后面的参数是具体传入的值。

demo执行分析完毕!

下次有空写JAVA反射总结(3) 

over!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值