Encapsulation is not about secrecy, it is about reducing dependency over separate part of the application.
We control dependency (loose / weak / low coupling) by hiding information over separate part of the application.
Adding to Uche Dim's answer, look at the following example:
Two Connections:
public class Area {
// fields to calculate area
private int length;
private int breadth;
// constructor to initialize values
Area(int length, int breadth) {
this.length = length;
this.breadth = breadth;
}
public int getLength() {
return length;
}
public void setLength(int length) {
this.length = length;
}
public int getBreadth() {
return breadth;
}
public void setBreadth(int breadth) {
this.breadth = breadth;
}
public int getArea() {
int area = length * breadth;
return area;
}
}
class Main {
public static void main(String[] args) {
Area rectangle = new Area(5, 6);
// Two Connections
int length = rectangle.getLength();
int breadth = rectangle.getBreadth();
int area = length * breadth;
System.out.println("Area: " + area);
}
}
Please note that in the Main
class, we are calling two methods (getLength()
and getBreadth()
) of Area
class.
One Connection:
public class Area {
// fields to calculate area
private int length;
private int breadth;
// constructor to initialize values
Area(int length, int breadth) {
this.length = length;
this.breadth = breadth;
}
public int getArea() {
int area = length * breadth;
return area;
}
}
class Main {
public static void main(String[] args) {
Area rectangle = new Area(5, 6);
// One Connection
int area = rectangle.getArea();
System.out.println("Area: " + area);
}
}
Here, in the Main
class, we are calling one methods (getArea()
) of Area
class.
So in the second example, the connection is weaker than the previous one (first one calling two methods or the Area
class, second one calling one method of the Area
class). Given, less connection (lower / weaker coupling) is better, the second example is better.
We should always keep fields and methods private unless necessary. In the Two Connections example, we made the mistake of creating the getters unnecessarily. As we have created it, the IntelliJ Idea (auto suggestion of modern IDE) suggested the developer who was working on the Main
class that you can use the getLength()
and getBreadth()
methods and he did. He did not inquire further to check if there was a getArea()
method. As a result he created stronger coupling than necessary.
We should not unnecessarily create getters. We should not unnecessarily make fields public or protected. If you must, first try protected, if that does not work then make it public. That way we will have a lesser possibility of having a tighter coupling.
If you still have the question "what is the difference between making a field public compared to making a field private but it's getters public?", in other words "Why should we use a function to get a value instead of getting it directly?" Well it gives you another layer of abstraction. For example, if you need some extra processing of the data before receiving it (ex. validation), you can do it there. Moreover, once you expose internals of a class, you can not change that internal representation or make it better until making changes in all client codes.
For example, suppose you did something like:
public class Area {
private int length;
private int breadth;
}
class Main {
public static void main(String[] args) {
Area rectangle = new Area(5, 6);
int area = rectangle.length * rectangle.breadth;
System.out.println("Area: " + area);
}
}
Now, if you want to change breadth
to width
in Area
class, you can not do it without breaking the program, unless you search and replace rectangle.breadth
with rectangle.width
in all the clients where rectangle.breadth
was used (in this case Main
class).
There are other benefits as well. For example, Member variables cannot be overridden like methods. If a class has getters and setters, it's subclass can override these methods and return what makes more sense in the context of subclass.
Please check Why getter and setter are better than public fields in Java? for more details.
P.S. These are trivial examples, but in large scale, when program grows and frequent change requests are a reality, this makes sense.