Когда два интерфейса имеют конфликтующие типы возврата, почему один метод становится стандартным?
В 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 на самом деле не понимает варианты совместного варианта возврата.