反射的基石——Class类
java程序中各个java类属于同一类事物,描述这类事物的java类名就是Class
1、Class类代表java类,对应各个类在内存中存在的字节码,例如Person类的字节码,ArrayList类的字节码等等。
2、一个类被类加载器加载到内存中,占用一片存储空间,这个空间里面的内容就是类的字节码,不同的类的字节码
是不同的,所以它们在内存中的内容是不同的,这一个个的空间可分别用一个个的对象来表示,这些对象具有相同的
类型,这就是Class。
3、如何得到各个字节码对应的实例对象呢(Class类型)?
1)类名.class 。例如System.class
2)对象.getClass()。例如 new Date().getClass()
3)Class.forName("类名")。例如Class.forName("java.util.ArrayList") //反射的时候常用到这种方法
4)九个预定义的Class实例对象
8个基本数据类型和void
总结:只要在程序中出现的类型,都有各自的Class实例对象
反射的定义:反射就是把java类中的各种成分映射成相应的java类!
下面将介绍java程序中不同部分的反射。
Constructor类
1、得到某个类所有的构造方法
Constructor[] constructors = Class.forName("java.lang.String").getConstructors();
2、得到某个具体的构造方法
Constructor constructor = Class.forName("java.lang.String").getConstructor(StringBuffer.class); //获得指定的构造方法时需要用到参数类型
3、创建实例对象
通常方式:String s1 = new String(new StringBuffer("abc"));
反射方式:String s1 = (String)Class.forName("java.lang.String").getConstructor(StringBuffer.class).newInstance(new StringBuffer("abc"));
//调用获得对象的方法时需要用到前面指定参数的实例对象作为参数,如上句红字所示。
Field类
代表某个类中的一个成员变量,提供有关类或接口的单个字段信息,当一个类中的某个成员变量时private的时候,可用暴力反射的手段进行获取。
下面用一个FieldPoint类来进行举例,如下图所示
ReflectPoint pt1 = new ReflectPoint(3,5);
Field fieldY = pt1.getClass().getField("y"); //获取参数y的反射
int y = fieldY.get(pt1); //获取在pt1对象中y的具体值,fieldY不是对象身上的变量,而是类上,要用它去取具体某个对象身上的值
由于x是私有参数,所以要用暴力手段去进行反射
Field fieldX = pt1.getClass().getDeclaredField("x"); //只要是已经声明过的都可以获取
fieldX.setAccessible(true);//设置权限为可访问的
System.out.println(fieldX.get(pt1));
练习:将任意一个对象中所有的String类型的成员所对象的字符串内容中的"b"改成"a"。
Method类
得到类中的一个方法。
例子:得到String中的charAt(int x)方法
Method charAt = Class.forName("java.lang.String").getMethod("charAt",int.class);//getMethod方法的参数为(方法名,方法的参数)
charAt.invoke("abc",1); //使用这个方法,用invoke()
如果传递给Method对象的invoke()方法的第一个参数为null,说明该Method对象对应的是一个静态方法。
下面演示一个类中用反射调用另一个类中的main方法:
数组的反射
HashCode的作用
1、在Hash集合中,每个对象都会有一个hashcode,每个对象根据自身的哈希码被分配到集合中的不同区域中,当存入新的对象时,只需根据这个
新对象的hashcode去其相对应的区域找有无相同的存在即可,提高了效率。
2、判断两个对象是否equals,也必须判断它们的hashcode。
3、当一个对象被存储进HashSet集合中后,就不能修改这个对象中参与计算hashcode的那些字段了,否则,修改后的对象与修改前的对象哈希值
就会不同,系统就会把修改前后的对象当成2个不同的对象,导致检索失败。更严重的会导致无法从HashSet中单独删除当前对象,从而造成内存泄露。