java语言反射机制

在java运行时环境中,对任意一个类,能否知道这个类有哪些属性和方法?对于任意一个对象,能发调用它的任意一个方法?答案肯定是能的。这种动态获取类信息以及动态调用对象方法的功能来自java语言的反射(Reflection)机制。

java反射机制提供以下功能:

  1. 在运行时判断任意一个类所属的方法和属性。
  2. 在运行时调用任意一个对象中的任意一个方法。
  3. 在运行时构造任意一个类的对象。
  4. 在运行时判断任意一个对象所属的类。

在JDK中由以下类来实现java反射机制,这些类都为与:

  1. Class类:代表一个类。
  2. Field类:代表类的成员变量。
  3. Method类:代表类的方法。
  4. Constructor类:代表类的构造方法。
  5. Array类:提供了动态创建数组,以及访问数组的元素的静态方法。

下面是利用java反射机制API的一个简单示例:

import java.lang.reflect.Method;

public class DumpMethods
{
    //功能:打印指定类名的所有方法
    public static void main(String args[]) throws Exception
    {
        // 加载并初始化指定的类,获取与指定的类对应的Class类(Class是一个java类,是java反射机制的核心类)
        Class<?> classType = Class.forName("java.lang.String");
        // getDeclareMethods()是获得类的所有方法,getMethods()是获得所有public的方法
        Method methods[] = classType.getDeclaredMethods();
        for (int i = 0; i < methods.length; i++)
        {
            System.out.println(methods[i].toString());//打印方法名
        }
    }
}//看效果自己运行。。。。

下面的示例进一步演示了Reflection API的基本使用方法。ReflectTester类有一个copy(Object object)方法,这个方法能够创建一个和参数object 同样类型的对象,然后把object对象中的所有属性值拷贝到新建的对象中,并将它返回

这个例子只能复制简单的JavaBean,假定JavaBean 的每个属性都有public 类型的getXXX()和setXXX()方法。其实实现上述功能很简单,这里只是为了理解java反射机制API的应用所以复杂化了。

import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class ReflectTester
{
    public Object copy(Object object) throws Exception
    {
        // 获得对象的类型
        Class<?> classType = object.getClass();
        System.out.println("Class:" + classType.getName());//打印出Class类所表示完整的类或借口的名字(简单理解就是打印类名)

        // 通过默认构造方法创建一个新的对象
        Object objectCopy = classType.getConstructor(new Class[] {}).newInstance(new Object[] {});//以后内容会详细解释用法和作用

        // getDeclaredFields()获得对象的所有属性,getFields()获得所有public的属性
        Field fields[] = classType.getDeclaredFields();

        for (int i = 0; i < fields.length; i++)
        {
            Field field = fields[i];

            String fieldName = field.getName();//获得属性的名字
            String firstLetter = fieldName.substring(0, 1).toUpperCase();//属性的第一个字母转化成大写
            // 获得和属性对应的getXXX()方法的名字
            String getMethodName = "get" + firstLetter + fieldName.substring(1);
            // 获得和属性对应的setXXX()方法的名字
            String setMethodName = "set" + firstLetter + fieldName.substring(1);

            // 获得和属性对应的getXXX()方法,没有参数所以传递了Class类型的空数组
            Method getMethod = classType.getMethod(getMethodName, new Class[] {});
            // 获得和属性对应的setXXX()方法,field.getType():field代表属性,getType()返回属性的类型所对应的Class类(java在运行时每个类都有一个对应的Class类,来实现反射机制)
            Method setMethod = classType.getMethod(setMethodName, new Class[] { field.getType() });

            // 调用原对象的getXXX()方法,object代表你所要调用的那个方法所属的对象(调用一个方法理所应当知道要调用那个对象得),getMethod代表调用的方法
            Object value = getMethod.invoke(object, new Object[] {});//value调用方法所返回的值
            System.out.println(fieldName + ":" + value);
            // 调用拷贝对象的setXXX()方法
            setMethod.invoke(objectCopy, new Object[] { value });
        }
        return objectCopy;
    }

    public static void main(String[] args) throws Exception
    {
        Customer customer = new Customer("Tom", 21);
        customer.setId(new Long(1));

        Customer customerCopy = (Customer) new ReflectTester().copy(customer);
        System.out.println("Copy information:" + customerCopy.getId() + " " + customerCopy.getName() + " "
                + customerCopy.getAge());
    }
}

