java强化篇(二)---反射(Reflect),javareflect
java强化篇(二)---反射(Reflect),javareflect
反射的基石Class类
在java中就是反射就是把Java类中的各种成分映射成相应的java类。
1.Java程序中的各个Java类属于同一类事物,描述这类事物的Java类名就是Class。对比提问:众多的人用一个什么类表示?众多的Java类用一个什么类表示?
人--->>Person
Java类--->>Class
2.Class类代表Java类,它的各个实例对象又分别对应什么呢?
对应各个类在内存中的字节码,例如,Person类的字节码,ArrayList类的字节码,等等。
一个类被类加载器加载到内存中,占用一片存储空间,这个空间里面的内容就是类的字节码,不同的类的字节码是不同的,所以它们在内存中的内容是不同的,这一个个的空间可分别用一个个的对象来表示,这些对象显然具有相同的类型,这个类型是什么呢?( Class类型)
3.如何得到各个字节码对应的实例对象( Class类型)
类名.class,例如,System.class
对象.getClass(),例如,newDate().getClass()
Class.forName("类名"),例如,Class.forName("java.util.Date");
Constructor类
Constructor类代表某个类中的一个构造方法
得到某个类所有的构造方法:
例子:
Constructor[] constructors=
Class.forName("java.lang.String").getConstructors();
得到某一个构造方法:
例子:
Constructorconstructor =
Class.forName(“java.lang.String”).getConstructor(StringBuffer.class);
//获得方法时要用到类型
创建实例对象:
通常方式:String str = newString(new StringBuffer("abc"));
反射方式:
String str =(String)constructor.newInstance(new StringBuffer("abc"));
//调用获得的方法时要用到上面相同类型的实例对象
Class.newInstance()方法:
例子:
String obj =(String)Class.forName("java.lang.String").newInstance();
该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象。
该方法内部的具体代码是怎样写的呢?用到了缓存机制来保存默认构造方法的实例对象。
Field类
Field类代表某个类中的一个成员变量.
Field flY =rp1.getClass().getField("y"); //FLY不是对象上的变量,代表类身上字节码的变量 ,要用它去取某个对象上对应的值。
flY.get(rp1); //用get取得y的值
暴力反射:取私有变量
Field flX = rp1.getClass().getDeclaredField("x");//x为私有变量,所以用此方法
flX.setAccessible(true);//设置可用
System.out.println(flX.get(rp1));
Method类
Method类代表某个类中的一个成员方法
得到类中的某一个方法:
例子:
Method charAt =Class.forName("java.lang.String").getMethod("charAt",int.class);
调用方法:
通常方式:System.out.println(str.charAt(1));
反射方式:System.out.println(charAt.invoke(str, 1));
如果传递给Method对象的invoke()方法的第一个参数为null,这有着什么样的意义呢?说明该Method对象对应的是一个静态方法!
String string ="abc";
Method methodCharAt =String.class.getMethod("charAt", int.class); //取得String的charAt方法的字节数组
System.out.println(methodCharAt.invoke(string, 1));//如果底层方法是静态的,该参数可以为 null,因为静态方法没有对象。
如果方法的参数列表为数组,用Object数组来传递对象
System.out.println(methodCharAt.invoke(string,
newObject[]{new Integer(2)})); //JDK1.4的形式
System.out.println(methodCharAt.invoke(string,
newObject[]{2})); //JDK1.5的形式,可以自动装箱
jdk1.4和jdk1.5的invoke方法的区别:
Jdk1.5:public Objectinvoke(Object obj,Object... args)
Jdk1.4:public Objectinvoke(Object obj,Object[] args),即按jdk1.4的语法,需要将一个数组作为参数传递给invoke方法时,数组中的每个元素分别对应被调用方法中的一个参数,所以,调用charAt方法的代码也可以用Jdk1.4改写为 charAt.invoke(“str”, newObject[]{1})形式。
注:Class.getMethod(name,Class... args)中的args参数就代表所要获取的那个方法的各个参数的类型的列表。
再强调一遍参数类型用什么来表示啊?用Class对象!
数组的反射
具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象(此处比较与值无关)。
代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class。
基本类型的一维数组可以被当作Object类型使用,不能当作Object[]类型使用;非基本类型的一维数组,既可以当做Object类型使用,又可以当做Object[]类型使用。
采用类加载器管理资源和配制文件
用完整路径:安装目录+内部目录——getRealPath(); +内部目录
类加载器:当文件或资源放入源文件目录时,Ecplice会自动将其复制到.class目录中。类加载器从ClassPath指定的根目录开始查找(需写从根目录开始的完整路径名)。
格式:类名.class.getClassLoader().getResourceAsStream(“xxx”); 获取资源目录。
getClassLoader()也可省略。此时只需写上资源的名称即可。
缺点:无OutputStream,无法写入文件,只能读取。
1、InputStream ips =new FileInputStream("config.properties");
2、InputStream ips =
Reflecttest2.class.getClassLoader().getResourceAsStream("cn/itcast/source/config.properties");//从根目录开始查找
3、InputStream ips =
Reflecttest2.class.getResourceAsStream(“source/config.properties”);
// getClassLoader()也可省略。此时只需写上资源的名称即可。
4、InputStream ips =
Reflecttest2.class.getResourceAsStream("/cn/itcast/source/config.properties"); //source前加上"/" 表示要从根目录下查找
小结:
HashCode()方法的作用?
两个对象相等,equal相等,则hashCode值相等,是针对Hash算法的集合。
只有存储集合是Hash算法的集合,HashCode的值才有意义。
跟ArrayList没有关系.
这里会出现内存泄漏。
如果突然改变一个成员变量的值,相应的HashCode的值就会发生改变,这时候在从集合中删除一个元素,就会删除失败.
collections.add(pt1);
collections.add(pt2);
collections.add(pt3);
pt1.y = 7;
collections.remove(pt1); //删除失败,元素还是存在的
相关文章
- 暂无相关文章
用户点评