CodeGym /Blogue Java /Random-PT /Getters e setters
John Squirrels
Nível 41
San Francisco

Getters e setters

Publicado no grupo Random-PT
Olá! Nas lições anteriores, você já aprendeu como declarar suas próprias classes completas com métodos e campos. Na lição de hoje, falaremos sobre Getters e Setters em Java. Este é um progresso sério, muito bem! Mas agora tenho que lhe contar uma verdade desagradável. Não declaramos nossas classes corretamente! Por que? À primeira vista, a seguinte classe não tem erros:

public class Cat {

   public String name;
   public int age;
   public int weight;

   public Cat(String name, int age, int weight) {
       this.name = name;
       this.age = age;
       this.weight = weight;
   }

   public Cat() {
   }

   public void sayMeow() {
       System.out.println("Meow!");
   }
}
Mas funciona. Imagine que você está sentado no trabalho e escreva esta classe Cat para representar os gatos. E então você vai para casa. Enquanto você está fora, outro programador chega para trabalhar. Ele cria sua própria classe Main , onde começa a usar a classe Cat que você escreveu.

public class Main {

   public static void main(String[] args) {

       Cat cat = new Cat();
       cat.name = "";
       cat.age = -1000;
       cat.weight = 0;
   }
}
Não importa por que ele fez isso e como aconteceu (talvez o cara esteja cansado ou não tenha dormido o suficiente). Outra coisa importa: nossa classe Cat atual permite que os campos recebam valores absolutamente insanos. Como resultado, o programa possui objetos com um estado inválido (como este gato que tem -1000 anos). Então, que erro cometemos ao declarar nossa classe? Expusemos os dados de nossa classe. Os campos nome, idade e peso são públicos. Eles podem ser acessados ​​em qualquer lugar do programa: basta criar um objeto Cat e qualquer programador tem acesso direto aos seus dados através do operador ponto ( . )

Cat cat = new Cat();
cat.name = "";
Aqui estamos acessando diretamente o campo nome e definindo seu valor. Precisamos de alguma forma proteger nossos dados de interferência externa imprópria. O que precisamos para fazer isso? Primeiro, todas as variáveis ​​de instância (campos) devem ser marcadas com o modificador private. Private é o modificador de acesso mais estrito em Java. Depois de fazer isso, os campos da classe Cat não poderão ser acessados ​​fora da classe.

public class Cat {

   private String name;
   private int age;
   private int weight;

   public Cat(String name, int age, int weight) {
       this.name = name;
       this.age = age;
       this.weight = weight;
   }

   public Cat() {
   }

   public void sayMeow() {
       System.out.println("Meow!");
   }
}

public class Main {

   public static void main(String[] args) {

       Cat cat = new Cat();
       cat.name = "";//error! The Cat class's name field is private!
   }
}
O compilador vê isso e imediatamente gera um erro. Agora os campos estão meio que protegidos. Mas descobrimos que fechamos o acesso talvez com muita força: você não pode obter o peso de um gato existente no programa, mesmo que precise. Esta também não é uma opção. Do jeito que está, nossa classe é essencialmente inutilizável. Idealmente, precisamos permitir algum tipo de acesso limitado:
  • Outros programadores devem ser capazes de criar objetos Cat
  • Eles devem ser capazes de ler dados de objetos existentes (por exemplo, obter o nome ou a idade de um gato existente)
  • Também deve ser possível atribuir valores de campo. Mas, ao fazer isso, apenas valores válidos devem ser permitidos. Nossos objetos devem ser protegidos de valores inválidos (por exemplo, idade = -1000, etc.).
Essa é uma lista decente de requisitos! Na realidade, tudo isso é facilmente obtido com métodos especiais chamados getters e setters.
Getters e setters - 2
Esses nomes vêm de "get" (ou seja, "método para obter o valor de um campo") e "set" (ou seja, "método para definir o valor de um campo"). Vamos ver como eles ficam em nossa classe Cat :

public class Cat {

   private String name;
   private int age;
   private int weight;

   public Cat(String name, int age, int weight) {
       this.name = name;
       this.age = age;
       this.weight = weight;
   }

   public Cat() {
   }

   public void sayMeow() {
       System.out.println("Meow!");
   }

   public String getName() {
       return name;
   }

   public void setName(String name) {
       this.name = name;
   }

   public int getAge() {
       return age;
   }

   public void setAge(int age) {
       this.age = age;
   }

   public int getWeight() {
       return weight;
   }

   public void setWeight(int weight) {
       this.weight = weight;
   }
}
Como você pode ver, eles parecem bem simples :) Seus nomes geralmente consistem em "get"/"set" mais o nome do campo relevante. Por exemplo, o método getWeight() retorna o valor do campo de peso para o objeto no qual é chamado. Veja como fica em um programa:

public class Main {

