文档章节

Java 反射机制

 久眠深巷
发布于 2016/11/13 21:23
字数 1204
阅读 12
收藏 2

 Java反射是Java语言的一个很重要的特征,它使得Java具有了“动态性”。

   一般而言,开发者社群说到动态语言,大致认同的一个定义 是:“程序运行时,允许改变程序结构或者变量类型,这种语言称为动态语言”。从这个观点看,Perl,Python,Ruby是动态语言,C++,Java,C#不是动态语言。

   Reflection是java被视为动态(或准动态)语言的一个关键性质。

 

Java反射机制主要提供了一下功能:

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

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

   3、在运行时判断任意一个类所具有的成员变量和方法。

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

 

在JDK中,主要由一下类来实现Java反射机制,这些类都位于java.lang.reflect包中:

   1、Class类:代表一个类

   2、Field类:代表类的成员变量(成员变量也称为类的属性)

   3、Method类:代表类的方法

   4、Constructor类:代表类的构造方法。

   5、Array类:提供了动态创建数组,以及访问数组的元素的静态方法。

 

一、通过Class类获取成员变量、成员方法、接口,超类,构造方法等。

在java.lang.Object类中定义了getClass()方法,因此对于任意一个Java对象,都可以通过此方法获得对象的类型。Class类是ReflectionAPI中核心的类,它有以下方法

getName():获得类的完整名字

getFields():获得类的public类型的属性

getDeclaredFields():获得类的所有属性

getMethods():获得类的public类型的方法

getDeclaredMethods():获得类的所有方法

getMethod(String name,Class[] parameterTypes):获得类的特定方法,name参数指定方法的名字,parameterType参数指定方法的参数类型。

getConstructors():获得类的public类型的构造方法。

getConstructor(Class[] parameterTypes):获得类的特定构造方法,parameterType参数指定构造方法的参数类型

newInstance():通过类的不带参数的构造方法创建这个类的一个对象。

 

二、运行时复制对象

