Java 类型推断:引用在 Java 8 中是不明确的,但在 Java 7 中不是 [英] Java type inference: reference is ambiguous in Java 8, but not Java 7

查看:29
本文介绍了Java 类型推断:引用在 Java 8 中是不明确的,但在 Java 7 中不是的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我们有 2 个班级.一个空类Base,以及这个类的一个子类Derived.

公共类 Base {}public class Derived extends Base {}

然后我们在另一个类中有几个方法:

import java.util.Collection公共类消费者{公共无效测试(){设置(新派生(),新消费者().get());}public <T extends Base>获取(){返回(T)新派生();}公共无效集(基础 i,派生 b){System.out.println("基数");}public void set(Derived d, Collection o) {System.out.println("对象");}}

这在 Java 7 中编译并成功运行,但在 Java 8 中无法编译.错误:

Error:(8, 9) java: 对 set 的引用不明确Consumer 中的方法 set(Base,Derived) 和消费者匹配中的方法集(Derived,java.util.Collection)

为什么可以在 Java 7 中运行,而不能在 Java 8 中运行? ever 如何匹配 Collection?

解决方案

问题是类型推断已经改进.你有一个像

这样的方法

public 获取(){返回(T)新派生();}

基本上说,调用者可以决定我返回Base的哪个子类",这显然是无稽之谈.每个编译器都应该在 (T) 此处为您的类型转换提供未经检查的警告.

现在你有一个方法调用:

set(new Derived(), new Consumer().get());

回想一下你的方法 Consumer.get() 说调用者可以决定我返回什么".因此,假设可能存在一种扩展 Base 并同时实现 Collection 的类型是完全正确的.所以编译器说我不知道是调用 set(Base i, Derived b) 还是 set(Derived d, Collection o)".

您可以通过调用 set(new Derived(), new Consumer().<Derived>get()); 来修复"它,但为了说明您的方法的疯狂,请注意你也可以把它改成

public >无效测试(){set(new Derived(), new Consumer().get());}

现在将调用 set(Derived d, Collection o) 而没有任何编译器警告.实际的不安全操作发生在 get 方法内部.

因此,正确的解决方法是从 get 方法中删除类型参数,并声明它真正返回的内容,Derived.<小时>

顺便说一句,让我恼火的是你声称这段代码可以在 Java 7 下编译.它有限的类型推断和嵌套方法调用导致在嵌套调用上下文中处理 get 方法就像返回 Base 一样,它不能传递给需要 Derived 的方法.因此,尝试使用符合标准的 Java 7 编译器编译此代码也会失败,但原因不同.

Lets say we have 2 classes. An empty class Base, and a subclass of this class Derived.

public class Base {}

public class Derived extends Base {}

Then we have a few methods in another class:

import java.util.Collection

public class Consumer {

    public void test() {
        set(new Derived(), new Consumer().get());
    }

    public <T extends Base> T get() {
        return (T) new Derived();
    }

    public void set(Base i, Derived b) {
        System.out.println("base");
    }

    public void set(Derived d, Collection<? extends Consumer> o) {
        System.out.println("object");
    }

}

This compiles and runs successfully in Java 7, but does not compile in Java 8. The error:

Error:(8, 9) java: reference to set is ambiguous
  both method set(Base,Derived) in Consumer and 
  method set(Derived,java.util.Collection) in Consumer match

Why does work in Java 7, but not Java 8? How could <T extends Base> ever match Collection?

解决方案

The problem is that the type inference has been improved. You have a method like

public <T extends Base> T get() {
    return (T) new Derived();
}

which basically says, "the caller can decide what subclass of Base I return", which is obvious nonsense. Every compiler should give you an unchecked warning about your type cast (T) here.

Now you have a method call:

set(new Derived(), new Consumer().get());

Recall that your method Consumer.get() says "the caller can decide what I return". So it’s perfectly correct to assume that there could be a type which extends Base and implement Collection at the same time. So the compiler says "I don’t know whether to call set(Base i, Derived b) or set(Derived d, Collection<? extends Consumer> o)".

You can "fix" it by calling set(new Derived(), new Consumer().<Derived>get()); but to illustrate the madness of your method, note that you can also change it to

public <X extends Base&Collection<Consumer>> void test() {
    set(new Derived(), new Consumer().<X>get());
}

which will now call set(Derived d, Collection<? extends Consumer> o) without any compiler warning. The actual unsafe operation happened inside the get method.

So the correct fix would be to remove the type parameter from the get method and declare what it really returns, Derived.


By the way, what irritates me, is your claim that this code could be compiled under Java 7. Its limited type inference with nested method calls leads to treating the get method in a nested invocation context like returning Base which can’t be passed to a method expecting a Derived. As a consequence, trying to compile this code using a conforming Java 7 compiler will fail as well, but for different reasons.

这篇关于Java 类型推断:引用在 Java 8 中是不明确的,但在 Java 7 中不是的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