Class类
java中所有的类是一类事物,我们用一个名为Class的类来描述这类事物。
获取Class类对象的三种方法:
类名.class
new 类名().getClass()
Class.forName("类的全称") // 类的全称指包名.类名
第三种方式,可以用一个字符串变量代替括号里的字符串。在程序运行时,从配置文件里加载字符串变量的值,所以可以事先不知道类名。但前两种方式必须要先知道类名才行。
java中的9中数据类型(boolean, byte, char, short, int, long, float, double, void)都有对应的Class对象。
反射的概念
java的类,这类事物有很多属性,比如包名、方法、成员变量等等。每一个属性又是一类事物,所以把每一种属性又定义为一个类。这就是java中反射的概念。
构造函数的反射:
得到所有构造方法实例
//得到所有类的构造方法对象得到一个构造方法
Constructor[] conss = Class.forName("java.lang.String").getConstructors();
//获取String类的传入参数为StringBuffer对象的构造方法对象创建实例对象
Constructor cons = Class.forName("java.lang.String").getConstructor(StringBuffer.class);
//普通方式
String s1 = new String(new StringBuffer("abc"));
System.out.println(s1);
//反射方式由构造函数对象得到原类的实例对象
String s2 = (String)cons.newInstance(new StringBuffer("abc"));
System.out.println(s2);
调用空参构造方法创建实例的反射方式
String s3 = (String)Class.forName("java.lang.String").newInstance();
与下面的方式是一样的
String s4 = (String)Class.forName("java.lang.String").getConstructor().newInstance();
分析:上面这些例子里之所以需要String类型强制转换,是因为在编译阶段,虚拟机是不知道赋值号右边是String类型的,因为类名是通过字符串方式获得的。
成员变量的反射:
先定义一个类,在这个类里定义两个成员变量,然后我们用成员变量的反射来取这两个成员变量。
public class ReflectPoint {
private int x;
public int y;
public ReflectPoint(int x, int y) {
super();
this.x = x;
this.y = y;
}
}
下面我们用成员变量的反射,先来取public的变量y
//创建ReflectPoint对象,给x,y传值
ReflectPoint rp = new ReflectPoint(3,5);
//获取成员变量y的反射
Field fy = rp.getClass().getField("y");
//通过反射获得对象rp对应的y值
int y = fy.getInt(rp);
//输出rp对应的y值
System.out.println(y);
接下来,我们看private的变量x
首先,如果我们像取y的反射一样来获得x的反射,会发生NoSuchFieldException异常,因为x是私有的。
Field fx = rp.getClass().getField("x");我们通过下面的方法获得x的反射
Field fx = rp.getClass().getDeclaredField("x");
然后我们想用类似于y的方法获得rp对象对应的x值
int x = fx.getInt(rp);这时又出现了新的异常IllegalAccessException。通过上面的方法我们能够获得x的反射,但是无法获得私有变量的值。
我们能够通过一种称为暴力反射的方式获得私有成员变量x的值
fx.setAccessible(true);
int x = fx.getInt(rp);
下面的例子是成员变量反射的一个应用:
需求:获得一个类的所有String类型成员变量,并把其中含有的‘b’修改成‘a’
过程:
我们先定义一个类
public class ReflectPoint {
private int x = 3;
private int y = 5;
public String str1 = "baba";
public String str2 = "book";
public String str3 = "element";
}
然后通过成员变量的反射实现修改。其中有些函数的异常没有处理,请先在主函数抛出。
//创建ReflectPoint对象
ReflectPoint rp = new ReflectPoint();
//获取ReflectPoint的所有成员变量
Field[] fields = rp.getClass().getFields();
//遍历所有成员变量
for(Field field: fields){
//判断String类型,由于String类型字节码文件只有一个,所以比较用==
if(field.getType() == String.class){
//获取rp对象对应的成员变量值
String oldValue = (String)field.get(rp);
//替换字母
String newValue = oldValue.replace('b','a');
//将新值写入rp对象中
field.set(rp, newValue);
}
}
//打印修改后的字符串
System.out.println(rp.str1);
System.out.println(rp.str2);
System.out.println(rp.str3);
成员方法的反射:
得到类中的一个方法:
Method methodCharAt = String.class.getMethod("charAt", int.class);方法调用这个动作是方法自身的属性。所以用下面的方式来调用指定对象的方法,并打印,结果为b
System.out.println(methodCharAt.invoke("abcd", 1));
如果第一个参数是null,代表这是个静态方法。
System.out.println(methodCharAt.invoke(null, 1));
数组的反射:
只要数组元素类型相同而且维度相同,那么它们的字节码文件就是同一个。
数组的字节码文件类的父类是Object类。
注意:基本类型数组,例如int[ ],不能自动转化为Object[ ]。因为int类型不是Object类型,但int[ ] 类型是Object类型,所以int[]会被当成一个Object进行处理。
例如:
1. 很多函数的传入参数是Object[ ]类型,当我们传入一个int[ ]是不行的,无法转化。
2. 很多函数在jdk1.4里面的传入参数是Object[ ]类型,但在jdk1.5中改成了可变参数Object...类型。但jdk向下兼容,当我们传入一个String[ ]时,虚拟机会按照jdk1.4的方式进行处理,但是当我们传入参数类型为int[ ]时,虚拟机不会认为它是Object[ ]类型,所以会按照jdk1.5的传入方式,把int[ ]当成一个Object变量传入函数。
数组反射的应用例子:
需求:打印Object对象的内容,如果是个数组就打印数组内容,如果是单个对象,就打印单个对象内容。
如果我们用下面的方法:
public static void printObject(Object obj){
System.out.println(obj.toString());
}
调用上面的函数
String[] a2 = new String[]{"a","b","c"};
String s = "abc";
printObject(a2);
printObject(s);
结果是:
[Ljava.lang.String;@6d9dd520
abc
当我们往里面传入数组时,打印出来的是这个数组的类型以及它的哈希值。这不是我们希望的结果。
下面我们用数组反射Array来实现
public static void printObject(Object obj){调用上面的函数:
Class cls = obj.getClass();
if(cls.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.toString());
}
}
String[] a2 = new String[]{"a","b","c"};
String s = "abc";
printObject(a2);
printObject(s);
打印结果:
a
b
c
abc
反射的作用:
用来构建框架。框架是提前写好的,当我再用这个框架时,是框架调用我写的类,也就是说,在我们写类之前,框架就可以写调用程序,这时框架不知道类名,肯定无法用new关键字创建对象,这时候就体现了反射的作用。
------- Windows Phone 7手机开发、 .Net培训、期待与您交流! -------