¿Cuál es la diferencia entre up-cast y down-cast con respecto a la variable de clase

138

¿Cuál es la diferencia entre up-cast y down-cast con respecto a la variable de clase?

Por ejemplo, en la siguiente clase de programa Animal contiene solo un método, pero la clase Dog contiene dos métodos, y luego cómo convertimos la variable Dog en Animal Variable.

Si se realiza el lanzamiento, ¿cómo podemos llamar al perro otro método con la variable 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();
    }
}
Dhivakar
fuente
A Doges un Animal. La mayoría de las veces la transmisión es innecesaria a menos que desee utilizar un cierto método sobrecargado. callmeexiste en ambos Animaly Dog. callme2solo existe en Dog, en el que echas apara Dogque funcione.
Brian
¿Cuál es el resultado de su código?
Malwinder Singh
¡Lo interesante es que d.callme devuelve 'In callme of Dog' aunque d fue lanzado a un animal!
Chris311
44
@ Chris311, tanto 'd' como 'a' apuntan al mismo objeto ... que es un perro, pero 'a' solo tiene acceso a métodos específicos de perro cuando está desactivado en tiempo de ejecución. De hecho: Animal a = (Animal) d; es innecesario, solo necesitas Animal a = d; mientras estás volteando
Mark Keen

Respuestas:

223

Upcasting se convierte a un supertipo, mientras que downcasting se convierte a un subtipo. La conversión hacia arriba siempre está permitida, pero la conversión hacia abajo implica una verificación de tipo y puede arrojar un ClassCastException.

En su caso, un reparto de un Doga un Animales un upcast, porque un Dogis-a Animal. En general, puede transmitir cuando haya una relación is-a entre dos clases.

Downcasting sería algo como esto:

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

Básicamente lo que hace es decirle al compilador que usted sabe lo que el tipo de ejecución del objeto realmente es. El compilador permitirá la conversión, pero seguirá insertando una comprobación de sanidad en tiempo de ejecución para asegurarse de que la conversión tenga sentido. En este caso, la conversión es posible porque en tiempo de ejecución animales realmente Dogaunque el tipo estático de animales Animal.

Sin embargo, si hicieras esto:

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

Conseguirías un ClassCastException. La razón es porque animalel tipo de tiempo de ejecución es Animal, y cuando le dices al tiempo de ejecución que realice el lanzamiento, ve que animalno es realmente a Dogy por lo tanto arroja a ClassCastException.

Para llamar al método de una superclase, puede hacerlo super.method()o realizando la transmisión ascendente.

Para llamar al método de una subclase, debe hacer un downcast. Como se muestra arriba, normalmente corre el riesgo ClassCastExceptionde hacer esto; sin embargo, puede usar el instanceofoperador para verificar el tipo de tiempo de ejecución del objeto antes de realizar el lanzamiento, lo que le permite evitar 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;
}
awksp
fuente
¿La bajada adecuada asegura que no ClassCastExceptiono no? ¿Como en el primer caso?
Malwinder Singh
@MS ¿Qué quieres decir con "adecuado"?
awksp
2
@awksp Esta es una respuesta excelente y articulada. Resume casi todo lo que necesito saber sobre Casting.
Gautham Honnavara
seguramente no has hecho clases donde el animal es una instancia de perro, ¿verdad? Entonces, ¿por qué lo estás buscando?
barlop
62

Down-casting y up-casting fue el siguiente:
ingrese la descripción de la imagen aquí

Upcasting : cuando queremos lanzar una Subclase a Super class, usamos Upcasting (o ensanchamiento). Sucede automáticamente, no es necesario hacer nada explícitamente.

Downcasting : cuando queremos lanzar una Superclase a Subclase, usamos Downcasting (o estrechamiento), y Downcasting no es directamente posible en Java, explícitamente tenemos que hacerlo.

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
Premraj
fuente
Entonces, ¿no hay tal forma de hacer una transmisión para llamar al padre del método?
karlihnos
32

Upcasting y downcasting son una parte importante de Java, que nos permite crear programas complicados utilizando una sintaxis simple y nos brinda grandes ventajas, como el polimorfismo o la agrupación de diferentes objetos. Java permite que un objeto de un tipo de subclase sea tratado como un objeto de cualquier tipo de superclase. Esto se llama upcasting. La transmisión se realiza automáticamente, mientras que la programación debe realizarla manualmente el programador , y voy a dar lo mejor de mí para explicar por qué es así.

Subir y bajar NO es como lanzar primitivas de uno a otro, y creo que eso es lo que causa mucha confusión, cuando el programador comienza a aprender a lanzar objetos.

Polimorfismo: todos los métodos en Java son virtuales por defecto. Eso significa que cualquier método puede anularse cuando se usa en herencia, a menos que ese método se declare como final o estático .

Puede ver el siguiente ejemplo de cómo getType();funciona según el tipo de objeto (perro, mascota, perro policía).

Supongamos que tienes tres perros

  1. Perro: esta es la superclase.

  2. Pet Dog - Pet Dog extiende Dog.

  3. Perro policía - Perro policía extiende perro mascota.

    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";
     }
    }

Polimorfismo: todos los métodos en Java son virtuales por defecto. Eso significa que cualquier método puede anularse cuando se usa en herencia, a menos que ese método se declare como final o estático (la explicación pertenece al concepto de tablas virtuales)

Tabla virtual / Tabla de despacho: la tabla de despacho de un objeto contendrá las direcciones de los métodos vinculados dinámicamente del objeto. Las llamadas a métodos se realizan recuperando la dirección del método de la tabla de despacho del objeto. La tabla de despacho es la misma para todos los objetos que pertenecen a la misma clase y, por lo tanto, generalmente se comparte entre ellos.

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

Huellas dactilares Normal Dog

  obj2.getType();

Huellas dactilares Pet Dog

 obj3.getType();

Huellas dactilares Police Dog

El programador debe realizar el downcasting manualmente

Cuando intenta invocar el secretID();método en el obj3cual se hace PoliceDog objectreferencia a Dogcuál es una superclase en la jerarquía, arroja un error ya obj3que no tiene acceso al secretId()método. Para invocar ese método, necesita Downcast que obj3 manualmente para PoliceDog

  ( (PoliceDog)obj3).secretID();

que imprime ID

De forma similar para invocar el dogName();método en PetDogla clase que necesita abatido obj2a PetDogdesde obj2 está referenciada a Dogy no tienen acceso a dogName();método

  ( (PetDog)obj2).dogName();

¿Por qué es así, que la transmisión es automática, pero la descarga debe ser manual? Bueno, ya ves, la transmisión nunca puede fallar. Pero si usted tiene un grupo de perros diferentes y desea abatido a todos ellos a una de sus tipos, entonces existe la posibilidad de que algunos de estos perros son en realidad de diferentes tipos, es decir, PetDog, PoliceDog, y el proceso falla, lanzando ClassCastException.

Esta es la razón por la que necesita bajar sus objetos manualmente si ha hecho referencia a sus objetos al tipo de superclase.

Nota: Aquí al hacer referencia significa que no está cambiando la dirección de memoria de sus objetos cuando los rechaza, sigue siendo la misma, solo los está agrupando a un tipo particular en este caso Dog

