JavaRush /Blogue Java /Random-PT /Expansão e contração de tipos de referência

Expansão e contração de tipos de referência

Publicado no grupo Random-PT
Olá! Em uma das palestras anteriores, discutimos a conversão de tipos primitivos. Vamos lembrar brevemente do que estávamos falando. Expansão e contração de tipos de referência - 1Representamos os tipos primitivos (neste caso, numéricos) como bonecos de nidificação de acordo com a quantidade de memória que ocupam. Como você se lembra, colocar uma boneca menor em uma maior será simples tanto na vida real quanto na programação Java.
public class Main {
   public static void main(String[] args) {
        short smallNumber = 100;
        int bigNumber =  smallNumber;
        System.out.println(bigNumber);
   }
}
Este é um exemplo de conversão automática ou extensão . Isso acontece por conta própria, portanto não há necessidade de escrever código adicional. No final, não estamos fazendo nada de incomum: estamos simplesmente colocando uma boneca menor em uma boneca maior. Outra questão é tentarmos fazer o oposto e colocar uma boneca matryoshka grande em uma menor. Isso não pode ser feito na vida, mas na programação pode ser feito. Mas há uma ressalva. Se tentarmos colocar um valor intem uma variável short, não funcionará tão facilmente. Afinal, apenas 16 bits de informação cabem em uma variável short, mas o valor intleva 32 bits! Como resultado, o valor transmitido será distorcido. O compilador nos dará um erro (“ cara, você está fazendo algo suspeito! ”), mas se especificarmos explicitamente para qual tipo estamos convertendo nosso valor, ele ainda executará tal operação.
public class Main {

   public static void main(String[] args) {

       int bigNumber = 10000000;

       bigNumber = (short) bigNumber;

       System.out.println(bigNumber);

   }

}
No exemplo acima, fizemos exatamente isso. A operação foi concluída, mas como shortapenas 16 dos 32 bits cabiam na variável, o valor final foi distorcido e, como resultado, obtivemos o número -27008 . Esta operação é chamada de conversão explícita ou estreitamento .

Exemplos de extensão e contração de tipos de referência

Agora falaremos sobre as mesmas operações, mas aplicáveis ​​não a tipos primitivos, mas a objetos e variáveis ​​de referência ! Como isso funciona em Java? Muito simples, na verdade. Existem objetos que não estão relacionados entre si. Seria lógico supor que eles não podem ser convertidos entre si, nem explícita nem automaticamente:
public class Cat {
}

public class Dog {
}

public class Main {

   public static void main(String[] args) {

       Cat cat = new Dog();//error!

   }

}
Aqui, é claro, obteremos um erro. As classes não Catestão Dogrelacionadas entre si e não escrevemos um “conversor” de uma para outra. É lógico que não conseguiremos fazer isso: o compilador não tem ideia de como converter esses objetos entre si. Outra questão é se os objetos estão conectados uns aos outros! Como? Primeiro de tudo, usando herança. Vamos tentar criar um sistema de classes pequeno com herança. Teremos uma aula geral representando os animais:
public class Animal {

   public void introduce() {

       System.out.println("i'm Animal");
   }
}
Os animais, como você sabe, são domésticos e selvagens:
public class WildAnimal extends Animal {

   public void introduce() {

       System.out.println("i'm WildAnimal");
   }
}

public class Pet extends Animal {

   public void introduce() {

       System.out.println("i'm Pet");
   }
}
Por exemplo, tomemos cães - um cão doméstico e um coiote:
public class Dog extends Pet {

   public void introduce() {

       System.out.println("i'm Dog");
   }
}





public class Coyote extends WildAnimal {

   public void introduce() {

       System.out.println("i'm Coyote");
   }
}
Nossas aulas são deliberadamente as mais primitivas para torná-las mais fáceis de serem percebidas. Na verdade, não precisamos de campos aqui e um método é suficiente. Vamos tentar executar o seguinte código:
public class Main {

