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

在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);
        }
    }
}

Java 1.8 生成以下输出:

public abstract com.company.Bar com.company.FooInterface2.getBar()
public default com.company.BarInterface com.company.FooInterface2.getBar()

这似乎很奇怪,不仅因为这两种方法都存在,还因为其中一种方法突然莫名其妙地成为默认方法。

在Java 7中运行相同的代码会产生一些不那么出乎意料的东西,尽管仍然令人困惑,因为这两种方法具有相同的签名:

public abstract com.company.Bar com.company.FooInterface2.getBar()
public abstract com.company.BarInterface com.company.FooInterface.getBar()

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);
        }
    }
}

收益 率

public com.company.Bar com.company.Foo2.getBar()
public com.company.BarInterface com.company.Foo2.getBar()

这是怎么回事?为什么Java将这些枚举为单独的方法,其中一个接口方法如何设法成为没有实现的默认方法?


答案 1

这不是您提供的方法,而是桥接方法。在已定义的父接口中。default

public BarInterface getBar();

并且您必须有一个可以调用的方法来实现此目的。

例如:

FooInterface fi = new Foo();
BarInterface bi = fi.getBar(); // calls BarInterface getBar()

但是,您还需要能够将其称为共变体返回类型。

FooInterface2 fi = new Foo();
Bar bar = fi.getBar(); // calls Bar getBar()

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

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

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


答案 2