当前位置: 首页 > 知识库问答 >
问题:

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

黎震博
2023-03-14

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

例如,以以下代码段为例:

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()

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

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

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个答案

祁辰阳
2023-03-14

它不是您提供的默认方法,而是桥接方法。在您定义的父接口中。

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()

这些都是相同的方法,唯一的区别是一个调用另一个并铸造返回值。它是在执行此操作的接口上具有默认实现的方法。

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

它这样做的原因是JVM允许有多个返回类型不同的方法,因为返回类型是签名的一部分。也就是说,调用者必须声明它所期望的返回类型,而JVM实际上并不理解协变返回类型。

 类似资料:
  • 学习Java8默认方法。这个链接就像互联网上的其他资源一样说 在“最严格的意义上”,默认方法是一种倒退,因为它们允许你用代码“污染”你的接口。但它们提供了允许向后兼容的最优雅和最实用的方法。它使Oracle更容易更新所有集合类,也使您更容易为Lambda修改现有代码。 我的理解是Java8Dev/Designers在接口中提供了默认方法,这样所有实现类就不必不必要地重写相同的行为,从而提供了向后兼

  • 其中是我自己的班级。 此方法的返回类型是什么?为什么它似乎有两种返回类型?

  • 问题内容: 考虑下面的类层次结构。 运行该程序将出现以下错误: 这是因为我将ClassA.hello标记为私有。 如果我将ClassA.hello标记为受保护或删除了可见性修饰符(即使其成为默认作用域),那么它将显示编译器错误为: 但是,按照上面的异常stacktrace, 我得到一个运行时IllegalAccessError。 我不明白为什么在编译时没有检测到这个。有什么线索吗? 问题答案: 更

  • 问题内容: 我在接口上苦苦挣扎。考虑一下: 我希望函数返回a 或an ,具体取决于是否从或调用 当我尝试对此进行编译时,出现以下错误: 不能将s( StringGenerator类型)用作数组或切片文字中的Generator类型: StringGenerator不实现Generatorer(getValue方法的类型错误) 有getValue()字符串 要getValue() 我该如何实现? 问题

  • 当到达第1行时,和的默认行为是什么? 当到达第3行时,和返回相同的结果类型()。第3行会覆盖第2行定义的行为吗?我的意思是,会返回而不是吗? 我的意思是,方法签名是so在示例中是类型的元素,其值可能为。那么,方法如何能够确定不同的调用是作为参数传递的?

  • 我最近开始使用MapStruct,并有这个疑问。因此,可以将映射从一个方法继承到另一个方法,该方法用于映射前一个方法输出的子类。 对于例如-如果我有一个Car类,它需要映射成两个类FourWheeler和DetailedFourWheeler(扩展了FourWheeler类),我可以使用为将Car转换成FourWheeler而定义的映射到将Car转换成DetailedFourWheeler的方法中