为什么Eclipse Compiler会丢失固定类型参数?

时间:2015-06-24 06:57:49

标签: eclipse generics java-8 optional type-parameter

我努力为这个问题找到合适的头衔,因为我观察到的现象非常奇怪。因此,我逐字逐句解释我的问题,而是向您展示一些(希望)自我描述的代码。请考虑以下参数化类:

public class GenericOptional<T> {

    public GenericOptional(T someValue) {}

    public T getValue() { return null; }

    public Optional<String> getOptionalString() { return Optional.empty(); }
}

我想强调的是方法Optional<String>的返回类型getOptionalString()不依赖于 type-parameter T

现在看看下面的代码,它使用 Java 8u45 Eclipse Luna 4.4.2 中编译:

public static void main(String[] args) {
    Object obj = new GenericOptional<>(Boolean.TRUE);
    GenericOptional go = (GenericOptional) obj;
    Optional os = go.getOptionalString();
}

本地变量os的类型Optional没有 type-parameter String Eclipse 编译器丢失了有关固定类型参数的信息。有谁知道为什么?

现在看第二个代码示例:

public static void main(String[] args) {
    Object obj = new GenericOptional<>(Boolean.TRUE);
    GenericOptional<?> go = (GenericOptional) obj;
    Optional<String> os = go.getOptionalString();
}

通过将局部变量go声明为GenericOptional<?>,方法getOptionalString()的返回类型现在按预期为Optional<String>

愿任何人解释这种行为吗?

2 个答案:

答案 0 :(得分:4)

它不是关于Eclipse或任何东西,而是关于原始类型。

让我们回顾一下这个片段:

public static void main(String[] args) {
    Object obj = new GenericOptional<>(Boolean.TRUE);
    GenericOptional go = (GenericOptional) obj;
    Optional os = go.getOptionalString();
}

在这里,您正在创建GenericOptional原始实例,这意味着类型参数信息将完全关闭。因此,实例化原始 GenericOptional意味着该实例将公开方法如下:

public class GenericOptional {

    public GenericOptional(Object someValue) {}

    public Object getValue() { return null; }

    public Optional getOptionalString() { return Optional.empty(); }
}

但是,如果我们现在审核第二个代码段

public static void main(String[] args) {
    Object obj = new GenericOptional<>(Boolean.TRUE);
    GenericOptional<?> go = (GenericOptional) obj;
    Optional<String> os = go.getOptionalString();
}

我们可以看到您正在制作GenericOptional的通用实例。即使它的类型参数是<?>,编译器也不会关闭关于类型参数的关注,因此实例将公开参数化的getOptionalString()方法,如下所示:

public Optional<String> getOptionalString() { return Optional.empty(); }

答案 1 :(得分:4)

您正面临raw types的行为。当您使用原始类型时,无论成员的通用签名和类的类型参数之间是否存在连接,泛型都会完全完全

这背后的原因是原始类型是仅与前Generics代码向后兼容的功能。所以要么你有泛型,要么你没有。

如果Generic方法不依赖于类的实际类型参数,则问题很容易解决:

GenericOptional<?> go = (GenericOptional<?>) obj;
Optional<String> os = go.getOptionalString();

使用<?>暗示“我不知道实际的类型参数,我不在乎,但我正在使用通用类型检查”。