为什么此代码在sourceCompatibility = 1.8时失败

时间:2015-04-17 06:56:29

标签: java generics java-8

以下代码在使用sourceCompatibility = 1.7或1.6编译时有效,但在切换到1.8后失败:

public class Java8Wat {
  interface Parcelable {
  }

  static class Bundle implements Parcelable {
    public void put(Parcelable parcelable) {
    }

    public void put(Serializable serializable) {
    }

    public <T extends Parcelable> T getParcelable() {
      return null;
    }
  }

  static {
    Bundle inBundle = new Bundle();
    Bundle outBundle = new Bundle();

    outBundle.put(inBundle.getParcelable());
  }
}

编译输出:

Java8Wat.java:23: error: reference to put is ambiguous
        outBundle.put(inBundle.getParcelable());
             ^
both method put(Parcelable) in Bundle and method put(Serializable) in Bundle match

这是代码失败的回购:https://github.com/chalup/java8-wat。只需从项目目录中调用./gradlew clean build

我浏览了JLS for Java 8,但我没有发现任何相关内容。

其他观察:如果我将getParcelable()签名更改为:

,则代码会编译
public Parcelable getParcelable()

为什么java编译器认为put(Serializable)outBundle.put(inBundle.getParcelable())调用的潜在适用方法,应该对Parcelable / Bundle类进行哪些更改?额外问题:为什么这个错误只发生在Java 8上而不发生在Java 7上?

2 个答案:

答案 0 :(得分:3)

我建议这是因为在java 8中进行推理的方式发生了变化。Parcelable是一个接口。 因此,getParcelable的推理返回类型会导致调用不明确,因为推理返回类型可以应用于这两种方法。

我会主要参考另一个问题以获得更清楚的解释:Why can this generic method with a bound return any type?

至于真正理解推理如何在这个特定情况下工作以及为什么它在java 7和8之间有所不同,这需要对JLS的inference part进行更深入的研究。

答案 1 :(得分:1)

正如消息所说reference to put is ambiguous

你必须对值进行探索,以便编译器知道你想要使用的方法:

outBundle.put((Parcelable)Bundle.getParcelable());

outBundle.put((Serializable)Bundle.getParcelable());