Система типов Java: почему эти назначения, вызовы методов и приведение типов не выполняются? - PullRequest
0 голосов
/ 12 ноября 2018

Допустим, у меня определены следующие интерфейс и классы:

public interface I { void a(); }

public class A implements I {
    public void a() { System.out.println("A"); }
}

public class B implements I {
    public void a() { System.out.println("B"); }
    public void b() { System.out.println("C"); }
}

И затем я запускаю следующий код:

public class Main {
    public static void main(String[] args) {
        A a = new A();
        B b = new B();
        I i;
        i = a;
        i.a();    // prints "A"
        i = b;
        i.a();    // prints "B"
        i.b();    // 1st problem: i can't seem to find method b. Why?
        b = i;    // 2nd problem: b can't be assigned to i although i references an object of class B?
        b = (B)i; //              why does this work fine...
        a = (A)i; // 3rd problem: ...but this here doesn't?
    }
}

Итак, вот мои вопросы:

Первая проблема

Почему нельзя вызвать i.b()?

i указывает на тот же объект, что и b, объект класса B, который имеетметод b.

Так почему i.a() вызывает правильный метод (тот, который выводит "B"), но i.b() не разрешает вообще?

Имеет ли факт, что i был объявлен как тип I (интерфейс), какое-либо отношение к этому?Означает ли это, что в присваивании X x = new Y(), где Y extends X, можно вызывать только те методы x, которые уже объявлены в X, а не только для Y?

SecondПроблема

Почему нельзя b присвоить i, хотя i ссылается на объект класса B?b и i уже ссылаются на один и тот же объект, не так ли?Так почему же это вызывает ошибку, если я пытаюсь присвоить b i - конечный результат которого должен быть идентичен состоянию программы до этого назначения, если я что-то не пропустил

Третья проблема

Почему я могу привести i к типу B сейчас, хотя я не мог присвоить b к i ранее, и почему не кастуетi до A работа?

Я предполагаю, что мое заблуждение каким-то образом коренится в неясном различении между ссылочными переменными и объектами, на которые они ссылаются, а также различиях между типами этихпеременные и объекты.Я просто не могу объяснить эти случаи, в частности, первая проблема меня сильно смущает.

Ответы [ 3 ]

0 голосов
/ 12 ноября 2018

Прежде всего, изучите Java (и / или OO (объектно-ориентированное) ) программирование ...

  1. Переменная i является ссылкой на экземпляр объекта, который реализует интерфейс I. Метод b() не был объявлен в интерфейсе I, поэтому он не виден через i.b().
    Чтобы его можно было вызвать, необходимо выполнить i, например: ((B) i).b()
  2. Переменная b является ссылкой на объект, который является экземпляром класса B, и не может быть назначена какой-либо ссылке, которая сама не объявлена ​​как экземпляр B.
    Опять же, необходим актерский состав, например: b = (B) i
  3. Класс B не является потомком класса A. Они оба реализуют интерфейс I, но A не является родителем B.
0 голосов
/ 12 ноября 2018

Это совсем не проблема, но это поведение наследования и полиморфизма.

Обратите внимание, что когда вы

I i = new A();

Левая часть (I) сообщит компилятору, какие методы он может вызывать с использованием этой ссылки.

Правая часть (A) сообщит среде выполнения, какой метод должен выполняться с использованием этого вызова метода

Так в вашем случае

1 Задача

вы не можете позвонить b(), поскольку b() нет в inteface I

2 Задача

вы приводите интерфейс к объекту b, а затем вызываете b(), чтобы он работал нормально.

0 голосов
/ 12 ноября 2018

Для первой задачи: Вы можете использовать ссылку на интерфейс для вызова только методов, которые она объявляет

Для второй задачи: Вы можете использовать ссылку на интерфейс для вызова методов в классах, которые реализуют интерфейс. Однако назначать ссылку на интерфейс для ссылки на класс не имеет смысла, так как ссылка на интерфейс не имеет методов, которые могут быть вызваны.

для третьей задачи: Вы назначили ранее

        i=b 

и, следовательно,

     b=(B)i 

отлично работает.

Тем не менее, а = (А) я не будет работать, потому что я храню б, а не

...