Реализация нескольких интерфейсов, имеющих тот же метод
Этот код работает отлично. Метод test() работает для обоих интерфейсов. Что именно происходит под капотом? И как эта функция полезна в практическом сценарии?
interface A
{
void test();
}
interface B
{
void test();
}
class C implements A, B
{
public void test()
{
System.out.println("abc");
}
}
A a = new C();
a.test();
B b = new C();
b.test();
Ответы
Ответ 1
Потому что это интерфейс не наносит вреда. Вы в основном используете план для своего класса C
, реализуя A
и B
. Оба A
и B
говорят, что C
должен реализовать метод под названием test()
Ваш класс C
реализует этот метод, поэтому интерфейсы выполнили свою работу.
В основном ваш класс C
говорит: "О, эй, мне нужно реализовать test()
из-за интерфейса A
", и вы его реализуете. Затем ваш класс C
говорит: "О, эй, мне нужно снова реализовать test()
из-за интерфейса B
", и он видит, что уже реализован метод под названием test()
, поэтому он удовлетворен.
Вы также можете найти дополнительную информацию здесь: JLS §8.4.8.4
Ответ 2
JLS §8.4.8.4 говорит,
Наследование методов с переопределяющими эквивалентными сигнатурами
Класс может наследовать несколько методов с переопределяющими эквивалентными сигнатурами (§8.4.2)
...
Может существовать несколько путей, по которым одно и то же объявление метода может быть унаследовано от интерфейса. Этот факт не вызывает затруднений и никогда сам по себе не приводит к ошибке времени компиляции.
Похоже, что обоснование заключается в том, что если класс имеет несколько деклараций с тем же именем и сигнатурой, поскольку класс может унаследовать их через несколько путей - реализация интерфейса, а также подкласс класса, реализующего этот интерфейс, например, - нет вред.
Ответ 3
Предположим, что у нас есть два интерфейса...
public interface StockBroker{
//Give our client some investment strategies.
public String adviseClient(Client c);
}
public interface Doctor{
//Examine our client and give them some medical advice
public String adviseClient(Client c);
}
И класс, реализующий оба интерфейса....
public class JackOfAllTrades implements StockBroker, Doctor{
public String adviseClient(Client c){
}
}
Хотя синтаксически корректно реализовать оба интерфейса с одним методом, вы не можете получить желаемое поведение. Например, биржевой брокер и врач обычно дают своим клиентам совершенно разные советы.
Кто-то, использующий объект, реализующий интерфейс Doctor
, ожидает, что метод adviseClient()
даст медицинскую консультацию. Но кто-то, использующий объект, реализующий интерфейс StockBroker
, ожидает, что метод adviseClient()
выдаст инвестиционные стратегии.
В этом случае объект JackOfAllTrades
не знает, какой совет давать, потому что метод adviseClient()
не имеет параметров, указывающих, какой интерфейс он должен реализовывать при вызове adviseClient()
.
Это недостаток в Java, потому что человек, проектирующий интерфейс Doctor
, возможно, не знал, что кто-то другой разработает интерфейс StockBroker
с той же сигнатурой метода.
Для всех, кто создает интерфейсы, его, вероятно, хорошая практика, чтобы сделать имена методов достаточно уникальными, чтобы столкновения имен были редкими.
Ответ 4
interface A
{
void test();
}
interface B
{
void test();
}
class C implements A, B {
public void test()
{
System.out.println("common to all");
}
public A choose(A a){
return new A(){
public void test() {
System.out.println("test of A");
}
};
}
public B choose(B b){
return new B(){
public void test() {
System.out.println("test of B");
}
};
}
}
class Demo {
public static void main(String[] args) {
C c =new C();
A a = new C();
B b = new B();
a = c.choose(a);
b = c.choose(b);
a.test();
b.test();
}
}
Ответ 5
Не в синтаксисе, но если intent
одного из methods
не соблюдается, его контракт прерывается и код может считаться сломанным..
Используя вашу аналогию, если бы я обещал Майклу носить синюю рубашку вместо красной рубашки, и я не могу носить две рубашки, тогда мне придется сломать хотя бы одно обещание.
То же самое можно использовать для методов: если сохранение одного контракта означало бы размыкание другого, то это на самом деле плохая идея для implement
как interfaces
.
Изменить: контракт сломан, согласно Class C signature
Он должен реализовать два метода, но в конечном итоге реализовать только один method
и опустить другой.
Ссылка