什么是反射?
反射就是把Java类中的各种成分映射成相应的java类。
1,反射的基石——Class类
java类的作用:用于描述一类事物的共性,该类事物有什么属性,没有什么属性,至于这个属性的值是什么,则是由这个类的实例对象来确定的,不同的实例对象有不同的属性值。
Class类的作用:用于描述java类。
得到Class实例对象的三种方式:1,类名.class 2,对象.getClass() 3,Class.forName("类名")
九个预定义的Class实例对象:8个基本数据类型 + void
数组类型的Class实例对象:Class.isArray()
小结:只要是在源程序中出现的类型,都有各自的Class实例对象,例如,int[],void…
2,反射相关的类
Constructor:代表某个类中的一个构造方法
public static void main(String[] args){ //new String(new StringBuffer("abc"));//普通方式 Constructor constructor1 = String.class.getConstructor(StringBuffer.class); String str2 = (String)constructor1.newInstance(/*"abc"*/new StringBuffer("abc")); //注:编译时只检查语法变成二进制文件,并不执行,只知道是构造方法并不知道是哪个类的什么构造方法,所以要强转并参数要传对。 System.out.println(str2.charAt(2)); }
Filed:代表某个类中的一个成员变量
练习:将任意一个对象中的所有String类型的成员变量所对应的字符串内容中的"b"改成"a"。public static void main(String[] args) throws Exception { ReflectPoint pt1 = new ReflectPoint(3,5); Field fieldY = pt1.getClass().getField("y"); //fieldY的值是多少?是5,错!fieldY不是对象身上的变量,而是类上,要用它去取某个对象上对应的值 System.out.println(fieldY.get(pt1)); /*先用getField方法获取变量x时报错,用完getDeclardField方法后还是报错,但两者的错误不一样*/ Field fieldX = pt1.getClass().getDeclaredField("x");//通过getDeclaredField方法可以得到类中私有的成员变量 fieldX.setAccessible(true);//通过setAccessible方法,可以得到类中某个私有成员变量对应的实例对象上的值。称为“暴力反射”。 System.out.println(fieldX.get(pt1)); }
public static void main(String[] args){ ReflectPoint pt1 = new ReflectPoint(); changeStringValue(pt1); System.out.println(pt1); } private static void changeStringValue(Object obj) throws Exception { Field[] fields = obj.getClass().getFields(); for(Field field : fields){ //if(field.getType().equals(String.class)){ //用==比较好,因为字节码比较,只有一份。 if(field.getType() == String.class){ String oldValue = (String)field.get(obj); String newValue = oldValue.replace('b', 'a'); field.set(obj, newValue); } } }
Method:代表某个类中的一个成员方法
public static void main(String[] args) throws Exception { String str1 = "abc"; //str1.charAt(1); Method methodCharAt = String.class.getMethod("charAt", int.class); System.out.println(methodCharAt.invoke(str1, 1)); System.out.println(methodCharAt.invoke(str1, new Object[]{2}));//jdk1.4中的调用方式。 }
3,数组的反射综合案例:用反射的方式执行某个类的main方法
public class ReflectTest { public static void main(String[] args) throws Exception { //TestArguments.main(new String[]{"111","222","333"}); String startingClassName = args[0];//需要在程序运行时传递一个参数进来,否则会发生数组角标越界。 Method mainMethod = Class.forName(startingClassName).getMethod("main", String[].class); //mainMethod.invoke(null, new Object[]{new String[]{"111","222","333"}});//jdk1.5兼容jdk1.4所造成的问题 mainMethod.invoke(null, (Object)new String[]{"111","222","333"}); } } class TestArguments{ public static void main(String[] args){ for(String arg : args){ System.out.println(arg); } } }
具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象。
代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class。
基本类型的一维数组可以被当作Object类型使用,不能当作Object[]类型使用;非基本类型的一维数组,既可以当做Object类型使用,又可以当做Object[]类型使用。
Arrays.asList()方法处理int[]和String[]时的差异。(jdk1.5为了兼容jdk1.4,如果asList方法传入的参数是Object[]类型的,就会按照jdk1.4走;如果参数类型不属于Object[]就按1.5走,即可变参数。)
4,反射的最重要作用——实现框架的功能
public static void main(String[] args) throws Exception{
/*getRealPath();//金山词霸/内部
一定要记住用完整的路径,但完整的路径不是硬编码,而是运算出来的。*/
//InputStream ips = new FileInputStream("config.properties");
/*一个类加载器能加载.class文件,那它当然也能加载classpath环境下的其他文件,
既然它有如此能力,它没有理由不顺带提供这样一个方法。它也只能加载classpath环境下的那些文件。注意:直接使用类加载器时,不能以/打头。*/
//InputStream ips = ReflectTest2.class.getClassLoader().getResourceAsStream("cn/itcast/day1/config.properties");
//Class提供了一个便利方法,用加载当前类的那个类加载器去加载相同包目录下的文件
/*Class类也提供getResourceAsStream方法的比喻:如果你每次都找我给你商店买可乐,那我还不如直接向你买可乐,即直接提供一个买可乐的方法给你。*/
//InputStream ips = ReflectTest2.class.getResourceAsStream("resources/config.properties");
InputStream ips = ReflectTest2.class.getResourceAsStream("/cn/itcast/day1/resources/config.properties");
Properties props = new Properties();
props.load(ips);
ips.close();
String className = props.getProperty("className");
Collection collections = (Collection)Class.forName(className).newInstance();
//Collection collections = new HashSet();
ReflectPoint pt1 = new ReflectPoint(3,3);
ReflectPoint pt2 = new ReflectPoint(5,5);
ReflectPoint pt3 = new ReflectPoint(3,3);
collections.add(pt1);
collections.add(pt2);
collections.add(pt3);
collections.add(pt1);
System.out.println(collections.size());
}
public static void main(String[] args) throws Exception {
ReflectPoint pt1 = new ReflectPoint(3,5);
String propertyName = "x";
//"x"-->"X"-->"getX"-->MethodGetX--> //普通反射方式
//Object retVal = getProperty(pt1, propertyName);//抽取方法
PropertyDescriptor pd = new PropertyDescriptor(propertyName,pt1.getClass());
Method methodGetX = pd.getReadMethod();
Object retVal = methodGetX.invoke(pt1);
System.out.println(retVal);
Object value = 7;
//setProperties(pt1, propertyName, value);
PropertyDescriptor pd2 = new PropertyDescriptor(propertyName,pt1.getClass());
Method methodSetX = pd2.getWriteMethod();
methodSetX.invoke(pt1,value);
System.out.println(pt1.getX());
}