Qual é a diferença entre up-casting e down-casting com relação à variável de classe

138

Qual é a diferença entre up-casting e down-casting com relação à variável de classe?

Por exemplo, no programa a seguir, a classe Animal contém apenas um método, mas a classe Dog contém dois métodos; depois, como convertemos a variável Dog na variável Animal.

Se a conversão for feita, como podemos chamar o outro método de Dog com a variável 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
fonte
A Dogé um Animal. Na maioria das vezes, o upcasting é desnecessário, a menos que você queira usar um determinado método sobrecarregado. callmeexiste em ambos Animale Dog. callme2só existe em Dogque você joga apara Dogtorná-lo trabalho.
187 Brian Brian
Qual é a saída do seu código?
Malwinder Singh
O interessante é que d.callme retorna 'In callme of Dog', embora d tenha sido convertido em animal !!
precisa saber é o seguinte
4
@ Chris311 'd' e 'a' apontam para o mesmo objeto ... que é um cão, mas 'a' tem acesso apenas a métodos específicos de cachorro quando está inativo em tempo de execução. De fato: Animal a = (Animal) d; é desnecessário, você só precisa do Animal a = d; como você está upcasting.
Mark Keen

Respostas:

223

Upcasting está transmitindo para um supertipo, enquanto downcasting está transmitindo para um subtipo. Upcasting é sempre permitido, mas o downcasting envolve uma verificação de tipo e pode gerar a ClassCastException.

No seu caso, um elenco de um Dogpara um Animalé um upcast, porque um Dogé um Animal. Em geral, você pode fazer upcast sempre que houver um relacionamento entre duas classes.

Downcasting seria algo como isto:

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

Basicamente, o que você está fazendo é dizer ao compilador que você sabe qual é realmente o tipo de tempo de execução do objeto . O compilador permitirá a conversão, mas ainda inserirá uma verificação de integridade de tempo de execução para garantir que a conversão faça sentido. Neste caso, o elenco é possível porque em tempo de execução animalé na verdade um Dogmesmo que o tipo estático animalé Animal.

No entanto, se você fizer isso:

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

Você receberia um ClassCastException. A razão é porque animalo tipo de tempo de execução é Animal, e então, quando você instrui o tempo de execução para executar o elenco, ele vê que animalnão é realmente um Doge, portanto, gera um ClassCastException.

Para chamar o método de uma superclasse, você pode fazer super.method()ou executando o upcast.

Para chamar o método de uma subclasse, você deve fazer um downcast. Como mostrado acima, você normalmente corre o risco ClassCastExceptionde fazer isso; no entanto, você pode usar o instanceofoperador para verificar o tipo de tempo de execução do objeto antes de executar a conversão, o que 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
fonte
O downcasting adequado garante não ClassCastExceptionou não? Como no primeiro caso?
Malwinder Singh
@MS O que você quer dizer com "adequado"?
awksp
2
@awksp Esta é uma resposta excelente e articulada. Praticamente resume tudo o que preciso saber sobre o Casting.
Gautham Honnavara
Certamente você não fez aulas onde animal é uma instância de cachorro, não é? então por que você está procurando isso?
barlop
62

Down-casting e up-casting foram os seguintes:
insira a descrição da imagem aqui

Upcasting : Quando queremos converter uma subclasse para Superclasse, usamos Upcasting (ou ampliação). Isso acontece automaticamente, sem necessidade de fazer nada explicitamente.

Downcasting : Quando queremos converter uma Superclasse para Subclasse, usamos Downcasting (ou restrição), e o Downcasting não é diretamente possível em Java, explicitamente precisamos fazer isso.

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
fonte
Portanto, não existe uma maneira de fazer upcasting para chamar o pai do método?
5137 karlihnos
32

Upcasting e downcasting são parte importante do Java, que nos permite criar programas complicados usando sintaxe simples e nos oferece grandes vantagens, como polimorfismo ou agrupamento de objetos diferentes. Java permite que um objeto de um tipo de subclasse seja tratado como um objeto de qualquer tipo de superclasse. Isso é chamado upcasting. O upcasting é feito automaticamente, enquanto o downcasting deve ser feito manualmente pelo programador , e eu darei o meu melhor para explicar por que é isso.

Upcasting e downcasting NÃO são como converter primitivas de uma para outra, e acredito que é isso que causa muita confusão, quando o programador começa a aprender a moldar objetos.

Polimorfismo: Todos os métodos em java são virtuais por padrão. Isso significa que qualquer método pode ser substituído quando usado em herança, a menos que esse método seja declarado como final ou estático .

Você pode ver o exemplo abaixo como getType();funciona de acordo com o tipo de objeto (Cão, Animal de estimação, Cão policial).

Suponha que você tem três cães

  1. Dog - Esta é a super classe.

  2. Pet Dog - Pet Dog estende Dog.

  3. Cão de Polícia - Cão de Polícia estende Dog Pet.

    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 os métodos em java são virtuais por padrão. Isso significa que qualquer método pode ser substituído quando usado em herança, a menos que esse método seja declarado como final ou estático (a explicação pertence ao conceito de tabelas virtuais)

Tabela Virtual / Tabela de Despacho: A tabela de despacho de um objeto conterá os endereços dos métodos vinculados dinamicamente ao objeto. As chamadas de método são realizadas buscando o endereço do método na tabela de despacho do objeto. A tabela de expedição é a mesma para todos os objetos pertencentes à mesma classe e, portanto, geralmente é compartilhada entre eles.

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

Impressões Normal Dog

  obj2.getType();

Impressões Pet Dog

 obj3.getType();

Impressões Police Dog

O downcasting precisa ser feito manualmente pelo programador

Quando você tenta invocar o secretID();método no obj3qual é PoliceDog objectreferenciado, mas Dogque é uma superclasse na hierarquia, gera erro, pois obj3não tem acesso ao secretId()método. Para invocar esse método, você precisa fazer o downcast desse obj3 manualmente para PoliceDog

  ( (PoliceDog)obj3).secretID();

que imprime ID

No caminho semelhante ao invocar o dogName();método na PetDogclasse que você precisa para downcast obj2para PetDogdesde obj2 é referenciado para Doge não têm acesso ao dogName();método

  ( (PetDog)obj2).dogName();

Por que é assim, que o upcasting é automático, mas o downcasting deve ser manual? Bem, veja bem, o upcasting nunca pode falhar. Mas se você tem um grupo de cães diferentes e quer downcast los todos para um de seus tipos, então há uma chance de que alguns destes cães são realmente de diferentes tipos ou seja, PetDog, PoliceDog, e processo falhar, atirando ClassCastException.

Esse é o motivo pelo qual você precisa fazer o downcast de seus objetos manualmente, se você os referenciou ao tipo de superclasse.

Nota: Aqui, por referência, significa que você não está alterando o endereço de memória de seus objetos quando o faz downcast, ele ainda permanece o mesmo; você apenas os agrupa para um tipo específico neste caso Dog

Nagarjuna Yelisetty
fonte
'O polimorfismo usa downcast automático durante chamadas de método.' Não, não faz. O mecanismo usado não está especificado, mas o mecanismo mais comum - uma tabela - não faz isso. Procure no código do objeto. Não há downcast.
Marquês de Lorne
Por que não? É isso que acontece corretamente. Você pode dar um exemplo em que não funcionará?
Nagarjuna Yelisetty
1
Por que não? É o que acontece corretamente. Você pode dar um exemplo em que a declaração 'Polimorfismo usa downcast automático durante chamadas de método'. falhará ou não será verdadeiro?
Nagarjuna Yelisetty
É a sua afirmação. Cabe a você provar isso. Mostrar onde no código do objeto ocorre o downcast. A resposta para a pergunta 'por que não' é 'porque não é necessária'. A vtable cuida do envio do método e a variável já aponta para o objeto inteiro.
Marquês de Lorne
1
"De acordo com meu conhecimento, minhas afirmações são verdadeiras e são válidas em todos os casos" não é uma prova. É uma mera afirmação. Estou lhe pedindo para provar suas declarações. Você não está fazendo isso. Na verdade, você está apenas se repetindo. E eu já forneci várias refutações. Eu também forneci um procedimento de decisão. Se você puder encontrar um downcast no código do objeto para uma chamada de método, você está certo e eu estou errado. É assim que a ciência é feita. Faça. E alegar que estou 'dependendo da documentação' é uma deturpação flagrante. Não faça isso.
Marquês de Lorne
12

Eu sei que esta pergunta foi feita há muito tempo, mas para os novos usuários desta pergunta. Leia este artigo onde contém uma descrição completa sobre upcasting, downcasting e uso da instância do operador

  • Não há necessidade de upcast manualmente, isso acontece por si só:

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

  • Mas o downcasting sempre deve ser feito manualmente:

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

Por que é assim, que o upcasting é automático, mas o downcasting deve ser manual? Bem, veja bem, o upcasting nunca pode falhar. Mas se você tem um grupo de animais diferentes e deseja baixá-los todos para um gato, há uma chance de que alguns desses animais sejam realmente cães, e o processo falha, lançando ClassCastException. É aqui que deve ser introduzido um recurso útil chamado "instanceof" , que testa se um objeto é instância de alguma classe.

 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 mais informações, leia este artigo.

Nadeesha Thilakarathne
fonte
ponto positivo: Mamífero m = (Mamífero) novo gato (); é igual a Mamífero m = novo Gato ();
Catbuilts
6

Melhor tentar esse método para upcasting, é fácil 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
fonte
e na última linha poderia ser: ((Dog) ref) .callme2 (); // para acesso ao método downcasting / estreitamento e callme2 () da classe Dog.
udarH3
6

Talvez esta tabela ajude. Chamando o callme()método de classe Parentou classe Child. Como princípio:

UPCASTING -> Ocultando

DOWNCASTING -> Revelando

insira a descrição da imagem aqui

insira a descrição da imagem aqui

insira a descrição da imagem aqui

Alexis
fonte
4

1.- Upcasting.

Ao fazer uma upcasting, você define uma tag de algum tipo, que aponta para um objeto de um subtipo (Tipo e subtipo podem ser chamados de classe e subclasse, se você se sentir mais confortável ...).

Animal animalCat = new Cat();

O que significa que essa tag, animalCat, terá apenas a funcionalidade (os métodos) do tipo Animal, porque a declaramos como tipo Animal, não como Cat.

Estamos autorizados a fazer isso de maneira "natural / implícita / automática", em tempo de compilação ou em tempo de execução, principalmente porque o Cat herda algumas de suas funcionalidades do Animal; por exemplo, mova (). (Pelo menos, gato é um animal, não é?)

2.- Downcasting.

Mas, o que aconteceria se precisássemos obter a funcionalidade do Cat, do nosso tipo de tag Animal ?.

Como criamos a tag animalCat apontando para um objeto Cat, precisamos de uma maneira de chamar os métodos de objeto Cat, de nossa tag animalCat de uma maneira bem inteligente.

Esse procedimento é o que chamamos de Downcasting, e podemos fazê-lo apenas no tempo de execução.

Hora de algum 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
fonte
2

Pai: Carro
Filho: Figo
Carro c1 = novo Figo ();

=====
Upcasting: -
Método: O objeto c1 se refere a Métodos de classe (Figo - O método deve ser substituído) porque a classe "Figo" é especificada com "novo".
Variável da Instância: O objeto c1 se refere à variável de instância da Classe de Declaração ("Carro").

Quando a classe Declaration é pai e o objeto é criado como filho, acontece a conversão implícita, que é "Upcasting".

======
Downcasting: -
Figo f1 = (Figo) c1; //
Método: O objeto f1 se refere ao Método da Classe (figo) quando o objeto inicial c1 é criado com a classe "Figo". mas uma vez feito o downcast, os métodos que estão presentes apenas na classe "Figo" também podem ser referidos pela variável f1.
Variável da Instância: O objeto f1 não se refere à variável de instância da classe Declaration do objeto c1 (a classe de declaração para c1 é CAR), mas com o downcast ele se refere às variáveis ​​de instância da classe Figo.

======
Use: Quando Object é da classe Child e a classe de declaração é Parent e a classe Child deseja acessar a variável Instance de sua própria classe e não da classe pai, isso pode ser feito com "Downcasting".

amit shah
fonte
1

upcasting significa converter o objeto em um supertipo, enquanto downcasting significa converter em um subtipo.

Em java, upcasting não é necessário, pois é feito automaticamente. E é geralmente chamado de elenco implícito. Você pode especificá-lo para deixar claro para outras pessoas.

Assim, escrevendo

Animal a = (Animal)d;

ou

Animal a = d;

leva exatamente ao mesmo ponto e, em ambos os casos, será executado o callme()from Dog.

O downcasting é necessário porque você definiu acomo objeto de Animal. Atualmente você sabe que é Dog, mas o java não tem garantias de que é. Na verdade, em tempo de execução, poderia ser diferente e o java lançaria um ClassCastException, isso aconteceria. Claro que não é o caso do seu exemplo de amostra. Se você não converter apara Animal, o java não poderá nem compilar o aplicativo porque Animalnão possui método callme2().

No seu exemplo você não pode alcançar o código de callme()de Animalpartir UseAnimlas(porque Dogsubstituí-lo) a menos que o método seria como segue:

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

Podemos criar um objeto para Downcasting. Neste tipo também. : chamando os métodos da classe base

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