JAVA高级(9)—— 反射

反射的基石-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不一致,无法删除对象,导致内存泄露

你可能感兴趣的:(JAVA高级(9)—— 反射)