What is the difference between up-casting and down-casting with respect to class variable
В чем разница между приведением вверх и приведением вниз по отношению к переменной класса
В чем разница между приведением вверх и приведением вниз по отношению к переменной класса?
Например, в следующей программе класс Animal содержит только один метод, а класс Dog содержит два метода, тогда как мы преобразуем переменную Dog в переменную Animal.
Если приведение выполнено, то как мы можем вызвать другой метод Dog с переменной Animal .
classAnimal { publicvoidcallme() { System.out.println("In callme of Animal"); } }
classDogextendsAnimal { publicvoidcallme() { System.out.println("In callme of Dog"); }
publicvoidcallme2() { System.out.println("In callme2 of Dog"); } }
Повышающее преобразование приводит к супертипу, в то время как понижающее преобразование приводит к подтипу. Повышающее преобразование всегда разрешено, но понижающее преобразование включает проверку типа и может вызвать ClassCastException.
В вашем случае приведение из a Dog в an Animal является приведением вверх, потому что a Dog это-a Animal. В общем, вы можете выполнять приведение вверх всякий раз, когда между двумя классами существует связь is-a.
По сути, то, что вы делаете, это сообщаете компилятору, что вы знаете, каков действительно тип объекта во время выполнения. Компилятор разрешит преобразование, но все равно вставит проверку работоспособности во время выполнения, чтобы убедиться, что преобразование имеет смысл. В этом случае приведение возможно, потому что во время выполнения animal фактически является Dog, хотя статический тип animal является Animal.
Вы получите ClassCastException. Причина в том, что animalтип среды выполнения - Animal, и поэтому, когда вы указываете среде выполнения выполнить приведение, она видит, что animal на самом деле это не a Dog и поэтому выдает a ClassCastException.
Чтобы вызвать метод суперкласса, вы можете выполнить super.method() или выполнив приведение вверх.
Чтобы вызвать метод подкласса, вы должны выполнить приведение вниз. Как показано выше, делая это, вы обычно рискуете ClassCastException; однако вы можете использовать instanceof оператор для проверки типа объекта во время выполнения перед выполнением приведения, что позволяет предотвратить ClassCastExceptions:
Animalanimal= getAnimal(); // Maybe a Dog? Maybe a Cat? Maybe an Animal? if (animal instanceof Dog) { // Guaranteed to succeed, barring classloader shenanigans DogcastedDog= (Dog) animal; }
Animalanimal= getAnimal(); // Maybe a Dog? Maybe a Cat? Maybe an Animal? if (animal instanceof Dog castedDog) { // now castedDog is available here as in the example above }
Ответ 2
Приведение вниз и приведение вверх было следующим:
Апкастинг: когда мы хотим преобразовать подкласс в суперкласс, мы используем апкастинг (или расширение). Это происходит автоматически, нет необходимости делать что-либо явно.
Даункастинг : когда мы хотим привести суперкласс к подклассу, мы используем даункастинг (или сужение), а даункастинг в Java невозможен напрямую, мы должны сделать это явно.
Dogd=newDog(); Animala= (Animal) d; //Explicitly you have done upcasting. Actually no need, we can directly type cast like Animal a = d; compiler now treat Dog as Animal but still it is Dog even after upcasting d.callme(); a.callme(); // It calls Dog's method even though we use Animal reference. ((Dog) a).callme2(); // Downcasting: Compiler does know Animal it is, In order to use Dog methods, we have to do typecast explicitly. // Internally if it is not a Dog object it throws ClassCastException
Преобразование вверх и преобразование вниз являются важной частью Java, которая позволяет нам создавать сложные программы, используя простой синтаксис, и дает нам большие преимущества, такие как полиморфизм или группирование различных объектов. Java позволяет обрабатывать объект типа подкласса как объект любого типа суперкласса. Это называется повышающим преобразованием. Преобразование вверх выполняется автоматически, в то время как преобразование вниз должно выполняться программистом вручную, и я собираюсь сделать все возможное, чтобы объяснить, почему это так.
Преобразование вверх и преобразование вниз НЕ похоже на преобразование примитивов из одного в другой, и я полагаю, что именно это вызывает много путаницы, когда программист начинает изучать преобразование объектов.
Полиморфизм: все методы в java по умолчанию виртуальные. Это означает, что любой метод может быть переопределен при использовании в наследовании, если только этот метод не объявлен как окончательный или статический.
Вы можете увидеть приведенный ниже пример того, как getType(); работает в соответствии с типом объекта (Dog, Домашнее животное, полицейская собака).
Предположим, у вас есть три собаки
Dog - это суперкласс.
Pet Dog - Pet Dog расширяет Dog.
Police Dog - Полицейская собака расширяет Pet Dog.
publicclassDog{ public String getType() { System.out.println("NormalDog"); return"NormalDog"; } }
/** * Pet Dog has an extra method dogName() */ publicclassPetDogextendsDog{ public String getType() { System.out.println("PetDog"); return"PetDog"; } public String dogName() { System.out.println("I don't have Name !!"); return"NO Name"; } }
/** * Police Dog has an extra method secretId() */ publicclassPoliceDogextendsPetDog{
public String secretId() { System.out.println("ID"); return"ID"; }
public String getType() { System.out.println("I am a Police Dog"); return"Police Dog"; } }
Полиморфизм : все методы в java по умолчанию являются виртуальными. Это означает, что любой метод может быть переопределен при использовании в наследовании, если только этот метод не объявлен как окончательный или статический.(Объяснение относится к концепции виртуальных таблиц)
Виртуальная таблица / таблица отправки : таблица отправки объекта будет содержать адреса динамически связанных методов объекта. Вызовы методов выполняются путем извлечения адреса метода из таблицы отправки объекта. Таблица отправки одинакова для всех объектов, принадлежащих к одному классу, и поэтому обычно используется совместно между ними.
publicstaticvoidmain(String[] args) { /** * Creating the different objects with super class Reference */ Dogobj1=newDog(); ` /** * Object of Pet Dog is created with Dog Reference since * Upcasting is done automatically for us we don't have to worry about it * */ Dogobj2=newPetDog(); ` /** * Object of Police Dog is created with Dog Reference since * Upcasting is done automatically for us we don't have to worry * about it here even though we are extending PoliceDog with PetDog * since PetDog is extending Dog Java automatically upcast for us */ Dogobj3=newPoliceDog(); }
obj1.getType();
С принтами Normal Dog
obj2.getType();
С принтами Pet Dog
obj3.getType();
С принтами Police Dog
Приведение вниз должно выполняться программистом вручную
При попытке вызвать secretID(); метод для obj3 которого естьPoliceDog object, но на который есть ссылка Dog который является суперклассом в иерархии, он выдает ошибку, поскольку obj3 нет доступа к secretId() методу.Чтобы вызвать этот метод, вам нужно вручную преобразовать этот obj3 вPoliceDog
( (PoliceDog)obj3).secretID();
который выводит ID
Аналогичным образом для вызова dogName();метода в PetDog классе вам нужно понизить значение obj2 до PetDog, поскольку obj2 ссылается на Dog и не имеет доступа к dogName(); методу
( (PetDog)obj2).dogName();
Почему это так, что преобразование вверх происходит автоматически, но преобразование вниз должно быть ручным? Ну, вы видите, преобразование вверх никогда не может завершиться неудачей. Но если у вас есть группа разных Dogs и вы хотите понизить их все до a по их типам, тогда есть шанс, что некоторые из этих Dogs на самом деле разных типов, т.Е., PetDog, PoliceDog, и процесс завершится с ошибкой, выбросив ClassCastException.
Это причина, по которой вам нужно понизить ваши объекты вручную, если вы ссылались на свои объекты с типом суперкласса.
Примечание: Здесь под ссылками подразумевается, что вы не меняете адрес памяти своих объектов, когда вы понижаете его, он все равно остается тем же, вы просто группируете их к определенному типу в этом случае Dog
Ответ 4
Я знаю, что этот вопрос задавался довольно давно, но для новых пользователей этого вопроса. Пожалуйста, прочтите эту статью, где содержится полное описание преобразования вверх, преобразования вниз и использования оператора instanceof
Нет необходимости выполнять приведение вручную, это происходит само по себе:
Mammal m = (Mammal)new Cat(); равно Mammal m = new Cat();
Но приведение вниз всегда должно выполняться вручную:
Catc1=newCat(); Animala= c1; //automatic upcasting to Animal Catc2= (Cat) a; //manual downcasting back to a Cat
Почему это так, что преобразование вверх происходит автоматически, но преобразование вниз должно быть ручным? Ну, вы видите, преобразование вверх никогда не может завершиться неудачей. Но если у вас есть группа разных животных и вы хотите низвести их всех до Кошки, то есть шанс, что некоторые из этих животных на самом деле собаки, и процесс завершится с ошибкой, вызвав исключение ClassCastException . Именно здесь следует ввести полезную функцию под названием "instanceof", которая проверяет, является ли объект экземпляром некоторого класса.
Catc1=newCat(); Animala= c1; //upcasting to Animal if(a instanceof Cat){ // testing if the Animal is a Cat System.out.println("It's a Cat! Now i can safely downcast it to a Cat, without a fear of failure."); Catc2= (Cat)a; }
Для получения дополнительной информации, пожалуйста, прочтите эту статью