The difference between encapsulation and abstraction in Java is that abstraction decides which operations a type offers to its callers, while encapsulation hides the type’s fields and enforces its rules behind those operations. Abstraction answers what an object does, and encapsulation answers who may touch its data and how.
We need both in almost every class we write. Abstraction lets us swap an implementation without changing the callers, and encapsulation stops callers from putting an object into an invalid state, for example a thermostat set to 300 degrees.
The following example shows both ideas in one small thermostat type.
interface Thermostat {
void setTarget(int celsius);
int target();
}
class RoomThermostat implements Thermostat {
private int targetCelsius = 20;
public void setTarget(int celsius) {
if (celsius < 5 || celsius > 30) {
throw new IllegalArgumentException("Target out of range: " + celsius);
}
targetCelsius = celsius;
}
public int target() {
return targetCelsius;
}
}
Thermostat living = new RoomThermostat();
living.setTarget(22);
int current = living.target(); // 22
living.setTarget(45); // IllegalArgumentException: Target out of range: 45
The snippet has two layers. The Thermostat interface is the abstraction, because callers see only setTarget() and target(). The private field and the range check are the encapsulation, because no caller can store 45 in targetCelsius. We look at each concept on its own and compare them in a table. We also cover accessor methods and records, which are the places where the two ideas are most often mixed up.
1. Abstraction Decides What Callers See
Abstraction is a design step. Before we write the inside of a class, we decide which operations the outside world needs and give them names and types. In Java, we write that decision down as an interface or as the public methods of a class. The abstraction in Java guide covers interfaces and abstract classes in detail.

