再谈Java反射机制

news/2024/5/19 6:19:07 标签: 反射
一、基本概念

  在Java运行时环境中,对于任意一个类,能否知道这个类有哪些属性和方法?对于任意一个对象,能否调用它的任意一个方法?

  答案是肯定的。

  这种动态获取类的信息以及动态调用对象的方法的功能来自于Java语言的反射(Reflection)机制。

二、Java反射机制主要提供了以下功能

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

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

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

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

三、Class对象

  要想使用反射,首先需要获得待操作的类所对应的Class对象。

  Java中,无论生成某个类的多少个对象,这些对象都会对应于同一个Class对象。

  这个Class对象是由JVM生成的,通过它能够获悉整个类的结构。
  常用的获取Class对象的3种方式:

  1.使用Class类的静态方法。例如:

Class.forName("java.lang.String");

      2.使用类的.class语法。例如:

String.class;

      3.使用对象的getClass()方法。如:

String str = "aa";
Class<?> classType1 = str.getClass();

getClass()方法定义在Object类中,不是静态方法,需要通过对象来调用,并且它声明为final,表明不能被子类所覆写。
  直接print所获得的Class对象classType会输出:
    class 完整类名
  如果调用该Class对象的getName()方法,则输出完整类名,不加class。

四、 利用反射调用私有方法、访问私有属性

利用反射,首先是Class对象的获取,之后是Method和Field对象的获取。
  以Method为例,从文档中可以看到:
  getMethod()方法返回的是public的Method对象,
  而getDeclaredMethod()返回的Method对象可以是非public的。
  Field的方法同理。
  访问私有属性和方法,在使用前要通过AccessibleObject类(Constructor、 Field和Method类的基类)中的setAccessible()方法来抑制Java访问权限的检查。

1、调用私有方法

假设有这样一个类,其中包含私有方法。

public class PrivateClass
{
    private String sayHello(String name)
    {
        return "Hello: " + name;
    }

}

利用反射机制在外部访问该方法。

import java.lang.reflect.Method;

public class TestPrivate
{

    public static void main(String[] args) throws Exception
    {
        PrivateClass p = new PrivateClass();

        Class<?> classType = p.getClass();

        // 获取Method对象
        Method method = classType.getDeclaredMethod("sayHello",
                new Class[] { String.class });

        method.setAccessible(true); // 抑制Java的访问控制检查
        // 如果不加上上面这句,将会Error: TestPrivate can not access a member of class PrivateClass with modifiers "private"
        String str = (String) method.invoke(p, new Object[] { "zhangsan" });

        System.out.println(str);
    }
}

2、 访问私有属性

一个包含私有属性的类。

public class PrivateClass2
{
    private String name = "zhangsan";

    public String getName()
    {
        return name;
    }
}

利用反射修改其私有属性的值。

import java.lang.reflect.Field;

public class TestPrivate2
{
    public static void main(String[] args) throws Exception
    {
        PrivateClass2 p = new PrivateClass2();
        Class<?> classType = p.getClass();

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

        field.setAccessible(true); // 抑制Java对修饰符的检查
        field.set(p, "lisi");

        System.out.println(p.getName());
    }

}

五、利用反射进行对象拷贝

ReflectTester类有一个copy(Object object)方法,这个方法能够创建一个和参数object同样类型的对象,然后把object对象中的所有属性拷贝到新建的对象中,并将它返回。
  这个例子只能复制简单的类,假定类的每个属性都有public类型的getXXX()和setXXX()方法。

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

public class ReflectTester
{

    // 该方法实现对Customer对象的拷贝操作
    public Object copy(Object object) throws Exception
    {
        Class<?> classType = object.getClass();


        /* 生成新的对象的讨论
        // 获得Constructor对象,此处获取第一个无参数的构造方法的
        Constructor cons = classType.getConstructor(new Class[] {});//不带参数,所以传入一个为空的数组
        // 通过构造方法来生成一个对象
        Object obj = cons.newInstance(new Object[] {});

        // 以上两行代码等价于:
        Object obj11 = classType.newInstance();  // 这行代码无法处理构造函数有参数的情况
        
        //用第二个带参数的构造方法生成对象
        Constructor cons2 = classType.getConstructor(new Class[] {String.class, int.class});
        Object obj2 = cons2.newInstance(new Object[] {"ZhangSan",20});
        
        */
        
        Object objectCopy = classType.getConstructor(new Class[]{}).newInstance(new Object[]{});
        
        //获得对象的所有成员变量
        Field[] fields = classType.getDeclaredFields();
        for(Field field : fields)
        {
            //获取成员变量的名字
            String name = field.getName();    //获取成员变量的名字,此处为id,name,age
            //System.out.println(name);

            //获取get和set方法的名字
            String firstLetter = name.substring(0,1).toUpperCase();    //将属性的首字母转换为大写            
            String getMethodName = "get" + firstLetter + name.substring(1);
            String setMethodName = "set" + firstLetter + name.substring(1);            
            //System.out.println(getMethodName + "," + setMethodName);
            
            //获取方法对象
            Method getMethod = classType.getMethod(getMethodName, new Class[]{});
            Method setMethod = classType.getMethod(setMethodName, new Class[]{field.getType()});//注意set方法需要传入参数类型
            
            //调用get方法获取旧的对象的值
            Object value = getMethod.invoke(object, new Object[]{});
            //调用set方法将这个值复制到新的对象中去
            setMethod.invoke(objectCopy, new Object[]{value});

        }

        return objectCopy;

    }

