您的位置:首页 > 职场人生

【黑马程序员】java基础加强_反射

2014-06-20 16:15 423 查看
------- android培训java培训、期待与您交流! ----------

反射,在我看来是一种很强大的技术。

定义:反射就是把java类中的各种成分映射成相应的java类。

也就是说,我们可以用各种方式来进行反射,得到字节码文件,然后可以拿到该字节码文件中其他成员。其方式有很多种

1、类反射。

我们可以通过类或者对象来拿到对应的字节码类。

返回的方式有三种:1)类名.class; 2)对象.getClass; 3)Class.forName("类名");该方法可以查询或者加载对应的字节码

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);

System.out.println(int.class.isPrimitive());//是否为基本类型true
System.out.println(int.class == Integer.class);//是否为同一个字节码文件  false
System.out.println(int.class == Integer.TYPE);//所包含的基本类型的字节码  true
System.out.println(int[].class.isPrimitive());//是否为基本类型 false 数组不是


2、构造方法反射。

通过通过泛型指定接收的参数类型,拿到类中构造的方法,再用改构造方法得到其字节码文件。

Constructor<String> constructor =
String.class.getConstructor(StringBuffer.class);//括号中加入接受的参数,从而指定构造的函数。
String str = constructor.newInstance(new StringBuffer("abc"));
System.out.println(str.charAt(0));


3、对象反射。

通过建立的对象,并指定可见参数,拿到字节码文件,并获取期中其他成员,private修饰的成员 无法访问,所以 提供一种名为“暴力反射”的方式,强制性让private变为可见,从而拿到这些参数的值。

ReflectPoint rp1 = new ReflectPoint(1,11);
ReflectPoint rp2 = new ReflectPoint(2,22);

Field fieldY = rp1.getClass().getField("y");	//getField()只能拿到可见参数。
//如:public

Field fieldX = rp1.getClass().getDeclaredField("x");
//getField()能拿到不可见参数。
//如:private
fieldX.setAccessible(true);//暴力反射,强制对定义过的变量可见
//作用在字节码上,没有定义在对象上,所以fieldY不等于5,需要从对象上取值
System.out.println(fieldY.get(rp1));
System.out.println(fieldX.get(rp1));

//    	Field fieldy2 = rp2.getClass().getField("y");
Field fieldx2 = rp2.getClass().getDeclaredField("x");
fieldx2.setAccessible(true);

System.out.println(rp2.getClass().getField("y").get(rp2));
System.out.println(fieldx2.get(rp2));

changeStringValue(rp1);
System.out.println(rp1);
拿单个字段用getField("x"); 而要拿所有字段的时候 则定义一个数组,然后通过getFields();方法循环获得所有字段。

4、方法反射。

先通过指定参数,来确定需要拿哪些方法,然后通过对象其中的方法来进行反射,拿到字节码方法,在对一个对象进行作用,若方法为静态,则传入的参数为null

//调用str1上的charAt(1);
Method methodCharAt = String.class.getMethod("charAt",int.class);//有多少参数,写多少class
System.out.println(methodCharAt.invoke(str1, 1));	//反射的方式拿到字节码的方法,<span style="font-family: Arial, Helvetica, sans-serif;">再用该方法作用某个对象</span>
//	调用
//    	System.out.println(methodCharAt.invoke(null, 1));	//静态方法不需要作用对象
//若为null 则该方法为静态方法

//自己写一个程序,用反射的方式调用其他程序中的main
String startingClassName = args[0];
Method mainMethod =
Class.forName(startingClassName).getMethod("main", String[].class);

mainMethod.invoke(null, (Object)new String[]{"111","222","333"});


5、数组反射。

通过数组,拿到字节码文件,这里需要提到的是,不同的数组类型 所拿到的字节码文件不同。

int[] a1 = new int[]{1,2,3};
int[] a2 = new int[4];
int[][] a3 = new int[2][3];
String[] a4 = new String[]{"a","b","c"};
System.out.println("a1 a2: " + (a1.getClass() == a2.getClass()));
//		System.out.println("a1 a3: " + (a1.getClass() == a3.getClass()));
//		System.out.println("a1 a4: " + (a1.getClass() == a4.getClass()));
//		明显类型不匹配,编译报错

System.out.println(a1.getClass().getName());//结果为{I  {表示数组,I表示整型
System.out.println(a1.getClass().getSuperclass().getName());
System.out.println(a4.getClass().getSuperclass().getName());//打印父类的名字


以上是我所知道的 五种反射方式。

反射还可以arrays工具类结合使用。

这里需要提到的是JDK1.5以及之前的版本的不同,之前的版本Arrays.asList(obj)接受的为Object类型,但是int属于基本类型,它并不在Object之内,在1.5可变参数的功能加入之后接受的类型变为可变参数,但之前的方法并没有废除,所以,当接受的参数类型为int时,直接交给1.5的方法处理,也就造成 整个数组变成一个整体输出,而不是数组。

System.out.println(Arrays.asList(a1));//int不属于Object类型,故由JDK1.5参数处理
//整形数组就被当成一个整体输出
System.out.println(Arrays.asList(a4));//JDK1.4接受Object参数

printObject(a1);
printObject(a4);


private static void printObject(Object obj) throws Exception{
Class cla = obj.getClass();
if(cla.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);

}
反射的功能很强大,感觉现在理解的不是很透彻,运用的也不多,希望在日后的学习中能多多接触和运用。

------- android培训java培训、期待与您交流! ----------
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