首頁  >  問答  >  主體

java - 关于泛型和反射的代码错误(cannot select from a type variable)

问题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;
}
迷茫迷茫2743 天前1111

全部回覆(3)我來回復

  • PHPz

    PHPz2017-04-18 10:53:04

    泛型,在編譯之後,就已經被擦除了,jvm根本看不到泛型的信息,這點是由於歷史遺留原因導致的,所以你說的p.getClass是不可能存在的

    第一個問題,想法很好,但是,據我所知是無法實現的,對像是無法獲知子類的情況的,java的多態機制也只能是從父類或者父接口中查詢方法

    我猜第一個問題你會覺得可以取得子類別的成員變數是覺得繼承之後子類別的toString方法一執行,也會呼叫自己的this,這是錯誤的。在運行的時候,jvm會從父類別的物件空間取得這個方法並執行。所以,怎麼搞都只是父類別的成員變數

    上述斜體的地方我說錯了,開了IDE測試了一下之後,對於自己之前理解的地方有誤,希望沒造成題主的困擾。
    下面貼的這段程式碼,就可以循環取得從子類別到父類別的所有變數。希望有幫助

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

    回覆
    0
  • 怪我咯

    怪我咯2017-04-18 10:53:04

    反射工具類

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

    問題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();
        }
    }

    問題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();
            }
        }

    回覆
    0
  • 怪我咯

    怪我咯2017-04-18 10:53:04

    第一個問題可以利用commons-beanutils做。

    回覆
    0
  • 取消回覆