Вопрос-ответ

What is the difference between up-casting and down-casting with respect to class variable

В чем разница между приведением вверх и приведением вниз по отношению к переменной класса

В чем разница между приведением вверх и приведением вниз по отношению к переменной класса?

Например, в следующей программе класс Animal содержит только один метод, а класс Dog содержит два метода, тогда как мы преобразуем переменную Dog в переменную Animal.

Если приведение выполнено, то как мы можем вызвать другой метод Dog с переменной Animal .

class Animal 
{
public void callme()
{
System.out.println("In callme of Animal");
}
}


class Dog extends Animal
{
public void callme()
{
System.out.println("In callme of Dog");
}

public void callme2()
{
System.out.println("In callme2 of Dog");
}
}

public class UseAnimlas
{
public static void main (String [] args)
{
Dog d = new Dog();
Animal a = (Animal)d;
d.callme();
a.callme();
((Dog) a).callme2();
}
}
Переведено автоматически
Ответ 1

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

В вашем случае приведение из a Dog в an Animal является приведением вверх, потому что a Dog это-a Animal. В общем, вы можете выполнять приведение вверх всякий раз, когда между двумя классами существует связь is-a.

Приведение вниз было бы примерно таким:

Animal animal = new Dog();
Dog castedDog = (Dog) animal;

По сути, то, что вы делаете, это сообщаете компилятору, что вы знаете, каков действительно тип объекта во время выполнения. Компилятор разрешит преобразование, но все равно вставит проверку работоспособности во время выполнения, чтобы убедиться, что преобразование имеет смысл. В этом случае приведение возможно, потому что во время выполнения animal фактически является Dog, хотя статический тип animal является Animal.

Однако, если бы вы должны были сделать это:

Animal animal = new Animal();
Dog notADog = (Dog) animal;

Вы получите ClassCastException. Причина в том, что animalтип среды выполнения - Animal, и поэтому, когда вы указываете среде выполнения выполнить приведение, она видит, что animal на самом деле это не a Dog и поэтому выдает a ClassCastException.

Чтобы вызвать метод суперкласса, вы можете выполнить super.method() или выполнив приведение вверх.

Чтобы вызвать метод подкласса, вы должны выполнить приведение вниз. Как показано выше, делая это, вы обычно рискуете ClassCastException; однако вы можете использовать instanceof оператор для проверки типа объекта во время выполнения перед выполнением приведения, что позволяет предотвратить ClassCastExceptions:

Animal animal = getAnimal(); // Maybe a Dog? Maybe a Cat? Maybe an Animal?
if (animal instanceof Dog) {
// Guaranteed to succeed, barring classloader shenanigans
Dog castedDog = (Dog) animal;
}

Понижение может быть выражено более кратко, начиная с Java 16, в которой введено сопоставление с образцом для instanceof:

Animal animal = 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 невозможен напрямую, мы должны сделать это явно.

Dog d = new Dog();
Animal a = (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

Автобоксинг-против-приведения

Ответ 3

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

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

Полиморфизм: все методы в java по умолчанию виртуальные. Это означает, что любой метод может быть переопределен при использовании в наследовании, если только этот метод не объявлен как окончательный или статический.

Вы можете увидеть приведенный ниже пример того, как getType(); работает в соответствии с типом объекта (Dog, Домашнее животное, полицейская собака).

Предположим, у вас есть три собаки


  1. Dog - это суперкласс.



  2. Pet Dog - Pet Dog расширяет Dog.



  3. Police Dog - Полицейская собака расширяет Pet Dog.


    public class Dog{ 
    public String getType () {
    System.out.println("NormalDog");
    return "NormalDog";
    }
    }

    /**
    * Pet Dog has an extra method dogName()
    */

    public class PetDog extends Dog{
    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()
    */

    public class PoliceDog extends PetDog{

    public String secretId() {
    System.out.println("ID");
    return "ID";
    }

    public String getType () {
    System.out.println("I am a Police Dog");
    return "Police Dog";
    }
    }


Полиморфизм : все методы в java по умолчанию являются виртуальными. Это означает, что любой метод может быть переопределен при использовании в наследовании, если только этот метод не объявлен как окончательный или статический.(Объяснение относится к концепции виртуальных таблиц)


Виртуальная таблица / таблица отправки : таблица отправки объекта будет содержать адреса динамически связанных методов объекта. Вызовы методов выполняются путем извлечения адреса метода из таблицы отправки объекта. Таблица отправки одинакова для всех объектов, принадлежащих к одному классу, и поэтому обычно используется совместно между ними.


public static void main (String[] args) {
/**
* Creating the different objects with super class Reference
*/

Dog obj1 = new Dog();
` /**
* Object of Pet Dog is created with Dog Reference since
* Upcasting is done automatically for us we don't have to worry about it
*
*/

Dog obj2 = new PetDog();
` /**
* 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
*/

Dog obj3 = new PoliceDog();
}



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();


  • Но приведение вниз всегда должно выполняться вручную:


    Cat c1 = new Cat();      
    Animal a = c1; //automatic upcasting to Animal
    Cat c2 = (Cat) a; //manual downcasting back to a Cat

Почему это так, что преобразование вверх происходит автоматически, но преобразование вниз должно быть ручным? Ну, вы видите, преобразование вверх никогда не может завершиться неудачей. Но если у вас есть группа разных животных и вы хотите низвести их всех до Кошки, то есть шанс, что некоторые из этих животных на самом деле собаки, и процесс завершится с ошибкой, вызвав исключение ClassCastException .
Именно здесь следует ввести полезную функцию под названием "instanceof", которая проверяет, является ли объект экземпляром некоторого класса.

 Cat c1 = new Cat();         
Animal a = 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.");
Cat c2 = (Cat)a;
}

Для получения дополнительной информации, пожалуйста, прочтите эту статью

java