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

[学习]Java反射机制

    博客分类:
  • J2SE
 
阅读更多

 

[学习]Java反射机制

 

1. 三类成员Constructor, Field, Method

java.lang.reflect.Member 是一种接口,反映有关单个成员(字段或方法)或构造函数的标识信息。

所有已知实现类: Constructor, Field, Method

 

2. 二个字段PUBLIC, DECLARED

java.lang.reflect.Member 接口有二个字段:

int java.lang.reflect.Member.PUBLIC = 0 [0x0]

Identifies the set of all public members of a class or interface, including inherited members.

说明:标识类或接口的所有公共成员(包括继承成员)的集合。

 

int java.lang.reflect.Member.DECLARED = 1 [0x1]

Identifies the set of declared members of a class or interface. Inherited members are not included.

说明:标识类或接口的所有已声明成员的集合。不包括继承成员。

 

注:接口是可以有字段的,接口中的字段必须用public static final来修饰,默认如此,可不必添加。这是与接口只能被实现有关。

 

3. 三类方法getXXXConstructorX, getXXXFieldX, getXXXMethodX

这些方法根据成员类型,成员访问权限不同可简单归为以上三类。

中间加有Declared的方法能够调用所有已声明成员的集合,但不包括继承成员。

中间没有Declared的方法能够调用所有公共成员(包括继承成员)的集合。

未尾加有s的方法返回所有对应的成员集,e.g. getConstructors()返回所有公共构造方法。

a. 调用构造函数(Constructor)的方法 - getXXXConstructorX(),包括:

    getConstructor(), getConstructors(),

    getDeclaredConstructor(), getDeclaredConstructors()

 

b. 调用字段(Field)的方法 - getXXXFieldX()

    getField(), getFields(),

    getDeclaredField(), getDeclaredFields()

 

c. 调用方法(Method)的方法 - getXXXMethodX()

    getMethod(), getMethods(),

    getDeclaredMethod(), getDeclaredMethods()

 

4. 调用构造函数的方法一般步骤

a. 返回与带有给定字符串名的类或接口相关联的 Class 对象。调用此方法等效于:

  Class.forName(className, true, currentLoader)

 其中 currentLoader 表示当前类的定义类加载器。

    public static Class<?> forName(String className)

                throws ClassNotFoundException

 

b. 返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法。parameterTypes 参数是 Class 对象的一个数组,这些 Class 对象按声明顺序标识构造方法的形参类型。 如果此 Class 对象表示非静态上下文中声明的内部类,则形参类型作为第一个参数包括显示封闭的实例。

无参构造函数,parameterTypes可以为空,可以为null,可以为new Class[]{}

有参构造函数,parameterTypes为各参数类型。

e.g.

基本类型:int.classlong.class...

/接口类型:String.classList.class...

数组类型:long[].classString[].class...

    public Constructor<T> getConstructor(Class<?>... parameterTypes)

        throws NoSuchMethodException, SecurityException

    public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)

        throws NoSuchMethodException, SecurityException

 

c. 使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。个别参数会自动解包,以匹配基本形参,必要时,基本参数和引用参数都要进行方法调用转换。

无参构造函数,parameterTypes可以为空,可以为null,可以为new Object[]{}

    public T newInstance(Object ... initargs)

    throws InstantiationException, IllegalAccessException,

               IllegalArgumentException, InvocationTargetException

 

5. 调用字段的方法一般步骤

a. 返回与带有给定字符串名的类或接口相关联的 Class 对象。调用此方法等效于:

  Class.forName(className, true, currentLoader)

 其中 currentLoader 表示当前类的定义类加载器。

    public static Class<?> forName(String className)

                throws ClassNotFoundException

 

b. 返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段。name 参数是一个 String,它指定所需字段的简称。注意,此方法不反映数组类的 length 字段。

一般JavaBean中的字段都被 private 修饰,所以使用getDeclaredField(String name)方法。

注:getField(String name)方法,会因为只能访问公有成员而出错。

    public Field getField(String name)

        throws NoSuchFieldException, SecurityException

    public Field getDeclaredField(String name)

        throws NoSuchFieldException, SecurityException

 

c. 返回指定对象上此 Field 表示的字段的值。如果该值是一个基本类型值,则自动将其包装在一个对象中。

底层字段的值是按以下方式获得的:

如果底层字段是一个静态字段,则忽略 obj 变量;它可能为 null。 否则,底层字段是一个实例字段。如果指定的 obj 变量为 null,则该方法将抛出一个 NullPointerException。如果指定对象不是声明底层字段的类或接口的实例,则该方法将抛出一个 IllegalArgumentException。如果此 Field 对象强制实施 Java 语言访问控制,并且底层字段是不可访问的,则该方法将抛出一个 IllegalAccessException

如果底层字段是静态的,并且声明该字段的类尚未初始化,则初始化这个类。否则,从底层实例字段或静态字段中获取该值。如果该字段是一个基本类型字段,则在返回前将该值包装在一个对象中,否则照原样返回。 如果字段隐藏在 obj 的类型中,则根据前面的规则获得字段的值。

除了通用的方法Object get(Object obj)外,还有int getInt(Object obj)long getLong(Object obj)等用来返回基本类型值的方法。

注:

1. Object obj 是包含有该字段的类实例

