【问题标题】:Generics - Get the reference type泛型 - 获取引用类型
【发布时间】:2015-03-11 02:48:22
【问题描述】:

我在获取列表类型时遇到问题。问题是在声明时我没有指定类型。我只在运行时设置它。

我有一个 POJO 类

public class MyObject<T> {

    private String name;
    private List<T> list;

//getter and setter
}

我已关注this SO question 并尝试了我的以下代码

public class ListType {

    public static void main(String[] args) throws NoSuchFieldException, SecurityException {
        ListType listType = new ListType();
    List<Integer> listInt = new ArrayList<Integer>();
    MyObject<Integer> myObjectInt = new MyObject<Integer>();
    myObjectInt.setList(listInt);
    listType.initialize(myObjectInt);

    MyObject<String> myObjectStr = new MyObject<String>();
    List<String> listStr = new ArrayList<String>();
    myObjectStr.setList(listStr);
    listType.initialize(myObjectStr);
    }

    private void initialize(MyObject myObject) throws NoSuchFieldException, SecurityException {
        List list = myObject.getList();
        ListType listType = new ListType();
        listType.getListType(list);
    }

    private void getListType(List list) throws NoSuchFieldException, SecurityException {
        Field stringListField = MyObject.class.getDeclaredField("list");
        ParameterizedType stringListType = (ParameterizedType) stringListField.getGenericType();
        Class<?> stringListClass = (Class<?>) stringListType.getActualTypeArguments()[0];
        System.out.println(stringListClass);
    }

}

然后我得到以下异常

Exception in thread "main" java.lang.ClassCastException: sun.reflect.generics.reflectiveObjects.TypeVariableImpl cannot be cast to java.lang.Class
    at com.sample.listtype.ListType.getListType(ListType.java:35)
    at com.sample.listtype.ListType.initialize(ListType.java:27)
    at com.sample.listtype.ListType.main(ListType.java:15)

如果我在运行时设置,如何获取类型?

【问题讨论】:

  • 但是如果我在运行时设置,如何获取类型? List 在运行时没有类型 (erasure) 所以这个问题并不真正有道理。最好告诉我们你真正想要做什么。

标签: java generics reflection arraylist


【解决方案1】:

我认为您想要实现的目标是不可能的。但是,对代码稍作改动就可以解决问题:

public class MyObject {
    private List<?> list;
    private Class<?> type;

    public <T> void setList(List<T> list, Class<T> c) {
        this.list = list;
        this.type = c;
    }

    public List<?> getList() {
        return list;
    }

    public Class<?> getType() {
        return type;
    }
}

示例代码:

public static void main(String[] args) throws NoSuchFieldException,
        SecurityException {
    List<Integer> list = new ArrayList<Integer>();
    MyObject myObject = new MyObject();
    myObject.setList(list, Integer.class);

    System.out.println(myObject.getType());
}

输出:

class java.lang.Integer

【讨论】:

  • 也许使整个 MyObject 类通用化也是 OP 的一个选项。它不会因为类型擦除而避免额外的参数,但会引入更多的类型安全性。
  • 嗨,我已经编辑了代码。请检查。现在无论如何我怎样才能得到类型?
  • @AndreStannek 确实使 MyObject 成为泛型类会更安全,但是可以将列表设置为任何类型。 IE。 MyObject 不能设置任何 Double 列表,我猜这个功能从问题中是必要的。
  • @iProgrammer,如示例所示,调用MyObject的getType()方法获取类型。
  • MyObject&lt;Integer&gt; myObjectInt = new MyObject&lt;Integer&gt;(); 我正在这样做。那么为什么我需要声明一个单独的变量并设置和通过方法呢?
【解决方案2】:

方法getGenericType() 的返回类型为Type,其中可以是ClassParameterizedType。如果在没有参数化类型的字段上调用它,它不会返回 ParameterizedType 对我来说是有意义的。在这种情况下,它似乎返回 Classjavadoc 在这个问题上有点不确定。

关于如何在运行时获取实际类型的问题:通用类型信息在运行时被擦除。它仅用于确保编译时的类型安全。当您将具有实际类型ArrayList&lt;Integer&gt; 的对象分配给具有静态类型List 的变量时,您无法在运行时获得实际对象的泛型类型。您可以做的是检查列表中包含的对象的类型:

Class<?> foo = list.get(0).getClass();

【讨论】:

  • 这是一个很好的解决方法,但是当列表中没有任何元素时它就不起作用了...
  • 是的,如果列表为空怎么办?
  • @NielsBillen 是的,在那种情况下它不会起作用 ;-) 我喜欢你的回答,我不得不做一次类似的事情。
  • 嗨,我已经编辑了代码。请检查。现在无论如何我怎样才能得到类型?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-20
  • 1970-01-01
  • 1970-01-01
  • 2011-07-22
  • 1970-01-01
相关资源
最近更新 更多