【问题标题】:Code that compiles in java 7 does not compile in Java 8. Please provide an explanation在 Java 7 中编译的代码在 Java 8 中无法编译。请提供解释
【发布时间】:2017-04-09 14:00:43
【问题描述】:

为什么以下代码在 Java 8 中无法编译。 我知道类型推断是这里的罪魁祸首,但我想解释一下。

public class TypeInferenceProblem {

    class ATest<E extends B>
    {

        private E find(C<? extends E> CObj)
        {
            return null;
        }

        public void findCs(List<? extends C<? extends E>> cList)
        {

            find(new C());// This compiles fine
            for (C cObj : cList)
                {
                    E cachedEntity = find(cObj); // This cause error in java 8 but works fine in java 7
                }
        }
    }

     class B{
     }

     class C <T> {
     }
}

【问题讨论】:

  • 我在 Java 7 中遇到与 Java 8 相同的错误。请自行查看:Java 8 explodingJava 7 exploding
  • 当不涉及 lambdas(并且不能,应该是 Java 7 代码)时,您为什么要调用该类 LambdaTypeInferenceProblem
  • @Bohemian:这不是证明。之前已经注意到,Ideone 总是使用 Java 8 编译器,即使它声称使用 Java 7。你甚至可以在那里使用 lambda 表达式。
  • 当您将raw type C 传递给find 时,您基本上是在禁用泛型,因此,不能指望E 会被返回。我认为,这个应该也被以前的版本拒绝了,这是一个错误,它不是。
  • @Bohemian:见lambda expression in Java 7...

标签: java java-8 type-inference


【解决方案1】:

只是为了明确引用 Holger 的正确 cmets:

在 JLS 8 中,这是在 §18.5.2 中确定的,其中包含这句话(在第 6 个主要项目符号内):

如果在第 18.5.1 节中的约束集缩减期间该方法需要未经检查的转换,则通过将 θ' 应用于 m 的类型的参数类型来获得 m 的调用类型的参数类型,并且m的调用类型的返回类型和抛出类型由返回类型的擦除和m的类型的抛出类型给出。

我突出显示了相关部分。

类似的句子已经出现在 JLS 7 §15.12.2.6:

否则,如果要使该方法适用,则必须进行未经检查的转换,则结果类型是该方法声明的返回类型的擦除(第 4.6 节)。

这两个版本都相当于定义使用原始类型参数(需要未经检查的转换)调用find(..) 具有通过将声明的返回类型E 擦除为B 获得的返回类型。

如果 Java 7 的编译器没有报告这个错误,那么这是一个错误。

【讨论】:

  • 我发现一个讨论提到了这个领域的一个 javac 错误:bugs.eclipse.org/bugs/show_bug.cgi?id=277643#c31 及以下。再往下,您会看到 ecj 已更改为“与 javac 行为保持一致”(尽管存在已知错误)。 javac 错误从未得到解决,只是 Java 8 中的新推理绕过了该问题。不过不确定,是否与此问题中的问题相同。
  • 谢谢 :) 这解释了它
猜你喜欢
  • 2023-02-23
  • 1970-01-01
  • 2017-04-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-15
  • 2013-03-16
相关资源
最近更新 更多