Java reflection calls the get/set method, are you still splicing the method name?

foreword

In the latest work, I encountered a place where the get/set method is called through reflection. Although the performance of reflection is not very good, compared with hard-coded ones that are not easy to expand, getDeclareFields can get all member variables. When adding or deleting member variables later , there is no need to modify the code, and the number of applications is only used when modifying the data, so some performance is sacrificed to improve scalability

traditional way

I have seen many people call the get/set method through reflection by getting the name of the attribute, and then capitalizing the first letter through string interception, and then spelling get/set to do it

String fieldName = field.getName();
String getMethodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);

There are also slightly better students who convert the fieldName into a character array, the first character -32 to avoid string interception

String fieldName = field.getName();
char[] chars = fieldName.toCharArray();
chars[0] = (char)(chars[0] - 32);
String getMethodName = "get" + new String(chars);

Admittedly, I think both ways are possible, but I don’t know if I have encountered it. The generated get/set method does not start with get/set, but starts with is, such as a boolean member variable. At this time, we need to judge the type of the attribute, and then use different prefixes to splice the get/set method name. In fact, such a tool class is already included in jdk

Introspector和PropertyDescriptor

I will not talk about the detailed introduction of these two classes here. The simple understanding is the description of object information, which provides some APIs to facilitate us to obtain object information

BeanInfo beanInfo;
try {
    beanInfo = Introspector.getBeanInfo(template.getClass());
} catch (IntrospectionException e) {
    log.info("xxxxxxxxxxxxxxxx", e);
    return null;
}

List<PropertyDescriptor> descriptors = Arrays.stream(beanInfo.getPropertyDescriptors()).filter(p -> {
    String name = p.getName();
    //过滤掉不需要修改的属性
    return !"class".equals(name) && !"id".equals(name);
}).collect(Collectors.toList());

for (PropertyDescriptor descriptor : descriptors) {
    //descriptor.getWriteMethod()方法对应set方法
    Method readMethod = descriptor.getReadMethod();
    System.out.println(descriptor.getName());
    try {
        Object o = readMethod.invoke(template);
        System.out.println(o);
    } catch (IllegalAccessException | InvocationTargetException e) {
        log.info("xxxxxxxxxxxxxxxx", e);
        return null;
    }
}

The PropertyDescriptor class provides getReadMethod and getWriteMethod, which are actually for the get/set method. As for the method name, we don’t need to talk about it, so that we can avoid the misspelling of the method name. In addition, PropertyDescriptor can be obtained through Introspector, or it can be created by itself with new. Its construction method is relatively complete. Usually, it is f47c08cf6f95d65769aa98b29d6ba09f.pngenough to pass a property name and class object class.

List<Field> fields = Arrays.stream(template.getClass().getDeclaredFields()).filter(f -> {
    String name = f.getName();
    //过滤掉不需要修改的属性
    return !"id".equals(name) && !"serialVersionUID".equals(name);
}).collect(Collectors.toList());

for (Field field : fields) {
    try {
        PropertyDescriptor descriptor = new PropertyDescriptor(field.getName(), template.getClass());
        Method readMethod = descriptor.getReadMethod();
        Object o = readMethod.invoke(template);
        System.out.println(o);
    } catch (IntrospectionException | IllegalAccessException | InvocationTargetException e) {
        e.printStackTrace();
    }
}

Through the above two different implementation methods, we can see that Introspector will have an additional class attribute, but similar serialVersionUID will not be counted; while custom PropertyDescriptor needs to get all attributes through reflection, although there will be no class attribute, but serialVersionUID will be counted, you need to pay attention when using it. If you thought this was all Introspector could do, you'd be wrong. Introspector is different from ordinary reflection. Reflection once can be reused for a period of time. Why not permanent? Look at the source code

/**
     * Introspect on a Java Bean and learn about all its properties, exposed
     * methods, and events.
     * <p>
     * If the BeanInfo class for a Java Bean has been previously Introspected
     * then the BeanInfo class is retrieved from the BeanInfo cache.
     *
     * @param beanClass  The bean class to be analyzed.
     * @return  A BeanInfo object describing the target bean.
     * @exception IntrospectionException if an exception occurs during
     *              introspection.
     * @see #flushCaches
     * @see #flushFromCaches
     */
    public static BeanInfo getBeanInfo(Class<?> beanClass)
        throws IntrospectionException
    {
        if (!ReflectUtil.isPackageAccessible(beanClass)) {
            return (new Introspector(beanClass, null, USE_ALL_BEANINFO)).getBeanInfo();
        }
        ThreadGroupContext context = ThreadGroupContext.getContext();
        BeanInfo beanInfo;
        synchronized (declaredMethodCache) {
            beanInfo = context.getBeanInfo(beanClass);
        }
        if (beanInfo == null) {
            beanInfo = new Introspector(beanClass, null, USE_ALL_BEANINFO).getBeanInfo();
            synchronized (declaredMethodCache) {
                context.putBeanInfo(beanClass, beanInfo);
            }
        }
        return beanInfo;
    }

Pay attention to the bold and red code in the middle. In addition to synchronization, a local cache is also made here

BeanInfo getBeanInfo(Class<?> type) {
    return (this.beanInfoCache != null)
            ? this.beanInfoCache.get(type)
            : null;
}

This beanInfoCache is actually a WeakHashMap, every time gc is recycled, so the above said that it can be reused for a period of time instead of forever, it is also to avoid OOM

 Summarize

Let’s talk so much first, although it is not an advanced technology, but being able to solve small problems encountered in work is also growth!

078a83bc7e197149c98671eb041c28a8.jpeg

Guess you like

Origin blog.csdn.net/dot_life/article/details/128397651