Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/jquery-ui/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Eclipse/javac不同意编译带有默认方法冲突的签名;谁是对的?_Java_Eclipse_Generics_Java 8_Javac - Fatal编程技术网

Eclipse/javac不同意编译带有默认方法冲突的签名;谁是对的?

Eclipse/javac不同意编译带有默认方法冲突的签名;谁是对的?,java,eclipse,generics,java-8,javac,Java,Eclipse,Generics,Java 8,Javac,下面是一个简单的类来演示这个问题: package com.mimvista.debug; public class DefaultCollisionTest { public static interface Interface1 { public String getName(); } public static interface Interface2 { public default String getName() { ret

下面是一个简单的类来演示这个问题:

package com.mimvista.debug;

public class DefaultCollisionTest {
    public static interface Interface1 {
        public String getName();
    }

    public static interface Interface2 {
        public default String getName() { return "Mr. 2"; };
    }

    public static <X extends Interface1&Interface2> String extractName(X target) {
        return target.getName();
    }
}
package com.mimvista.debug;
公共类DefaultCollisionTest{
公共静态接口1{
公共字符串getName();
}
公共静态接口2{
公共默认字符串getName(){返回“先生2”;};
}
公共静态字符串提取名称(X目标){
返回target.getName();
}
}
Eclipse(Neon 2)愉快地编译了这个类,而javac(JDK 1.8.0_121)抛出了以下编译错误:

$ javac src/com/mimvista/debug/DefaultCollisionTest.java
src\com\mimvista\debug\DefaultCollisionTest.java:13: error: class INT#1 inherits abstract and default for getName() from types Interface2 and Interface1
        public static <X extends Interface1&Interface2> String extractName(X target) {
                       ^
  where INT#1 is an intersection type:
    INT#1 extends Object,Interface1,Interface2
1 error
$javac src/com/mimvista/debug/DefaultCollisionTest.java
src\com\mimvista\debug\DefaultCollisionTest.java:13:error:class INT#1从Interface2和Interface1类型继承getName()的抽象和默认值
公共静态字符串提取名称(X目标){
^
其中,INT#1是交叉点类型:
INT#1扩展对象、接口1、接口2
1错误

我相信Eclipse在这种情况下是正确的,但我不能完全确定错误,我认为它只应该在编译实现这两个接口的实际声明类时生成。看起来javac可能正在幕后生成一个中间类来处理该通用签名,并错误地将其置于默认方法冲突测试之下?

根据JLS,javac是正确的:

如果接口
I
继承了一个默认方法,其签名与
I
继承的另一个方法的重写等效,则会发生编译时错误。(无论另一个方法是抽象方法还是默认方法,都是这种情况。)

小字说明:

[……]当一个抽象方法和一个具有匹配签名的默认方法被继承时,我们会产生一个错误。在这种情况下,可能会优先考虑其中一个-也许我们会假设默认方法也为抽象方法提供了一个合理的实现。但这是有风险的,因为除了巧合的名称之外d签名,我们没有理由相信默认方法的行为与抽象方法的契约一致-默认方法可能在最初开发子接口时甚至不存在。在这种情况下,要求用户主动断言默认实现是适当的更安全(通过覆盖声明)

相反,类中继承的具体方法的长期行为是它们重写接口中声明的抽象方法(请参阅)。关于潜在契约冲突的相同论点也适用于此,但在这种情况下,类和接口之间存在固有的不平衡。为了保持类层次结构的独立性,我们更倾向于通过简单地优先考虑具体方法来最小化类接口冲突

也可与以下各项进行比较:

如果类C继承的默认方法的签名与C继承的另一个方法的重写等效,则这是编译时错误,除非存在一个在C超类中声明并由C继承的抽象方法,该抽象方法与这两个方法的重写等效

当在超类中声明抽象方法时,会出现严格的默认抽象和默认冲突规则的例外情况:来自超类层次结构的抽象性断言实质上胜过默认方法,使默认方法的行为如同它是抽象的一样。但是,来自类d的抽象方法oes不会覆盖默认方法,因为仍然允许接口细化来自类层次结构的抽象方法的签名

更简单的说:假设这两个接口在逻辑上不相关,并且都指定了某种行为契约。因此,假设
Interface2
中的默认实现是
Interface1
契约的有效实现是不安全的。更安全的做法是抛出一个错误,让开发人员把它整理好


我在JLS中没有找到一个地方可以准确地解决您的问题,但我认为错误在上述规范的要点中-您声明
extractName()
应该采用一个同时实现
Interface1
Interface2
的对象。但是对于这样一个对象,它只有在“存在一个在C超类中声明并由C继承的抽象方法,该方法与这两个方法的重写等价”时才有效。您的泛型声明没有指定任何关于超类
X
,因此编译器将其视为“抽象默认”冲突。

据我所知,问题是将已编译类的对象作为参数传递。因为您无法调用
extractName(X)
method使用抽象类或接口时,参数对象必须具有它的
getName()
方法已解析且明确。Java使用后期绑定来解析运行时调用的重写方法,因此我同意BonusLord的观点,即即使
javac
抛出错误,该方法也可以正确编译和运行。

Eclipse是正确的

我在中未发现此javac bug,因此报告了它:

更好的解释如下(见):


正确的,只有当交叉点类型格式不正确,因此交叉点为空时,才应该报告交叉点类型的错误。但正如这个答案所示,交叉点不是空的,因此应该是合法的。实际上,错误消息
class INT#1继承…
没有意义,因为在这一点上ody提到了一个INT#1,我们只有两个接口的交集,这个交集
interface I1 {
    String get();
}

interface I2 {
    String get();
}

interface IDefault {
    default String get() {
        return "default";
    };
}

public class Foo implements I1, I2, IDefault {

    @Override
    public String get() {
        return "foo";
    }

    public static void main(String[] args) {
        System.out.print(getOf(new Foo()));
    }

//  static <T extends I1 & IDefault> String getOf(T t) { // fails with javac
    static <T extends I1 & I2> String getOf(T t) { // OK
        return t.get();
    }

}