`
xtfncel
  • 浏览: 74486 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

java反射机制

阅读更多

Java反射机制

 

一、JAVA中的反射机制:

Java 运行时环境中(注意这里强调的是运行时),对于任意一个类,能否知道这个类有哪些属性和方法?对于任意一个对象,能否调用他的方法?这些答案是肯定的,这种动态获取类的信息,以及动态调用类的方法的功能来源于JAVA的反射。从而使java具有动态语言的特性。  

反射就是吧Java类中的各种成分映射成相应的Java; 例如一个Java类中用一个Class类的对象表示,一个类中的组成部分:成员变量,方法,构造方法,包等等信息也用一个个的Java类来表示. 一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示。

        

二、JAVA反射机制主要作用(以下所说都是强调在运行时环境)

1.在运行时判断任意一个对象所属的类

    2.在运行时构造任意一个类的对象

    3.在运行时判断任意一个类所具有的成员变量和方法(通过反射甚至可以调用private方法)

4.在运行时调用任意一个对象的方法

 

三、Java 反射相关的API简介:(位于java.lang.reflect包中)

--Class类:代表一个类

      --Filed类:代表类的成员变量

--Method类:代表类的方法

--Constructor类:代表类的构造方法

--Array类:提供了动态创建数组,以及访问数组的元素的静态方法。该类中的所有方法都是静态方法

 

四、常用方法详述

----Class

java Object类中的申明了几个应该在所有的java类中被改写的方法:hashCode(), equals(),clone(),toString(),getClass()等,其中的getClass()返回一个Class 类型的对象。

Class类十分的特殊,它和一般的类一样继承自Object,其实体用以表达java程序运行时的 class interface,也用来表达 enum,array,primitive,Java Types 以及关键字void,当加载一个类,或者当加载器(class loader)的defineClass()被JVM调用,便产生一个Class实例.

Class是反射的基础,针对任何你想探勘的class(类),唯有现为他产生一个Class的实例对象,接下来才能经由后者唤起为数十多个的反射API

Java允许我们从多种途径为一个类class生成对应的Class对象。

--运用 getClass():Object类中的方法,每个类都拥有此方法

         String str="abc";

            Class cl=str.getClass();//产生一个string Class实例

--运用Class.getSuperclass()Class类中的方法,返回该Class的父类的Class

--运用Class.forName()静态方法

--运用Class:类名.class

--运用primitive wrapper classesTYPE语法: 基本类型包装类的TYPE,如:Integer.TYPE

         注意:TYPE的使用,只适合原生(基本)数据类型

 

----Constructor:运行时生成instance

想在运行进动态的生成对象的实体,在反射动态机制中有两种方法,一个针对无变量的构造方法,一个针对带参数的构造方法,如果想调用带参数的构造方法,就比较的麻烦,不能直接调用Class类中的newInstance(),而是调用Constructor类中newInstance()方法,首先准备一个Class[]作为Constructor的参数类型,通过这个Class[]来断定你要调用类中的哪一个构造方法。然后调用该Class对象的getConstructor()方法获得一个专属的Constructor的对象,最后再准备一个Object[]作为Constructor对象的newInstance()方法的实参(这里是要把它做为构造方法的参数传进去)

在这里需要说明的是只有两个类拥有newInstance()方法,分别是Class类和Constructor.Class类中的newInstance()方法是不带参数的,而Constructro类中的newInstance()方法是带参数的需要提供必要的参数。

    :

     Class c=Class.forName("DynTest");

      Class[] ptype=new Class[]{double.class,int.class}

      Constructor ctor=c.getConstructor(ptypr);

      Object[] obj=new Object[]{new Double(3.1415),new Integer(123)};

      Object object=ctor.newInstance(obj);

      System.out.println(object);

 

----运行时调用Method

       成员方法的反射应用方法:先得到类字节码的方法,然后再指定在哪个对象上调用方法,最后进行调用。

    这个动作首先准备一个Class[]{}作为getMethodString nameClass[])方法的参数类型(这里和上面的Construtors一个意思),接下来准备一个Obeject[]放置自变量,然后调用Method对象的invokeObject objObject[])方法。Obj表示是调用该方法的对像,Object[]表示传给该方法的参数.

例如:利用反射调用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.invokenull,参数对象数组)

      无参静态方法反射调用要写成:方法对象method.invokenullnull

      JDK1.4版本注意参数类型构成:methodCharAt.invoke(str,new Object[]{1})

 

----运行时调用Field内容

变更Field不需要参数和自变量,首先调用ClassgetField()并指定field名称,获得特定的Field对象后便可以直接调用Field getObject obj)和set(Object obj,Object value)方法

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)后才可以访问

  成员变量的修饰符publicprotectprivate对反射类有不同的权限要求

 

----数组与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);

     }

  }

 注:本文部分内容来自网络

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics