Интерфейс Java: методы наследования, переопределения и перегрузки - PullRequest
7 голосов
/ 18 мая 2009

В "Языке программирования Java ™, четвертое издание" Кена Арнольда, Джеймса Гослинга, Дэвида Холмса упоминается, что:

пункт: (4.3.2) "Точно так же, если интерфейс наследует более одного метода с одной и той же сигнатурой, или если класс реализует разные интерфейсы, содержащие метод с одной и той же сигнатурой, существует только один такой метод. Реализация этого метода в конечном итоге определяется класс, реализующий интерфейсы, и здесь нет никакой двусмысленности. Если методы имеют одинаковую сигнатуру, но разные возвращаемые типы, то один из возвращаемых типов должен быть подтипом всех остальных, в противном случае возникает ошибка времени компиляции. должен определить метод, который возвращает этот общий подтип. "

Кто-нибудь может дать мне пример кода, который оправдывает пункты вышеупомянутого абзаца?

Я пытался написать код и проверить то, что упоминается, но я получаю ошибку во время компиляции подчиненный интерфейс скрывает метод базового интерфейса, поэтому может реализовывать только метод подчиненного интерфейса.

Заранее спасибо. -Arun

Ответы [ 5 ]

8 голосов
/ 18 мая 2009
interface A {
    void method();
    Object returnMethod();
}
interface B {
    void method();
    B returnMethod();
}

class Impl implements A,B 
{
    void method() { }
    B returnMethod() { }
}

Как видите, Impl.method() реализует оба A.method() и B.method(), в то время как Impl.returnMethod() возвращает B, который является потомком Object, таким образом выполняя контракт A.returnMethod(). Требуется ли последнему тип возвращаемого значения, который не является родителем возвращаемого типа B.returnMethod(), что будет ошибкой компиляции, поскольку в Impl.

такая реализация не может существовать.
2 голосов
/ 18 мая 2009

В следующих двух интерфейсах methodA() идентично определяется в терминах параметров (нет) и типа возвращаемого значения (int). Класс реализации внизу определяет единственный метод с этой точной сигнатурой. Поскольку он соответствует обоим интерфейсам, у вас не возникает проблем - любые вызовы, сделанные через ссылку типа InterfaceA или InterfaceB, будут отправлены этой реализации.

Второй methodB() определяется как возвращающий любой подтип Number (или Number) в InterfaceA. InterfaceB определяет methodB() как возвращающий Integer, который является подтипом Number. Класс реализации фактически реализует метод с Integer, что соответствует контракту как InterfaceA, так и InterfaceB. Здесь тоже нет проблем. Закомментированный случай реализации methodB() как возврата Double, однако, не будет работать: хотя он будет удовлетворять контракту InterfaceA, он будет конфликтовать с InterfaceB (что требует Integer).

Если бы InterfaceA и InterfaceB также указывали (разные) контракты для methodC() (закомментировано в примере), это было бы противоречиво и создавало бы ошибку компилятора. Реализация обеих подписей (различающихся только типом возврата) не разрешена в Java.

Приведенные выше правила также будут выполняться, если добавить методы к методам. Для простоты я исключил это из примера.

public interface InterfaceA {
    public int methodA();
    public Number methodB();
    // public int methodC(); // conflicting return type
}

public interface InterfaceB {
    public int methodA();
    public Integer methodB();
    // public String methodC(); // conflicting return type
}

public class ImplementationOfAandB implements InterfaceA, InterfaceB {
    public int methodA() {
        return 0;
    }
    public Integer methodB() {
        return null;
    }
    // This would NOT work:
    // public Double methodB() {
    //     return null;
    // }
}
1 голос
/ 07 сентября 2011
/**
 * This is what you have
 */
interface IXR {
        //bla-bla-bla
}

class CXR implements IXR {
        //concrete implementation of bla-bla-bla
}

interface IX {
        public IXR f();
} 

interface IYR {
        //some other bla-bla-bla
}

class CYR implements IYR {
        //concrete implementation of the some other bla-bla-bla
} 

interface IY {
        public IYR f();
}






/**
 * This is what you need to add
 */ 
interface IZR extends IXR, IYR {
        //EMPTY INTERFACE
}

class CZXR extends CXR implements IZR {
        //EMPTY CLASS
} 

class CZYR extends CYR implements IZR {
        //EMPTY CLASS
}

class CZ implements IX, IY
{
        public static boolean someCondition = true;

        public IXR implementationOf_X_f()
        {
                System.out.println("CXR");
                return new CZXR();
        }

        public IYR implementationOf_Y_f()
        {
                System.out.println("CYR");
                return new CZYR();
        }

        public IZR f() {
                if (someCondition) {
                        return (IZR) implementationOf_X_f();
                } else {
                        return (IZR) implementationOf_Y_f();
                }
        }

}






/**
 * This is the usage of the required class
 */
class program 
{ 
        public static void main(String[] x) {
                CZ o = new CZ();
                IZR r = o.f();
                if (CZ.someCondition) {
                        CXR xr = (CXR) r;
                        //bla-bla-bla
                } else {
                        CYR yr = (CYR) r;
                        //bla-bla-bla
                }
        }
} /**
 * This is what you have
 */
interface IXR {
        //bla-bla-bla
}

class CXR implements IXR {
        //concrete implementation of bla-bla-bla
}

interface IX {
        public IXR f();
} 

interface IYR {
        //some other bla-bla-bla
}

class CYR implements IYR {
        //concrete implementation of the some other bla-bla-bla
} 

interface IY {
        public IYR f();
}






/**
 * This is what you need to add
 */ 
interface IZR extends IXR, IYR {
        //EMPTY INTERFACE
}

class CZXR extends CXR implements IZR {
        //EMPTY CLASS
} 

class CZYR extends CYR implements IZR {
        //EMPTY CLASS
}

class CZ implements IX, IY
{
        public static boolean someCondition = true;

        public IXR implementationOf_X_f()
        {
                System.out.println("CXR");
                return new CZXR();
        }

        public IYR implementationOf_Y_f()
        {
                System.out.println("CYR");
                return new CZYR();
        }

        public IZR f() {
                if (someCondition) {
                        return (IZR) implementationOf_X_f();
                } else {
                        return (IZR) implementationOf_Y_f();
                }
        }

}






/**
 * This is the usage of the required class
 */
class program 
{ 
        public static void main(String[] x) {
                CZ o = new CZ();
                IZR r = o.f();
                if (CZ.someCondition) {
                        CXR xr = (CXR) r;
                        //bla-bla-bla
                } else {
                        CYR yr = (CYR) r;
                        //bla-bla-bla
                }
        }
}
1 голос
/ 18 мая 2009

Это то, что вы имеете в виду?:

interface A {
    Object get();
}
interface B {
    Number get();
}

abstract class MyClass implements A, B {
    // Try to override A.get, but cause a compile error.
    public Object get() { return null; }
}

Такой метод в MyClass автоматически генерируется javac как метод синтетического моста. Вы должны реализовать один метод, возвращающий тип, совместимый со всеми реализованными / переопределенными методами (в данном случае Number / Integer / Double / etc).

1 голос
/ 18 мая 2009
interface A
{
   void foo();
   //int bar(); <-- conflicts with B.bar() because of different return type
}

interface B
{
   void foo();
   //double bar(); <-- conflicts with A.bar() because of different return type
}

class C implements A, B
{
   void foo() // this implements A.foo() AND B.foo()
   {
      ...
   }
}
...