    public static void main(String[] args) throws Exception
    {
        Customer customer = new Customer("Tom",20);
        customer.setId(1L);
        ReflectTester tester = new ReflectTester();
        
        Customer customer2 = (Customer)tester.copy(customer);
        
        System.out.println(customer2.getId() + "," + customer2.getName() + "," + customer2.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 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;
    }
}

步骤:
ReflectTester 类的copy(Object object)方法依次执行以下步骤
(1)获得对象的类型:
Class classType=object.getClass();
System.out.println("Class:"+classType.getName());
 
(2)通过默认构造方法创建一个新对象:
Object objectCopy=classType.getConstructor(new Class[]{}).newInstance(new Object[]{});
以上代码先调用Class类的getConstructor()方法获得一个Constructor 对象,它代表默认的构造方法,然后调用Constructor对象的newInstance()方法构造一个实例。
 
(3)获得对象的所有属性:
Field fields[]=classType.getDeclaredFields();
Class 类的getDeclaredFields()方法返回类的所有属性,包括public、protected、默认和private访问级别的属性。
 
(4)获得每个属性相应的getXXX()和setXXX()方法,然后执行这些方法,把原来对象的属性拷贝到新的对象中。



http://www.niftyadmin.cn/n/892352.html

相关文章

Myeclipse导入注释模板

具体步骤如下&#xff1a; 打开Window->Preferences->Java->Code Style->Code Templates codetemplates.xml内容如下&#xff1a; <?xml version"1.0" encoding"UTF-8" standalone"no"?><templates><template a…

Java IO流详尽解析

流的概念和作用 学习Java IO&#xff0c;不得不提到的就是JavaIO流。 流是一组有顺序的&#xff0c;有起点和终点的字节集合&#xff0c;是对数据传输的总称或抽象。即数据在两设备间的传输称为流&#xff0c;流的本质是数据传输&#xff0c;根据数据传输特性将流抽象为各种类…

Maven多模块 + Spring4.0.6 + SpringMVC4.0.6 + Mybatis 3.2.7 + log4j 2.1

参考: http://www.cnblogs.com/gwx238044/articles/6633252.html githud : https://github.com/2014team/Maven--Spring4.0.6-SpringMVC4.0.6-Mybatis-3.2.7-log4j-2.1

XSS防御-使用AntiSamy

AntiSamy是OWASP的一个开源项目&#xff0c;通过对用户输入的 HTML / CSS / JavaScript 等内容进行检验和清理&#xff0c;确保输入符合应用规范。AntiSamy被广泛应用于Web服务对存储型和反射型XSS的防御中。 1、maven依赖 AntiSamy直接导入到工程即可&#xff0c;但是其运行依…

Java 中正确使用 hashCode 和 equals 方法

hashCode() 的作用是获取哈希码&#xff0c;也称为散列码&#xff1b;它实际上是返回一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。 hashCode() 定义在JDK的Object.java中&#xff0c;这就意味着Java中的任何类都包含有hashCode() 函数。 虽然&#xff0c…

Google Guava Collections 使用介绍

Google Guava Collections 是一个对 Java Collections Framework 增强和扩展的一个开源项目。由于它高质量 API 的实现和对 JDK5 特性的充分利用&#xff0c;使得其在 Java 社区受到很高评价。笔者主要介绍它的基本用法和功能特性。 Google Guava Collections 使用介绍 Google…

JDK路径下目录的介绍

安装JDK1.7后路径下目录文件有哪些及功能介绍 要想编译和运行Java程序&#xff0c;离不开Java的编译和运行环境。Sun公司提供了自己的一套Java开发环境&#xff0c;通常称为JDK(Java Development Kit&#xff0c;Java开发工具集)。 JDK目录说明: bin目录包含一些用于开发Java…

Google Guava集合BiMap和Multimap

BiMap是一个有用的集合类型&#xff0c;很简单&#xff0c;它就是一个双向的映射。 反向转换一个Map 一个普通的map是一个key/value的集合&#xff0c;你可以使用key来查询 value&#xff0c;例如&#xff0c;我来创建一个字段&#xff1a; Map<String,String> bri…