也浅谈下Java反射

Java代码 复制代码
  1. import java.lang.reflect.Array;   
  2. import java.lang.reflect.Constructor;   
  3. import java.lang.reflect.Field;   
  4. import java.lang.reflect.Method;   
  5. import java.util.Arrays;   
  6.   
  7. /**  
  8.  * 浅谈Java反射  
  9.  *   
  10.  * @author leejon  
  11.  *   
  12.  */  
  13. public class ReflectTest {   
  14.     @SuppressWarnings("unchecked")   
  15.     public static void main(String[] args) throws Exception {   
  16.         /**  
  17.          * 反射的概念: 反射就是把Java类中的各种成分映射成相应的Java类 。  
  18.          * 例如:一个Java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包 等信息  
  19.          * 也用一个个的Java类来表示。就像汽车是一个类,汽车中的发动机,变速箱等等也是一个个的类。  
  20.          * 表示Java类的Class类显然要提供一系列的方法来获取其中的变量,方法,构造方法,修饰符,包等信息。 这些信息用相应类的实例对象来表示。  
  21.          * 他们就是Field,Method,Constructor,Package等。  
  22.          * 一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示, 通过调用Class类的方法可以得到这些实例对象。  
  23.          */  
  24.         System.out.println("==========Class类Demo========");   
  25.         Class<? extends Object> cla1 = String.class;   
  26.         Class<? extends Object> cla2 = Class.forName("java.lang.String");   
  27.         /**  
  28.          * 之所以相等。是因为在jvm中已经装载了String类对象的字节码  
  29.          */  
  30.         System.out.println("两对象是否相等:" + (cla1 == cla2));   
  31.         /**  
  32.          * String类不属于原始类型  
  33.          */  
  34.         System.out.println("是否是原始类型:" + cla1.isPrimitive());   
  35.         System.out.println("int 是否是原始类型?:" + int.class.isPrimitive());   
  36.         System.out.println("原始类型及其包装类型字节码:" + (Integer.class == int.class));   
  37.         /**  
  38.          * 基本类型的字节码==其包装类的TYPE属性的字节码  
  39.          */  
  40.         System.out.println(int.class == Integer.TYPE);   
  41.         /**  
  42.          * 数组不属于原始类型,是为另外一种类型:Array  
  43.          */  
  44.         System.out.println("原始类型的数组的字节码不是原始类型:" + (int[].class.isPrimitive()));   
  45.         System.out.println("数组是否为Array类型:" + int[].class.isArray());   
  46.   
  47.         System.out.println("=====================反射中构造方法demo=================");   
  48.         /**  
  49.          * 获取某个类的所有的构造函数,返回一个Constructor类型的数组  
  50.          */  
  51.         Constructor[] constructors = StringBuffer.class.getConstructors();   
  52.         for (Constructor constructor : constructors) {   
  53.             System.out.println(constructor.getName());   
  54.         }   
  55.         /**  
  56.          * 根据参数的类型获取某个类的构造函数  
  57.          */  
  58.         Constructor constructor = String.class  
  59.                 .getConstructor(StringBuffer.class);   
  60.         System.out.println(constructor.getName());   
  61.         /**  
  62.          * 注意:创建对象的时候指定的参数类型要和获取该Constructor对象时的类型相同  
  63.          * 如果类型不同,在IDE中可以通过编译,但是运行期则会抛出异常,----类型不匹配  
  64.          * 假设:constructor.newInstance(new StringBuffer("demo"));  
  65.          * 则运行异常,因为String.class.getConstructor(StringBuffer.class)  
  66.          * 获取Constructor实例时指定的参数类型为StringBuffer  
  67.          * =============================================================  
  68.          * ××××××要注意的地方:××××××××调用获得的方法时要用相同的类型×××××××××××××  
  69.          * =============================================================  
  70.          *   
  71.          * Class类的newInstance和Constructor对象的newInstance的关系:  
  72.          * Class类的newInstance方法为创建类的对象提供便利。  
  73.          * 一般情况下,创建对的对象步骤:class-->Constructor-->newIntance(Class<?>...paramType)  
  74.          * Class.newInstance():该方法内部先得到默认的构造方法,然后用该构造方法创建实例。/  
  75.          * 内部代码用到了缓存机制来保存默认构造方法的实例对象  
  76.          */  
  77.         String str = (String) constructor.newInstance(new StringBuffer("demo"));   
  78.         System.out.println("根据Constructor的newInstance方法所创建的实例:" + str);   
  79.         System.out.println("str的第二个字符:" + str.charAt(1));   
  80.   
  81.         System.out.println("=============成员变量的反射============");   
  82.         ReflectPoint pp1 = new ReflectPoint(35);   
  83.         Field fieldY = pp1.getClass().getField("y");   
  84.         /**  
  85.          * fieldY不表示某个对象代表的值,而单纯表示对象本身  
  86.          */  
  87.         System.out.println("FieldY:" + fieldY);   
  88.         /**  
  89.          * 如果要获取fieldY在具体对象上的值(字段的值)则:fieldY.get(OneObj)  
  90.          */  
  91.         System.out.println("fieldY的值:" + fieldY.get(pp1));   
  92.   
  93.         /**  
  94.          * 对于私有的成员变量,不能使用getField获得, 所以,以下代码运行时出错  
  95.          */  
  96.         // Field fieldX = pp1.getClass().getField("x");   
  97.         // System.out.println("FieldX:" + fieldX);   
  98.         // System.out.println("fieldX的值:"+fieldX.get(pp1));   
  99.   
  100.         /**  
  101.          * 对于私有的成员属性,可以采用getDeclaredField("属性名")的方式获取该成员(Filed)的引用  
  102.          * 并且要设置其为可访问:如:fieldX.setAccessible(true); 该访问成员的方式可称之为暴力反射^_^  
  103.          * ========================================================  
  104.          * 对于这里的fieldX和上面的fieldY,仅仅代表字节码的对象, 而不是表示某个对象中的一个成员属性的值  
  105.          * 如果要将其和某个对象相关联起来,则可以使用:fieldX.get(pp1),表示在pp1这个对象中x这个属性的值  
  106.          * ========================================================  
  107.          */  
  108.         Field fieldX = pp1.getClass().getDeclaredField("x");   
  109.         fieldX.setAccessible(true);   
  110.         System.out.println("FieldX:" + fieldX);   
  111.         System.out.println("fieldX的值:" + fieldX.get(pp1));   
  112.   
  113.         System.out.println("===========Medthod类===============");   
  114.         Method methodCharAt = String.class.getMethod("charAt"int.class);   
  115.         System.out.println(methodCharAt);   
  116.         /**  
  117.          * 以反射的方式调用某个对象的方法 用:invoke(要调用那个对象,参数数组): 后面的参数方法原型为可变长度参数,其内部以数组形式实现。  
  118.          */  
  119.         String methodStr = "HelloWorld!";   
  120.         System.out.println(methodCharAt.invoke(methodStr, 1));   
  121.   
  122.         System.out.println("============数组的反射==============");   
  123.         int[] arr1 = new int[] { 4556666778 };   
  124.         System.out.println(arr1.getClass().getSuperclass());   
  125.         int[] arr11 = new int[] { 123 };   
  126.         /**  
  127.          * 这里比较的是两个对象,所以不相等。而下面的getClass则比较的是字节码。 因为两个数组都是int型的, 所以,他们的字节码是相等的。  
  128.          */  
  129.         System.out.println("arr1==arr11:" + (arr1 == arr11));   
  130.         System.out.println("arr1.getClass()==arr11.getClass():"  
  131.                 + (arr1.getClass() == arr11.getClass()));   
  132.         int[][] arr2 = new int[][] { new int[] { 12345 },   
  133.                 new int[] { 678910 } };   
  134.         System.out.println("arr2:" + arr2);   
  135.         String[] arr3 = new String[] { "hello""world" };   
  136.         System.out.println("arr3:" + arr3);   
  137.         /**  
  138.          * 基本类型的一维数组只可以被当作Object使用而不能被当作Object[]来使用。  
  139.          * 非基本类型的一维数组,既可以作为Oject类型来使用,也可以作为Object[]类型来使用  
  140.          */  
  141.         System.out.println(arr2.getClass().getSuperclass());   
  142.         System.out.println("String superClass:"  
  143.                 + arr3.getClass().getSuperclass().getName());   
  144.         // Object[] obj1=arr1;(编译器报错)   
  145.         Object[] obj2 = arr2;   
  146.         Object[] obj3 = arr3;   
  147.         /**  
  148.          * 以下两行显示[[I@14318bb<br>  
  149.          * [Ljava.lang.String;@ca0b6  
  150.          */  
  151.         System.out.println(obj2);   
  152.         System.out.println(obj3);   
  153.         System.out.println("=============java.util.Arrays类==========");   
  154.         /**  
  155.          * 对于字符串类型的数组。用Arrays的静态方法asList(Object...a)能够将obj2作为一个List集合将其值输出,  
  156.          * 但是,对于int类型的数组,虽然转换成为了List,却还是输出其每个元素的地址,这是为什么呢?  
  157.          * 因为arr1数组是int型,属于基本类型。arr1  
  158.          * .getClass().getName()=[I,所以JDK编译器将整个数组作为一个Object(一个整型数组)进行处理.  
  159.          * 这也是Arrays.asList(Object...a)处理int[]和String[]时的差异  
  160.          */  
  161.         System.out.println(Arrays.asList(arr1));   
  162.         System.out.println(arr1.getClass().getName());   
  163.         System.out.println(Arrays.asList(obj3));   
  164.         /** 对数组进行反射操作 */  
  165.         Object printObj = arr3;   
  166.         Class clazz = printObj.getClass();   
  167.         if (clazz.isArray()) {   
  168.             /** 如果是数组 */  
  169.             /** 得到长度 */  
  170.             System.out.println("传入的参数是数组");   
  171.             int length = Array.getLength(printObj);   
  172.             for (int i = 0; i < length; i++) {   
  173.                 System.out.println(Array.get(printObj, i));   
  174.             }   
  175.         } else {   
  176.             System.out.println("传入的参数不是数组");   
  177.             System.out.println(printObj);   
  178.         }   
  179.     }   
  180. }  
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * 浅谈Java反射
 * 
 * @author leejon
 * 
 */