class Customer
{
//一个简单的javaBean
    private Long id;

    private String name;

    private int age;

    public Customer()
    {
    }

    public Customer(String name, int age)
    {
        this.name = name;
        this.age = age;
    }

    public Long getId()
    {
        return id;
    }

    public void setId(Long id)
    {
        this.id = id;
    }

    public String getName()
    {
        return name;
    }

    public void setName(String name)
    {
        this.name = name;
    }

    public int getAge()
    {
        return age;
    }

    public void setAge(int age)
    {
        this.age = age;
    }
}

下面详细介绍这个Class这个核心类常用的方法:

在java.lang.Object 类中定义了getClass()方法,因此对于任意一个Java对象,都可以通过此方法获得对象的类型。Class类是Reflection API 中的核心类,它是java反射机制的一个起源,你想对java的任何类勘探都要先获取

其对应的Class类才能进行相关的一系列操作,才能使用反射的数十个API。它有以下常用方法

getName():获得类的完整名字。
getFields():获得类的public类型的属性。
getDeclaredFields():获得类的所有属性。
getMethods():获得类的public类型的方法。
getDeclaredMethods():获得类的所有方法。
getMethod(String name, Class[] parameterTypes):获得类的特定方法,name参数指定方法的名字,parameterTypes 参数指定方法的参数类型。
getConstructors():获得类的public类型的构造方法。
getConstructor(Class[] parameterTypes):获得类的特定构造方法,parameterTypes 参数指定构造方法的参数类型。
newInstance():通过类的不带参数的构造方法创建这个类的一个对象。上述示例中的一段代码说明了getConstructors()和newInstance()的应用
Object objectCopy=classType.getConstructor(new Class[]{}).newInstance(new Object[]{});等价于Object objectCopy=classType.newInstance();,都是通过默认构造方法创建一个新对象。
以上代码先调用Class类的getConstructor()方法获得一个Constructor 对象,它代表默认的构造方法,然后调用Constructor对象的newInstance()方法构造一个实例。
在上述的例子我们是通过传递过来的object的默认的构造方法来复制一个同样的对象,如果我们通过有参数的构造方法来复制对象,应该怎么写?如下代码:
Class [] classArray = new Class[]{String.class,int.class};
Object [] objArray = new Object[]{"Tome",10};
//classArray数组下标0为String类型所对应的Class类(String.class),
//那么objInt对应位置的值的数据类型必须是String类型数值("Tome")
//这两个数组中的元素按照这样的规则意义对应
Object objectCopy = classType.getConstructor(classArray).newInstance(objArray);
下面的例子是用反射机制调用InvokeTester类的add()和echo()方法,说明了用Class类的getMethod()获得方法和利用invoke()调用方法时需要注意的地方。

package com.langsin.reflection;

import java.lang.reflect.Method;

public class InvokeTester
{
    public int add(int param1, int param2)
    {
        return param1 + param2;
    }

    public String echo(String msg)
    {
        return "echo: " + msg;
    }

    public static void main(String[] args) throws Exception
    {
        Class<?> classType = InvokeTester.class;
        Object invokeTester = classType.newInstance();

        // Object invokeTester = classType.getConstructor(new
        // Class[]{}).newInstance(new Object[]{});

       // 调用InvokeTester对象的add()方法
        Class classInt = new Class[] { int.class, int.class };//add()方法所接受参数类型对应的Class类型数组
        Method addMethod = classType.getMethod("add", classInt);
       //classInt1数组下标0为int类型所对应的Class类(int.class),
        //那么objInt对应位置的值的数据类型必须是int类型数值(new Integer(100))
        Object objInt = new Object[] { new Integer(100), new Integer(200) };//add()所接受的值
        Object result = addMethod.invoke(invokeTester,objInt});

        System.out.println((Integer) result);
       //-------------------------------------------
       // 调用InvokeTester对象的echo()方法
        Class classStr = new Class[] { String.class };
        Method echoMethod = classType.getMethod("echo",classStr);
       Object objStr = new Object[] { "Hello" }
       result = echoMethod.invoke(invokeTester,objStr);
       System.out.println((String) result);
    }
}

对以上示例的一段代码进行说明:

Method类的invoke(Object obj,Object args[])方法接收的参数必须为对象,invoke()方法的返回值总是对象,如果实际被调用的方法的返回类型是基本类型数据,那么invoke()方法会把它转换为相应的包装类型的对象,再将其返回。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值