`
yaqi0628
  • 浏览: 6457 次
  • 性别: Icon_minigender_1
  • 来自: 株洲
最近访客 更多访客>>
社区版块
存档分类
最新评论

java Reflection

阅读更多


/**
 * 反射--Class的基本分析
 * @author yaqi
 * @date 2012/06/26
 *
 */
public class ReflectionTest {

	/**
	 * Class 代表一类事物
	 * 
	 * Java类用于描述一类事物的共性,该类事物有什么
	 * 属性,没有什么属性,至于这个属性的值是什么,
	 * 则是由这个类的实例对象来确定的.
	 * 不同的实例对象有不同的属性值
	 * 
	 * eg:  
	 *     人  --> Person
	 *     Java类   --> Class
	 *     
	 * eg:
	 * 
	 *    Person p1 = new Person();
	 *    
	 *    Class cls1 = new Class();// 不成立
	 *    Class cls2 = 代表一份字节码;每一份的字节码都是一个类的实例对象
	 *    
	 *    故:
	 *    
	 *    Class cls3 = new Date.class  //成立
	 *    
	 *    延伸:
	 *       得到类的字节码(三种方式):
	 *    System.class  //类名.class
	 *    p1.getClass();  // 对象.getClass()
	 *    Class.forName("java.lang.String"); //类加载器 返回字节码  主要用在反射中
	 *   
	 *   类加载器的作用:
	 *    1.这份字节码之前已被加载到JVM中,直接返回
	 *    2.这份字节码还不存在,用类加载器去加载,把加载进来的类缓存到JVM中,
	 *    
	 *    
	 *    九个预定义的Class实例对象:
	 *    	八个基本类型+void
	 *    boolean byte char short int long float double <b>void</b>
	 *    
	 */
	
	public static void main(String[] args) throws ClassNotFoundException {
		
		String str1 = "abc";
		Class cls1 = str1.getClass();
		Class cls2 = String.class;
		Class cls3 = Class.forName("java.lang.String");
		
		System.out.println(cls1 == cls2);
		System.out.println(cls1 == cls3);
		
		/**
		 * result:
		 *      true
		 *      true
		 *      
		 * 结论:三个实例对象共用一份字节码
		 */
		
		System.out.println(cls1.isPrimitive()); //是否为原始类型
		/**
		 * result :
		 *         false
		 *结论: String 不是基本类型
		 */
		System.out.println(int.class.isPrimitive());
		/**
		 * result:
		 *        true
		 * 结论: int 是基本类型
		 */
		System.out.println(int.class == Integer.class);
		/**
		 * result:
		 *        false
		 * 结论: Integer 不是基本类型
		 */
		System.out.println(int.class == Integer.TYPE);
		/**
		 * result:
		 *       true
		 * 结论:Integer 中的  TYPE常量: 代表包装类型所包装的基本类型的字节码   其它包装类型也是一样
		 */
		
		System.out.println(int[].class.isPrimitive());
		/**
		 * result:
		 *       false
		 * 结论: 
		 *    数组也是一个类型,但它不属于基本类型
		 *    数组类型的判断方法: Class.isArray()
		 */
		/***********************************************/
		/**
		 * 总之,只要是在源程序中出现的类型,都有各自的Class实例对象,eg: int[]
		 */
	}
}


/**
 * Reflection:
 * 反射就是把Java类中的各种成分映射成相应的Java类.
 * 
 * 一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示.
 * 
 * 反射会导致性能下降:因为它会对某一些构造方法进行缓存.耗内存.
 */

/**
 * 构造方法的反射应用
 * 
 * Constructor 类代表某个类中的<b>某一个</b>构造方法
 * 
 */
class ConstructorTest{
	
	public static void main(String[] args) throws SecurityException, NoSuchMethodException, 
		IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException {
		// 得到一个带StringBuffer为参数的构造方法的String对象
		Constructor con1 = String.class.getConstructor(StringBuffer.class);
		String str2 = (String)con1.newInstance(new StringBuffer("abc"));
		
		//用反射实现: new String(new StringBuffer("abc"));
	}
}

/**
 * 
 * 成员变量的反射
 * 
 * Field 
 */

class ReflectFieldTest{
	
	public static void main(String[] args) throws SecurityException, NoSuchFieldException,
			IllegalArgumentException, IllegalAccessException {
		ReflectPoint pt1 = new ReflectPoint(3, 5);
		
		Field fieldY = pt1.getClass().getField("y"); //getField() 只能得到可见的变量
		// fieldY 不是对象身上的变量,而是类上的变量,要用它来读取某个对象所对应的值
		//获得fieldY的值
		fieldY.get(pt1);
		
		//取x的值
		Field fieldX = pt1.getClass().getDeclaredField("x"); //能得到所有的变量,但对于私有变量"可见不可得"
		fieldX.setAccessible(true); //对于私有变量使用"暴力反射",使之"可见又可得"
	}
}

/**
 * 成员变量的反射的综合案例
 * 
 * 扫描一个对象身上所有的String类型的变量,将'b'转换成'a'
 */
class ReflectFieldTest2{
	
	public static void changeStringValue(Object obj) throws IllegalArgumentException, IllegalAccessException{
		Field[] fields = obj.getClass().getFields();
		for(Field f : fields){
			if(f.getType() == String.class){ //同一份字节码用'=='来比较,而不用'equels'
				String oldVal = (String)f.get(obj);
				String newVal = oldVal.replace('b', 'a');
				f.set(obj, newVal); // 改变对象身上的值
			}
		}
	}
}

/**
 * 成员方法的反射
 * 
 * 模拟String.charAt(int) 的两种调用方法
 */
class ReflectMethodTest{
	
	public static void main(String[] args) throws SecurityException, NoSuchMethodException, 
			IllegalArgumentException, IllegalAccessException, InvocationTargetException {
		String str1 = "abc";
		//method 1:
		str1.charAt(2);
		
		//method 2:
		Method methodCharAt = String.class.getMethod("charAt", int.class);
		methodCharAt.invoke(str1, 1); //invoke 方法类的具体方法的调用工具(方法)
		//司机把火车刹车了:
		// 司机发了一个信号给火车,然后火车自己调用了自己的刹车方法将火车刹住了
		// invoke: 是方法的调用,但需要一个对象
		methodCharAt.invoke(null, 1); //invoke 使用一个空对象,说明该对象的这个方法的是一个static的;
		
	}
}

/**
 * 23_对接收数组参数的成员方法进行反射
 * 
 * 这个程序能够根据用户提供的类名,去执行该类中的main方法
 */
class ReflectMethodTest2{
	
	public static void main(String[] args) throws SecurityException, NoSuchMethodException, ClassNotFoundException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
		
		//method 1:
		TestArguments.main(new String[]{"1","2","3"});
		
		//method 2:
		String className = args[0]; // 假设第一个参数表示要执行的类名
		Method mainMethod = Class
							.forName(className)
							.getMethod("main",String.class);
		
		//main方法是static 故invoke 可以是传一个null对象
		mainMethod.invoke(null,new String[]{"111","22","33"});
		//会报错 ,原因看jdk源码 ;jdk会将传过来的数组进行拆包,故实际传过去的是三个参数,而不是一个;
		//编译器会作特殊处理,编译时不把参数当作数组看待,也就是打散成若干个参数.

		mainMethod.invoke(null,new Object[]{new String[]{"111","22","33"}});//将这个数组对象再次打包成一个数组,而jdk只会进行一个拆包操作,故实际传的只是一个参数,只不过是一个数组类型的参数
		//Or
		mainMethod.invoke(null,(Object)new String[]{"111","22","33"});  // 强制说明这个数组为一个Object类型,即为一个参数,因此编译器会视其为一个参数.
	}
}

class TestArguments{
	public static void main(String[] args) {
		for(String s : args){
			System.out.println(s);
		}
	}
}


/**
 * 数组与Object的关系及其反射类型
 * 
 * Every array also belongs to a class that
 * with the same element type and number dimensions (维数)
 * 
 * 每一个数组都属于同一个字节码:具有相同类型和维数
 */

class ReflectArrayTest{
	
	public static void main(String[] args) {
		
		int[] a1 = new int[3];
		int[] a2 = new int[4];
		int[][] a3 = new int[2][3];
		String[] a4 = new String[3];
		
		System.out.println(a1.getClass() == a2.getClass());  //true 
		System.out.println(a1.getClass() == a4.getClass());  //false
		System.out.println(a1.getClass() == a3.getClass());  //false
		
		//得到父类的类名
		System.out.println(a1.getClass().getSuperclass().getName());
	//  result : java.lang.Object
	//	                              数组的父类是Object
		Object aObj1 = a1;  //向上转
		Object aObj2 = a4;
		Object[] aObj3 = a3;  // 数组是Object 数组的数组也就是Objcet数组
		
		Object obj4 = a4;   // 可以, a4是引用类型String 父类是Object
		Object obj5 = a1;   // 不行, a1 是基本类型的数组 不是Object
	
		
		//********************************************
		
		int[] a = new int[]{1,2,3};
		String[] aa = new String[]{"a","b","c"};
		System.out.println(a1);
		System.out.println(aa);
	//result:
//		[I@1cfb549 
//		[Ljava.lang.String;@186d666
		
		//如若希望看到的结果是具体的值 ,而不是这样的Hash码
		System.out.println(Arrays.asList(a));;
		System.out.println(Arrays.asList(aa));
		//Arrays : Array的工具类
	//result:
//		[I@1cfb549 
//      [a,b,c]
		
		//why? 为什么会是这样的结果
		
		//Arrays.asList(Objetc[] obj)   jdk1.4 当成Object[] 来处理
		//Arrays.asList(T ...a)         jdk1.5  当成一个对象来处理
		
	}
	
	/**
	 * 对数组进行反射
	 * java.lang.reflect.Array
	 */
	
	/**
	 * 对数组进行打印
	 * 传的参数有可以是数组,也有可以只是一个对象值
	 * @param obj
	 */
	public void printObject(Object obj){
		//
		Class clazz = obj.getClass();
		//判断是否为数组
		if(clazz.isArray()){
			int len = Array.getLength(obj);  //得到长度
			for(int i=0;i<len;i++){
				System.out.println(Array.get(obj, i));
			}
		}else{
			System.out.println(obj);
		}
	}
	
	/**
	 * 怎么得到数组中值的类型?
	 * 
	 */
}

class ReflectPoint {
	
	private int x;
	
	public int y;
	
	public String str1 = "ball";
	public String str2 = "basketball";
	public String str3 = "cccca";

	public ReflectPoint(int x, int y) {
		super();
		this.x = x;
		this.y = y;
	}

	@Override
	public String toString() {
		return "ReflectPoint [x=" + x + ", y=" + y + ", str1=" + str1
				+ ", str2=" + str2 + ", str3=" + str3 + "]";
	}
}



分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics