简体   繁体   English

带有擦除的Java类型推断

[英]Java type inference with erasure

having some problem with erasure & type inference. 在擦除和类型推断方面遇到一些问题。 I have the following class hierarchy, which doesn't look very complicated: 我有以下的类层次结构,看起来并不十分复杂:

public class Foo<T> {

}

public class Bar<T> {
    private final Class<T> clazz;

    public Bar(Class<T> clazz) {
        this.clazz = clazz;
    }
}

And what I'm trying to do is something like this: 我想做的是这样的:

Bar<Foo<?>> bar = new Bar<>(Foo.class);

which, of course, doesn't work, as Foo is not quite Foo<?> . 这当然是行不通的,因为Foo并不是Foo<?> The question is how to construct such a Bar? 问题是如何建立这样的酒吧? I need exactly Bar<Foo<?>> , not Bar<Foo> , as there is method which accepts only Bar<Foo<?>> as a parameter. 我确实需要Bar<Foo<?>> ,而不是Bar<Foo> ,因为有些方法只接受Bar<Foo<?>>作为参数。 Appreciate ideas. 欣赏想法。

Sorry, there is no such Class object, because, as you note, erasure means that there can't be. 抱歉,没有这样的Class对象,因为正如您所指出的,擦除意味着不可能。 You need to cast it: 您需要强制转换:

((Class<Foo<?>>)(Class)Foo.class)

This will give you the bounds you want, but may generate a compiler warning because you are performing an unchecked generic cast. 这将为您提供所需的界限,但可能会产生编译器警告,因为您正在执行未经检查的泛型转换。 This is reasonable: the compiler is requiring you to acknowledge that you are leaving behind the compile-time safety of generics. 这是合理的:编译器要求您确认您遗漏了泛型的编译时安全性。 But in this case there's really no way this case can generate a runtime error, at this point in your program or in the future, so it's fine. 但是在这种情况下,实际上在这种情况下,无论是在您的程序中还是在将来,这种情况都不会产生运行时错误,所以很好。

The double-cast is necessary because the compiler knows that Foo.class is not compatible with Class>, so you have to first cast it to the "raw" type Class: using raw types in an expression disables the compiler's generic-type checks for that expression, so then the "impossible" cast works okay. 双播是必要的,因为编译器知道Foo.class与Class>不兼容,因此您必须首先将其转换为“原始”类型Class:在表达式中使用原始类型会禁用编译器的泛型检查这样的表达方式,那么“不可能”的转换就可以了。

You cannot create generic object without providing Type information in <> , as shown in your question post. 如问题帖所示,如果不在<>提供类型信息,就无法创建通用对象。 You must supply a Type or use the raw version. 您必须提供Type或使用原始版本。 If you are forced to use the wild card parameter type, then just suppress the warning by using raw type, as shown below 如果您被迫使用通配符参数类型,则只需使用原始类型抑制警告,如下所示

@SuppressWarnings("rawtypes")
Bar<Foo<?>> bar = new Bar(Foo.class);       

//Bar is having no type "<>" (but this is not recommended

Since java.lang.Class is immutable, you could use a weaker type declaration in the constructor of Bar: 由于java.lang.Class是不可变的,因此可以在Bar的构造函数中使用较弱的类型声明:

class Foo<T> {}

class Bar<T> {
    private final Class<? extends T> clazz;

    public Bar(Class<? extends T> clazz) {
        this.clazz = clazz;
    }
}

If you'd still need the field to be of type Class<T> rather than Class<? extends T> 如果您仍然需要该字段的类型为Class<T>而不是Class<? extends T> Class<? extends T> it's safe to cast it within the constructor. Class<? extends T> ,将其强制转换为构造函数是安全的。

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

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