反射概念与应用

透彻分析反射的基础_Class类
  Class类:Java程序中的各个Java类属于同一类事物,描述这类事物的Java类名就是Class
  如何得到各个类的字节码,即Class类?
  1、类名.class //直接使用类.class获得
  2、对象.getClass()//通过对象调用其getClass方法
  3、Class.forName(“java.util.Date”) //使用类加载器加载
  Java原始基本类型:boolean, byte, char, short, int, long, float,double 和关键词 void同样都有Class类,通过.class可获得他们的类字节码
理解反射的概念
  反射就是吧Java类中的各种成分映射成相应的Java类,例如一个Java类中用一个Class类的对象表示,一个类中的组成部分:成员变量,方法,构造方法,包等等信息也用一个个的Java类来表示,就想七成是一个类,汽车中的发动机,变速箱等等也是一个个的类。表示Java的Class类显然要提供一系列的方法,来获得其中的变量、方法、构造方法,修饰符、包等信息,这些信息就是用相应的类的实例对象来表示,他们是Field、Method、Contructor、Package等等。
  一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示。
构造方法的反射应用  
  Constructor 类,各种类的构造方法的反射类。
  Constructor 反射类对象的获得:
  例:Constructor constructor=String.class.getConstructor(StringBuffer.class);
  构造方法可以用于构造实例对象
  String str=(String)constructor.newInstance(new StringBuffer("abc"));
  Class本身也还有newInstance方法,可以直接调用,例如
  String obj=(String)String.class.newInstance();
  //类似于调用无参的构造方法。
成员变量的反射
  Field 类,类中成员变量的反射类。
  Field 对象的反射获得:
  class Person
  {
    public String personname;
    protected String personcity;
    private String personadd;
    public int personage;
    public Person(String personname, String personcity, String personadd)
    {
      this.personname = personname;
      this.personcity = personcity;
      this.personadd = personadd;
      this.personage=0;
    }
  }
  ...... 
  //一下为Field反射类的应用部分
  ...... 
  Person person=new Person("myname","mycity","myaddress");
  Field fieldname=person.getClass.getField("personname");//基本方式获得public成员变量
  Field fieldcity=person.getClass.getDeclaredField("personcity");//获得声明的成员变量
  Field fieldadd=person.getClass.getDeclaredField("personadd");//获得声明的成员变量
  //Field[] fields=person.getClass.getDeclaredFields();//获得声明的所有成员变量数组  
  System.out.println("personname:" + fieldname.get(person));//打印成员变量的值
  System.out.println("personcity:" + fieldcity.get(person));//protect修饰变量可直接读取
  personadd.setAccessible(true);//设置成员变量可访问,包括private成员变量(暴力反射)
  System.out.println("personcity:" + fieldadd.get(person));//private成员必须设置访问权限setAccessible(true)后才可以访问
  成员变量的修饰符public、protect、private对反射类有不同的权限要求,注意红色字体部分。
成员变量反射的综合案例
  循环访问类示例对象的成员变量,并修改其变量值:
  public class Java_Test  //声明运行主体类
  {
    public Java_Test()
    {
      // TODO Auto-generated constructor stub
    }
    public static void main(String[] args) throws Exception
    {
      System.out.println("-------------------------------");
      Person person=new Person("myname","mycity","myaddress");
      System.out.println(person.toString());  //打印原始对象成员变量的值
      System.out.println("-------------------------------");
      chageFields(person);  //调用方法访问并修改类成员变量的值
      System.out.println(person.toString());  //打印修改后的成员变量值
      System.out.println("-------------------------------");
    }
    public static void chageFields(Object obj) throws IllegalAccessException
    {
      String str;
      Field[] fields=obj.getClass().getDeclaredFields();  //获得成员变量反射类对象数组
      for(Field field:fields)  //循环访问数组成员
      {
        field.setAccessible(true);  //设置成员变量可访问(暴力反射)
        if(field.getType()==String.class)
        {
          str=(String)field.get(obj);  //读取成员变量的值
          str=str.replace('_',' ');  //修改
          field.set(obj,str);  //重新设置成员变量的值
        }
      }
    }
  }
  class Person  //声明要操作的类
  {
    public String personname;
    protected String personcity;
    private String personadd;
    public int personage;
    public Person(String personname, String personcity, String personadd)
    {
      this.personname = personname;
      this.personcity = personcity;
      this.personadd = personadd;
      this.personage=0;
    }
    @Override  //覆盖toString方法,显示成员变量的值
    public String toString()
    {
      return "personname:" + personname +"\npersoncity:"+personcity + "\npersonadd:" + personadd;
    }
  }
成员方法的反射  
  Method 类,类中各个成员方法的反射类
  成员方法的反射应用方法:先得到类字节码的方法,然后再指定在哪个对象上调用方法,最后进行调用。
  例如:利用反射调用String类的charAt方法
  String str=new String("abc")
  Method methodCharAt=String.class.getMethod("charAt",int.class);
  //注意参数类型及意义:类字节码class.getMethod(“方法名”,方法参数类型.class)
  System.out.println(methodCharAt.invoke(str,1));  //方法对象.invoke(原对象,参数对象数组)
  输出结果同直接调用对象方法,即:str.charAt(1)
  *注意* 静态方法的反射调用可以写成:方法对象method.invoke(null,参数对象数组)
      无参静态方法反射调用要写成:方法对象method.invoke(null,null)
      JDK1.4版本注意参数类型构成:methodCharAt.invoke(str,new Object[]{1})
对接收数组参数的成员方法进行反射
  示例:调用其他类的main方法 public static void main(String[] args)
  String mainClassName=new String("MainClassName");
  Method mainMethod=Class.forName(mainClassName).getMethod("main", String[].class);
  mainMethod.invoke(null, new Object[]{new String[]{"Ling","Dong","Cao"}});
  mainMethod.invoke(null, (Object)new String[]{"Ling","Dong","Cao"});
  为兼容JDK1.4,invoke会将数组参数拆分为单个的元素来作为参数列表。在以上示例中如果直接使用数组作为参数,则会出现main方法参数个数错误:
  //错误的写法:mainMethod.invoke(null,new String[]{"Ling","Dong","Cao"});
数组与Object的关系及其反射类型
  1、具有相同维数和元素类型的数组属于统一个类型,即具有相同的Class实例对象
  2、代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class。
  3、基本类型的一维数组可以被当做Object类型使用,不能当做Object[]类型使用,非基本类型的一维数组既可以当做Object类型使用,又可以当做Object[]类型使用。
  示例:
  int[] num1=new int[3];
  int[] num2=new int[4];
  int[][] num12=new int[3][4];
  String[] str=new String[3];
  下面说明各个对象的反射类的关系
  num1.getClass()==num1.getClass()
  num1.getClass()!=num12.getClass()
  num1.getClass()!=str.getClass()
  数组与Object的关系:
  num1.getClass().getSuperClass().getName()==str.getClass().getSuperClass().getName()=="java.lang.Object"
  Object objint1=num1;
  Object objint12=num12;
  Object objstr=str;
  //Object[] objint=num1;  //错误的写法,int基本类型不是Object
  Object[] objint12=num12;  //正确写法,因其成员为int[],为Object。
  Object[] obj_str=str;  //正确,因为String实例即为Object对象类型
  Array.asList()方法处理int[]和String[]的差异。
  int[] num=new int[]{1,2,3};
  String[] str=new String[]{"aaa","bbb","ccc"};
  System.out.println(Arrays.asList(num1));  //打印输出类似“[[I@c17164]”的字符
  System.out.println(Arrays.asList(str));  //打印类似“[aaa, bbb, ccc]”的字符
数组的反射应用
  打印传入对象,如果为单一对象,直接打印,如果为数组,则逐一打印数组元素(对数组对象的判断应用)
  public void printObject(Object obj)
  {
     Class cla=obj.getClass();
     if(cla.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);
     }
  }

猜你喜欢

转载自cdzm5211314.iteye.com/blog/2254297