黑马程序员-反射

------- android培训java培训、期待与您交流! ----------

反射:

我总结的是:用字节码得到类组件,然后用这些组件去作用于这个类的某个对象。

反射的基石→Class

Java程序中所有类都属于同一类事物,描述这类事物的java类名就是Calss

Class9个预定义Class实例对象 8个基本数据类型和void

其他类型数据类型也有Class实例对象


反射就是把Java类中的各种成分映射为相应的Java


如何得到Class实例化对象:

对象用:点class

对象变量用:点getClass()

未知对象用:Class.fonName(“完整的类名”);

 

方法:

Class.isPrimitive();判断字节码是否是原始类型,基本数据类型的包装类Class.TYPE能得到该包装类的原始数据类型的字节码。包括Void也可以获得void的字节码。

Class.isArray();判断字节码是否是数组类型。

Constructor类:

代表某个类中的一个构造方法

//得到String类中一个需要传入Stringbuffer对象的构造方法

Constructor constr = String.class.getConstructor(StringBuffer.class);

//根据得到的构造方法创建一个String类型的对象。

String str = (String)constr.newInstance(new StringBuffer(“aa”));

//也可用字节码直接调用newInstrance();得到一个无参的对象

Field 类:

getField();获得类中的属性,注意:这里得到的是这个类的属性,而不是这个类对象的属性!

getFields();获得类中所有的属性


getDeclaredFields();获得类种的所有属性,包括用private修饰的属性

getDeclaredField();用来获得用private修饰了的属性。

setAccessible(true);获得private修饰的属性的第二步,设置可以获得private修饰的属性,称之为暴力反射。

Method类:

getMethod(“方法名”,方法需要传入的参数类型);获得method,如果没有参数,参数类型就不填。

invoke(对象,参数);执行方法,如果对象位置写的null表示该方法为静态的。

注意:在JDK1.5后,传入的参数是引用类型数组会被认为是一个可变参数列表,基本数据类型的数组只被认为是一个Object,所有会对传入的数组进行一次拆包,也就是说你传入的一个数组,在方法方法中执行的时候变为几个参数了,就会抛出异常:参数不对

IllegalArgumentException: wrong number of arguments

所以我们在传入引用类型的数组的时候要对数组进行一次封装,可以把数组转换为Object,也可以把数组放到一个数组中。

 1 package test.enhance.reflect;
 2 
 3 import java.lang.reflect.Constructor;
 4 import java.lang.reflect.Field;
 5 import java.lang.reflect.Method;
 6 
 7 /**
 8  * 反射
 9  * @author Administrator
10  *
11  */
12 public class ReflectTest {
13     public static void main(String[] args) throws Exception {
14         
15         //------------------获取构造函数
16         //根据类的字节码的getConstructor();把该类构造方法需要参数的字节码传入得到该类构造方法ReflectPoint(int,int,String,String)
17         Constructor  constrRP = ReflectPoint.class.getConstructor(int.class,int.class,String.class,String.class);
18         
19         //-----------------获取对象
20         //根据得到的构造方法创建一个对象
21         ReflectPoint rp = (ReflectPoint)constrRP.newInstance(1,2,"zhangsan","itcast");
22         System.out.println(rp.getStr());
23         
24         
25         //-----------------获取属性
26         //根据getField();得到该类的属性
27         //注意:这里得到的是这个类的属性,而不是这个类对象的属性!
28         Field fieldStr = rp.getClass().getField("str");
29         String str = (String)fieldStr.get(rp);
30         System.out.println(str);
31         
32         //-----------------获取私有属性
33         //获得private修饰的属性getDeclaredField();
34         Field fieldX = rp.getClass().getDeclaredField("x");
35         //暴力反射
36         fieldX.setAccessible(true);
37         int x = (Integer)fieldX.get(rp);
38         System.out.println(x);
39         
40         //将rp对象属性值中带有a的把a全部替换为b
41         Field[] fields = rp.getClass().getDeclaredFields();
42         for(Field field : fields){
43             //用双等号比用equals好,字节码每个类只有一份
44             if(field.getType() == String.class){
45                 
46                 field.setAccessible(true);
47                 
48                 //取得值,替换,重新赋值
49                 field.set(rp, (((String) field.get(rp)).replaceAll("a","b")));
50                 System.out.println(field.get(rp));
51             }
52             
53         }
54         
55         
56         //----------------获取方法
57         //获得名字getX的方法
58         Method methodGetX = rp.getClass().getMethod("getX");
59         //执行rp对象的getX方法
60         System.out.println("getX: " + methodGetX.invoke(rp));
61         
62         Method methodShow = rp.getClass().getMethod("show", String[].class);
63         //这行在执行的时候会报错
64 //        methodShow.invoke(null, new String[]{"ss","aa","bb"});
65         methodShow.invoke(null, (Object)new String[]{"ss","aa","bb"});
66     }
67 }


通过反射获得泛型参数的实际类型:

我们用普通方法是得不到泛型的类型的,用发射就可以,要多经过几个步骤,首先建一个方法把泛型传进去,然后利用反射得到该方法,在1.5以后方法就可以获得泛型参数,再根据泛型参数获得实际类型。

	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		//获得该方法
//		Method method =  ReflectGetGenericType.class.getMethod("test", List.class);
		Method method =  ReflectGetGenericType.class.getDeclaredMethod("test", List.class);
		
		//获得该方法的所有泛型参数
		Type[] types = method.getGenericParameterTypes();
		//types[0]的值为:java.util.List<java.util.Date>
		//转换为参数化类型
		ParameterizedType pt =(ParameterizedType)types[0];
		//获得原始类型
		System.out.println(pt.getRawType());
		//获取第一个泛型,有的可能有几个泛型如map集合
		System.out.println(pt.getActualTypeArguments()[0]);
	}
	//创建方法传入泛型
	private void test(List<Date> list){
		
	}




版权声明:本文为a413867670原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。