抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

感谢这篇博客:https://blog.csdn.net/ju_362204801/article/details/90578678,让我对反射有了新的理解。

写在前面

什么是反射?反射就是就是把Java类中的各个部分(成员变量,方法,构造方法,等),映射成一个个的Java对象,可以进行任意调用。打个贴合文章标题的比方,new一个对象,这个对象就是一个美女,她告诉你她今天传了一件性感内衣,然后啥都没告诉你,这时候你灵光一现使用反射即可了解她穿这件内衣始末!下面会通过代码解释!

了解美女对象穿内衣始末

创建实体类

/**
 * 创建一个美女对象类
 */
public class Beauty {

    /**
     * 对象名字
     */
    public String name;
 
    /**
     * 对象穿内衣原因
     */
    private String reason;
 
    /**
     * 内衣大小
     */
    private double size;
 
    public Beauty() {
        System.err.println("无参构造:穿内衣");
    }
 
    public Beauty(String name, String reason, double size) {
        this.name = name;
        this.reason = reason;
        this.size = size;
    }
 
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name=name;
    }
 
    public String getReason() {
        return reason;
    }
 
    public void setReason(String reason) {
        this.reason = reason;
    }
 
    public double getSize() {
        return size;
    }
 
    public void setSize(double size) {
        this.size = size;
    }
}

1.无参构造:

public class Test {
 
    public static void main(String[] args) throws Exception {
        //传统创建一个对象
        Beauty customer = new Beauty();
 
        //利用反射创建一个对象
        Class clazz = Class.forName(customer.getClass().getName());
        //调用无参构造
        clazz.getConstructor(null).newInstance(null);
 
    }
}

从写法上来,好像下边的要麻烦一些。运行结果:
https://img-blog.csdnimg.cn/20200806165547655.png

2.有参构造:

//调用Customer的有参构造
Beauty customer1 = new Beauty("佟丽娅","穿内衣给我老公看",36d);
System.out.println(customer1.getName());

//利用反射调用有参构造
customer = (Beauty)clazz.getConstructor(String.class,String.class,double.class).newInstance("高圆圆","穿内衣给我老公看",36d);
System.out.println("谁在传内衣给他对象看:"+customer.getName());

都是穿内衣给他老公看。还是反射麻烦些。

https://img-blog.csdnimg.cn/20200806170349518.png

3.获取属性值:

为了更好的区分,此时需要在美女类加一个私有属性。

public String love1 = "陈思诚";
private String love2 = "赵又廷";
//传统获取属性值,获取不到2
System.out.println("让我看看她们在想谁");
System.err.println(customer1.love1);

//暴力获取私有属性
Field love2 = clazz.getDeclaredField("love2");
love2.setAccessible(true);
System.err.println(""+love2.get(customer));

利用反射暴力获取值,发现他俩想的都不是你!!!

https://img-blog.csdnimg.cn/20200806173924828.png

4.给属性赋值

让俩美女都想你!

//赋值
customer1.love1="我自己";
System.err.println(customer1.love1); 

Field f = clazz.getDeclaredField("love2");
f.setAccessible(true);
f.set(customer,"我自己");
System.err.println(""+f.get(customer));

https://img-blog.csdnimg.cn/20200806174448138.png
开心吗?都是你了!

### 5.调用方法
 //调用get,set方法
customer.setName("佟丽娅");
System.err.println(customer.getName());

//反射调用set方法
Method clazzMethod = clazz.getMethod("setName", String.class);
clazzMethod.invoke(customer,"高圆圆");
//反射调用get方法
Method m = clazz.getMethod("getName", null);
String returnValue = (String)m.invoke(customer, null);
System.err.println(returnValue);

此处情况众多,请参考文章https://img-blog.csdnimg.cn/20200806174448138.png,按需分析情况。

为了更好的贴合主题,举例一种!

6.贴合主题的例子

在美女对象中加入

    private void getStr(String[] name,int password){
        for (int i=0 ;i<name.length;i++){
            if (password==123456) {
                System.err.println(name[i] + ":其实我真正爱的是隔壁老王");
            }else{
                System.err.println("密码输入错误,你看不到我心里的想法");
            }
        }
    }

私有方法,传统方式没法子调用。

Method m = clazz.getDeclaredMethod("getStr", String[].class,int.class);
m.setAccessible(true);
m.invoke(customer, (Object)new String[]{"佟丽娅","高圆圆"},123456);

看到这里你可能已经流泪了!那么接下来就是更流泪的事。

