Как посмотреть, является ли даункатинг легальным в Java? - PullRequest
0 голосов
/ 20 января 2019

Предположим, у меня есть три класса A, B и C.

C расширяет B и B расширяет A. А реализует интерфейс InterfaceA B реализует интерфейсы InterfaceB1 и InterfaceB2.

Как лучше всего найти все возможные комбинации понижения?

Что я имею в виду?

Предположим, у нас есть: B b = новый B (); InterfaceA i = (InterfaceA) (A) (B) b.

Как мы можем легко узнать, компилируется ли это и вызовет ли исключение classcastException без IDE?

Я знаю, как работают объекты и ссылки, и хорошо понимаю полиморфизм в Java.

Я начал рисовать эскиз класса и структуры интерфейса.

РЕДАКТИРОВАТЬ: я знаю, что мой пример не является правильным, но я всегда борюсь, когда интерфейсы присоединяются к истории.

Ответы [ 2 ]

0 голосов
/ 20 января 2019

Прежде всего, в вашем сценарии следующее совсем не является понижением, потому что в описанной иерархии B - это B, B - это A, а B - это InterfaceA. Таким образом, любое из этих приведений может быть опущено.

InterfaceA i = (InterfaceA)(A)(B) b;

Тогда, отвечая на ваш вопрос. Даункастинг будет компилироваться тогда и только тогда, когда это будет возможно во время выполнения. Давайте введем дополнительный класс D, который расширяет класс A и реализует InterfaceB1.

A a = new A();
InterfaceB1 b1 = (InterfaceB1) a; // compilable as A reference can contain object of class B that implements InterfaceB1
InterfaceB2 b2 = (InterfaceB2) a; // compilable as A reference can contain object of class B that implements InterfaceB2
b1 = (InterfaceB1) b2; // compilable as InterfaceB2 reference can contain object of class B that implements both InterfaceB1, InterfaceB2
B b = (B) a; // compilable as A reference can contain object of class B
C c = (C) a; // compilable as A reference can contain object of class C
D d = (D) a; // compilable as A reference can contain object of class D
d = (D) b1; // compilable as InterfaceB1 reference can contain object of class D in runtime

b = (B) d; // not compilable since D reference can NEVER contain object of class B in runtime
c = (C) d; // not compilable since D reference can NEVER contain object of class D in runtime

Что касается создания ClassCastException, оно всегда о том, что на самом деле содержится в ссылке на ваш объект.

A a1 = new A();
A a2 = new B();

InterfaceB1 b1 = (InterfaceB1) a1; // compiles but causes ClassCastException as A cannot be cast to InterfaceB1
InterfaceB1 b2 = (InterfaceB1) a2; // compiles and runs just normally as B can be cast to InterfaceB1
0 голосов
/ 20 января 2019

Давайте сначала разберемся с вопросом «компилируется он или нет».

Ключом к определению этого является взгляд на тип времени компиляции, то есть на объявленный тип переменных.

Обычно,

  • Преобразование из типа интерфейса времени компиляции в тип интерфейса всегда компилируется.
  • Преобразование из типа интерфейса времени компиляции в класс компилируется, только если выполняется одно из следующих условий:
    • класс не является окончательным
    • класс реализует интерфейс
  • Преобразование из типа класса времени компиляции в тип интерфейса компилируется только при наличииверно следующее:
    • класс не является окончательным
    • класс реализует интерфейс
  • Приведение типа класса времени компиляции к другомуТип класса компилируется только в том случае, если один из них наследует от другого класса.

Чтобы определить, успешно ли приведено преобразование во время выполнения, ключ должен посмотреть на тип времени выполнения объекта, хранящегося в переменной.Например:

A a = new B();

Тип времени компиляции a равен A, но тип времени выполнения - B.

Как правило, приведение из класса класса времени выполнения Tк классу или типу интерфейса U успешен, только если T наследуется от U или реализует U.


Для будущих читателей

Если вместо этого вы хотитезнаете, как проверить, успешно ли приведен с использованием кода , вы должны обратиться к этому вопросу .

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