   public static void main(String[] args) {

       Cat smudge = new Cat("Smudge", 5, 4);
       String smudgeName = smudge.getName();
       int smudgeAge = smudge.getAge();
       int smudgeWeight = smudge.getWeight();

       System.out.println("Cat's name: " + smudgeName);
       System.out.println("Cat's age: " + smudgeAge);
       System.out.println("Cat's weight: " + smudgeWeight);
   }
}
Saída do console:
Cat's name: Smudge
Cat's age: 5
Cat's weight: 4
Agora outra classe ( Main ) pode acessar os campos Cat , mas somente através de getters. Observe que os getters têm o modificador de acesso público, ou seja, estão disponíveis em qualquer lugar do programa. Mas e quanto à atribuição de valores? É para isso que servem os métodos setter

public void setName(String name) {
   this.name = name;
}
Como você pode ver, eles também são simples. Chamamos o método setName() em um objeto Cat , passamos uma string como argumento e a string é atribuída ao campo de nome do objeto.

public class Main {

   public static void main(String[] args) {

       Cat smudge = new Cat("Smudge", 5, 4);

       System.out.println("Cat's original name: " + smudge.getName());
       smudge.setName("Mr. Smudge");
       System.out.println("Cat's new name: " + smudge.getName());
   }
}
Aqui estamos usando getters e setters. Primeiro, usamos um getter para obter e exibir o nome original do gato. Em seguida, usamos um setter para atribuir um novo nome ("Mr. Smudge"). E então usamos o getter mais uma vez para obter o nome (para verificar se realmente mudou). Saída do console:
Cat's original name: Smudge
Cat's new name: Mr. Smudge
Então, qual é a diferença? Ainda podemos atribuir valores inválidos aos campos, mesmo que tenhamos configuradores:

public class Main {

   public static void main(String[] args) {

       Cat smudge = new Cat("Smudge", 5, 4);
       smudge.setAge(-1000);

       System.out.println("Smudge's age: " + smudge.getAge());
   }
}
Saída do console:
Smudge's age: -1000 years
A diferença é que um setter é um método completo. E ao contrário de um campo, um método permite escrever a lógica de verificação necessária para evitar valores inaceitáveis. Por exemplo, você pode evitar facilmente que um número negativo seja atribuído como uma idade:

public void setAge(int age) {
   if (age >= 0) {
       this.age = age;
   } else {
       System.out.println("Error! Age can't be negative!");
   }
}
E agora nosso código funciona corretamente!

public class Main {

   public static void main(String[] args) {

       Cat smudge = new Cat("Smudge", 5, 4);
       smudge.setAge(-1000);

       System.out.println("Smudge's age: " + smudge.getAge());
   }
}
Saída do console:
Error! Age can't be negative!
Smudge's age: 5 years
Dentro do setter, criamos uma restrição que nos protegia da tentativa de setar dados inválidos. A idade de Smudge não foi alterada. Você deve sempre criar getters e setters. Mesmo que não haja restrições sobre quais valores seus campos podem assumir, esses métodos auxiliares não causarão danos. Imagine a seguinte situação: você e seus colegas estão escrevendo um programa juntos. Você cria uma classe Cat com campos públicos. Todos os programadores estão usando como quiserem. E então um belo dia você percebe: "Droga, mais cedo ou mais tarde alguém pode acidentalmente atribuir um número negativo ao peso! Precisamos criar setters e tornar todos os campos privados!" Você faz exatamente isso e quebra instantaneamente todo o código escrito por seus colegas. Afinal, elesCat campos diretamente.

cat.name = "Behemoth";
E agora os campos são privados e o compilador apresenta vários erros!

cat.name = "Behemoth";//error! The Cat class's name field is private!
Nesse caso, seria melhor ocultar os campos e criar getters e setters desde o início. Todos os seus colegas os teriam usado. E se você percebeu tardiamente que precisava restringir de alguma forma os valores do campo, você poderia ter apenas escrito o cheque dentro do setter. E o código de ninguém seria quebrado. Obviamente, se você deseja que o acesso a um campo seja apenas "somente leitura", pode criar apenas um getter para ele. Somente os métodos devem estar disponíveis externamente (ou seja, fora de sua classe). Os dados devem ser ocultados. Poderíamos fazer uma comparação com um telefone celular. Imagine que, em vez do habitual telefone celular fechado, você recebesse um telefone com uma caixa aberta, com todos os tipos de fios salientes, circuitos etc. capaz de fazer uma chamada. Mas você'
Getters e setters - 3
Em vez disso, o fabricante oferece uma interface: o usuário simplesmente insere os dígitos corretos, pressiona o botão verde de chamada e a chamada é iniciada. Ela não se importa com o que acontece dentro dos circuitos e fios, ou como eles realizam seu trabalho. Neste exemplo, a empresa limita o acesso ao "interior" do telefone (dados) e expõe apenas uma interface (métodos). Como resultado, o usuário obtém o que deseja (a capacidade de fazer uma chamada) e certamente não quebrará nada por dentro. Para reforçar o que você aprendeu, sugerimos que você assista a uma vídeo aula do nosso Curso de Java
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION