反射的基石-Class类
- Java程序中的各个Java类属于同一类事物,描述这类事物的Java类名就是Class。
- Class类描述了类的名称,类的属性,所属的包,方法名称等
- Classs类的实例对象:对应各个类在内存中的字节码,然后用该字节码去创建多个实例对象。
三种得到字节码对应的实例对象
a)Class cls1 = Date.class
;
b)Date d1 = new Date(); Class cls2 = d1.getClass()
;
c)Class.forName("java.lang.String")
; //主要用这种比较多,参数可以通过配置文件配置。forName的作用:返回字节码。两种方式:若不在内存中,用类加载器加载到内存中;已在内存中,直接返回。
- 9个预定义的Class类的实例对象(8个基本类型+1个Void)
a)int.class == Integer.Type --包装的基本类型的字节码void.class
b)程序中出现的类型,都有对应的Class实例对象(字节码),例如:int[],void
Class类的方法
-
isPrimitive()
//是否是基本类型 -
isArray()
//是否为数组 -
getConstructors()
Constructor[] //得到所有的构造方法 -
getConstructor(Class<?>... paramType)
//得到某个构造方法 -
getMethod(str,Class ...)
//返回公共方法;str:方法名;Classs ... :参数列表,获得的是类上的方法 -
newInstance()
//调用该字节码的无参的构造方法 -
getField(str) Field
//返回类中可见的某个变量,类似getFields();不是对象身上的变量,而是类上的 变量,再调用get(obj),调用具体的某个对象的变量的值 -
getDeclaredField(str) Field
//返回类中的某个变量 -
getSuperclass() Class
//获取父类 -
getClassLoader().getResourceAsStream(String name) InputStream
//加载文件到内存 -
getResourceAsStream(String name) InputStream
//加载文件到内存
反射
把Java类中的各种成分映射成相应的Java类,如:Method,Constructor,Package,Field等。
- 一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示。
- 反射会导致程性能下降(先获得Constructor实例对象保存到内存中)
Constructor类
- 得到某类所有的构造方法
Constructor[] cons = String.class.getConstructors()
; - 得到某个具体的构造方法
Constructor[] cons = String.class.getConstructor(StringBuffer.class)
; - Constructor类的方法:
newInstance(Object... obj)
//调用某个构造方法来创建实例对象,对比Class.newInstance()
Constructor cons = String.class.getConstructor(StringBuffer.class)
; //用到类型
String str = (String)cons.newInstance(new StringBuffer("abc"))
; //用到这个类型的对象;必须一致
Field类
-
get(obj) Object
//返回obj对象上对应变量的值 set(obj,str)
-
setAccessible(boolean)
//是否允许访问,如果是私有的变量,尽管getDeclaredField可以得到,但是不设置为true,还是会报错 -
getType() Class<?>
//获取成员变量的字节码(Class类的实例对象)
Method
- invoke(obj,obj ... ) //obj:某个对象的这个方法;obj ... :方法传递的参数;关门的这个方法应该是在门身上,而不是人;变量在谁身上,就该由谁来操作;invoke(null,obj ....) 调用的是静态方法
案例:启动java程序的main方法的参数一个字符串数组,即public static void main(String[] args),用反射调用main方法,如何为invoke方法传递参数呢?jdk1.5语法,把整个数组当做一个参数;jdk1.4语法,数组中的每一个元素当做一个参数,若把字符串数组传递给invoke方法,为了兼容jdk1.4,肯定按1.4处理,所以用invoke(null,new String[]{"1","2"})报错
解决:invoke(null,(Object)new String[]{})或invoke(null,new Object[]{new String[]{}})
数组的反射
- 具有相同维数和元素类型的数组属于同一类型,即具有相同的Class实例对象(字节码)
-
Arrays数组工具类
输出:
原因:因为Arrays.asList(T ... a) 1.5,Arrays.asLiist(Object[] a) 1.4,而a4可以按照1.4处理,a1不能赋值给Object[ ](因为int不是一个Object),所以按照1.5处理,相当于一个参数,所以才会出现这样的打印结果 - Array工具类用于完成对数组的反射操作
getLength(obj) static int
get(obj,int) static Object
HashCode
- HashCode仅对Hash类型的集合有效
- 通常情况下,一个类的两个对象equals方法比较相同时,它们的HashCode码也应该相同
- 当一个对象被存进Hash类型的集合后,不要去修改对象中参与HashCode计算的字段,否则会造成HashCode不一致,无法删除对象,导致内存泄露