什么是反射?
反射主要是指程序可以访问、检测和修改它本身状态或行为的一种能力。它允许运行中的 Java 程序对自身进行检查,或者说"自审",并能直接操作程序的内部属性。例如,使用它能获得 Java 类中各成员的名称并显示出来。反射就是把java类中的各种成分映射成相应的java类
反射的基石Class
反射的基石是Class.只有存在Class才可能有反射,应为反射是针对字节码进行的,如果连字节码都没有还怎么反射?
弄清6个问题:
1,Class代表一类什么样的事物?
描述java程序中的各个java类
2,Class类的实例对象是什么?
Class的实例对象就是某个类的字节码.
3,Class类有没有构造方法?
Class类中没有构造函数。当内存用到Person.java时,首先要先编译时生成的字节码Person.class加载到内存中,然后再用类的字节码Person.class复制出多个对象,而内存中的每一份字节码就是Class类的一个实例对象
4,如何得到各个字节码对应的实例对象?
a: 类名.class
b: 对象.getClass( )
c: Class.forName("类名")
eg:
Class c1 = String.class;
Class c2 = "abc".getClass();
Class c3 = Class.forName("java.lang.String");
5,基本数据类型和void有没有对应的class?
有,有九种预定义的Class 对象,表示八个基本类型和 void
6,字节码的比较用“==”,还是equals?
只能用“==”
反射的作用
Java反射机制容许程序在运行时加载、探知、使用编译期间完全未知的classes。换言之:如果我们在写程序时发现要使用的元素不是现在就知道的而是要等到程序运行起来是才知道,那么就不能使用这个元素了,这就很苦恼了,于是反射机制的出现解决了这个问题.比如我们要在不不加载类的情况下使用类中的元素
构造方法的反射应用:
Constructor<String> c = String.class.getConstructor(byte[].class,int.class,int.class);
byte[] buf = "abcdefg".getBytes();
String str = c.newInstance(buf,0,buf.length);
System.out.println(str);
成员变量的反射应用:
Field fieldx = Reflact_Fieldusing.class.getField("x");
//y是私有的不能看到
//Field fieldy = Reflact_Fieldusing.class.getField("y");
Field fieldy = Reflact_Fieldusing.class.getDeclaredField("y");
Reflact_Fieldusing rf = new Reflact_Fieldusing(3,5);
System.out.println(fieldx.get(rf));
//y是私有的不能直接访问
fieldy.setAccessible(true);
System.out.println(fieldy.get(rf));
//将所有rf对象中的字符窜字段中的b换成a;
Reflact_Fieldusing rf = new Reflact_Fieldusing(3,5);
changeValue(rf);
System.out.println(rf);
注意:如果要反射的成员变量是私有或者默认权限就必须暴力反射,使用getDeclareField()setAccessible(true)方法
成员方法的反射引用:
注意:静态方法不需要对象就可以调用,所以invoke中的第一个参数可以写null
Method m1 = String.class.getMethod("charAt", int.class);
System.out.println(m1.invoke("aabc",3));
//我们在编译是不知道要调用哪个类的方法,只用运行时传入参数才知道要调用这个
// 这个参数相关的方法。
//静态方法不需要对象调用对象写null就可
String CLASS_NAME = args[0];
Method m2 = Class.forName(CLASS_NAME).getMethod("main", String[].class);
m2.invoke(null, (Object)new String[]{"kmh","wea","123"});
数组的反射应用:
对于数组相同类型相同维度的数组其对应的字节码相同否则字节码不同
eg:
<span style="white-space:pre"> </span>int[] i1 = new int[]{1,2};
int[] i2 = new int[2];
int[][] i3 = new int[2][2];
String[] s1 = new String[1];
String[] s2 = new String[]{"a","b"};
System.out.println(i1.getClass() == i2.getClass());
System.out.println(s1.getClass() == s2.getClass());
System.out.println(i2.getClass() == i3.getClass());
运行结果:
-->ture
-->ture
-->false
为了对反射有更深刻理解,做一个小实验:
通过反射绕过编译器,给有泛型限定的集合添加一个不再泛型限定范围内的元素
ArrayList<Integer> al = new ArrayList<Integer>();
Method m = al.getClass().getMethod("add", Object.class);
m.invoke(al, "abc");
System.out.println(al.get(0));
//总结:泛型限定只是给编译器看的,运行时泛型限定消失
运行结果:
-->abc
反射的缺点
反射会导致计算机性能下降
eg:两种方式建立对象的区别
1,String str = new String ("abc")
2,Constructor con = Class.forName("java.lang.String").getConstructor(String.class)
String str2 = (String)con.newInstance("abc")
第一种方法:class--------------------------->new Object
第二中方法:class----->Constructor---->new Object
显然第一中方法速度快,内部代码用到了缓存机制保存了默认的构造方法,而第二种方法要去加载string字节码文件让后找到选的的构造方法区new对象效率性能下降。