Nagarjuna Yelisetty
fuente
'El polimorfismo utiliza el rechazo automático durante las llamadas a métodos'. No, no lo hace. El mecanismo utilizado no se especifica, pero el mecanismo más habitual, una vtable, no hace tal cosa. Mira en el código objeto. No abatido.
Marqués de Lorne
Por qué no? Esto es lo que sucede, ¿puedes dar un ejemplo donde no funcionará?
Nagarjuna Yelisetty
1
Por qué no? Esto es lo que sucede bien ... ¿puede dar un ejemplo en el que la afirmación "El polimorfismo utiliza el rechazo automático durante las llamadas a métodos". fallará o no será verdad?
Nagarjuna Yelisetty
Es tu contención. Depende de usted demostrarlo. Mostrar en qué parte del código objeto se produce el downcast. La respuesta a la pregunta 'por qué no' es 'porque no es necesario'. El vtable se encarga del envío del método, y la variable ya apunta a todo el objeto.
Marqués de Lorne
1
"Según mi conocimiento, mis declaraciones son verdaderas y se cumple en todos los casos" no es una prueba. Es una mera afirmación. Le pido que pruebe sus declaraciones. No lo estas haciendo. En efecto, solo te estás repitiendo. Y ya he proporcionado varias refutaciones. También he proporcionado un procedimiento de decisión. Si puede encontrar un downcast en el código objeto para una llamada al método, tiene razón y me equivoco. Así es como se hace la ciencia. Hazlo. Y afirmar que estoy 'audazmente dependiendo de la documentación' es una tergiversación flagrante. No hagas eso.
Marqués de Lorne
12

Sé que esta pregunta se hizo hace bastante tiempo, pero para los nuevos usuarios de esta pregunta. Lea este artículo donde contiene una descripción completa sobre la transmisión, la descarga y el uso de la instancia del operador

  • No hay necesidad de transmitir manualmente, sucede solo:

    Mammal m = (Mammal)new Cat(); igual a Mammal m = new Cat();

  • Pero el downcasting siempre debe hacerse manualmente:

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

¿Por qué es así, que la transmisión es automática, pero la descarga debe ser manual? Bueno, ya ves, la transmisión nunca puede fallar. Pero si tiene un grupo de animales diferentes y desea rechazarlos a un gato, existe la posibilidad de que algunos de estos animales sean perros y el proceso falle lanzando ClassCastException. Aquí es donde debe introducir una característica útil llamada "instancia de" , que prueba si un objeto es una instancia de alguna clase.

 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;
    }

Para más información por favor lea este artículo

Nadeesha Thilakarathne
fuente
buen punto: Mamífero m = (Mamífero) nuevo Gato (); es igual a Mamífero m = nuevo Cat ();
Catbuilts
6

Mejor pruebe este método para la transmisión, es fácil de entender:

/* upcasting problem */
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) 
    {
        Animal animal = new Animal ();
        Dog dog = new Dog();
        Animal ref;
        ref = animal;
        ref.callme();
        ref = dog;
        ref.callme();
    }
}
UWAIS
fuente
y en la última línea podría ser: ((Dog) ref) .callme2 (); // para el acceso al método downcasting / estrechamiento y callme2 () de la clase Dog.
udarH3
6

Quizás esta tabla ayude. Llamando al callme()método de clase Parento clase Child. Como principio

ACTUALIZACIÓN -> Ocultar

DOWNCASTING -> Revelando

ingrese la descripción de la imagen aquí

ingrese la descripción de la imagen aquí

ingrese la descripción de la imagen aquí

Alexis
fuente
4

1.- Upcasting.

Al realizar una conversión ascendente, define una etiqueta de algún tipo, que apunta a un objeto de un subtipo (Tipo y subtipo pueden llamarse clase y subclase, si se siente más cómodo ...).

Animal animalCat = new Cat();

Lo que significa que dicha etiqueta, animalCat, tendrá la funcionalidad (los métodos) de tipo Animal solamente, porque la hemos declarado como tipo Animal, no como tipo Cat.

Se nos permite hacerlo de forma "natural / implícita / automática", en tiempo de compilación o en tiempo de ejecución, principalmente porque Cat hereda parte de su funcionalidad de Animal; por ejemplo, move (). (Al menos, el gato es un animal, ¿no?)

2.- Downcasting.

Pero, ¿qué sucedería si necesitamos obtener la funcionalidad de Cat, de nuestra etiqueta Animal tipo?

Como hemos creado la etiqueta animalCat que apunta a un objeto Cat, necesitamos una forma de llamar a los métodos del objeto Cat, desde nuestra etiqueta animalCat de una manera bonita e inteligente.

