JavaRush /Java Blog /Random EN /Getters and Setters

Getters and Setters

Published in the Random EN group
Hello! In previous lectures, you have already learned how to create your own full-fledged classes, with fields and methods. This is serious progress, well done! But now I have to tell you an unpleasant truth. We didn't create our classes quite right! Why? At first glance, there are no errors in this class:
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!");
   }
}
In fact, there is. Imagine that while sitting at work you wrote a class like this Cat, denoting cats. And he went home. While you were away, another programmer came to work, created his own class Main, where he began to use the class you wrote Cat.
public class Main {

   public static void main(String[] args) {

       Cat cat = new Cat();
       cat.name = "";
       cat.age = -1000;
       cat.weight = 0;
   }
}
It doesn’t matter why he did it or how it happened: maybe the person was tired or didn’t get enough sleep. Another thing is important: our current class Catallows you to assign crazy values ​​to fields. As a result, the program contains objects with an incorrect state, such as this cat with an age of -1000 years. What mistake did we end up making? When we created the class, we exposed its data. Fields name, ageand weightare in the public domain. They can be accessed anywhere in the program: just create an object Cat- and that’s it, any programmer has access to its data directly through the “ .” operator
Cat cat = new Cat();
cat.name = "";
Here we directly access the field nameand set its value. We need to somehow protect our data from incorrect outside interference. What is needed for this? First, all instance variables (fields) must be marked with a modifier private. Private is the strictest access modifier in Java. If you use it, the fields of the class Catwill not be accessible outside of it.
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 name field in the Cat class has private access!
   }
}
The compiler sees this and immediately produces an error. Now the fields seem to be protected. But it turns out that access to them is “tightly” closed: the program cannot even get the weight of an existing cat, if necessary. This is also not an option: in this form our class is practically impossible to use. Ideally we need to allow some kind of limited access to the data:
  • Other programmers should be able to create objectsCat
  • They should be able to read data from already existing objects (for example, get the name or age of an already existing cat)
  • It should also be possible to assign field values. But at the same time - only correct values. Our objects must be protected from incorrect ones (no “age = -1000 years” and the like).
The list of requirements is decent! But in fact, all this is easily achieved using special methods - getters and setters .
Getters and setters - 2
The name comes from the English “ get ” - “ receive ” (i.e., “method for getting the value of a field”) and set - “ set ” (i.e., “method for setting the value of a field”). Let's see what they look like using our class as an example 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;
   }
}
As you can see, everything is quite simple :) Their names most often consist of the word get/set + the name of the field for which they are responsible. For example, a method getWeight()returns the field value weightof the object for which it was called. This is what it looks like in the program:
public class Main {

   public static void main(String[] args) {

       Cat barsik = new Cat("Barsik", 5, 4);
       String barsikName = barsik.getName();
       int barsikAge = barsik.getAge();
       int barsikWeight = barsik.getWeight();

       System.out.println("Cat name: " + barsikName);
       System.out.println("Cat's age: " + barsikAge);
       System.out.println("Weight of the cat: " + barsikWeight);
   }
}
Console output:

Name кота: Барсик
Возраст кота: 5
Вес кота: 4
Now from another class ( Main) there is access to the fields Cat, but only through getters . Please note that getters have an access modifier public, meaning they are accessible from anywhere in the program. What about assigning values? Setter methods are responsible for this
public void setName(String name) {
   this.name = name;
}
Their work, as you can see, is also simple. We call a method setName()on an object Cat, pass it a string as an argument, and this string is assigned to a field nameof our object.
public class Main {

   public static void main(String[] args) {

       Cat barsik = new Cat("Barsik", 5, 4);

       System.out.println("The original name of the cat is " + barsik.getName());
       barsik.setName("Basil");
       System.out.println("The new name of the cat -" + barsik.getName());
   }
}
Here we used both getters and setters. First, using a getter, we received and output to the console the initial name of the cat. Then, using a setter, namea new value was assigned to its field - “Vasily”. And then, using a getter, we got the name again to check if it really changed. Console output:

Изначальное Name кота — Барсик
Новое Name кота — Васorй
It would seem, what is the difference? We can also assign incorrect values ​​to object fields, even if we have setters:
public class Main {

   public static void main(String[] args) {

       Cat barsik = new Cat("Barsik", 5, 4);
       barsik.setAge(-1000);

       System.out.println("Age of Barsik -" + barsik.getAge() + " years");
   }
}
Console output:

Возраст Барсика — -1000 лет
The difference is that a setter is a full-fledged method . And in a method, unlike a field, you can put the verification logic you need to prevent unacceptable values. For example, you can easily disable assigning a negative number as age:
public void setAge(int age) {
   if (age >= 0) {
       this.age = age;
   } else {
       System.out.println("Error! Age cannot be negative!");
   }
}
And now our code works correctly!
public class Main {

   public static void main(String[] args) {

       Cat barsik = new Cat("Barsik", 5, 4);
       barsik.setAge(-1000);

       System.out.println("Age of Barsik -" + barsik.getAge() + " years");
   }
}
Console output:

Ошибка! Возраст не может быть отрицательным числом!
Возраст Барсика — 5 лет
There is a restriction inside the setter, and it protects against attempts to set incorrect data. Barsik's age remained unchanged. Getters and setters should always be created. Even if your fields have no restrictions on possible values, there will be no harm from them. Imagine a situation: you and your colleagues are writing a program together. You created a class Catwith public fields, and all programmers use them as they want. And then one fine day it dawns on you: “Damn, sooner or later someone might accidentally assign a negative number to a variable weight! We need to create setters and make all fields private!” You create them, and all the code written by your colleagues instantly breaks. After all, they had already written a bunch of code where they accessed the fields Catdirectly.
cat.name = "Hippopotamus";
And now the fields have become private and the compiler produces a bunch of errors!
cat.name = "Hippopotamus";//error! The name field of the Cat class has private access!
In such a situation, it would be better to hide the fields and create getter-setters from the very beginning . All your colleagues would use them, and if it dawned on you late that you needed to limit the field values, you would simply add a check inside the setter. And no one would break the already written code. Of course, if you want read-only access to a certain field, you can create one getter for it. “Outside”, that is, outside your class, only methods should be accessible. The data must be hidden.
Getters and setters - 4
An analogy can be made with a mobile phone. Imagine that instead of a regular mobile phone turned on, you were given a phone with an open case, where all the wires, circuits, etc. are. sticking out. The phone works: if you try hard and fiddle with the diagrams, you might even be able to make a call. But you'll probably just break it. Instead, the manufacturing company gives you an interface: the client simply dials the required numbers, presses the green button with the handset, and the call begins. And he doesn’t care what’s going on inside with the circuits and wires and how they perform their task. In this example, the company has limited access to the “internals” (data) of the phone and left only the interface (methods) outside. As a result, the client will get what he wanted (make a call) and definitely won’t break anything inside.
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION