JAVA反射机制

在运行状态中,对任意一个类(class文件),能够知道这个类的所有属性和方法,对任意一个对象都可以调用其属性和方法,这种动态获取信息以及调用对象的方法的功能称之为java反射机制。

好处:提高了程序扩展性;

类加载器如何工作的,参加文章:
http://blog.csdn.net/cdw8131197/article/details/67056507

准备类:

import java.util.Date;

public class UserTest {

    private String name;

    private int age;

    @Deprecated
    public Date time = new Date();

    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;
    }

    public Date getTime() {
        return time;
    }

    public void setTime(Date time) {
        this.time = time;
    }

    public UserTest(String name, int age, Date time) {
        super();
        this.name = name;
        this.age = age;
        this.time = time;
    }
    static{
        System.out.println("UserTest的静态代码块");
    }

    public UserTest() {
        super();
    }

}

一、获取类字节码的方式

**方式一:**Object类中的getClass方法获取字节码;
缺点:必须明确类,并且创建类的对象;

方式二:使用类中的静态属性.class获取类字节码;
缺点:必须明确类,不利于扩展;
注意,有一点很有趣,当使用“.class”来创建Class对象的引用时,不会自动地初始化该class对象。我们知道为使用类而做的三个步骤是:加载、链接、初始化,初始化主要做的工作为:执行类构造器<clinit>、static变量 、static{}语句被赋值等。所以当使用”.class”创建的对象的初始化被延迟到了对静态方法(构造器隐式地是静态的)或者非常数静态域首次引用时才执行。
常数静态域如:static final int staticFinal = 47;
非常数静态域如:static final int staticFinal = new Random(47);
方式三:使用Class类中的forName(类的全限定名称)方法;(推荐使用)

示例代码:

public class RefectMain {

    public static void main(String[] args) throws Exception {
        //方式一:Object类中的getClass方法获取字节码。
        //缺点:必须明确类,并且创建类的对象
//      UserTest ut = new UserTest();
//      Class clazz_1 = ut.getClass();
        System.out.println("--------1---------");
        //方式二:使用类中的静态属性.class获取类字节码
        //缺点:必须明确类,不利于扩展
        Class clazz_2 = UserTest.class;
        System.out.println("--------2---------");
        //方式三:使用Class类中的forName(类的全限定名称)方法
        Class clazz_3 = null;
        clazz_3 = Class.forName("com.cn.oneday.UserTest");
        System.out.println("--------3---------");
        System.out.println(clazz_2==clazz_3);
    }
}

执行结果:
——–1———
——–2———
UserTest的静态代码块
——–3———
true

从执行结果中可以看,当.class的时候没有执行UserTest中的静态代码块,当用class.forName的时候执行了静态代码块。之所以将方式一注释,是由于方式一在创建对象是就会加载类,初始化类,从而执行静态代码块,而我们知道,静态代码块只执行一次。这样就看不出.class会不会执行静态代码块。

二、利用反射机制创建对象

方式一:使用类的newInstance()方法
通过jdk api
Creates a new instance of the class represented by this 类 object. The class is instantiated as if by a new expression with an empty argument list. The class is initialized if it has not already been initialized.
可以看出:
newInstance()方法是使用了该类的无参构造函数,若是该类没有初始化则会进行初始化。即当使用”.class”方式获取的字节码,则在调用newInstance方法时,会进行初始化动作,即调用静态代码块;
示例代码:
Class clazz_2 = UserTest.class;
Object o2 = clazz_2.newInstance();
执行结果:
UserTest的静态代码块
UserTest的无参构造函数

若是类中无无参构造方法会怎样???运行程序报错如下:
Exception in thread “main” java.lang.InstantiationException: com.cn.oneday.UserTest
at java.lang.Class.newInstance(Class.java:427)
at com.cn.oneday.RefectMain.main(RefectMain.java:14)
Caused by: java.lang.NoSuchMethodException: com.cn.oneday.UserTest.()
at java.lang.Class.getConstructor0(Class.java:3082)
at java.lang.Class.newInstance(Class.java:412)
… 1 more

