Java内省和反射机制三步曲之 - 反射

 

经过多方面的资料搜集整理,写下了这篇文章,本文主要讲解java的反射和内省机制,希望对大家有点帮助,也希望大家提出不同的看法!

1).通俗的讲,反射就是把java类中的各种成分映射成相应的java类.如一个java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等信息也用一个个的java类表示。那么java类的Class类显然要提供一系列的方法来获得其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应的类的实例对象来表示,它们是Field,Method,Construtor,Package等。

JAVA反射机制是在运行状态中, 对于任意一个类,都能够得到这个类的所有属性和方法; 对于任意一个对象,都能够调用它的任意一个方法; 这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制.

2).一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示。

3).Constructor类:Constructor类代表某个类中的一个构造方法.

.1)得到某个类所有的构造方法:例如: Constructor[] cons = String.class.getConstructors();
.2)得到某一个构造方法:例如: Constructor cons = String.class.getConstructor(StringBuffer.class);//获得构造方法时要调用的参数类型,因为要识别构造方法,必须靠参数类型。
.3)创建实例对象:
通常情况下:String str = new String(new StringBuffer("abc"));
反射方式: String str = (String) cons.newInstance(new StringBuffer("abc"));//调用获得方法时要用到上面相同类型的实例对象
.4)Class.newInstance()方法,它是把class - constructor - new obj 简化为 class - newInstance
原理:该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象,该方法内部用到了缓存机制来保持默认构造方法的实例对象,相当于调用 无参的构造方法,反射会导致系统性能下降.所以使用反射要慎重。
例如: String sr = String.class.newInstance();

相关代码:
public static void main(String[] args) throws Exception {
    Constructor constructor = String.class.getConstructor(StringBuffer.class);
    String str2 =(String)constructor.newInstance(new StringBuffer("abc"));
    //newInstance()返回的是一个Object,所以要用类型转换
    System.out.println(str2);
   
    String str3 = (String)constructor.newInstance("abc");
    System.out.println(str3);//有异常:argument type mismatch
    //获得构造方法时要调用的参数类型和调用获得方法时要有相同的参数类型
}

4).Field类:Field类代表类中的一个成员变量
相关代码一:
public class Point {
public Integer x;
private Integer y;

public Point(Integer x, Integer y) {
    super();
    this.x = x;
    this.y = y;
}
}

public static void main(String[] args) throws Exception {
    Point reflect = new Point(2, 5);
    Field fieldX = Point.class.getField("x");
    // 此时fieldX的值不是5,fieldX不是对象身上的变量,而是类上,要用它去取对象身上的值,必须和实例对象结合使用。

    Integer valueX = (Integer) fieldX.get(reflect);
    System.out.println(valueX);// 2

//    Field fieldY = Point.class.getField("y");
//    // 由于属性y的修饰符是private,所以程序运行到此处就有异常,说该属性不存在:java.lang.NoSuchFieldException: y
//    Integer valueY = (Integer) fieldY.get(reflect);

//    // 下面的方法可以解决无法查看私有属性的方法
//     Field fieldY2 = Point.class.getDeclaredField("y");
//    //getDeclaredField():只要声明的变量都可以查看,运行到此处无异常
//     Integer valueY2 = (Integer) fieldY2.get(reflect);
//    // 在这里会有异常,属性虽然存在,但无法访问:Class com.sun.Reflect can not access a member of class com.sun.Point with modifiers "private"


    // 暴力反射,即使设为private的属性变量依然可以访问,
    Field fieldY3 = Point.class.getDeclaredField("y");
    fieldY3.setAccessible(true);
    Integer valueY3 = (Integer) fieldY3.get(reflect);
    System.out.println(valueY3);// 5
    //一个代表看不见,一个代表看见了但取出到值,就类如:一我看不到别人的钱,而是我看到了,但是用不到,暴力反射就相当于"抢劫".
}

相关代码二:
public class Point {
public String str1 = "who";
public String str2 = "when";
public String str3 = "where";
public Integer num = 5;
public boolean istrue = true;

public String toString() {
    return str1 + "-" + str2 + "-" + str3 + "-" + num + "-" + istrue;
}
}

public class Reflect {
public static void main(String[] args) throws Exception {
    Point point = new Point();
    System.out.println(point);// who-when-where-5-true
    changeFieldValues(point);
    System.out.println(point);// Who-When-Where-5-true:把"w"改成了大写的"W"
    //我们看到了反射可以任意改变属性的值,这种应用在很多框架中都有使用!
}

private static void changeFieldValues(Point point) throws IllegalAccessException {
    Field[] fields = Point.class.getFields();
    for (Field field : fields) {
      if (field.getType() == String.class) {
        String oldVal = (String) field.get(point);
        String newVal = oldVal.replace("w", "W");
        field.set(point, newVal);
      }
    }
}
}

5).Method:Method类代表某个类中的一个构造方法;
.1)得到某个类中某一个方法:例如:Method stringCharAt = String.class.getMethod("charAt", int.class);
.2)创建实例对象:
通常方式: System.out.println("abcd".charAt(1));
反射方式: System.out.println(stringCharAt.invoke("abcd", 1));//b,如果invoke得第一个参数为空,那么该method对应的是一个静态方法
.3)invoke()在JDK1.4,和1.5中的参数形式不同。
相关代码:
public static void main(String[] args) throws Exception {
    String str = "welcome!";
    Method charAt = String.class.getMethod("charAt", int.class);
    System.out.println(charAt.invoke(str, 0));// w
}

posted @ 2010-04-16 13:44  夜色狼  阅读(243)  评论(0)    收藏  举报