Java编程思想笔记(十八) —— 再谈反射

Posted iaiti

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java编程思想笔记(十八) —— 再谈反射相关的知识,希望对你有一定的参考价值。

Java编程思想(十五) —— 类型信息之反射Java编程思想(十六) —— 联系JVM再谈Class,书上只用了3页就讲完了,还有讲了那么多Class的东西,接下来要从反射中怎么用,自己结合API和其他资料再写多一些。

 

示例:Test.java

 

public class Test 
        public Test() 
        
        public Test(int i) 
          System.out.println(i);
         private void pri() 
		System.out.println("private");
	

	public void pub() 
		System.out.println("public");
	

	protected void pro() 
		System.out.println("protected");
	

	private String pristr;
	public String pubstr;
	protected String pro;


有不同的方法和域。

 

 

测试:

 

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


public class Reflect 
	public static void main(String[] args) 
		try 
			//测试参数类型后面跟着三点的作用
			Test t = new Test();
			t.three();
			t.three("a","b","c");
			//输出[] [a,b,c] 证明...表示的参数可以为空或者是传字符数组  即可传可不传  英文成为varargs
			
			//将Test装载进命名空间   得到代表Test的Class对象引用
			Class c = Class.forName("Test");
			
			//Method类  拿到名为pub的方法
			try 
				Method one = c.getMethod("pub");
				try 
					//方法调用 invoke(Object obj, Object... args)  obj为所要调用方法所属的类  args为方法所传的参数
					//所传obj要为实例 ,不然会有object is not an instance of declaring class
					one.invoke(c.newInstance());
				 catch (IllegalAccessException e) 
					e.printStackTrace();
				 catch (IllegalArgumentException e) 
					e.printStackTrace();
				 catch (InvocationTargetException e) 
					e.printStackTrace();
				 catch (InstantiationException e) 
					e.printStackTrace();
				
			 catch (NoSuchMethodException e1) 
				e1.printStackTrace();
			 catch (SecurityException e1) 
				e1.printStackTrace();
			
			
			//这种返回的方法的数组   为公共方法 包括那些父类和父接口中继承的方法
			Method[] method = c.getMethods();
			//返回的是该Class对象代表的类声明的所有方法  这样就包括public private protected方法 
			Method[] declaredmethod = c.getDeclaredMethods();
			Class[] array = c.getClasses();
			Field[] field = c.getFields();
			Field[] declaredfield = c.getDeclaredFields();
			for (int i = 0; i < array.length; i++) 
				System.out.println("Classes array is "+array[i].getName());
			
			
			for (int i = 0; i < method.length; i++) 
				System.out.println("Methods array is "+method[i].getName());
			
			
			//getReturnType拿到方法返回的属性。
			for (int i = 0; i < declaredmethod.length; i++) 
				System.out.println("DeclaredMethods array is "+declaredmethod[i].getReturnType().getName()+
						" "+declaredmethod[i].getName());
				try 
					try 
						String s[] ="1","2"; 
						
						//如果没有设置 就会有Class Reflect can not access a member of class Test with 
						//modifiers "private"异常
						//Constructor, Field, Method 为AccessibleObject的子类
						//有着访问控制的权限  默认是false  会强制java进行 访问检查  所以private是禁止访问的  Filed同理
						declaredmethod[i].setAccessible(true);
						System.out.println(declaredmethod[i].getName());
						if(declaredmethod[i].getName().equals("three"))
							System.out.println("true");
							//下面这条会报 wrong number of arguments异常 
							//这个问题是搞了我最久的东西  中文都是前篇一律的胡说八道
							//invoke(Object obj, Object... args)   数组是协变的 String[]被当成Object[]
							//String[] 被当成了整个参数 而string数组里面的元素又不是object 
							//而不是args的第一个参数,其实,我们String数组是Objec数组的第一个元素
							
							/*这是因为编译器会把字符串数组当作一个可变长度参数传给对象o,而我们取得方法只有一个参数,
							所以就会出现wrong number of
							arguments的异常,我们只要把字符串数组强制转换为一个Object对象就可以解决这个异常了  这个简直就是放屁*/
							//declaredmethod[i].invoke(c.newInstance(),s);
							declaredmethod[i].invoke(c.newInstance(),new Object[]s);
							declaredmethod[i].invoke(c.newInstance(),(Object)new String[]"1","2","3");
							declaredmethod[i].invoke(c.newInstance(),(Object)null);
							declaredmethod[i].invoke(c.newInstance(),(Object)new String[]);
						else
							declaredmethod[i].invoke(c.newInstance());
						
					 catch (InstantiationException e) 
						e.printStackTrace();
					
				 catch (IllegalAccessException e) 
					e.printStackTrace();
				 catch (IllegalArgumentException e) 
					e.printStackTrace();
				 catch (InvocationTargetException e) 
					e.printStackTrace();
				
			
			
			
			//与Method同理,只不过Filed拿到的是域。
			for (int i = 0; i < field.length; i++) 
				System.out.println("Fields array is "+field[i].getName());
			
			
			for (int i = 0; i < declaredfield.length; i++) 
				System.out.println("Declaredfieds array is "+declaredfield[i].getName());
				try 
					declaredfield[i].setAccessible(true);
					declaredfield[i].set(t, "a");
				 catch (IllegalArgumentException e) 
					e.printStackTrace();
				 catch (IllegalAccessException e) 
					e.printStackTrace();
				
			
			System.out.println(t.pro);
			System.out.println(t.pub);
		 catch (ClassNotFoundException e) 
			e.printStackTrace();
		
	

 

 

 

