当两个接口具有冲突的返回类型时,为什么一个方法成为默认值?

sch*_*mod 13 java interface return-type java-8 default-method

在Java 8中,如果我有两个具有不同(但兼容)返回类型的接口,则反射告诉我两个方法中的一个是默认方法,即使我实际上没有将该方法声明为默认方法或提供方法体.

例如,请使用以下代码段:

package com.company;
import java.lang.reflect.Method;

interface BarInterface {}
class Bar implements BarInterface {}

interface FooInterface {
    public BarInterface getBar();
}

interface FooInterface2 extends FooInterface {
    public Bar getBar();
}

class Foo implements FooInterface2 {
    public Bar getBar(){
        throw new UnsupportedOperationException();
    }
}

public class Main {
    public static void main(String[] args) {
        for(Method m : FooInterface2.class.getMethods()){
            System.out.println(m);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Java 1.8生成以下输出:

public abstract com.company.Bar com.company.FooInterface2.getBar()
public default com.company.BarInterface com.company.FooInterface2.getBar()
Run Code Online (Sandbox Code Playgroud)

这看起来很奇怪,不仅因为两种方法都存在,而且因为其中一种方法突然而且莫名其妙地变成了默认方法.

尽管两种方法具有相同的签名,但在Java 7中运行相同的代码会产生一些不太意外的情况,尽管仍然令人困惑:

public abstract com.company.Bar com.company.FooInterface2.getBar()
public abstract com.company.BarInterface com.company.FooInterface.getBar()
Run Code Online (Sandbox Code Playgroud)

Java肯定不支持多种返回类型,所以这个结果仍然很奇怪.


显而易见的下一个想法是:"好吧,也许这是一种特殊的行为,只适用于接口,因为这些方法没有实现."

错误.

class Foo2 implements FooInterface2 {
    public Bar getBar(){
        throw new UnsupportedOperationException();
    }
}

public class Main {
    public static void main(String[] args) {
        for(Method m : Foo2.class.getMethods()){
            System.out.println(m);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

产量

public com.company.Bar com.company.Foo2.getBar()
public com.company.BarInterface com.company.Foo2.getBar()
Run Code Online (Sandbox Code Playgroud)

这里发生了什么?为什么Java将这些方法枚举为单独的方法,以及如何将其中一个接口方法设法成为没有实现的默认方法?

Pet*_*rey 9

它不是default您提供的方法,而是桥接方法.在您定义的父接口中.

public BarInterface getBar();
Run Code Online (Sandbox Code Playgroud)

你必须有一个可以调用的方法来实现它.

例如

FooInterface fi = new Foo();
BarInterface bi = fi.getBar(); // calls BarInterface getBar()
Run Code Online (Sandbox Code Playgroud)

但是,您还需要能够调用它的共变量返回类型.

FooInterface2 fi = new Foo();
Bar bar = fi.getBar(); // calls Bar getBar()
Run Code Online (Sandbox Code Playgroud)

这些是相同的方法,唯一的区别是一个调用另一个并转换返回值.这个方法似乎有一个default实现,因为它在接口上执行此操作.

注意:如果您有多个级别的接口/类,并且每个接口/类具有不同的返回类型,则会累积方法的数量.

这样做的原因是JVM允许多个方法具有不同的返回类型,因为返回类型是签名的一部分.我是调用者必须声明它期望的返回类型,并且JVM实际上并不理解共变量返回类型.