Class类
。Class类实例对象对应各个类在内存中的字节码
一个类被类加载器加载到内存中,占用一片存储空间,这个空间里面的内容就是类的字
节码,不同类的字节码是不同的,所以它们在内存中的内容是不同的,这一个个的空间
可分别用一个个的对象来表示,这些对象具有相同的类型Class类型
。获得各个字节码对应的实例对象有三种方法
1)类名.class System.class
2)对象.getClass() new Date().getClass()
3)Class.forName("类名") Class.forName("java.util.Date")
该方法获得字节码两种方式 1 类字节码已经加载到内存中,直接在内存中获得。2 在
虚拟机中还没有该类字节码,需要类加载器加载字节码到内存,再获得字节码。
int.class.isPrimitive() 判断是否是基本数据类型的字节码
int.class.isPrimitive() == Integer.classisPrimitive() 结果为false 因为int为
基本数据类型。这就是9大数据类型预定义 多出的是void.class
int.class.isPrimitive() == Integer.TYPE 结果为true TYPE字段代表其对应基本
数据类型的字节码
数组类型的Class实例对象 Class.isArray()
总结:只要是源程序中出现的类型,都有各自的Class实例对象 ,例:int[] void 等
Constructor类 代表某个类中的一个构造方法
Constructor con1 = String.class.getConstruactor(StringBuffer.class);
获取Class的构造方法getConstructor() 传的参数表示获取String具体哪一个构造方法
String str = con1.newInstance(new StringBuffer("abc"));
因为获得了具体的构造方法,那么可以用该构造方法创建一个String对象,
newInstance()就是使用该构造方法,参数为该构造方法应传入的参数。
步骤:先获得字节码---->根据Class获得构造方法(参数确定具体哪个)---->根据
Constructor的newInstance()方法创建对象(因为构造方法确定,要传入上面类型的对象)
Class类中有newInstance()方法:其实该方法将获得构造方法的部分封装了,该方法
得到默认的构造方法,在用该构造方法创建对象。其实内部有Constructor对象。
Field类 代表某类中的一个成员变量
public class ReflectPoint {
private int x ;
public int y ;
public String str1 = "ball";
public String str2 = "baseketball";
public String str3 = "itcast";
public ReflectPoint(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public String toString(){
return str1+".."+str2+"..."+str3;
}
}
ReflectPoint pt = new ReflectPoint(3,5);
Field fieldY = pt.getClass().getField("y");
//这里的fieldY是ReflectPoint类中的成员变量y,没有具体的值,它的值要由一个具体对象获得
System.out.println(fieldY.get(pt));//fieldY.get(pt);就是获得pt这个对象中的y的值
Field fieldX = pt.getDeclaredField("x");
//因为x是private修饰私有的,所以要获得类中的私有变量要用getDeclaredField()方法
fieldX.setAccessible(true);//已经获得类中的x,要去取实例对象x具体值时,需要设置权限,可以获取对象中x的值
System.out.println(fieldY.get(pt));
/*对具体对象变量值的改变*/
private static void changStringValue(Object obj)throws Exception {
Field[] fields = obj.getClass().getFields();//获得类中的所有成员变量
for(Field field : fields){ //遍历数组
if(field.getType() == String.class){//判断类中的一个对象是否是String类型的,用==时因为类的字节码在内存中是唯一的
String oldstr = (String)field.get(obj);//get方法获取某个对象中具体变量的值
String newstr = oldstr.replace('b', 'a');//将变量的值转变
field.set(obj, newstr);//将变化完的变量值在设置到该对象中
}
}
System.out.println(obj);//结果是aall..aaseketaall...itcast
}
Method类 代表某个类中的一个方法
通常方式:str.charAt(1);
Mehtod methodCharAt = String.class.getMethod("charAt",int.class);
获得类中的一个方法,参数是方法的名称和方法的参数类型
methodCharAt.invoke(str, 1)
已经获得方法,要运行方法就调用该方法对象的运行方法invoke(),参数是运行
methodCharAt方法的对象str和传入方法的int类型的参数1.
如果invoke(null, 1)则说明对应的方法为静态方法
数组的反射
。维数和元素类型相同的数组属于同一类型(具有相同的Class实例对象)
。代表数组的Class实例对象的getSuperclass()方法返回的父类为Object对应的Class
。基本类型的一维数组可以被当做Object类型使用,不可以当做Object[]类型使用
非基本类型的都可以
。Arrays.asList()方法处理int[]和String[]时的差异。
1.4版本 asList(Object[] obj) 1.5版本 asList(T...a)
因为int[]不可以转换成Object[],所以是1.5版本的方法,接收的是对象,打印哈希码
而String[]可以被当做Object[]类型,所以是1.4版本方法
Array工具类完成对数组的反射操作
public void printObject(Object obj)
{
Class class = obj.getClass();
if(class.isArray()) //通过该方法判断是不是数组
{
int len = Array.getLength(obj); //获取obj数组长度
for(int x=0;x<len; x++)
{
System.out.println(Array.get(obj,x));//获取obj数组第x个元素
}
}else{
System.out.println(obj);
}
}
ArrayList HashSet比较及HashCode分析
集合存储的元素都是引用,ArrayList元素存储是有顺序的,按存储的前后顺序
HashSet元素是比较是否相同,不能存储相同的元素
HashCode可以解决当向HashSet存储元素时要和其内存在的元素挨个进行比较,HashSet
内存储的元素根据HashCode的不同进行分区域,这样比较时,根据元素HashCode在HashSet
中比较存储。 当HashCode相同时,则用equals方法比较,所以equals相等时,让HashCode
也相等,当元素存储到HashSet中后不能对它的HashCode的定义内容改变,因为该元素的
HashCode会改变,该元素remove不出去,会占用资源,当大量出现时会内存泄漏。
//反射的作用 实现框架功能
//配置文件config.properties内容:classname=java.util.HashSet
import java.io.*;
import java.util.*;
public class ReflectTest2 {
public static void main(String[] args) throws Exception{
InputStream in = new FileInputStream("config.properties");//读取流读取配置文件
Properties proper = new Properties();//创建集合,该集合可以将读取到的键值对直接存储
proper.load(in);//将流读取的内容存储到Properties集合中
in.close();
String classname = proper.getProperty("classname");//由键获取到对应的值
Collection collections = (Collection)Class.forName(classname).newInstance();
//Class.forName() 获取某类类型 newInstance()调用该类型的无参构造方法
ReflectPoint pt1 = new ReflectPoint(3,3);
ReflectPoint pt2 = new ReflectPoint(5,5);
ReflectPoint pt3 = new ReflectPoint(4,3);
//Collection collections = new HashSet();
collections.add(pt1);
collections.add(pt2);
collections.add(pt3);
System.out.println(collections.size());
}
}
其实配置文件的加载都是用的类加载器
InputStream in = ReflectTest2.class.getClassLoader.getResourceAsStream("config.properties");
该方式是通过类获得类加载器getClassLaoder() 通过类加载器的方法获得配置文件getResourceAsStream()
InputStream in = ReflectTest2.class.getResourceAsStream("config.properties");
该方法直接通过类就由类加载器加载配置文件,其实方法内部有调用getClassLoader()方法