12.6 Encapsulation and Accessor Methods (Getters and Setters)
Encapsulation is one of the four fundamental pillars of object-oriented programming (OOP), along with inheritance, polymorphism and abstraction. Encapsulation is the practice of keeping the fields (instance variables) of a class private and providing access to them through public methods. This is done to maintain control over the values being set and obtained, and to protect the integrity of the data held by the class.
Accessor methods, known as getters and setters, are the standard way of implementing encapsulation in Java. They are public methods that serve to obtain (get) and set (set) the value of private fields of a class.
Naming Conventions for Getters and Setters
In Java, there is a well-established naming convention for getters and setters that helps keep code readable, consistent, and accessible to other tools and frameworks that rely on these conventions.
For a field called name
, for example, the getter would be named getName()
and the setter would be named setName()
. This convention applies to all fields, with some specific rules for Boolean fields, where the getter often starts with is
instead of get
, such as isActive( )
to a field called active
.
Here are the general rules for naming getters and setters:
- Getters: The method begins with the word
get
followed by the field name with the first letter capitalized. If the field is of type boolean, you can also useis
instead ofget
. - Setters: The method begins with the word
set
followed by the field name with the first letter capitalized.
These methods must be marked as public so that they can be accessed from outside the class. Additionally, the setter method usually returns void
and accepts a parameter of the same type as the field it is defining, while the getter returns a value of the same type as the field.
Example of Implementation of Getters and Setters
public class Person {
private String name;
private int age;
private boolean active;
// Getter for name field
public String getName() {
return name;
}
// Setter for the name field
public void setName(String name) {
this.name = name;
}
// Getter for the age field
public int getAge() {
return age;
}
// Setter for the age field
public void setAge(int age) {
this.age = age;
}
// Getter for the active field (note the use of 'is' instead of 'get')
public boolean isActive() {
return active;
}
// Setter for the active field
public void setActive(boolean active) {
this.active = active;
}
}
Why Use Getters and Setters?
Although it may seem simpler to access fields directly, there are several advantages to using getters and setters:
- Access Control: You can control whether a field is read-only or write-only, or whether it must follow certain validation rules when defined.
- Implementation Hiding: The class can change the way data is stored internally without affecting the classes that use it.
- Flexibility: You can add additional logic to accessor methods, such as notifying other objects about changes in the value, performing validations, or even deferring the calculation of the value until it is actually needed (lazy loading ).
- Framework Compatibility: Many Java frameworks, such as Spring and Hibernate, rely on getters and setters to function correctly.
It is important to note that although getters and setters are common practice, they are not mandatory. In some cases, where the class is very simple and does not require additional control over its fields, it may be acceptable to expose the fields directly. However, this must be done with caution and understanding the consequences for the maintainability and flexibility of the code.
In summary, getters and setters are a crucial part of encapsulation in Java. They provide a controlled interface for accessing and modifying a class's fields while maintaining code integrity and flexibility. Following the naming conventions for these methods is essential to maintain consistency and ensure proper interaction with other parts of the Java ecosystem.