(Начинающий Java) Понижающая передача / Upcasting / Интерфейс

#java

#java

Вопрос:

Я готовлюсь к экзамену, и я застрял на следующем вопросе.

Будет ли следующее скомпилировано? Если да, будет ли это запущено? Каков результат?

 e) IX i = new C(); A a = (A) i; a.doIt(1.0);

// --- Interfaces and classes
interface IX {void doIt(double d);}

class A implements IX {
public void doIt(double d){out.println("doIt A");}}

class B extends A {public void doIt(int i){out.println("doIt B");}
}

class C extends A{public void doIt(double d){out.println("doIt C");}
}

class D {public void doIt(double d){out.println("doIt D");}
}
  

Итак, я понимаю это после некоторого поиска в Google:

Когда мы говорим, IX i = new C(); мы имеем в виду: мы создаем объект НЕКОТОРОГО типа (и у него есть ссылочная переменная i ), но каким бы типом он ни был, он должен реализовывать интерфейс IX. И прямо сейчас этот тип является C .

Хорошо, затем мы говорим, что ссылочная переменная a , которая ссылается на объект типа A , ссылается на тот же объект, что и i , но после того, как мы приведем ее к (A) .

Итак, когда мы вызываем, a.doit(1.0) компилятор посмотрит на тип, который a имеет, и проверит, есть ли у if вызываемый метод doIt , который принимает double в качестве входных данных. Итак, я предполагаю, что это должно быть распечатано "doIt A" , но я ошибаюсь. Он выводится "doIt C" . Чего я не понимаю? Я действительно пытался погуглить, но я нахожу всю тему понижающей / повышающей передачи довольно запутанной atm.

Комментарии:

1. Эта часть не касается кастинга. Речь идет о переопределении и полиморфизме. Попробуйте поискать их.

2. @JBNizet — Она / Он сделал. -> >> Он выводит «doIt C»<<

3. Все методы в Java по умолчанию являются виртуальными. Реализация класса C и объявление метода таким же образом, как это было сделано в A, указывает на то, что вы переопределяете его. Таким образом, выводится ‘doIt C’. Однако я почти уверен, что компилятор выдал бы некоторые предупреждения, такие как отсутствие аннотации @Override.

4. У вас есть объект типа C . Какие интерфейсы (не interface ) реализует / выполняет этот класс?

5. Это работает как в реальной жизни. Если я дам вам звуковой сигнал, и вы не знаете, что это звуковой сигнал, но все, что вы знаете, это то, что у этого чего-то есть кнопка, на которую можно нажать, тогда, когда вы нажмете на кнопку, она загудит. IX — это «Pushable», A — это «SomeBlackBoxWithAPushableButton». C — это «Звуковой сигнал».

Ответ №1:

 IX i = new C();
  

Создайте новый экземпляр C и присвоите ему статический тип IX — легальный, поскольку C является IX.

 A a = (A) i;
  

Создайте ссылку A и присвоите ей статический тип A. Безопасно во время компиляции и выполнения. Мы знаем, что A является родительским классом C.

 a.doIt(1.0);
  

Отправьте вызов метода объекту a и вызовите метод A::doIt(double).

Этот метод переопределяется фактическим (динамическим) типом C. Поэтому следует напечатать «doIt C».

Ответ №2:

Поправьте меня, если я ошибаюсь, но в нем что-то приведено, например, Bar b = new Bar(); Foo a = Foo(b), где Bar расширяет Foo . Foo имеет метод wobble, а bar имеет переопределенный метод wobble и новый метод wibble. Тогда b не может запускать wibble, но он может запускать wobble. Он будет запускать версию wobble от Bar. Таким образом, по сути, это просто означает, что вы можете запускать только те методы, которые есть у Foo ; не методы, которые есть у Bar. Однако методы Foo, которые переопределяются Bar (такие как wobble), будут запускаться через версию Bar. Предполагается, что интерфейс сбивает вас с толку. Итак, в примере кода:

 abstract class Foo{
    public void wobble() {
        //code A
    }
}

class Bar extends Foo{
    //overridden
    public void wobble() {
        //code B
    }

    public void wibble() {
        //some other code C
    }
}

public class Test {
    public static void main(String[] args) {
        Bar b = new Bar();
        b.wobble(); //runs code B
        b.wibble(); //runs code C

        Foo f = (Foo)b;
        f.wobble(); //runs code B
        f.wibble(); //doesn't compile

        Foo foo2 = new Foo(); //trick cannot instantiate abstract class
        foo2.wobble(); //runs code A (if instantiated which it cant be)
        foo2.wibble(); //will not compile because Foo does not have the wibble method
    }

}
  

Комментарии:

1. когда вы говорите: «foo2.wibble(); // не будет выполняться, потому что у Foo нет метода wibble», вы имеете в виду, что он не будет компилироваться