基本所有的问题和属性方法都在里面,不过wrong number of arguments异常,是我查了最久的异常,静下心来后看懂了。

这是因为编译器会把字符串数组当作一个可变长度参数传给对象o,而我们取得方法只有一个参数,
所以就会出现wrong number of arguments的异常,我们只要把字符串数组强制转换为一个Object对象就可以解决这个异常了。

 

全部都是这个错误的答案,invoke(Object obj, Object... args)  ,数组是协变的 String[]被当成Object[]。

String[] 被当成了整个参数 ,而string数组里面的元素又不是object 。
而不是args的第一个参数,其实,我们String数组是Objec数组的第一个元素。

 

慢慢看就理解了。

 

后面补充:

 

Constructor<?>[] ct = Class.forName("Test").getConstructors();
			for (int i = 0; i < ct.length; i++) 
				System.out.println("Constructor:" + ct[i].getName());
			
			System.out.println("new instance");
			try 
				ct[0].newInstance();
				ct[1].newInstance(123);
			 catch (InstantiationException | IllegalAccessException
					| IllegalArgumentException | InvocationTargetException e2) 
				e2.printStackTrace();
			


Constructor就是构造器,不过不同于Class的newInstace方法,Constructor的newInstance(Object... initargs) 为varargs,即上面提到的三点。可以进行参数的传入。

 

而有趣的一点是,Constructor数组是有序的,前提是你的构造方法写在类里面最前面,如果前面有其他方法,那么数组的顺序就不是按照排序而排了。

 

反射的作用,就是运行时检查对象的类型,任意调用对象的方法(Spring和servlet中都用到了,注意到没有,我们在xml配置,然后属性会根据xml注入),同时可以知道方法参数和属性。

 

虽然这算是打破了所谓的封装性,private属性,不过想想,没有后门,语言岂不是死了?

对于反射,想了解跟多的可以看看国外的反射教程,http://www.programcreek.com/2013/09/java-reflection-tutorial/

以上是关于Java编程思想笔记(十八) —— 再谈反射的主要内容,如果未能解决你的问题,请参考以下文章

Go语言精修(尚硅谷笔记)第十七和十八章

再谈编程范式—程序语言背后的思想

机器学习笔记十八:概率分类思想

Java编程思想 学习笔记12

java编程思想读书笔记三(11-21)

《Java编程思想》读书笔记