java强化篇(二)---反射(Reflect)

来源:互联网 发布:设计图纸软件下载 编辑:程序博客网 时间:2024/06/11 18:46

反射的基石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);  //删除失败,元素还是存在的

0 0