Tal procedimiento es lo que llamamos Downcasting, y solo podemos hacerlo en tiempo de ejecución.

Tiempo para un código:

public class Animal {
    public String move() {
        return "Going to somewhere";
    }
}

public class Cat extends Animal{
    public String makeNoise() {
        return "Meow!";
    }   
}

public class Test {

    public static void main(String[] args) {
        
    //1.- Upcasting 
    //  __Type_____tag________object
        Animal animalCat = new Cat();
    //Some animal movement
        System.out.println(animalCat.move());
        //prints "Going to somewhere"
        
    //2.- Downcasting   
    //Now you wanna make some Animal noise.
        //First of all: type Animal hasn't any makeNoise() functionality.
        //But Cat can do it!. I wanna be an Animal Cat now!!
        
        //___________________Downcast__tag_____ Cat's method
        String animalNoise = ( (Cat) animalCat ).makeNoise();
        
        System.out.println(animalNoise);
        //Prints "Meow!", as cats usually done.
        
    //3.- An Animal may be a Cat, but a Dog or a Rhinoceros too.
        //All of them have their own noises and own functionalities.
        //Uncomment below and read the error in the console:
        
    //  __Type_____tag________object
        //Cat catAnimal = new Animal();
        
    }

}
Lemmy_Caution
fuente
2

Padre: Coche
Niño: Figo
Coche c1 = nuevo Figo ();

=====
Upcasting: -
Método: el objeto c1 se referirá a Métodos de clase (Figo - El método debe ser anulado) porque la clase "Figo" se especifica con "nuevo".
Variable de instancia: el objeto c1 se referirá a la variable de instancia de la clase de declaración ("Auto").

Cuando la clase de declaración es primaria y se crea un objeto secundario, se produce una conversión implícita que es "Upcasting".

======
Downcasting: -
Figo f1 = (Figo) c1; //
Método: el objeto f1 se referirá al Método de clase (figo) ya que el objeto inicial c1 se crea con la clase "Figo". pero una vez que se realiza la conversión, los métodos que solo están presentes en la clase "Figo" también pueden ser referidos por la variable f1.
Variable de instancia: el objeto f1 no se referirá a la variable de instancia de la clase de declaración del objeto c1 (la clase de declaración para c1 es CAR) pero con la conversión descendente se referirá a las variables de instancia de la clase Figo.

======
Uso: cuando el objeto es de clase secundaria y la clase de declaración es primaria y la clase secundaria quiere acceder a la variable de instancia de su propia clase y no de la clase primaria, entonces se puede hacer con "Downcasting".

amit shah
fuente
1

la conversión ascendente significa lanzar el objeto a un supertipo, mientras que la conversión descendente significa emitir a un subtipo.

En java, la transmisión no es necesaria, ya que se realiza automáticamente. Y generalmente se conoce como casting implícito. Puede especificarlo para dejarlo claro a los demás.

Así, escribiendo

Animal a = (Animal)d;

o

Animal a = d;

conduce exactamente al mismo punto y en ambos casos se ejecutará callme()desde Dog.

Downcasting es necesario porque lo definiste acomo objeto de Animal. Actualmente sabes que es un Dog, pero Java no tiene garantías de que lo sea. En realidad, en tiempo de ejecución podría ser diferente y Java arrojará un ClassCastException, si eso sucediera. Por supuesto, no es el caso de su ejemplo de muestra. Si no echaría aa Animal, java ni siquiera podía compilar la aplicación, ya que Animalno tiene método callme2().

En su ejemplo no puede comunicarse con el código de callme()de Animalde UseAnimlas(porque Dogsobreescribirla) a menos que el método sería de la siguiente manera:

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

Podemos crear objetos para Downcasting. En este tipo también. : llamar a los métodos de la clase base

Animal a=new Dog();
a.callme();
((Dog)a).callme2();
Rakesh
fuente