2. 调用方法用来返回某个字段值,需要遵循权限访问规则。若字段在当前方法中不可见,则无法访问,抛出异常。可见,调用字段方法一般用来获取其字段信息,而不会用来直接设置、获取其字段值。若想设置、获取其值,则可以通过getter/setter方法来完成。

    public Object get(Object obj)

        throws IllegalArgumentException, IllegalAccessException

 

6. 调用方法的方法一般步骤

a. 返回与带有给定字符串名的类或接口相关联的 Class 对象。调用此方法等效于:

  Class.forName(className, true, currentLoader)

 其中 currentLoader 表示当前类的定义类加载器。

    public static Class<?> forName(String className)

                throws ClassNotFoundException

 

b. 返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。name 参数是一个 String,用于指定所需方法的简称。parameterTypes 参数是按声明顺序标识该方法形参类型的 Class 对象的一个数组。如果 parameterTypes null,则按空数组处理。

 

    public Method getMethod(String name, Class<?>... parameterTypes)

        throws NoSuchMethodException, SecurityException

    public Method getDeclaredMethod(String name, Class<?>... parameterTypes)

        throws NoSuchMethodException, SecurityException

 

c. 对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。个别参数被自动解包,以便与基本形参相匹配,基本参数和引用参数都随需服从方法调用转换。

如果底层方法是静态的,那么可以忽略指定的 obj 参数。该参数可以为 null

如果底层方法所需的形参数为 0,则所提供的 args 数组长度可以为 0 null

如果底层方法是实例方法,则使用动态方法查找来调用它,这一点记录在 Java Language Specification, Second Edition 的第 15.12.4.4 节中;在发生基于目标对象的运行时类型的重写时更应该这样做。

如果底层方法是静态的,并且尚未初始化声明此方法的类,则会将其初始化。

如果方法正常完成,则将该方法返回的值返回给调用者;如果该值为基本类型,则首先适当地将其包装在对象中。但是,如果该值的类型为一组基本类型,则数组元素不被包装在对象中;换句话说,将返回基本类型的数组。如果底层方法返回类型为 void,则该调用返回 null

注:Object obj 是包含有该字段的类实例

    public Object invoke(Object obj, Object... args)

    throws IllegalAccessException, IllegalArgumentException,

           InvocationTargetException

 

实例:

 

/**

 * Copyright (c) 2011 Trusted Software and Mobile Computing(TSMC)

 * All right reserved.

 *

 * Created on Aug 19, 2011 12:12:06 PM

 * http://jarg.iteye.com/

 * Author: Jarg Yee <yeshaoting@gmail.com>

 */

package com.iteye.jarg.test;

 

import java.lang.reflect.Constructor;

import java.lang.reflect.Field;

import java.lang.reflect.Method;

 

/**

 * TODO [学习]Java反射机制

 */

public class ReflectEx

{

    public static void main(String[] args) throws Exception

    {

       Class<?> clazz = Class.forName("com.iteye.jarg.test.ReflectBean");

      

       //无参构造函数参数数组可不写,可用new Class[]{},可用null

       Constructor<?> constructor = clazz.getConstructor();

      

       //无参构造函数参数数组可不写,可用new Object[]{},可用null

       Object obj = constructor.newInstance();  

       ReflectBean bean = (ReflectBean)obj;

       bean.display("1");

      

       constructor = clazz.getConstructor(String.class);

       obj = constructor.newInstance("字段 name 参数值");

       bean = (ReflectBean)obj;

       bean.display("2");

      

        //虽然getDeclaredField能查看字段相关信息,但是获取字段值还得遵循权限访问规则

       //若使用getField("name"),则会因为它只能访问公共成员而出错

       Field field = clazz.getDeclaredField("name");

      

       //获取实例相应字段值,而不是字段初始值

       System.out.println("3. name:\t" + field.get(bean));

      

       System.out.println("-------------------------------");

       Object obj2 = clazz.newInstance();

       Method method = clazz.getMethod("setName", String.class);

       method.invoke(obj2, "字段 name 全新值");

       bean = (ReflectBean)obj2;

       bean.display("4");

      

       obj2 = clazz.newInstance();

       method = clazz.getMethod("setValue", int[].class);

       method.invoke(obj2, new int[]{1,2,3,4});

       bean = (ReflectBean)obj2;

       System.out.println("5. value:\t" + bean.getValue()[2]);

      

      

    }

}

 

class ReflectBean

{

    int[] value = new int[4];

 

    String name = "字段 name 初始值";

   

    public ReflectBean(String name)

    {

       this.name = name;

       System.out.println("测试 \"\" 参构造函数");

    }

   

    public ReflectBean()

    {

       System.out.println("测试 \"\" 参构造函数");

    }

 

    public String getName()

    {

       return name;

    }

 

    public void setName(String name)

    {

       this.name = name;

    }

   

    public int[] getValue()

    {

       return value;

    }

 

    public void setValue(int[] value)

    {

       this.value = value;

    }

   

    public void display(String id)

    {

       System.out.println(id + ". name:\t" + name);

       System.out.println("-------------------------------");

    }

}

 

 

输出结果:

 

测试 "" 参构造函数

1. name:   字段 name 初始值

-------------------------------

测试 "" 参构造函数

2. name:   字段 name 参数值

-------------------------------

3. name:   字段 name 参数值

-------------------------------

测试 "" 参构造函数

4. name:   字段 name 全新值

-------------------------------

测试 "" 参构造函数

5. value:  3

 

 

0
4
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics