Java的反射机制
1.反射的相关概念
Java语言的反射机制:在java 运行时环境中,对于任意一个类,能否知道这个类有哪些
属性和方法,对于任意一个对象,能否调用它的任意一个方法,答案是肯定的,这种动态获
取类的信息以及动态调用对象的方法的功能来自于java 语言的反射(Reflection)机制。
Java反射机制主要提供了以下的功能:
1.在运行时判断任意一个对象所属的类。
2.在运行时构造任意一个类的对象。
3.在运行时判断任意一个类所具有的成员变量和方法。
4.在运行时调用任意一个对象的方法。
反射(Reflection):是java 被视为动态(或准动态)语言的一个关键性质。这个机制
允许程序在运行时通过Reflecttion APIs 取得任意一个已知名称的class 的内部信
息,包括其修饰符(诸如public static 等等)父类(例如Object) 实现之接口(例
如serializable),也包括成员变量和方法的所有信息,并可于运行时改变成员变量的内
容或者调用方法(包括私有方法,我们知道被private 修饰的封装的机制,是不能被外部
所使用的,但是通过反射,我们可以改变私有变量和方法)。
动态语言和非动态语言:一般而言,开发者社群说到的动态语言,大致认同的一个定义是:
“程序运行时,允许改变程序结构或者变量类型,这种语言称为动态语言。”从这个观点看,
Perl Python Ruby javascript 是动态语言,C++,java,C#不是动态语言。
Java语言的动态性:尽管我们刚才说道,在这样的定义与分类下java 不是动态语言,它
却有着一个非常突出的动态相关机制:反射(Reflection)。这个词的意思是“反射,影
响,倒影”,用在java 身上指的是我们可以于运行时加载,探知,使用编译期间完全位置
的classes。换句话说,java 程序可以加载一个运行时才得知名称的class 获悉其完整
结构(但不包括方法定义),并生成其对象的实体,或对其成员变量设置,或者唤起其方法,
这种“看透class”的能力被称为introspection(内省,内观)反射和内观是经常并提
的两个术语。
2、具体Api
以上是对java 的反射机制的一个大体的了解,但是还是有一种朦胧的感觉,摸不着头脑,
下面我们从jdk 中,从具体的API 中,认识java 的反射机制:
在JDK 中,主要由以下类来实现java 的反射机制,这些类都位于java.lang.reflect
包中:
--Class类:代表一个类
--Field类:代表类的成员变量(成员变量也称为类的属性)
--Method类,代表类的方法
--Constructor类:代表类的构造方法
--Array类:提供了动态创建数组,以及访问数组的元素的静态方法。
以上类,是在使用反射机制时一定会用到的
2.反射的基石------Class类
Java类用于描述一类事物的共性,该类事物有什么属性,没有什么属性,至于这个属性的值是什么,则是由这个类的实例对象来确定的,不同的实例对象有不同的属性值,java程序中的各个java类,他们是否属于同一类事物,是不是可以用一个类来描述这类事物呢?这个类的名字就是Class,要注意与小写的class关键字的区别,Class类描述了哪些方面的信息呢,类的名字,类的访问属性,类所在的包,字段名称的列表,方法名称的列表等等,学习反射,首先要明白Class这个类。
一句话,java程序中的各个类属于同一类事物,描述这类事物的java类名就是Class。
1.对比提问:众多的人用一个什么来表示?众多的java类用一个什么类来表示?
(1)人---person
(2)Java类---Class
2.对比提问:Person类代表人,它的实例对象就是张三,李四这样一个个具体的人,Class类代表java类,它的各个实例对象又分别对应什么呢?
(1)对应各个类在内存中的字节码,例如,Person类的字节码,ArrayList类额字节码等、
(2)一个类被类加载器加载到内存中,占用了一片存储空间,这个空间里面的内容就是类的字节码,不同的类的字节码是不同的,所以他们在内存中的内容是不同的,这一个个的空间可分别用一个个的对象来表示,这些对象显然具有相同的类型,这个类型是什么呢?
3.如何得到各个字节码对应的实例对象(Class类型)?
(1)类名.class 例如System.class
(2)对象.getClass 例如new Date().getClass();
(3)Class.forName("类型") 例如Class.forName("java.util.Date");
Class.forName("类型")的含义:获取该类的内存字节码(两个含义,一个是该类已经被加载到内存中,然后获取,另外一个是该类第一次被加载到内存中)
4.九个预定义Class实例对象:八个基本数据类型+void
(1)查看Class.isPrimitive方法的帮助
(2)Int.class == Integer.TYPE 返回true
5.数组类型的Class实例对象
class.isArray()返回是否是一个数组类
总之,只要是在源程序中出现的类型,都有各自的Class实例对象,例如int[] void
3.构造方法的反射应用
--Constructor类:代表类的构造方法
--得到某个类的所有构造方法:
Constructor[] constructor = Class.forName("java.lang.String").getConstructor();
--创建实例对象
通用方式:String str = new String(new StringBuffer("abc"));
反射方式:
Constructor constructor1 = String.class.getConstructor(StringBuffer.class);
String str2 = constructor1.newInstance(new StringBuffer("abc"));
--实例使用两种创建String的方式创建对象
除此之外,在我们获得构造方法对象以后,这个对象还有其它很多的方法,可以参考帮助文档,最重要的一个方法就是newInstance创建该类型的实例的方法。另外,除了这样一种创建实例的方法外,Class类还为我们提供了另外一种无参的创建实例的方法。
当然,我们可以不使用A方法,完全使用B方法,不会影响反射机制,A方法的使用也有好处,但我们需要创建无参实例的时候,就可以省略一步:
A:Class.newInstance()
B: Class.getConstructor().newInstance();
4.成员变量的反射
--Field类:代表类的成员变量(成员变量也称为类的属性)
--得到某个类的特定成员变量:
Field field = 类.class.getField("属性名");
--得到某个类的所有成员变量(非private修饰):
Field[] field = 类.class.getFields();
--通过反射,获取该类的所有属性(一个是private修饰一个是public修饰)
这种方式可以获得其属性值,但是只适用于public修饰的,公共的,如果我们按照同样的方法访问private修饰的属性的时候,会出现什么状况呢?会出现很多异常,为此我们需要解决两个问题:
(1)如何得到被private修饰的属性的Field对象(字节码) --getDeclaredField
(2)如何访问使用被private修饰的属性 --privateField.setAccessible(true)
5.成员变量的使用--实例
做一个实例,在ReflectTest类中新增三个String成员变量,通过反射机制访问这个类的所有属性,如果发现属性的类型是String类型的,则将其属性的值中b的字符全部变成a,然后输出。
6.成员方法的反射
--Method类,代表类的方法
--获取类中指定方法的字节码方法:
Method method = 类.class.getMethod('方法名字',方法参数[]);方法参数为type非具体值
--如何执行方法
Method.invoke("执行类的对象","具体参数");
1.4与1.5的invoke方法的区别:
Jdk1.5:public Object invoke(Object obj,Object args)
Jdk1.4:public Object invoke(Object obj,Object[]{ args1,args2});即按照1.4的语法,需要将一个数组作为参数传递给invoke方法时,数组中每个元素分别对应被调用的方法中的一个参数,所以调用charAt方法的代码也可以用jdk1.4改写为method.invoke(str,new Object[]{1})的形式
--用反射方式执行某个类中的main方法
通用方式:类.main(new String[]{args1,args2...});
反射方式:
7.数组的反射应用
每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。比如:
1.具有相同维数和元素类型的数组属于同一个类型,即具有相同的class实例对象
2.代表数组的Class实例对象的getSuper()方法返回父类为Oject类对应的Class
3.基本类型的一纬数组可以被当作Object类型使用,不能当作Object[]数组使用,非基本类型的一维数组既可以当作Object类型使用,又可以当作Object[]类型使用
4.Array.asList()方法处理int[]和String[]时的差异
5.Array工具类用于完成对数组的反射操作
下面一个例子,使用反射接受一个Object对象,如果这个对象是一个数组,则打印这个数组的所有元素,反之,则直接打印这个object的值
思考,如果得到数组中的元素类型?