Сигнатура абстрактного метода Java

Я совершенно запутался в сигнатурах абстрактных методов, которые реализуют классы Java.

Например, рассмотрим:

interface Programmer {
    Object program();
}

class Linus implements Programmer {
    public String program() {
        return "goto end;";
    }
}

public class Main {
    public static void main(String[] args) {
        System.out.println(new Linus().program());
    }
}

Это, по-видимому, приемлемо, поскольку все, что ожидает Object от Linus.program(), получит его (в частности, String).

Но теперь подумайте об этом:

interface OS {
    void run(String code);
}

class Linux implements OS {
    public void run(Object code) {
        System.out.println("Hello world");
    }
}

public class Main {
    public static void main(String[] args) {
    new Linux().run("print 'Hello world'");
    }
}

Это не скомпилируется и выдает ошибку:

The type Linux must implement the inherited abstract method OS.run(String)

Теперь можно было ожидать, что что угодно сможет передать String в любой экземпляр интерфейса ОС, и вы, безусловно, можете сделать это с Linux.

Я не вижу причин, по которым второй не может скомпилироваться. Из последствий того, что Java скомпилирует вторую программу, я упустил что-то, что делает это запретительным?


person Paul Draper    schedule 09.03.2013    source источник


Ответы (3)


То, что вы делаете во втором случае, — это перегрузка метода.
Сигнатура метода — это «имя метода» и «количество и типы аргументов»
Во втором случае вы меняете тип аргумента, который компилятор - это другой метод, и он попросит вас реализовать абстрактные (нереализованные) методы. И если вы реализуете методы, присутствующие в интерфейсе public void run(String code), то этот метод public void run(Object code) будет рассматриваться как перегруженный метод.

ПРИМЕЧАНИЕ. Переопределение метода никогда не основывается на типе возвращаемого значения метода. Поскольку возвращаемый тип не считается сигнатурой метода

person asifsid88    schedule 09.03.2013

Вы не можете передать экземпляр базового класса Object вместо экземпляра класса String, но обратное допустимо. В вашей интерфейсной ОС параметр метода запуска имеет тип String, а в классе реализации вы обобщаете параметр как недопустимый тип объекта. Следовательно, компилятор жалуется.

person Drona    schedule 09.03.2013
comment
Это не объясняет. Я обращаюсь к базовому классу Linux. Если бы я вызывал интерфейс ОС, то этот пункт был бы действителен. Базовый класс Linux принимает все объекты, включая строки. - person Paul Draper; 16.03.2013
comment
Суть в том, что вы не можете изменить параметры в контракте, навязанном интерфейсом. Здесь вы меняете тип параметра со String на Object, что технически делает его новым определением метода, а не реализацией контракта интерфейса и, следовательно, ошибкой. - person Drona; 21.03.2013

Вы говорите: «Теперь можно ожидать, что что-нибудь сможет передать строку в любой экземпляр интерфейса ОС, и вы, безусловно, можете сделать это с Linux». => Проблема в том, что вы могли бы, но не обязаны.

Учтите следующее: поскольку версия метода для Linux принимает объект в качестве параметра, вы можете попробовать передать, например, коллекцию. Таким образом, вы не будете уважать интерфейс, который явно ограничивает параметр строкой. Поэтому Linux-версия метода не считается «дочерней» версии для ОС.

И поскольку у каждого метода в интерфейсе должен быть свой «дочерний элемент», компилятор жалуется, что вы не реализовали «дочерний элемент» для OS.run(String)

person Steph    schedule 09.03.2013
comment
Так что же это за код, который был бы двусмысленным или не мог бы работать? - person Paul Draper; 18.03.2013