//获得对象的所有属性
    Field fields[]=clazz.getDeclaredFields();
    for (int i=0; i<fields.length;i++){
        Field field=fields[i];
        String fieldName=field.getName();
        System.out.println("具体属性参数:"+fieldName);
    }
    //获得对象的所有方法
    Method[] declaredMethods = clazz.getDeclaredMethods();
    for (int i=0; i<declaredMethods.length;i++){
        Method methods = declaredMethods[i];
        String methodName=methods.getName();
        System.out.println("所有方法名称:"+methodName);
    }

这就好比你的女朋友心里想的不仅不是你,而且她穿的什么颜色的内衣已经他们嘿嘿嘿的方式,都应经被你知道了,你现在是不是觉得头上有点奇怪的东西!

映射封装工具类分享

网上找的,这个算是很全了!

/**
 * 反射工具类.
 * 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数.
 * @author aqian666
 * @version
 */
public class ReflectUtils {
    private static final String SETTER_PREFIX = "set";
    private static final String GETTER_PREFIX = "get";
    private static final String CGLIB_CLASS_SEPARATOR = "$$";
    private static Logger logger = LoggerFactory.getLogger(ReflectUtils.class);
/** * 调用Getter方法. * 支持多级,如:对象名.对象名.方法 */ public static Object invokeGetter(Object obj, String propertyName) { Object object = obj; for (String name : StringUtils.split(propertyName, ".")){ String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(name); object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {}); } return object; }
/** * 调用Setter方法, 仅匹配方法名。 * 支持多级,如:对象名.对象名.方法 */ public static void invokeSetter(Object obj, String propertyName, Object value) { Object object = obj; String[] names = StringUtils.split(propertyName, "."); for (int i=0; i<names.length; i++){ if(i<names.length-1){ String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(names[i]); object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {}); }else{ String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(names[i]); invokeMethodByName(object, setterMethodName, new Object[] { value }); } } }
/** * 直接读取对象属性值, 无视private/protected修饰符, 不经过getter函数. */ public static Object getFieldValue(final Object obj, final String fieldName) { Field field = getAccessibleField(obj, fieldName); if (field == null) { throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + obj + "]"); } Object result = null; try { result = field.get(obj); } catch (IllegalAccessException e) { logger.error("不可能抛出的异常{}", e.getMessage()); } return result; }
/** * 直接设置对象属性值, 无视private/protected修饰符, 不经过setter函数. */ public static void setFieldValue(final Object obj, final String fieldName, final Object value) { Field field = getAccessibleField(obj, fieldName); if (field == null) { throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + obj + "]"); } try { field.set(obj, value); } catch (IllegalAccessException e) { logger.error("不可能抛出的异常:{}", e.getMessage()); } }
/** * 直接调用对象方法, 无视private/protected修饰符. * 用于一次性调用的情况,否则应使用getAccessibleMethod()函数获得Method后反复调用. * 同时匹配方法名+参数类型, */ public static Object invokeMethod(final Object obj, final String methodName, final Class<?>[] parameterTypes, final Object[] args) { Method method = getAccessibleMethod(obj, methodName, parameterTypes); if (method == null) { throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + obj + "]"); } try { return method.invoke(obj, args); } catch (Exception e) { throw convertReflectionExceptionToUnchecked(e); } }
/** * 直接调用对象方法, 无视private/protected修饰符, * 用于一次性调用的情况,否则应使用getAccessibleMethodByName()函数获得Method后反复调用. * 只匹配函数名,如果有多个同名函数调用第一个。 */ public static Object invokeMethodByName(final Object obj, final String methodName, final Object[] args) { Method method = getAccessibleMethodByName(obj, methodName); if (method == null) { throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + obj + "]"); } try { return method.invoke(obj, args); } catch (Exception e) { throw convertReflectionExceptionToUnchecked(e); } }
/** * 循环向上转型, 获取对象的DeclaredField, 并强制设置为可访问. * * 如向上转型到Object仍无法找到, 返回null. */ public static Field getAccessibleField(final Object obj, final String fieldName) { Validate.notNull(obj, "object can't be null"); Validate.notBlank(fieldName, "fieldName can't be blank"); for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) { try { Field field = superClass.getDeclaredField(fieldName); makeAccessible(field); return field; } catch (NoSuchFieldException e) {//NOSONAR // Field不在当前类定义,继续向上转型 continue;// new add } } return null; }
/** * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问. * 如向上转型到Object仍无法找到, 返回null. * 匹配函数名+参数类型。 * * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args) */ public static Method getAccessibleMethod(final Object obj, final String methodName, final Class<?>... parameterTypes) { Validate.notNull(obj, "object can't be null"); Validate.notBlank(methodName, "methodName can't be blank"); for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) { try { Method method = searchType.getDeclaredMethod(methodName, parameterTypes); makeAccessible(method); return method; } catch (NoSuchMethodException e) { // Method不在当前类定义,继续向上转型 continue;// new add } } return null; }
/** * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问. * 如向上转型到Object仍无法找到, 返回null. * 只匹配函数名。 * * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args) */ public static Method getAccessibleMethodByName(final Object obj, final String methodName) { Validate.notNull(obj, "object can't be null"); Validate.notBlank(methodName, "methodName can't be blank"); for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) { Method[] methods = searchType.getDeclaredMethods(); for (Method method : methods) { if (method.getName().equals(methodName)) { makeAccessible(method); return method; } } } return null; }
/** * 改变private/protected的方法为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。 */ public static void makeAccessible(Method method) { if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers())) && !method.isAccessible()) { method.setAccessible(true); } }
/** * 改变private/protected的成员变量为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。 */ public static void makeAccessible(Field field) { if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers()) || Modifier .isFinal(field.getModifiers())) && !field.isAccessible()) { field.setAccessible(true); } }
/** * 通过反射, 获得Class定义中声明的泛型参数的类型, 注意泛型必须定义在父类处 * 如无法找到, 返回Object.class. * eg. * public UserDao extends HibernateDao<User> * * @param clazz The class to introspect * @return the first generic declaration, or Object.class if cannot be determined */ @SuppressWarnings("unchecked") public static <T> Class<T> getClassGenricType(final Class clazz) { return getClassGenricType(clazz, 0); }
/** * 通过反射, 获得Class定义中声明的父类的泛型参数的类型. * 如无法找到, 返回Object.class. * * 如public UserDao extends HibernateDao<User,Long> * * @param clazz clazz The class to introspect * @param index the Index of the generic ddeclaration,start from 0. * @return the index generic declaration, or Object.class if cannot be determined */ public static Class getClassGenricType(final Class clazz, final int index) { Type genType = clazz.getGenericSuperclass(); if (!(genType instanceof ParameterizedType)) { logger.warn(clazz.getSimpleName() + "'s superclass not ParameterizedType"); return Object.class; } Type[] params = ((ParameterizedType) genType).getActualTypeArguments(); if (index >= params.length || index < 0) { logger.warn("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: " + params.length); return Object.class; } if (!(params[index] instanceof Class)) { logger.warn(clazz.getSimpleName() + " not set the actual class on superclass generic parameter"); return Object.class; } return (Class) params[index]; }
public static Class<?> getUserClass(Object instance) { Validate.notNull(instance, "Instance must not be null"); Class clazz = instance.getClass(); if (clazz != null && clazz.getName().contains(CGLIB_CLASS_SEPARATOR)) { Class<?> superClass = clazz.getSuperclass(); if (superClass != null && !Object.class.equals(superClass)) { return superClass; } } return clazz; }
/** * 将反射时的checked exception转换为unchecked exception. */ public static RuntimeException convertReflectionExceptionToUnchecked(Exception e) { if (e instanceof IllegalAccessException || e instanceof IllegalArgumentException || e instanceof NoSuchMethodException) { return new IllegalArgumentException(e); } else if (e instanceof InvocationTargetException) { return new RuntimeException(((InvocationTargetException) e).getTargetException()); } else if (e instanceof RuntimeException) { return (RuntimeException) e; } return new RuntimeException("Unexpected Checked Exception.", e); }
/** * 判断属性是否为日期类型 * * @param clazz * 数据类型 * @param fieldName * 属性名 * @return 如果为日期类型返回true,否则返回false */ public static <T> boolean isDateType(Class<T> clazz, String fieldName) { boolean flag = false; try { Field field = clazz.getDeclaredField(fieldName); Object typeObj = field.getType().newInstance(); flag = typeObj instanceof Date; } catch (Exception e) { // 把异常吞掉直接返回false } return flag; }
/** * 根据类型将指定参数转换成对应的类型 * * @param value * 指定参数 * @param type * 指定类型 * @return 返回类型转换后的对象 */ public static <T> Object parseValueWithType(String value, Class<?> type) { Object result = null; try { // 根据属性的类型将内容转换成对应的类型 if (Boolean.TYPE == type) { result = Boolean.parseBoolean(value); } else if (Byte.TYPE == type) { result = Byte.parseByte(value); } else if (Short.TYPE == type) { result = Short.parseShort(value); } else if (Integer.TYPE == type) { result = Integer.parseInt(value); } else if (Long.TYPE == type) { result = Long.parseLong(value); } else if (Float.TYPE == type) { result = Float.parseFloat(value); } else if (Double.TYPE == type) { result = Double.parseDouble(value); } else { result = (Object) value; } } catch (Exception e) { // 把异常吞掉直接返回null } return result; } }

评论