   public static void main(String[] args) {

       Animal animal = new Pet();
       animal.introduce();
   }
}
O que você acha que será enviado para o console? introduceA classe Petou método de classe funcionará Animal? Tente justificar sua resposta antes de continuar lendo. E aqui está o resultado! eu sou Pet Por que a resposta ficou assim? É simples. Temos uma variável pai e um objeto filho. Por escrito:
Animal animal = new Pet();
Estendemos um tipo de referênciaPet e armazenamos seu objeto em uma variável Animal. Tal como acontece com os tipos primitivos, a extensão dos tipos de referência em Java é feita automaticamente. Não há necessidade de escrever código adicional para isso. Agora temos um objeto filho anexado à referência pai e, como resultado, vemos que o método é chamado na classe filha. Se você ainda não entende completamente por que esse código funciona, reescreva-o em linguagem simples:
Животное животное = new ДомашнееЖивотное();
Não há problema com isso, certo? Imagine que isto é a vida real e que o link neste caso é uma simples etiqueta de papel que diz “Animal”. Se você pegar esse pedaço de papel e fixá-lo na coleira de qualquer animal de estimação, tudo ficará bem. Qualquer animal de estimação ainda é um animal! O processo inverso, ou seja, descer na árvore de herança até os herdeiros, é um estreitamento:
public class Main {

   public static void main(String[] args) {

       WildAnimal wildAnimal = new Coyote();

       Coyote coyote = (Coyote) wildAnimal;

       coyote.introduce();
   }
}
Como você pode ver, aqui indicamos explicitamente para qual classe queremos converter nosso objeto. Anteriormente tínhamos uma variável WildAnimal, e agora Coyote, que desce na árvore de herança. É lógico que o compilador não irá pular tal operação sem uma indicação explícita, mas se você especificar o tipo entre parênteses, tudo funcionará. Expansão e contração de tipos de referência - 2 Vejamos outro exemplo, mais interessante:
public class Main {

   public static void main(String[] args) {

       Pet pet = new Animal();//error!
   }
}
O compilador gera um erro! Qual é a razão? O fato é que você está tentando atribuir um objeto pai a uma variável filha. Em outras palavras, você quer fazer isso:
ДомашнееЖивотное домашнееЖивотное = new Животное();
Mas talvez se indicarmos explicitamente o tipo para o qual estamos tentando transmitir, teremos sucesso? Os números parecem funcionar, vamos tentar! :)
public class Main {

   public static void main(String[] args) {

       Pet pet = (Pet) new Animal();
   }
}
Exceção no thread "main" java.lang.ClassCastException: Animal não pode ser convertido em Pet Error! O compilador não reclamou desta vez, mas como resultado recebemos uma exceção. Já sabemos o motivo: estamos tentando atribuir um objeto pai a uma variável filha. Por que, de fato, isso não pode ser feito? Porque nem todos os animais são animais de estimação. Você criou um objeto Animale está tentando atribuí-lo a uma variável Pet. Mas, por exemplo, um coiote também é Animal, mas não é Pet, um animal doméstico. Em outras palavras, quando você escreve:
Pet pet = (Pet) new Animal();
new Animal()Qualquer animal pode estar ali , e não precisa ser doméstico! Naturalmente, sua variável Pet petsó é adequada para armazenar animais de estimação (e seus descendentes), e não para todos. Portanto, para tais casos, uma exceção especial foi criada em Java - ClassCastExceptionum erro ao lançar classes. Vamos repetir para ficar mais claro. Uma variável pai (referência) pode apontar para um objeto de uma classe descendente:
public class Main {

   public static void main(String[] args) {

       Pet pet =  new Pet();
       Animal animal = pet;

       Pet pet2 = (Pet) animal;
       pet2.introduce();
   }
}
Por exemplo, não teremos problemas aqui. Temos um objeto Petapontado por um link Pet. Então um novo link começou a apontar para o mesmo objeto Animal. Depois disso fazemos a conversão animalpara Pet. A propósito, por que fizemos isso? Da última vez tivemos uma exceção! Porque desta vez nosso objeto original é Pet pet!
Pet pet =  new Pet();
E no exemplo anterior era um objeto Animal:
Pet pet = (Pet) new Animal();
Uma variável descendente não pode receber um objeto ancestral. Pelo contrário, você consegue.
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION