简体   繁体   English

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

[英]How to get class of generic type when there is no parameter of it?

I just learned about this fine looking syntax 我刚学会了这种精美的语法

Collections.<String>emptyList()

to get an empty List with elements which are supposedly of type String . 获取一个空List ,其中的元素应该是String类型。 Java's source looks like this: Java的源代码如下:

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

Now if I code a method in that way where the generic type does not appear in the parameter list, is there any way how I can access the actual class that becomes T ? 现在,如果我以这种方式编写方法,其中泛型类型没有出现在参数列表中,有什么方法可以访问成为T的实际类?

I'm saying, up to now my approach to code the same thing would have been 我说,到目前为止,我的代码处理方法本来就是这样

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

If I removed the clazz -parameter I wouldn't be able to do the cast() . 如果我删除了clazz -parameter,我就无法进行强制转换cast() Obviously I could do 显然我能做到

  return (T) value;

but that gives me the usual warning Type safety: Unchecked cast from Object to T . 但是这给了我通常的警告Type safety: Unchecked cast from Object to T Ok, @SuppressWarnings("unchecked") helps here, but actually I want to do something with the intended return type of the method. 好的, @SuppressWarnings("unchecked")在这里有所帮助,但实际上我想用该方法的预期返回类型做一些事情。 If I add a local variable 如果我添加一个局部变量

T retValue;

I'd have to initialise it with something, null doesn't help. 我必须用一些东西初始化它, null无济于事。 After I assign it like 在我分配之后

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

I could do, eg 我可以做,例如

retValue.getClass().getName()

but if the cast fails I end up with no information about T again. 但如果演员表失败,我最终没有关于T信息。

Since Java (or at least my Java 6) does not have the generic info any more during runtime, I currently can't think of a way to do this. 由于Java(或至少我的Java 6)在运行时不再具有通用信息,因此我目前无法想到这样做的方法。 Is there a way? 有办法吗? Or do I have to stick with my "old" approach here? 或者我必须坚持我的“旧”方法吗?

Please note that the example I lined out is very simple and doesn't make much sense. 请注意,我列出的示例非常简单,没有多大意义。 I want to do more complicated stuff here, but that's out of the scope. 我想在这里做更复杂的事情,但这超出了范围。

If you want the generic type at runtime you need to either have it as a field or create a sub-class of a type for a specific combination of types. 如果您希望在运行时使用泛型类型,则需要将其作为字段使用,或者为特定的类型组合创建类型的子类。

eg 例如

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

prints 版画

class java.lang.String

You can't, unfortunately. 不幸的是,你不能。 All generics and type parameters are erased in runtime. 所有泛型和类型参数都在运行时擦除。 So in runtime the type of your T is simply Object 所以在运行时,你的T的类型就是Object

retValue.getClass().getName() will always return the runtime type of the object and not the class name of the parameter type. retValue.getClass().getName()将始终返回对象的运行时类型,而不是参数类型的类名。

If you want to grab the parameter class, there's no other way than to use your first solution. 如果你想获取参数类,除了使用你的第一个解决方案之外别无他法。 (That is, pass the class object explicitly.) (也就是说,明确传递类对象。)

As you mentioned, Java generics are build time only. 正如您所提到的,Java泛型只是构建时间。 They are not used at run time. 它们在运行时不使用。

Because of this, the old approach you were using will be your only way to accomplish this. 因此,您使用的旧方法将是您实现此目标的唯一方法。

I find out that there is one solution for getting Class<?> from T: 我发现从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]);
}

The usage of code above: 上面代码的用法:

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

getGenericType(myAction);

I did not tested this with primitive types (int, byte, boolean). 我没有用原始类型(int,byte,boolean)测试它。

I think that it is not very fast, but you do not have to pass Class<?> to constructor. 我认为它不是很快,但你不必将Class<?>传递给构造函数。

EDIT: 编辑:

The usage above is not right, because generic superclass is not available for Action<String> . 上面的用法不正确,因为Action<String>不能使用通用超类。 Generic super class will be available only for inherited class like class ActionWithParam extends Action<String>{} . 通用超类仅适用于继承类, class ActionWithParam extends Action<String>{} This is reason why I changed my mind and now I suggest to pass class parameter to constructor, too. 这就是我改变主意的原因,现在我建议将类参数传递给构造函数。 Thanks to newacct for correction. 感谢newacct的纠正。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM