Как в этом коде был выбран один метод над другим? - PullRequest
6 голосов
/ 25 сентября 2010

Это еще один из тех вопросов SCJP.Код ниже печатает Alpha:fooBeta:fooBeta:barBeta:bar, и я не понимаю, почему первый вызов foo выбрал foo Альфы вместо беты.Если параметр Alpha.foo изменяется на String вместо String ..., то вывод будет Beta:fooBeta:fooBeta:barBeta:bar, что имеет смысл.

Насколько я понимаю, когда вы говорите Alpha a = new Beta();, компилятор проверяет наличие Alpha.foo, но JVM фактически запустит Beta.foo.Во-первых, у Beta есть метод foo, чья сигнатура соответствует вызову.С другой стороны, я думал, что методы varargs запускаются только тогда, когда нет другого доступного метода, соответствующего вызову.Так что это две причины, я думаю, что Alpha.foo не должен запускаться.Какая часть этого понимания неверна?

Спасибо!

class Alpha {

    public void foo(String... args) { //if this were String args, then it makes sense
        System.out.print("Alpha:foo");
    }

    public void bar(String a) {
        System.out.print("Alpha:bar");
    } }

public class Beta extends Alpha {

    public void foo(String a) {
        System.out.print("Beta:foo");
    }

    public void bar(String a) {
        System.out.print("Beta:bar");
    }

    public static void main(String[] arg) {
        Alpha a = new Beta();
        Beta b = (Beta) a;
        a.foo("test");//confusing line
        b.foo("test");
        a.bar("test");
        b.bar("test");
    } }

Редактировать: Мне кажется, я знаю, где я теперь неправильно понял вещи.Я думал, что в ситуации SuperClass sc = new SubClass(); любой метод, вызываемый на sc, будет найден в SubClass во время выполнения, хотя он будет найден в SuperClass во время компиляции.Оказывается, как я теперь понимаю, я понимаю, что любой метод, вызываемый в sc, будет искать в SuperClass в и во время компиляции и во время выполнения, UNLESS SubClass предоставил «лучшую» версиюметод.Тогда даже во время компиляции компилятор будет знать, что вызываемый метод является версией подкласса.

Ответы [ 5 ]

6 голосов
/ 25 сентября 2010

Метод с параметром String[] или String... и метод с параметром String не имеют одинаковую сигнатуру.Массив строк - это совершенно отдельный тип, поэтому он является стандартной перегрузкой и полиморфизма не происходит.Компилятор видит, что это экземпляр типа «Альфа», и вызывает найденный там метод foo.Метод foo в бета-версии не вызывается, поскольку он не является переопределением альфа-версии.

(Здесь удобна аннотация @Override. Если вы попытаетесь использовать ее в бета-версии foo, вы получите ошибку компилятора.)

4 голосов
/ 25 сентября 2010

Перегрузка метода реализована во время компиляции, переопределение метода - во время выполнения.

В вашем случае foo в Beta не переопределяет foo в Alpha. Он перегружает его различными аргументами (Вы можете доказать это, добавив аннотацию @Override, которая является наилучшей практикой для обнаружения таких не столь очевидных потенциальных проблем).

Еще одна хитрость в том, что вы не можете вызвать Alpha#foo(..) из ссылки Beta - т.е. b.foo("test") всегда будет вызывать метод не-varargs. Как это происходит, смотрите в этом вопросе

2 голосов
/ 25 сентября 2010

Когда вы говорите Super a = new Sub (); и сделайте a.methodCall (); применяется следующее правило ..

Проверьте, есть ли у подкласса метод, который переопределяет метод в суперклассе и вызывает его.

Но здесь метод в подклассе не переопределяет, а перегружает метод в супер, поэтому вызывается реализация суперкласса. Когда вы делаете аргументы для двух методов одинаковы. Тогда применяется главный принцип.

2 голосов
/ 25 сентября 2010

Поскольку методы a и b "foo ()" не имеют одинаковую сигнатуру, метод b "foo ()" не переопределяет метод "foo ()".

По этой причине, когда вы вызываете "a.foo ()", Alpha.foo ().

Чтобы убедиться в этом, вы можете попробовать добавить аннотацию "@Override" в "b.foo ()метод.Это приведет к ошибке компиляции (так как "b.foo ()" ничего не переопределяет).

0 голосов
/ 25 сентября 2010

Переопределение происходит во время выполнения, здесь в вашем случае вы не переопределяете метод foo, так как параметры методов в суперклассе и подклассе различаются. Метод с параметром String[] or String... и метод с параметром String не то же самое.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...