疯狂java


您现在的位置: 疯狂软件 >> 新闻资讯 >> 正文

Java的反射机制


 

         一、分析

  比如:Person有什么那?姓名,身高,睡觉行为等;而Class用于描述java的类,那有什么那?类名,所属包名,成员变量,成员方法等;Class类没有构造方法,它对应的是个各类的字节码文件,也就是.class文件,同理就是说,每一个类的字节码,都是Class类的实例对象;Person的字节码是Class类的实例对象;Person.class就表示Person在内存中的字节码Date的字节码同样也是Class类的实例对象;Date.class

  一》得到各个字节码对应的实例对象(Class类型)三种方法

  1.类名.class;如:System.class;

  2.对象.getClass();如:new Date().getClass();前提必须由对象名;

  3.Class.forName(“类名”);如;Class.forName(“java.util.Date”);

  Class的静态方法forName();指定类的完整名称;

  返回字节码文件。

  反射用的通常是这种方式:因为写源程序的时候还不知道类的名字;

  通常用一个变量表示;

  二》有九个预定义的class对象,8个基本数据类型,1个void.class

  三》

  String s = "abc";

  Class cls1 = s.getClass();

  Class cls2 = String.class;

  Class cls3 = Class.forName("java.lang.String");

  //因为内存中只有一份字节码,所以不管用那种方式创建,都相等;

  System.out.println(cls1 == cls2);

  System.out.println(cls1 == cls3);

  二、构造方法的反射应用(Constructor类):getConstructor()

  一、.得到某个类的所有构造函数:所有的构造方法会装到一个数组里面;

  Constructor[] constructors = Class.forName(“java.lang.String”).getConstructors();

  二、getConstructor()得到某一个构造方法,构造方法那么多,得到的具体是哪一个那?

  就要根据参数类型,参数类型用class对象表示

  Constructor cons1 =

  String.class.getConstructor(StringBuffer.class ,int.class);

  就是表示得到String类中,参数为StringBuffer和int的构造方法;

  三、Constructor类中有一个newInstance()方法,根据构造方法创建实例对象;

  String str = (String)cons1.newInstance(new StringBuffer("abc"));

  四、上面是利用String有参数的构造函数创建对象,其实Class类给我们提供了一个创建对象的方法newInstance(),但是这个方法只能调用无参数的构造方法,比较方便,

  String s=(String)Class.forName(“java.lang.String”).newInstance();

  同样也创建了一个String对象;

  三、成员变量的反射(Field类)getField()

  public class ReflectPoint {

  private int x;

  public int y;

  public ReflectPoint(int x, int y) {

  super();

  this.x = x;

  this.y = y;

  }

  }

  ReflectPoint pt1 = new ReflectPoint(3,5);

  //利用反射得到成员Y,用Filed类,先得到该类的字节码。

  //然后得到字节码中的成员变量。

  Field fieldY = pt1.getClass().getField("y");

  //fieldY的值是多少那?5,错,fieldY对应的是该类的字节码中变量y

  //fieldY不是对象身上的变量,而是类上,

  //要用它去取某个对象上的值;

  System.out.println(fieldY);

  System.out.println(fieldY.get(pt1));

  //获取x变量,因为x是私有的,java中定义了专用的方法

  //反射获取私有变量getDeclaredField();

  Field fieldX = pt1.getClass().getDeclaredField("x");

  //前面已经获取,下面设置访问私有变量;

  //强制访问,setAccessible(true)不能省略,否则运行失败,不让访问私有变量

  fieldX.setAccessible(true);

  System.out.println(fieldX.get(pt1));

  ..应用一下:

  //将任意个对象中的所有String类型的成员变量所对应

  //的字符串内容的“b”替换“a”;

  public static void changeStringValue(Object obj)throws Exception

  {

  //获取字节码中所有的成员变量

  Field[] fields = obj.getClass().getFields();

  for(Field field : fields)

  {

  //遍历是否是String类型变量

  //这里应该用==号,而不是equals,因为只有一份String字节码,他们用的都是同一分

  if(field.getType() == String.class)

  {

  String oldValue = (String)field.get(obj);

  //将b替换成a

  String newValue = oldValue.replace("b", "a");

  //把新值set给对象

  field.set(obj, newValue);

  }

  }

  }

  public class ReflectPoint {

  public String str1 = "ball";

  public String str2 = "basketball";

  public String str3 = "itcast";

  @Override

  public String toString()

  {

  return str1+"::"+str2+"::"+str3;

  }

  }