Правила приведения классов Java - PullRequest
0 голосов
/ 24 апреля 2018
    public static void main(String[] args) {
       new Redwood().go();
    }
    void go() {
       go2(new Tree(), new Redwood());
       go2((Redwood) new Tree(), new Redwood());
    }
    void go2(Tree t1, Redwood r1) {
       Redwood r2 = (Redwood)t1;
       Tree t2 = (Tree)r1;
    }
}

Учитывая, что класс Redwood расширяет Tree, метод main () находится в Redwood, а Tree является пустым классом только с конструктором по умолчанию; ответ на этот вопрос экзамена: «ClassCastException будет выдан, когда код попытается преобразовать дерево в Redwood».

Я хочу знать, почему исключение и где. Насколько я понимаю, вы можете объявить Tree t1 = new Redwood (), так почему я не могу напрямую преобразовать Tree в Redwood?

Ответы [ 4 ]

0 голосов
/ 24 апреля 2018

Переменная типа Tree не содержит объект типа Tree;вместо этого он содержит либо null, либо ссылку на объект, который гарантированно будет использоваться как Tree объект.Аналогично с переменной типа Redwood.

Поскольку Redwood наследуется от Tree, объект Redwood гарантированно будет использоваться как объект Tree, а переменная типа Tree может содержать ссылку на такой объект.Если попытаться преобразовать переменную типа Tree в переменную типа Redwood, такое преобразование будет успешным, если переменная содержит null [поскольку переменная типа Redwood может содержать null], илиесли переменная содержит ссылку на объект, который можно использовать как Redwood [поскольку переменная этого типа может содержать любую такую ​​ссылку], но произойдет сбой, если переменная содержит ссылку на объект, который нельзя использовать как Redwood [переменные типа Redwood не могут содержать ссылки на такие объекты].

Обратите внимание, что если вы попытаетесь привести результат выражения new, система будет вести себя так, как будто этот результат был сохранен ввременная переменная, и приведение было применено к этому.Независимо от того, существует ли какой-либо способ, по которому переменная может фактически содержать ссылку на объект, который можно использовать как Redwood, компилятор может по-прежнему вести себя так, как будто переменная может содержать или не содержать такую ​​ссылку, и обнаруживать, что она не't, когда код выполняется.

0 голосов
/ 24 апреля 2018

Используя приведение, вы по существу говорите компилятору: «Поверь мне. Я профессионал, я знаю, что я делаю, и я знаю, что, хотя ты не можешь гарантировать это, я говорю тебе, что это переменная дерева определенно будет красным деревом. "

Поскольку дерево на самом деле не является красным деревом (это дерево, вы можете сделать Tree tree = new Redwood (); и это будет красное дерево), виртуальная машина выдает исключение во время выполнения, потому что вы нарушили это доверие. (вы сказали компилятору, что все будет хорошо, и это не так!)

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

Поскольку вы, по сути, просто не позволяете компилятору жаловаться, каждый раз, когда вы приводите, важно убедиться, что вы не вызовете ClassCastException, используя instanceof в операторе if (или что-то в этом роде).

взять ссылку http://www.xyzws.com/Javafaq/why-down-casting-throws-classcastexception/125

0 голосов
/ 24 апреля 2018

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

0 голосов
/ 24 апреля 2018

Каждый Redwood является Tree.Вот почему Tree t2 = (Tree) r1; работает.

Не каждый Tree является Redwood.Вот почему Redwood r2 = (Redwood) t1; не будет работать, если t1 является Tree, но не Redwood.

Более формально см. JLS §5.1.6 :

Шесть видов преобразований называются сужающими эталонными преобразованиями:

  • Из любого эталонного типа S в любой эталонный тип T при условии, что S является надлежащим супертипом T (§4.10).

  • Важным частным случаем является то, что существует сужающее ссылочное преобразование из типа класса Object в любой другой ссылочный тип (§4.12.4).

  • Из любого типа класса C в любой непараметрический интерфейс типа K, при условии, что C не является окончательным и не реализует K.

  • Из любого интерфейса типа J влюбой непараметрический тип класса C, который не является окончательным.

  • Из любого интерфейса типа J в любой непараметрический интерфейс типа K, при условии, что J не является подинтерфейсом K.

  • Из типов интерфейса Cloneable и java.io.Serializable для любого массиватип T [].

  • Из любого типа массива SC [] в любой тип массива TC [], при условии, что SC и TC являются ссылочными типами, и существует сужающееся ссылочное преобразование из SC вTC.

Такие преобразования требуют проверки во время выполнения, чтобы выяснить, является ли фактическое эталонное значение допустимым значением нового типа.Если нет, то генерируется исключение ClassCastException.

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