Say a smart home app supports thermostats from two vendors. One vendor’s device takes Celsius over a local network, and the other takes Fahrenheit through a cloud API. The app screens call Thermostat.setTarget(22) in both cases. Each vendor class converts and sends the value its own way, and the screens never know which device sits behind the interface.
class CloudThermostat implements Thermostat {
private int targetFahrenheit = 68;
public void setTarget(int celsius) {
if (celsius < 5 || celsius > 30) {
throw new IllegalArgumentException("Target out of range: " + celsius);
}
targetFahrenheit = celsius * 9 / 5 + 32;
}
public int target() {
return (targetFahrenheit - 32) * 5 / 9;
}
}
Thermostat office = new CloudThermostat();
office.setTarget(25);
int officeTarget = office.target(); // 25
We can see that the abstraction stays the same while the stored unit changes completely. That is the payoff of abstraction, and it works only because each class hides its own field, which brings us to encapsulation.
2. Encapsulation Protects the Data Behind It
Encapsulation means keeping an object’s fields together with the methods that work on them, and blocking direct access to those fields from outside. In Java, we do it with access modifiers, most often a private field plus methods that check every change. The class becomes the only place that can break its own rules, so we fix a bug in one file instead of hunting through the whole codebase.
The following class has no encapsulation, because its field is public.
class OpenThermostat {
public int targetCelsius = 20;
}
OpenThermostat hallway = new OpenThermostat();
hallway.targetCelsius = 300;
int hallwayTarget = hallway.targetCelsius; // 300
Any class in the app can write 300 into the field, and the heating controller finds out only when it tries to send that value to the device. With RoomThermostat, the same mistake throws an IllegalArgumentException at the exact line that made it, and the stack trace points to the caller. Encapsulation also lets us rename the field or change its unit later, because no other class refers to it.
3. Difference Between Encapsulation and Abstraction
The two principles answer different questions, and the table puts them side by side. The last row is the quickest way to tell them apart in an interview or a code review.
| Aspect | Abstraction | Encapsulation |
|---|---|---|
| Main question | What does the object do? | Who can read or change its data? |
| Level | Design of the public contract | Implementation of the class |
| Java tools | Interfaces, abstract classes, public method signatures | private fields, access modifiers, validation in methods |
| Hides | Which class does the work and how | The fields and the rules that keep them valid |
| Without it | Callers depend on concrete classes and break when they change | Any caller can put the object into an invalid state |
| Example in the JDK | The Map interface with get() and put() | The internal array of nodes inside HashMap |
| Quick test | Decides which methods exist | Decides which fields are visible |
Abstraction and encapsulation are not alternatives, because a well-designed class uses both, with the abstraction on the outside and the encapsulation on the inside. A common phrasing is that encapsulation is how we implement the abstraction we designed.
4. Getters and Setters Do Not Make a Class Encapsulated
A class with private fields and a generated getter and setter for each one looks encapsulated, but the setter accepts any value and the getter may hand out internal objects. Two problems show up again and again in real code.
- A setter without checks lets callers store invalid values, the same as a public field.
- A getter that returns a mutable collection lets callers change the object’s state without calling any of its methods.
The following schedule class shows the second problem and its fix side by side.
class LeakySchedule {
private final List<Integer> hours = new ArrayList<>(List.of(6, 18));
List<Integer> hours() {
return hours;
}
}
class HeatingSchedule {
private final List<Integer> hours = new ArrayList<>(List.of(6, 18));
List<Integer> hours() {
return List.copyOf(hours);
}
void addHour(int hour) {
if (hour < 0 || hour > 23) {
throw new IllegalArgumentException("Hour out of range: " + hour);
}
hours.add(hour);
}
}
LeakySchedule leaky = new LeakySchedule();
leaky.hours().add(99);
List<Integer> leakedHours = leaky.hours(); // [6, 18, 99]
HeatingSchedule schedule = new HeatingSchedule();
schedule.hours().add(99); // UnsupportedOperationException
schedule.addHour(22);
List<Integer> safeHours = schedule.hours(); // [6, 18, 22]
The call List.copyOf() returns an unmodifiable copy, so the only way to change the schedule is addHour(), which checks the value. If a field does not need to change after construction, we skip the setter entirely and make the field final.
5. Records and Encapsulation
A Java record (Java 16) is a class for plain data with private final fields and accessor methods generated by the compiler. Records give up part of encapsulation on purpose, because their fields are part of the public API. They keep the other part, since nobody can reassign a field, and the compact constructor is the place for validation and defensive copies.
record Setpoint(String room, int celsius) {
Setpoint {
if (celsius < 5 || celsius > 30) {
throw new IllegalArgumentException("Target out of range: " + celsius);
}
}
}
record WeeklyPlan(List<Setpoint> points) {
WeeklyPlan {
points = List.copyOf(points);
}
}
Setpoint bedroom = new Setpoint("bedroom", 19);
int bedroomTarget = bedroom.celsius(); // 19
Setpoint sauna = new Setpoint("sauna", 90); // IllegalArgumentException: Target out of range: 90
List<Setpoint> source = new ArrayList<>(List.of(bedroom));
WeeklyPlan plan = new WeeklyPlan(source);
source.clear();
int planSize = plan.points().size(); // 1
Clearing the source list after construction does not affect plan, because the compact constructor stored a copy. A record is the right choice when the data is the abstraction, such as a setpoint sent to a device, and a class with hidden fields is the right choice when callers must not see how the data is stored.
6. Both Principles in HashMap
The JDK class HashMap shows the split clearly. The abstraction is the Map interface, where we call put(), get() and remove() and expect each key to map to one value.
The encapsulation is everything we cannot see. The class HashMap stores entries in an internal array of nodes, and since Java 8 it turns long buckets into balanced trees. None of that is part of its API. The JDK team changed those internals between releases, and our code kept working because it only used the Map methods.
7. Encapsulation and Abstraction FAQs
Both terms overlap with data hiding and with each other, so most follow-up questions ask where one principle ends and the other starts.
7.1. Is encapsulation the same as data hiding?
Not quite. Data hiding means making fields inaccessible from outside, most often with private. Encapsulation is the broader idea of bundling fields with the methods that guard them, so data hiding is one part of encapsulation.
7.2. Can we have abstraction without encapsulation?
Yes, but it does not last long. An interface is an abstraction with no fields at all. A class that implements it with public fields still offers the abstraction, but any caller can bypass the methods and break the rules the interface promises.
7.3. Which comes first, abstraction or encapsulation?
Abstraction comes first in design, because we decide the operations before we write the class. Encapsulation comes during implementation, when we choose the fields and protect them.
7.4. Are private fields enough for encapsulation?
No. A private field that a getter returns as a mutable object, or that a setter changes without checks, is still open to any caller. Encapsulation needs validation in the methods that change state and copies or unmodifiable views for mutable data.
8. Conclusion
Abstraction is the outside of a type, namely the operations it promises. Encapsulation is the inside, namely the hidden fields and the checks that keep them valid. The thermostat example used both, with an interface for the contract and a private field with a range check for the state.
When we review a class, we check two things separately. The first is whether the public API says only what callers need, which is abstraction. The second is whether any caller can put the object into an invalid state, which is encapsulation. Both are part of the OOP concepts in Java.
9. References
- Java Tutorials, Controlling Access to Members of a Class
- JLS 25, Access Control
- JEP 395, Records
- List.copyOf() Javadoc
Happy Learning !!
You type a number and press/touch “DIAL” button. This dial button is actually an example of abstraction of making call.
is encapsulation and data hiding the same ?
In layman term, yes data hiding is encapsulation. But, encapsulation is not only data hiding but much more than that.
Can we say abstraction is a thought process and encapsulation is an implementation of abstraction ???
Not really. Both are parts of implementation. In fact, abstraction is mostly represented via interfaces and encapsulation via implemeting classses.