若是我们使用的类没有无参构造方法该怎么办???
查看jdkapi,发现以下方法:
这里写图片描述
getConstructor(类<?>... parameterTypes) —获取该类的执行参数构造器,入参是可变参数,传递的是class类;返回参数:Constructor<T>
getConstructors() 获取类的所有构造函数,返回类型是构造函数数组Constructor<?>[]
Constructor<T>中有方法newInstance(Object... initargs) 创建对象

示例代码:

import java.lang.reflect.Constructor;
import java.util.Date;

public class RefectMain {

    public static void main(String[] args) throws Exception {
        Class clazz_3 = Class.forName("com.cn.oneday.UserTest");
        Constructor<UserTest> c = clazz_3.getConstructor(String.class,int.class,Date.class);
        c.newInstance("小明",29,new Date(System.currentTimeMillis()));
    }
}

运行结果:
UserTest的静态代码块

三、利用反射机制操作field

1、操作普通的public修饰的field,使用方法:
getField(String name) 获取某个成员变量,返回值:java.lang.reflect
类 Field
getFields() 获取所有的成员变量 返回值:Field数组

示例代码:

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.Date;

public class RefectMain {

    public static void main(String[] args) throws Exception {
        Class clazz_3 = Class.forName("com.cn.oneday.UserTest");
        Constructor<UserTest> c = clazz_3.getConstructor(String.class,int.class,Date.class);
        UserTest ut = c.newInstance("小明",29,new Date(System.currentTimeMillis()));
        Field f = clazz_3.getField("time");
        System.out.println(f.get(ut));
    }
}

执行结果:
UserTest的静态代码块
Wed Mar 29 22:30:48 CST 2017

可以用得到的Field对象get或者set field的值

此方法访问私用变量是报错:
Exception in thread “main” java.lang.NoSuchFieldException: xxx
at java.lang.Class.getField(Class.java:1703)
at com.cn.oneday.RefectMain.main(RefectMain.java:13)

2、或是访问私用变量则使用方法:
getDeclaredField
getDeclaredFields()

得到的Field,直接进行get set时报错:
Exception in thread “main”
java.lang.IllegalAccessException:
Class com.cn.oneday.RefectMain can not access a member of class com.cn.oneday.UserTest with modifiers “private”

我们要对得到的field,进行权限处理,语句:
f.setAccessible(true);
表示可以对filed进行操作

示例代码:

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.Date;

public class RefectMain {

    public static void main(String[] args) throws Exception {
        Class clazz_3 = Class.forName("com.cn.oneday.UserTest");
        Constructor<UserTest> c = clazz_3.getConstructor(String.class,int.class,Date.class);
        UserTest ut = c.newInstance("小明",29,new Date(System.currentTimeMillis()));
        Field f = clazz_3.getDeclaredField("age");
        f.setAccessible(true);
        System.out.println(f.get(ut));
    }
}

执行结果:
UserTest的静态代码块
29

四、利用java反射机制操作method

同理有方法:

//获取指定名称和参数类型方法,无论方法是否为私有
getDeclaredMethod(String name, 类<?>... parameterTypes) 
//获取所有方法,无论方法是否为私有,包括其父类方法
getDeclaredMethods() 
//获取可以访问的指定名称和参数类型方法
getMethod(String name, 类<?>... parameterTypes)
//获取所有可以访问的方法,包括其父类方法
getMethods() 

调用方法使用:
invoke(Object obj, Object… args)

Object obj—-调用那个对象的方法,传递的是那个对象。即newInstance得到的
Object…args —–可变参数,即方法需要的参数具体指。

调用私有方法之前需要设置权限:setAccessible(true);

更多方法参加JDK API

工作中使用案例–拷贝对象,用了反射和json转化方式:

import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.FatalBeanException;

import com.alibaba.dubbo.common.utils.Assert;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

/**
    * 
    * @ClassName: BeanCopy
    * @Description: 实体类间相互转化工具
    * @author admin
    * @date Oct 11, 2016
    *
 */
public class BeanCopy extends BeanUtils{

