java - 关于泛型和反射的代码错误(cannot select from a type variable)
迷茫
迷茫 2017-04-18 10:51:04
0
3
1169

问题1:
想写个requestInfo的toString方法,把所有的成员变量都打印出来,子类就不用每次都写个toString方法了,但是父类怎么获取子类成员变量的值?

public class RequestInfo
{
    public String toString()
    {
        StringBuilder sb = new StringBuilder();
        Field[] fields = this.getClass().getDeclaredFields();
        for(Field field : fields)
        {
            sb.append(field.getName(), " = ", (这里怎么获取属性值?), ";");
        }
        return "";
    }
}

问题2
下面那个类P怎么实例化,也没懂错误的原因,用P.getClass()还是不行

public abstract class AbstractService<Q extends RequestInfo, P extends ResponseInfo>
{
    public static final Logger LOGGER = LoggerFactory.getLogger(AbstractService.class);

    private String logTag;

    private P respBean;

    public P execute(Q reqBean)
    {
        init();
        LOGGER.info(StringUtil.appendStr("Request : {}, req = {}", logTag, reqBean.toString()));

        try
        {
            if (checkInput(reqBean))
            {
                handle(reqBean, respBean);
            }
            else
            {
                throw new Exception(StringUtil.appendStr(logTag, " check input param invalid"));
            }
        }
        catch (Exception e)
        {
            LOGGER.error(StringUtil.appendStr(logTag, " Exception: "), e);
        }
        return respBean;
    }

    protected void init()
    {
        logTag = getClass().getSimpleName();
        respBean =P.class.newInsance();//这里报错,cannot select from a type variable
    }

    protected boolean checkInput(Q reqBean)
    {
        return true;
    }

    protected abstract void handle(Q reqBean, P respBean)
            throws Exception;
}
迷茫
迷茫

业精于勤,荒于嬉;行成于思,毁于随。

reply all(3)
PHPzhong

Generics have been erased after compilation. The jvm cannot see the generic information at all. This is due to historical reasons, so the p.getClass you mentioned cannot exist

The first question is a good idea, but as far as I know it cannot be implemented. The object cannot know the status of the subclass. Java's polymorphic mechanism can only query methods from the parent class or parent interface.

I guess the first question you think you can get the member variables of a subclass is that once the toString method of the subclass is executed after inheritance, your own this will also be called, which is wrong. At run time, the jvm will obtain this method from the object space of the parent class and execute it. So, no matter what, they are just member variables of the parent class

I made a mistake in the above italicized part. After running the IDE to test it, I found that I was wrong about what I understood before. I hope it didn’t cause trouble to the questioner.
The code posted below can loop to obtain all variables from the subclass to the parent class. Hope it helps

public String toString() {
        StringBuilder sb = new StringBuilder();
        Class clazz = this.getClass();
        while(clazz.getSuperclass() != null){
            Field[] fields = clazz.getDeclaredFields();
            try {
                for (Field field : fields) {
                    field.setAccessible(true);
                    sb.append(field.getName()).append("=").append(field.get(this))
                        .append("\n");
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            clazz = clazz.getSuperclass();
        }
        
        return sb.toString();
    }
刘奇

Reflection tool class

package cn.hylexus.app.util;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class ReflectionUtils {

    public static List<Field> getFields(Class<?> clz) {
        List<Field> ret = new ArrayList<>();
        for (Class<?> c = clz; c != Object.class; c = c.getSuperclass()) {
            Field[] fields = c.getDeclaredFields();
            ret.addAll(Arrays.asList(fields));
        }
        return ret;
    }

    /**
     * @param cls
     *            子类对应的Class
     * @param index
     *            子类继承父类时传入的索引,从0开始
     * @return
     */
    public static Class<?> getSuperClassGenericType(Class<?> cls, int index) {
        if (index < 0)
            return null;

        Type type = cls.getGenericSuperclass();
        if (!(type instanceof ParameterizedType))
            return null;

        ParameterizedType parameterizedType = (ParameterizedType) type;
        Type[] typeArguments = parameterizedType.getActualTypeArguments();
        if (typeArguments == null || typeArguments.length == 0 || index > typeArguments.length - 1)
            return null;

        Type t = typeArguments[index];
        if (!(t instanceof Class)) {
            return null;
        }
        return (Class<?>) t;
    }

    public static Class<?> getSuperClassGenericType(Class<?> cls) {
        return getSuperClassGenericType(cls, 0);
    }
}

Question 1

public class RequestInfo {

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        //可以拿到多层次基础的属性
        List<Field> fields = ReflectionUtils.getFields(this.getClass());
        for (Field f : fields) {
            f.setAccessible(true);
            try {
                sb.append(f.getName()).append("=").append(f.get(this)).append("\n");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return sb.toString();
    }
}

Question 2

    @SuppressWarnings("unchecked")
    protected void init() {
        logTag = getClass().getSimpleName();
        try {
            //这里可以拿到动态绑定的Class信息
            Class<?> clz = ReflectionUtils.getSuperClassGenericType(this.getClass(), 1);
            respBean = (P) clz.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
刘奇

The first question can be solved using commons-beanutils.

Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template