------- android培训、java培训、期待与您交流! --------------
一、反射的基石→Class类
Java类用于描述一类事物的共性,该类事物有什么属性,没有什么属性,至于这个属性是什么,则是由这个类的实例对象来确定的,不同的实例对象有不同的属性值。
Java程序中的各个Java类属于同一类事物,描述这类事物的Java类名就是Class。
Class类描述了类的名字,类的访问属性,类所属包名,字段名称的列表,方法名称的列表等等,学习反射,首先就要学习Class这个类。
Class类的各个实例对象分别对应各个类在内存中的字节码。
一个类被类加载器加载到内存中,占用一片存储空间,这个空间里面的内容就是类的字节码,不同的类的字节码是不同的,所以它们在内存中的内容是不同的,这一个个的空间可
分别用一个个的对象来表示。
如何得到各个字节码对应的实例对象(Class类型)?
1、类名.class,例如:System.class
2、对象.getClass(),例如:new Date().getClass()
3、Class.forName("类名"),例如:Class.forName("java.util.Date")
开发中第3种最常使用,因为参数可以写为字符串变量。
九个预定义Class实例对象
1、有九种预定义的 Class 对象,表示八个基本类型和 void。这些类对象由 Java 虚拟机创建,与其表示的基本类型同名,即 boolean、byte、char、short、int、long、float 和double。
2、int.class = Integer.TYPE
判断是否为基本类型的Class实例对象Class.isPrimitive()
判断是否为数组类型的Class实例对象Class.isArray()
总之,只要是源程序中出现的类型,都有各自的Class实例对象,例如:int[],void...
二、反射的概念
反射就是把Java类中的各个成分映射成相应的Java类。
例如:一个Java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量、方法、构造方法、包等等信息也用一个个的Java类来表示,就像汽车是一个类,汽车的发动机、变速箱等等也是一个个的类。表示Java类的Class类显然要提供一系列的方法,来获得其中的变量、方法、构造方法、修饰符、包等信息,这些信息就是用相应的类的实例对象来表示,它们是Field、Method、Constructor、Package等等。
一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示,通过调用Class类的方法可以得到这些实例对象,如何使用这些实例对象正是应用反射的要点。
三、构造方法 Constructor类
Constructor类代表某个类中的一个构造方法
得到某个类中的所有构造方法 Class.getConstructors() :
Constructor constructors[] = Class.forName("java.lang.String").getConstructors()
得到某个类中的一个构造方法 Class.getConstructor(Class<?>... parameterTypes) :
Constructor constructor = Class.forName("java.lang.String").getConstructor("StringBuffer.class")
创建实例对象:
通常方式:String str = new String(new StringBuffer("abc"));
反射方式:
1、Constructor.newInstance(Object... initargs)
String str = (String)constructor.newInstance(new StringBuffer("abc"));
//调用获得的构造方法时要用到上面相同类型的实例对象
2、Class.newInstance()
空参数的构造方法可用这个方法更方便地创建实例对象。
该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象。
该方法内部代码用到了缓存机制来保存默认构造方法的实例对象。
四、成员变量 Field类
Field类代表某个类中的一个成员变量
得到某个类中的所有成员变量: Class.getField()
得到某个类中的一个成员变量: Class.getField(String name)
得到某个类中的包括私有的变量:Class.getgetDeclaredField(String name) 、Class.getDeclaredFields()
调用成员变量:Field.get(Object obj)
暴力反射(调用私有变量前声明):setAccessible(true)
问:得到的Field对象是对应到类上面的成员变量,还是对应到对象上的成员变量?类只有一个,而该类的实例对象有多个,如果是与对象关联,那关联的是哪个对象呢?所以字段FieldX戴表的是x的定义,而不是具体的x变量。
五、成员方法 Method类
Method类代表某个类中的一个成员方法
例子:Method charAt = Class.forName("java.lang.String").getMethod("charAt", int.class);
调用方法: Method.invoke(Object obj, Object... args)
1、通常方式:System.out.println(str.charAt(1));
2、反射方式:System.out.println(charAt.invoke(str, 1));
注:如果传递给Method对象的invoke()方法的第一个参数为null,说明该Method对象对应的是一个静态方法。
六、数组 Array
具有相同维数和元素类型的数组属于同一类型,即具有相同的Class实例对象。
代表数组的Class实例对象的getSuperclass()方法返回的父类为Object类对应的Class。
基本类型的一维数组可以被当做Object类型使用,不能当做Object[]类型使用;非基本类型的一维数组,既可以当做Object类型使用,也可以当做Object[]类型使用。
一个Array类的反射应用:
/*
* 定义一个函数,实现打印对象的功能,如果对象为数组则获取数组每一个元素并打印
*/
import java.lang.reflect.Array;
public class ArrayTest {
public static void main(String[] args) {
int[] i = {1,2,3};
printObject(i);
String[] str = {"a","bb","ccc"};
printObject(str);
printObject("abc");
}
public static void printObject(Object obj) {
if(obj.getClass().isArray()){
int len = Array.getLength(obj);
for(int i = 0; i < len; i++) {
System.out.println(Array.get(obj, i));
}
}
else
System.out.println(obj);
}
}