Почему объект суперкласса не может быть неявно преобразован в объект подкласса в Java? - PullRequest
4 голосов
/ 19 марта 2012

У меня есть следующий код:

class A {
}

class B extends A {
    public void fB(){};
}

Согласно правилу Java:

Случай 1:

B b = new B();
A a = b;
((B)a).fB();

Случай 2:

A a = new A();
B b = a;

Согласно правилу Java, Случай 1 в порядке , а Случай 2 не в порядке .Почему Случай 2 не в порядке ?И что на самом деле делает эта строка ((B)a).fB(); (я имею в виду, что происходит внутри)?

Ответы [ 4 ]

14 голосов
/ 19 марта 2012

Почему случай 1 в порядке, а случай 2 не в порядке: потому что Dog является Animal, но не каждый Animal является Dog.

class Animal { }
class Dog extends Animal { }
class Cat extends Animal { }

Dog fifi = new Dog();
Cat tommy = new Cat();

// OK because Dogs and Cats are Animals
Animal pet1 = fifi;
Animal pet2 = tommy;

// Not OK because an Animal is not always a Dog
Dog doggy = pet2;

Обратите внимание, что приведениеничего не делает с объектом;в частности, он не выполняет никакого преобразования объектов.Кастинг только говорит компилятору: «У меня есть этот объект, и я лучше вас знаю, что это такое; я хочу, чтобы вы относились к нему как к типу X и не давали мне никаких сообщений об ошибках».

строка как это:

Dog doggy = pet2;

компилятор будет жаловаться, потому что он не может быть уверен, что pet2 на самом деле Dog;он только знает, что это Animal - и не все Animal с Dog с.Вы можете выполнить приведение, чтобы компилятор не жаловался на это:

// Tell the compiler that you want it to treat pet2 as a Dog
Dog doggy = (Dog)pet2;

Но когда вы запустите программу, Java все равно проверит, действительно ли pet2 является Dog, и если это не так.', вы получите ClassCastException.

(и вопрос в вашем названии совершенно противоположен тому, что вы имеете в виду, как заметил biziclop).

2 голосов
/ 19 марта 2012

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

Теперь вот ваш пример.

Person p = new Person(); // somebody that does not know to do anything special.
Doctor d = (Doctor)p; // do you think that casting makes person that does not know anything to be a doctor?

Хотите ли вы лечить человека, которого «бросили» за доктора?

Я считаю, что ответ ясен.Каждый врач - это человек (случай 1), но не каждый человек является врачом, потому что не каждый человек может лечить.Точно то же самое относится и к иерархии классов.Подкласс наследует свойства своего суперкласса и, вероятно, добавляет свои.Поэтому ни один экземпляр суперкласса не может быть приведен к подклассу.

0 голосов
/ 19 марта 2012

Предположим, что вариант 2 также работает, тогда ваш компилятор видит "b" как объект класса "B".Теперь вы можете сказать "b.fb ()".Но на самом деле «b» - это объект «A» (помните, вы назначили объект класса «A» для «b»).в классе "A" нет функции fb ().ваше приложение вылетает !!

0 голосов
/ 19 марта 2012

Случай 1 в порядке, потому что с (B) частью вы явно указываете компилятору:

, даже если вы знаете только, что a имеет тип AI, я говорю вам, что он имеет типB

, поэтому объект a обрабатывается так, как если бы он был типа B

Случай 2 не подходит, поскольку компилятор не может безопасно назначить b для a.Это будет принято, если вы напишите

A a = new A();
B b = (B)a;

, но это вызовет исключение во время выполнения

...