package reflection;
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());
        // 通过默认构造方法创建一个新的对象
        System.out.println("该类的构造方法有:"+classType.getConstructors()[0]);
        Object objectCopy = classType.getConstructor()
                .newInstance();
        // 获得对象的所有属性
        Field[] fields = classType.getDeclaredFields();
        for (int i = 0; i < fields.length; i++) {
            Field field = fields[i];
            String fieldName = field.getName();
            System.out.println("fieldName:"+fieldName);
            String firstLetter = fieldName.substring(0, 1).toUpperCase();
            // 获得和属性对应的getXXX()方法的名字
            String getMethodName = "get" + firstLetter + fieldName.substring(1);
            // 获得和属性对应的setXXX()方法的名字
            String setMethodName = "set" + firstLetter + fieldName.substring(1);
            // 获得和属性对应的getXXX()方法
            Method getMethod = classType.getMethod(getMethodName,
                    new Class[] {});
            // 获得和属性对应的setXXX()方法
            Method setMethod = classType.getMethod(setMethodName,
                    new Class[] { field.getType() });
            // 调用原对象的getXXX()方法
            Object value = getMethod.invoke(object);
            System.out.println(fieldName + ":" + value);
            // 调用拷贝对象的setXXX()方法
            setMethod.invoke(objectCopy, new Object[] { value });
        }
        return objectCopy;
    }
    public static void main(String[] a) throws Exception {
        Customer customer = new Customer("Tom", 21);
        customer.setId(new Long(1));
        Customer customerCopy = (Customer) new ReflectTester().copy(customer);
        System.out.println(customerCopy==customer);
        System.out.println(customerCopy.equals(customer));
        System.out.println("Copy information:" + customerCopy.getId() + ""
                + customerCopy.getName() + "" + customerCopy.getAge());
    }
}
class Customer {
    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 String getName() {
        return name;
    }
    public int getAge() {
        return age;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

解释:ReflectTester类的copy(object,object)方法依次执行以下步骤

(1)获得对象的类型

  Class classType=object.getClass();

  System.out.println("Class:"+classType.getName());

(2)通过默认构造方法创建一个新对象:

 Object objectCopy=classType.getConstructor().newInstance();

以上代码先调用Class类的getConstructor()方法获得一个Constructor对象,它代表默认的构造方法,然后调用Constructor对象的newInstance()方法构造一个实例。

(3)获得对象的所有属性:

    Field[] fields=classType.getDeclaredFields();

    Class类的getDeclaredFields()方法返回类的所有属性。

(4)获得每个属性对应的getXXX()和setXXX()然后执行这些方法,把原来的属性拷贝到新的对象中。

三、用反射机制调用对象的方法

package reflection;
import java.lang.reflect.InvocationTargetException;
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 InstantiationException, IllegalAccessException, SecurityException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException{
      Class<?> classType=InvokeTester.class;
      Object invokeTester =classType.newInstance();
      
      //获取InvokeTester类的add()方法
      Method addMethod=classType.getMethod("add", int.class,int.class);
      //调用invokeTester对象上的add()方法
      Object result=addMethod.invoke(invokeTester,100,200);
      System.out.println((Integer)result);
      
      //获取InvokeTester类的echo方法
      Method echoMethod=classType.getMethod("echo", java.lang.String.class);
      
    Object echoResult=echoMethod.invoke(invokeTester, "HelloWorld");
    System.out.println(echoResult);
      
  }
}

四、动态创建和访问数组

创建简单的一维数组

public class ArrayTester2 {
    /**
     * @param args
     */
    public static void main(String[] args) {
        
      //创建一个int类型的3维数组,维度分别是5,10,15
      Object array=Array.newInstance(int.class, 5,10,15);
      Object arrayObj=Array.get(array, 3);
      Class<?> cls=arrayObj.getClass().getComponentType();
      System.out.println(array.getClass().getComponentType());
      System.out.println(cls);
      
      arrayObj=Array.get(arrayObj, 5);
      Array.setInt(arrayObj, 10, 37);
      int[][][] arrarCast=(int[][][]) array;
      System.out.println(arrarCast[3][5][10]);
    }
}

 

© 著作权归作者所有

粉丝 0
博文 4
码字总数 2992
作品 0
武汉
程序员
私信 提问

暂无文章

如何使用 rsync 备份 Linux 系统的一些介绍

备份一直是 Linux 世界的热门话题。回到 2017,David Both 为 Opensource.com 的读者在使用 rsync 备份 Linux 系统方面提了一些建议,在这年的更早时候,他发起了一项问卷调查询问大家,在 ...

xiangyunyan
28分钟前
0
0
二进制位操作

单片机,或者一些模块的设置操作,都是由一个字节数据来完成,每位各有定义。就需进行位操作来组合需要的数字结果。 以JavaScript为例,编写位操作。 我们期望得到这样一个二进制数:0101101...

format
42分钟前
3
0
聊聊中国的通信行业:从“七国八制”到“中华”脊梁

本期文章和大家一起来聊一聊我曾经从事过的通信行业吧。最近各方面信息的泛滥,包括和华为的同学聊天,自己确实也感慨颇多。想想我自己本科主修通信工程,研究生再修信息与通信工程,从本科开...

CodeSheep
今天
7
0
MDK:ARM M451M:exceed the range of code meory, continue to erase or not?

问题: 代码空间超限 几天前就遇到:exceed the range of code meory, continue to erase or not? 如下所示: 解决过程 开始以为中MDK软件的128KB限制,如是就不能生成HEX文件,应该链接时有提...

SamXIAO
今天
1
1
OSChina 周六乱弹 —— 因违反《中华人民共和国治安管理处罚法》第四十四条之规定

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @xiaoshiyue :#今日歌曲推荐# 惊艳分享谷微的单曲《安守本份》(@网易云音乐) 《安守本份》- 谷微 手机党少年们想听歌,请使劲儿戳(这里) ...

小小编辑
今天
628
13

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部