Olá! Hoje falaremos sobre o operador instanceof, veremos exemplos de seu uso e abordaremos alguns pontos relacionados ao seu funcionamento :) Nos níveis iniciais do JavaRush, você já encontrou esse operador. Você se lembra por que é necessário? Se não, não importa, vamos lembrar juntos. O operador instanceof é necessário para verificar se o objeto referenciado pela variável X foi criado a partir de alguma classe Y. Parece simples. Por que voltamos a este tópico? Em primeiro lugar, porque agora você está bem familiarizado com o mecanismo de herança em Java e outros princípios de OOP. O tópico instanceof será muito mais claro e veremos casos de uso mais avançados. Ir! Você provavelmente se lembra que o operador instanceof retorna verdadeiro se o teste for verdadeiro ou falso se o resultado for falso. Consequentemente, é mais frequentemente encontrado em vários tipos de condições de teste (
if…else
). Vamos começar com exemplos mais simples:
public class Main {
public static void main(String[] args) {
Integer x = new Integer(22);
System.out.println(x instanceof Integer);
}
}
O que você acha que será enviado para o console? Bem, é óbvio aqui :) O objeto х
é um Inteiro, então o resultado será verdadeiro . Saída do console: true Vamos tentar verificar se pertence, por exemplo, a String:
public class Main {
public static void main(String[] args) {
Integer x = new Integer(22);
System.out.println(x instanceof String);// error!
}
}
Recebemos um erro. E preste atenção: o compilador o emitiu antes mesmo de o código ser executado! Ele percebeu imediatamente que Integer e String não podem ser convertidos automaticamente entre si e não têm relacionamentos de herança. Portanto, um objeto da classe Integer não será criado a partir da String. Isso é conveniente e ajuda a evitar erros estranhos durante a execução do programa, então o compilador nos ajudou aqui :) Agora vamos tentar ver exemplos mais complexos. Já que mencionamos herança, vamos trabalhar com este sistema de classes pequenas:
public class Animal {
}
public class Cat extends Animal {
}
public class MaineCoon extends Cat {
}
Já sabemos como instanceof se comporta quando verificamos se um objeto pertence a uma classe em uma situação normal, mas o que acontece se adicionarmos um relacionamento pai-filho aqui? Por exemplo, o que você acha que a seguinte verificação produzirá:
public class Main {
public static void main(String[] args) {
Cat cat = new Cat();
System.out.println(cat instanceof Animal);
System.out.println(cat instanceof MaineCoon);
}
}
Saída: verdadeiro falso A principal questão que precisa ser respondida é como exatamente instanceof decifra o conceito de “um objeto criado com base em uma classe”? Como resultado, conseguimos Сat instanceof Animal == true
, mas pode-se encontrar falhas nessa formulação. Por que este objeto é Cat
criado com base na classe Animal
? Não é criado apenas com base em sua própria classe? A resposta é bastante simples e você já deve ter descoberto. Lembre-se da ordem em que os construtores são chamados e as variáveis são inicializadas ao criar um objeto. Já abordamos esse tópico no artigo sobre o construtor de classes . Aqui está um exemplo dessa palestra:
public class Animal {
String brain = "The initial value of brain in the Animal class";
String heart = "The initial value of heart in the Animal class";
public static int animalCount = 7700000;
public Animal(String brain, String heart) {
System.out.println("The constructor of the Animal base class is being executed");
System.out.println("Have the variables of the Animal class already been initialized?");
System.out.println("The current value of the static variable animalCount = " + animalCount);
System.out.println("Current value of brain in class Animal = " + this.brain);
System.out.println("Current value of heart in class Animal = " + this.heart);
this.brain = brain;
this.heart = heart;
System.out.println("Animal base class constructor completed!");
System.out.println("Current value of brain = " + this.brain);
System.out.println("Current value of heart = " + this.heart);
}
}
class Cat extends Animal {
String tail = "The initial value of tail in the Cat class";
static int catsCount = 37;
public Cat(String brain, String heart, String tail) {
super(brain, heart);
System.out.println("The constructor of the Cat class has started (the Animal constructor has already been executed)");
System.out.println("The current value of the static variable catsCount = " + catsCount);
System.out.println("Current value tail = " + this.tail);
this.tail = tail;
System.out.println("Current value tail = " + this.tail);
}
public static void main(String[] args) {
Cat cat = new Cat("Brain", "Heart", "Tail");
}
}
E se você executá-lo no IDE, a saída do console ficará assim: O construtor da classe base Animal está rodando. As variáveis da classe Animal já foram inicializadas? Valor atual da variável estática animalCount = 7700000 Valor atual do cérebro na classe Animal = Valor inicial do cérebro na classe Animal Valor atual do coração na classe Animal = Valor inicial do coração na classe Animal O construtor da classe base Animal completou seu trabalho! Valor atual de brain = Brain Valor atual de heart = Heart O construtor da classe Cat começou a funcionar (o construtor Animal já foi executado) Valor atual da variável estática catsCount = 37 Valor atual de tail = Valor inicial de tail no Classe Cat Valor atual de tail = Tail Você se lembra agora? :) O construtor da classe base, se houver, é sempre chamado primeiro ao criar qualquer objeto. Instanceof segue este princípio quando tenta determinar se um objeto foi А
criado a partir de uma classe Б
. Se o construtor da classe base for chamado, não haverá dúvida. Com a segunda verificação tudo fica mais simples:
System.out.println(cat instanceof MaineCoon);
O construtor MaineCoon
não foi chamado durante a criação Cat
, o que é lógico. Afinal, MaineCoon
ele é descendente Cat
, não ancestral. Mas Cat
não é um modelo para. Ok, isso parece claro. O que acontecerá se fizermos isso:
public class Main {
public static void main(String[] args) {
Cat cat = new MaineCoon();
System.out.println(cat instanceof Cat);
System.out.println(cat instanceof MaineCoon);
}
}
Hmm... isso é mais complicado. Vamos tentar raciocinar. Temos uma variável do tipo Cat
e atribuímos a ela um objeto do tipo MaineCoon
. A propósito, por que isso funciona? É possível fazer isso? Pode. Afinal, qualquer Maine Coon é um gato. Se não estiver totalmente claro, lembre-se do exemplo com extensões de tipo primitivo:
public class Main {
public static void main(String[] args) {
long x = 1024;
}
}
O número 1024 é curto : cabe facilmente na variável long , pois a quantidade de bytes é suficiente para isso (lembra do exemplo das bonecas aninhadas?). Um objeto filho sempre pode ser atribuído a uma variável ancestral. Apenas lembre-se disso por enquanto, e nas próximas palestras analisaremos mais detalhadamente esse processo. Então, o que nosso exemplo produzirá?
Cat cat = new MaineCoon();
System.out.println(cat instanceof Cat);
System.out.println(cat instanceof MaineCoon);
O que instanceof verificará: nossa variável de classe Cat
ou nosso objeto de classe MaineCoon
? Na verdade, a resposta a esta pergunta é simples. Basta ler novamente a definição do nosso operador: O operador instanceof é necessário para verificar se o objeto referenciado pela variável foi X
criado com base em alguma classe Y
. O operador instanceof verifica a origem de um objeto, não de uma variável. Portanto, no exemplo, nas duas vezes será exibido true no console : temos um objeto do tipo MaineCoon
. Naturalmente, ele foi criado com base na classe MaineCoon
, mas também com base na classe pai Cat
!
GO TO FULL VERSION