如果没有参数,如何获得泛型类?

时间:2011-12-08 18:50:09

标签: java generics

我刚刚了解了这个fine looking syntax

Collections.<String>emptyList()

获取一个空的List,其元素应该是String类型的元素。 Java的源代码如下:

public static final List EMPTY_LIST = new EmptyList<Object>();
:
public static final <T> List<T> emptyList() {
  return (List<T>) EMPTY_LIST;
}

现在,如果我以通用类型未出现在参数列表中的方式编写方法,那么我是否可以访问变为T的实际类?

我说,到目前为止我的代码处理方法一直是

private <T> T get(String key, Class<T> clazz) {
  // here I can do whatever I want with clazz, e.g.:
  return clazz.cast(value);
}

如果我删除clazz - 参数,我将无法执行cast()。显然我可以做到

  return (T) value;

但这给了我通常的警告Type safety: Unchecked cast from Object to T。好的,@SuppressWarnings("unchecked")在这里有帮助,但实际上我想用方法的预期返回类型做一些事情。如果我添加一个局部变量

T retValue;

我必须用一些东西初始化它,null没有帮助。在我分配之后

@SuppressWarnings("unchecked")
T retValue = (T) value;

我能做到,例如

retValue.getClass().getName()

但如果演员表失败,我最终没有再次提供有关T的信息。

由于Java(或至少我的Java 6)在运行时不再具有通用信息,因此我目前无法想到这样做的方法。有办法吗?或者我必须坚持我的“旧”方法吗?

请注意,我列出的示例非常简单,没有多大意义。我想在这里做更复杂的事情,但这超出了范围。

5 个答案:

答案 0 :(得分:5)

如果您希望在运行时使用泛型类型,则需要将其作为字段或为特定类型组合创建类型的子类。

e.g。

List<String> list = new ArrayList<String>() {}; // creates a generic sub-type
final Class type = (Class) ((ParameterizedType) list.getClass()
                            .getGenericSuperclass()).getActualTypeArguments()[0];
System.out.println(type);

打印

class java.lang.String

答案 1 :(得分:4)

不幸的是,你不能。所有泛型和类型参数都在运行时擦除。因此,在运行时,T的类型只是Object

答案 2 :(得分:2)

retValue.getClass().getName()将始终返回对象的运行时类型,而不是参数类型的类名。

如果你想获取参数类,除了使用你的第一个解决方案之外别无他法。 (也就是说,明确传递类对象。)

答案 3 :(得分:1)

正如您所提到的,Java泛型只是构建时间。它们不会在运行时使用。

因此,您使用的旧方法将是您实现此目标的唯一方法。

答案 4 :(得分:-2)

我发现从T获得Class<?>有一个解决方案:

public class Action<T>{
}

public Class<?> getGenericType(Object action) throws ClassNotFoundException{
   Type type =
   ((ParameterizedType)action.getClass().getGenericSuperclass())
      .getActualTypeArguments()[0];
   String sType[] = type.toString().split(" ");

   if(sType.length != 2)
      throw new ClassNotFoundException();

   return Class.forName(sType[1]);
}

以上代码的使用:

Action<String> myAction = new Action<String>();

getGenericType(myAction);

我没有用原始类型(int,byte,boolean)测试它。

我认为它不是很快,但您不必将Class<?>传递给构造函数。

修改

上述用法不正确,因为Action<String>无法使用通用超类。通用超类仅适用于class ActionWithParam extends Action<String>{}等继承类。这就是我改变主意的原因,现在我建议将类参数传递给构造函数。感谢newacct进行更正。