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

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

public class Inheritance {

    public static class Animal {        
        public void Scream() {
            System.out.println("I'm an animal");
        }       
    }

    public  static class Mammal extends Animal{
        public void Scream(){
            System.out.println("I'm a mammal");
        }       
    }

    public  static class Tiger extends Mammal{
        public void Scream(){
            System.out.println("I'm a tiger");
        }       
    }

    public static void main (String[] args){

        Animal tiger = new Tiger();
        tiger.Scream(); //true

        Object tiger = new Tiger();
        tiger.Scream(); //false

        Object tiger = new Tiger();
        ((Animal) tiger).Scream(); //true

    }

}

Ответы [ 4 ]

5 голосов
/ 23 марта 2012

Вы хотите знать, почему мы используем явное приведение типов. это все о наследовании -

Позвольте мне прояснить это - Предположим, у нас есть два класса Класс A и Класс B . И Класс B является подклассом класса A . Это означает, что Класс B имеет все функциональные возможности Класс A , это означает, что Класс B может делать все, что может Класс A . Так что если

 A a = new B();

прекрасно, потому что Класс B может делать то, что может Класс A . Здесь ссылка varaible a имеет тип класса A, из которого будет вызываться метод класса A. Теперь объект B (new B ();) обладает всеми функциональными возможностями: Класс A (как Наследование), поэтому все методы Класс A будут задействованы.

Если мы изменим условие следующим образом ->

      B b =new A();

Невозможно, потому что Класс B может реализовывать свои собственные функции (методы и переменные), которых нет в Класс A . Но здесь ссылочная переменная имеет тип B , все функции класса B будут активированы, но фактический объект имеет тип A , поэтому возникнет ошибка.

Тот же случай с Объект класса . Поскольку все остальные классы автоматически наследуют Объект Класс.

Поэтому, когда любому объекту, имеющему ссылочную переменную типа Class Object, требуется явное приведение, потому что это не уверенно, какие более или менее функциональные возможности содержатся в этом объекте.

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

Поскольку Scream() не объявлен как открытый метод Object, его нельзя вызвать для переменной типа Object. Компилятор знает только переменные (ссылки) типа static , поэтому он не может ни сказать, ни проверить, что эта ссылка будет указывать на объект типа Tiger во время выполнения (который будет его динамический тип). Вот почему вы получаете ошибку компиляции.

Вы можете сказать, что для компилятора было бы тривиально проверить динамический тип в приведенном выше случае, что более или менее правильно. Однако в реальной жизни это обычно не так просто. Рассмотрим

Factory factory = new SomeFactory();
Object obj = factory.getProduct(param);
// What is obj's dynamic type?

Компилятор теоретически может обнаружить, что динамический тип factory равен SomeFactory. Затем все, что нужно сделать, это статически проанализировать код в SomeFactory.getProduct(), чтобы определить тип возвращаемого продукта. Конечно, getProduct может возвращать различные типы реальных продуктов в зависимости от его параметров. Таким образом, компилятор должен был бы обнаружить возможное значение (я) param в момент вызова ... Который может поступать из любого количества источников, например, пользовательский ввод, файл конфигурации, БД ... Но даже если все это было преодолимо, конкретный класс продукта может загружаться динамически загрузчиком классов во время выполнения из файла JAR, который может даже не быть доступен во время компиляции. Таким образом, компилятор может даже не знать о существовании этого конкретного класса, а тем более о его открытом интерфейсе.

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

Дано утверждение: Object o = new Tiger();

Тип переменной (Object) контролирует доступные вам взаимодействия (методы), а тип значения (Tiger) контролирует поведение, выполняемое для данного взаимодействия.

Используя ссылку на объект для экземпляра Tiger, как в этом примере, вы говорите, что хотите использовать экземпляр Tiger в качестве объекта. Ну, у объекта нет метода Scream(), поэтому он не даст вам такой возможности. Если вы хотите иметь возможность Scream(), используйте его как тип, который действительно знает, как Scream(), как Animal или Mammal

Кстати, методы должны начинаться со строчной буквы

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

Как только вы присвоили tiger ссылку Object, компилятор больше не знает, что это на самом деле Tiger.Все, что он знает, это то, что объект tiger является Object - это может быть String, Integer, Fruitcake или Animal.

Это именно то, что предполагаетсяна работу.

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