public class ReflectTest {
	@SuppressWarnings("unchecked")
	public static void main(String[] args) throws Exception {
		/**
		 * 反射的概念: 反射就是把Java类中的各种成分映射成相应的Java类 。
		 * 例如:一个Java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包 等信息
		 * 也用一个个的Java类来表示。就像汽车是一个类,汽车中的发动机,变速箱等等也是一个个的类。
		 * 表示Java类的Class类显然要提供一系列的方法来获取其中的变量,方法,构造方法,修饰符,包等信息。 这些信息用相应类的实例对象来表示。
		 * 他们就是Field,Method,Constructor,Package等。
		 * 一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示, 通过调用Class类的方法可以得到这些实例对象。
		 */
		System.out.println("==========Class类Demo========");
		Class<? extends Object> cla1 = String.class;
		Class<? extends Object> cla2 = Class.forName("java.lang.String");
		/**
		 * 之所以相等。是因为在jvm中已经装载了String类对象的字节码
		 */
		System.out.println("两对象是否相等:" + (cla1 == cla2));
		/**
		 * String类不属于原始类型
		 */
		System.out.println("是否是原始类型:" + cla1.isPrimitive());
		System.out.println("int 是否是原始类型?:" + int.class.isPrimitive());
		System.out.println("原始类型及其包装类型字节码:" + (Integer.class == int.class));
		/**
		 * 基本类型的字节码==其包装类的TYPE属性的字节码
		 */
		System.out.println(int.class == Integer.TYPE);
		/**
		 * 数组不属于原始类型,是为另外一种类型:Array
		 */
		System.out.println("原始类型的数组的字节码不是原始类型:" + (int[].class.isPrimitive()));
		System.out.println("数组是否为Array类型:" + int[].class.isArray());

		System.out.println("=====================反射中构造方法demo=================");
		/**
		 * 获取某个类的所有的构造函数,返回一个Constructor类型的数组
		 */
		Constructor[] constructors = StringBuffer.class.getConstructors();
		for (Constructor constructor : constructors) {
			System.out.println(constructor.getName());
		}
		/**
		 * 根据参数的类型获取某个类的构造函数
		 */
		Constructor constructor = String.class
				.getConstructor(StringBuffer.class);
		System.out.println(constructor.getName());
		/**
		 * 注意:创建对象的时候指定的参数类型要和获取该Constructor对象时的类型相同
		 * 如果类型不同,在IDE中可以通过编译,但是运行期则会抛出异常,----类型不匹配
		 * 假设:constructor.newInstance(new StringBuffer("demo"));
		 * 则运行异常,因为String.class.getConstructor(StringBuffer.class)
		 * 获取Constructor实例时指定的参数类型为StringBuffer
		 * =============================================================
		 * ××××××要注意的地方:××××××××调用获得的方法时要用相同的类型×××××××××××××
		 * =============================================================
		 * 
		 * Class类的newInstance和Constructor对象的newInstance的关系:
		 * Class类的newInstance方法为创建类的对象提供便利。
		 * 一般情况下,创建对的对象步骤:class-->Constructor-->newIntance(Class<?>...paramType)
		 * Class.newInstance():该方法内部先得到默认的构造方法,然后用该构造方法创建实例。/
		 * 内部代码用到了缓存机制来保存默认构造方法的实例对象
		 */
		String str = (String) constructor.newInstance(new StringBuffer("demo"));
		System.out.println("根据Constructor的newInstance方法所创建的实例:" + str);
		System.out.println("str的第二个字符:" + str.charAt(1));

		System.out.println("=============成员变量的反射============");
		ReflectPoint pp1 = new ReflectPoint(3, 5);
		Field fieldY = pp1.getClass().getField("y");
		/**
		 * fieldY不表示某个对象代表的值,而单纯表示对象本身
		 */
		System.out.println("FieldY:" + fieldY);
		/**
		 * 如果要获取fieldY在具体对象上的值(字段的值)则:fieldY.get(OneObj)
		 */
		System.out.println("fieldY的值:" + fieldY.get(pp1));

		/**
		 * 对于私有的成员变量,不能使用getField获得, 所以,以下代码运行时出错
		 */
		// Field fieldX = pp1.getClass().getField("x");
		// System.out.println("FieldX:" + fieldX);
		// System.out.println("fieldX的值:"+fieldX.get(pp1));

		/**
		 * 对于私有的成员属性,可以采用getDeclaredField("属性名")的方式获取该成员(Filed)的引用
		 * 并且要设置其为可访问:如:fieldX.setAccessible(true); 该访问成员的方式可称之为暴力反射^_^
		 * ========================================================
		 * 对于这里的fieldX和上面的fieldY,仅仅代表字节码的对象, 而不是表示某个对象中的一个成员属性的值
		 * 如果要将其和某个对象相关联起来,则可以使用:fieldX.get(pp1),表示在pp1这个对象中x这个属性的值
		 * ========================================================
		 */
		Field fieldX = pp1.getClass().getDeclaredField("x");
		fieldX.setAccessible(true);
		System.out.println("FieldX:" + fieldX);
		System.out.println("fieldX的值:" + fieldX.get(pp1));

		System.out.println("===========Medthod类===============");
		Method methodCharAt = String.class.getMethod("charAt", int.class);
		System.out.println(methodCharAt);
		/**
		 * 以反射的方式调用某个对象的方法 用:invoke(要调用那个对象,参数数组): 后面的参数方法原型为可变长度参数,其内部以数组形式实现。
		 */
		String methodStr = "HelloWorld!";
		System.out.println(methodCharAt.invoke(methodStr, 1));

		System.out.println("============数组的反射==============");
		int[] arr1 = new int[] { 45, 5, 6, 666, 778 };
		System.out.println(arr1.getClass().getSuperclass());
		int[] arr11 = new int[] { 1, 2, 3 };
		/**
		 * 这里比较的是两个对象,所以不相等。而下面的getClass则比较的是字节码。 因为两个数组都是int型的, 所以,他们的字节码是相等的。
		 */
		System.out.println("arr1==arr11:" + (arr1 == arr11));
		System.out.println("arr1.getClass()==arr11.getClass():"
				+ (arr1.getClass() == arr11.getClass()));
		int[][] arr2 = new int[][] { new int[] { 1, 2, 3, 4, 5 },
				new int[] { 6, 7, 8, 9, 10 } };
		System.out.println("arr2:" + arr2);
		String[] arr3 = new String[] { "hello", "world" };
		System.out.println("arr3:" + arr3);
		/**
		 * 基本类型的一维数组只可以被当作Object使用而不能被当作Object[]来使用。
		 * 非基本类型的一维数组,既可以作为Oject类型来使用,也可以作为Object[]类型来使用
		 */
		System.out.println(arr2.getClass().getSuperclass());
		System.out.println("String superClass:"
				+ arr3.getClass().getSuperclass().getName());
		// Object[] obj1=arr1;(编译器报错)
		Object[] obj2 = arr2;
		Object[] obj3 = arr3;
		/**
		 * 以下两行显示[[I@14318bb<br>
		 * [Ljava.lang.String;@ca0b6
		 */
		System.out.println(obj2);
		System.out.println(obj3);
		System.out.println("=============java.util.Arrays类==========");
		/**
		 * 对于字符串类型的数组。用Arrays的静态方法asList(Object...a)能够将obj2作为一个List集合将其值输出,
		 * 但是,对于int类型的数组,虽然转换成为了List,却还是输出其每个元素的地址,这是为什么呢?
		 * 因为arr1数组是int型,属于基本类型。arr1
		 * .getClass().getName()=[I,所以JDK编译器将整个数组作为一个Object(一个整型数组)进行处理.
		 * 这也是Arrays.asList(Object...a)处理int[]和String[]时的差异
		 */
		System.out.println(Arrays.asList(arr1));
		System.out.println(arr1.getClass().getName());
		System.out.println(Arrays.asList(obj3));
		/** 对数组进行反射操作 */
		Object printObj = arr3;
		Class clazz = printObj.getClass();
		if (clazz.isArray()) {
			/** 如果是数组 */
			/** 得到长度 */
			System.out.println("传入的参数是数组");
			int length = Array.getLength(printObj);
			for (int i = 0; i < length; i++) {
				System.out.println(Array.get(printObj, i));
			}
		} else {
			System.out.println("传入的参数不是数组");
			System.out.println(printObj);
		}
	}
}


Java代码 复制代码
  1. public class ReflectPoint {   
  2.     private int x;   
  3.     public int y;   
  4.   
  5.     public ReflectPoint(int x, int y) {   
  6.         this.x = x;   
  7.         this.y = y;   
  8.         System.out.println("X:" + this.x + ",Y:" + this.y);   
  9.     }   
  10.   
  11.     @Override  
  12.     public String toString() {   
  13.         return "X:" + this.x + ",Y:" + this.y;   
  14.     }   
  15. }  
发布了26 篇原创文章 · 获赞 0 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/sameseam/article/details/5064281