    /**
    * 
    * @Title: bean2AppBean
    * @Description: 普通Bean对象转化为AppBean对象--效率不如反射高
    * @param sourceObject
    * @param targetClazz
    * @return
    * @throws InstantiationException
    * @throws IllegalAccessException    参数
    * @return E    返回类型
    * @throws
     */
    public static <E> E copyBeanByJson(Object sourceObject,Class<E> targetClazz) throws InstantiationException, IllegalAccessException{
        E appBean = targetClazz.newInstance();
        appBean = JSONObject.parseObject(JSON.toJSONString(sourceObject),targetClazz);
        return appBean;
    }

    /**
        * 
        * @Title: beans2ListAppBean
        * @Description: beans转化为AppBean列表--效率不如反射高
        * @param sourceObject
        * @param targetClazz
        * @return
        * @throws InstantiationException
        * @throws IllegalAccessException    参数
        * @return List<E>    返回类型
        * @throws
     */
    @SuppressWarnings("unchecked")
    public static <E> List<E> copyListByJson(Object sourceObject,Class<E> targetClazz) throws InstantiationException, IllegalAccessException{
        if(null==sourceObject || !(sourceObject instanceof ArrayList<?>)){
            return null;
        }
        List<?> sourceList = null;
        if (sourceObject instanceof ArrayList<?>){
            sourceList = (ArrayList<?>)sourceObject;
        }
        List<E> result = new ArrayList<E>();
        result = JSONObject.parseObject(JSON.toJSONString(sourceList),result.getClass());
        return result;
    }

    /**
    * 
    * @Title: beans2ListAppBean
    * @Description: beans转化为AppBean列表--效率不如反射高
    * @param sourceObject
    * @param targetClazz
    * @return
    * @throws InstantiationException
    * @throws IllegalAccessException    参数
    * @return List<E>    返回类型
    * @throws
    */
    public static <E> List<E> copyListOneByOneByJson(Object sourceObject,Class<E> targetClazz) throws InstantiationException, IllegalAccessException{
        if(null==sourceObject || !(sourceObject instanceof ArrayList<?>)){
            return null;
        }
        List<E> result = new ArrayList<E>();
        List<?> sourceList = null;
        if (sourceObject instanceof ArrayList<?>){
            sourceList = (ArrayList<?>)sourceObject;
        }
        for(int i = 0;null!=sourceList && i < sourceList.size(); i++){
            E appBean = targetClazz.newInstance();  
             JSONObject.parseObject(JSON.toJSONString(sourceList.get(i)),targetClazz);
            result.add(appBean);
        }
        return result;
    }

    /**
        * 
        * 
        * @Title: copyBeanByReflection
        * @Description: 通过Java反射方式copy实例
        * @param sourceObject
        * @param targetClazz
        * @return
        * @throws InstantiationException
        * @throws IllegalAccessException    参数
        * @return E    返回类型
        * @throws Exception 
     */
    public static <E> E copyBeanByReflection(Object sourceObject,Class<E> targetClazz) throws Exception{
        E appBean = targetClazz.newInstance();
        appBean = replaceProperties(sourceObject,appBean);
        return appBean;
    }

    /**
        * 
        * @Title: copyListOneByReflection
        * @Description: java反射方式copy列表
        * @param sourceObject
        * @param targetClazz
        * @return
        * @throws InstantiationException
        * @throws IllegalAccessException    参数
        * @return List<E>    返回类型
        * @throws Exception
     */
    public static <E> List<E> copyListOneByReflection(Object sourceObject,Class<E> targetClazz) throws Exception{
        if(null==sourceObject || !(sourceObject instanceof ArrayList<?>)){
            return null;
        }
        List<E> result = new ArrayList<E>();
        List<?> sourceList = null;
        if (sourceObject instanceof ArrayList<?>){
            sourceList = (ArrayList<?>)sourceObject;
        }
        for(int i = 0;null!=sourceList && i < sourceList.size(); i++){
            E appBean = targetClazz.newInstance();  
            appBean = replaceProperties(sourceList.get(i),appBean);
            result.add(appBean);
        }
        return result;
    }

