反射:
1、Class类
如何得到各个字节码对应的实例对象(Class类型)
1)类名.class,例如System.class
2)对象.getClass(),例如new Date().getClass()
3)Class.forName("类名"),例如,Class.forName("java.util.Date");
九个预定义Class实例对象:
参看Class.isPrimitive方法的帮助
int.class==Integer.TYPE(true)
int.class==Integer.class(false,因为int是基本类型,而Integer则是包装类型)
数组类型的Class实例对象
Class.isArray()
数组类型的class实例对象
Class.isArray()
总之,只要是在源程序中出现的类型,都有各自的Class实例对象,例如int[],void
2、Constructor类
(反射就是把Java类中的各种成分映射成相应的java类。
例如,一个Java类中用一个Class类的对象来表示,一个类的组成部分:成员变量,方法,构造方法,包等等信息也用一个个的java类来
表示,就像汽车是一个类,汽车中的发动机,变速箱等等也是一个个的类。表示java类的Class类显然要提供一系列的方法,来获得其中
的变量,方法,构造方法,修饰符,包等信息。这些信息就是用相应类的实例对象来表示,他们是Field,Method,Constructor,Package
等等。反射会导致程序变慢。)
Constructor类代表某个类中的一个构造方法
1)得到某个类中所有的构造方法
例子:Constructor[] constructors = Class.forName("java.lang.String").getConstructors();
2)得到某一个构造方法:
例子:Constructor constructor = Class.forName("java.lang.String").getConstructor(StringBuffer.class);
或:Constructor constructor = String.class.getConstructor(StringBuffer.class);
3)创建实例对象:
通常方式:String str = new String(new StringBuffer("abc")); //这里的StringBuffer是类型
反射方式:String str = (String)constructor.newInstance(new StringBuffer("abc"));//这里的StringBuffer是基本类型对应的实际变量
//调用获得的方法时要用到上面相同类型的实例对象
4)Class.newInstance()方法
例子:String obj = (String)Class.forName("java.lang.String").newInstance();
该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象。
该方法内部的具体代码是怎样写的呢?用到了缓存机制来保存默认构造方法的实例对象。
上面的3)创建实例对象的步骤是:class->constructor->new Object
4)的步骤是:class->newInstance(new Object)
3、Field类
Field类代表某个类中的一个成员变量
得到的Field对象是对应到类上面的成员变量,而不是对应到对象上的成员变量。
所以,创建对应到类中某个成员变量的field对象之后,可以用它来获取任意相应对象的该成员的值。
如:
ReflectPoint pt1 = new ReflectPoint(3,5);//创建自定义类的对象,并在构造方法中传递两个int参数
Field fieldX = pt1.getClass().getDeclaredField("x");//用getDeclaredField("x")获取对应到私有成员变量x上的field
Field fieldY = pt1.getClass().getField("y");//获取对应到成员变量y上的field
fieldX.setAccessible(true);//暴力反射,让x可以访问
System.out.println(fieldX.get(pt1));//3
System.out.println(fieldY.get(pt1));//5
4、Method类
Method类代表某个类中的一个成员方法
1)得到类中的某一个方法:
例子:Method method = Class.forName("java.lang.String").getMethod("charAt",int.class);
2)调用方法:
通常方式:System.out.println(str.charAt(1));
反射方式:System.out.println(methodCharAt.invoke(str,1));
如果传递给Method对象的invoke()方法的第一个参数为null,这说明什么呢?说明该Method对象对应的是一个静态方法。
如:
Method methodCharAt = String.class.getMethod("charAt", int.class);
char c = (Character)methodCharAt.invoke(str, 1);
//invode是methodCharAt这个方法对象上的方法,类似于画圆,人在黑板上画圆,这涉及到人、黑板、圆这三个对象,而圆心和半径是圆身上的,画这个动作是人发出的,但实际操作的是圆自身(invoke)。
//再一个例子:列车司机刹车,刹车这个动作只是人发出的(一个信号),但实际停车的是列车本身,这也是面向对象的设计原理
jdk1.4和jdk1.5的invoke方法的区别:
1)jdk1.5:public Object invoke(Object obj,Object...args)
2)jdk1.4:public Object invoke(Object obj,Object[] args),及按jdk1.4的语法,需要将一个数组作为参数传递给invoke方法,数组中 的每个元素分别对应被调用方法中的一个参数,所以,调用charAt方法的代码页可以用jdk1.4改写为methodCharAt.invoke(str,new Object[]{1})形式。