    /**
        * 
        * @Title: replaceProperties
        * @Description: 描述:将源非默认值的数据复制到目标相应数据中
        * @param source
        * @param target    参数
        * @return void    返回类型
        * @throws
     */
    @SuppressWarnings({"rawtypes"})
    private static <E> E replaceProperties(Object source, E target) throws Exception{ 
        if(null==source || null==target){
            return null;
        }
        Class actualEditable = target.getClass();
        // 获取copy的属性
        PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);
        for(int i = 0; i < targetPds.length; i++){
            PropertyDescriptor targetPd = targetPds[i];
            if(targetPd.getWriteMethod() != null){
                PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());// 从类中获取属性
                if(sourcePd != null && sourcePd.getReadMethod() != null){
                    try{
                        Method readMethod = sourcePd.getReadMethod();
                        Class sourceClass = sourcePd.getPropertyType();
                        if(!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())){
                            readMethod.setAccessible(true);
                        }
                        Object value = readMethod.invoke(source, new Object[0]);
                        if(null != value && !(sourceClass.equals(int.class) && (int) value == 0)){
                            Method writeMethod = targetPd.getWriteMethod();
                            if(!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())){
                                writeMethod.setAccessible(true);
                            }
                            writeMethod.invoke(target, new Object[] {value});
                        }
                    }catch (Exception ex){
                        throw new FatalBeanException("Could not copy properties from source to target", ex);
                    }
                }
            }
        }
        return target;
    }

    /**
        * 
        * @Title: copyPropertiesAccept
        * @Description: 描述:copy目标中允许的字段
        * @param source
        * @param target
        * @param acceptStrs    参数
        * @return void    返回类型
        * @throws
     */
    @SuppressWarnings("rawtypes")
    public static void copyPropertiesAccept(Object source, Object target, String[] acceptStrs) throws Exception{
        Assert.notNull(source, "copyPropertiesAccept source must not be null");
        Assert.notNull(target, "copyPropertiesAccept target must not be null");
        Class actualEditable = target.getClass();
        // 获取copy的属性
        PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);
        List acceptList = (acceptStrs != null) ? Arrays.asList(acceptStrs) : null;
        for(int i = 0; i < targetPds.length; i++){
            PropertyDescriptor targetPd = targetPds[i];
            if(targetPd.getWriteMethod() != null){
                PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());// 从类中获取属性
                if(sourcePd != null && sourcePd.getReadMethod() != null && acceptList.contains(targetPd.getName())){
                    try{
                        Method readMethod = sourcePd.getReadMethod();
                        if(!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())){
                            readMethod.setAccessible(true);
                        }
                        Object value = readMethod.invoke(source, new Object[0]);
                        Method writeMethod = targetPd.getWriteMethod();
                        if(!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())){
                            writeMethod.setAccessible(true);
                        }
                        writeMethod.invoke(target, new Object[] {value});
                    }catch (Exception ex){
                        throw new FatalBeanException("Could not copy properties from source to target", ex);
                    }
                }
            }
        }
    }

    /**
        * 
        * @Title: getProperties
        * @Description: 递归的方法获取属性值
        * @param source
        * @param propertiesName
        * @return    参数
        * @return Object    返回类型
        * @throws InvocationTargetException 
        * @throws IllegalArgumentException 
        * @throws IllegalAccessException 
     */
    public static Object getProperties(Object source, String propertiesName) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException{
        Assert.notNull(source, "getProperties source must not be null");
        Object value = null;
        if (propertiesName.contains(".")){
            String frontProperName = propertiesName.substring(0,propertiesName.indexOf("."));
            String backProperName  = propertiesName.substring(propertiesName.indexOf(".")+1);
            value = getProperties(getProperties(source, frontProperName), backProperName);
        }else {
            PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), propertiesName);
            if (sourcePd != null && sourcePd.getReadMethod() != null){
                Method readMethod = sourcePd.getReadMethod();
                if(!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())){
                    readMethod.setAccessible(true);
                }
                value = readMethod.invoke(source, new Object[0]);
            }
        }
        return value;
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值