So what is an abstraction in OOP programming?
Let’s imagine you have a car.
it has a lot of characteristics like a weight, dimensions, color, maximum speed etc.
To describe a Car
object you need only color and max speed for your use-case.
Weight and dimensions don’t matter to you.
Abstraction means showing only necessary to you details of an object.
Let’s imagine we need to describe parts of an engine like a cylinder or piston.
It makes sense to create an Engine
object and add cylinder and piston details there and Engine
will be a part of a Car
.
This is data abstraction layers.
Each abstraction layer is hiding its own implementation details and characteristics.
It’s reasonable to ask me what is a difference between encapsulation and abstraction?
Encapsulation hides object internal implementation, abstraction is more about splitting your data into logical pieces and using only that object details that you need.
Now you know the theory, but what does abstract mean in Java?
Java provides an abstract
keyword to create abstract classes and methods.
Let’s take a deeper look.
What is Abstract Classes and Methods in Java?
Let’s define what is an abstract class and what is the purpose of an abstract class in Java.
An abstract class is a class that contains an abstract keyword, it cannot be initiated, but you can subclass it.
An abstract method is a method without implementation.
If a class contains at least one abstract method it should be marked as abstract.
Why do we need that?
We need abstract classes to implement inheritance in Java.
For example, we have 2 classes Dog
and Cat
.
public class Dog {
private String name;
private String bread;
private String color;
private Set<String> commands;
}
A dog has a name, bread, color and knows a set of commands.
public class Cat {
private String name;
private String bread;
private String color;
private boolean likesToCatchMice;
}
A cat has a name, bread, and color as well and it has a boolean variable to check likes a cat to catch mice or not because some of them are really lazy.
As you see 2 these classes have 3 similar fields: name, bread, and color.
We can create an abstract class Animal
and extract similar fields there.
package com.explainjava;
public abstract class Animal {
private String name;
private String bread;
private String color;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getBread() {
return bread;
}
public void setBread(String bread) {
this.bread = bread;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}
Dog
class should extend Animal
:
package com.explainjava;
import java.util.Set;
public class Dog extends Animal {
private Set<String> commands;
public Set<String> getCommands() {
return commands;
}
public void setCommands(Set<String> commands) {
this.commands = commands;
}
}
A Cat
should do the same:
package com.explainjava;
public class Cat extends Animal {
private boolean likesToCatchMice;
public boolean isLikesToCatchMice() {
return likesToCatchMice;
}
public void setLikesToCatchMice(boolean likesToCatchMice) {
this.likesToCatchMice = likesToCatchMice;
}
}
Now Cat
and Dog
don’t have duplicated fields, so you need to write less code -> less tests -> development process is faster.
Now we want to teach our animals to speak.
The idea is to add abstract speak()
method to an animal and implement it in each subclass.
package com.explainjava;
public abstract class Animal {
// other fields and methods there
public abstract String speak();
}
Cat speak()
method:
package com.explainjava;
public class Cat extends Animal {
// other fields and method there
@Override
public String speak() {
return "meow";
}
}
Dog speak()
method:
package com.explainjava;
import java.util.Set;
public class Dog extends Animal {
// other fields and methods there
@Override
public String speak() {
return "woof-woof";
}
}
As you see speak()
method signature looks the same but implemented differently.
One more benefit here is a polymorphism.
We can put all animals (dogs, cats) into a collection and can ask to speak all of them and we don’t care about internal implementation.
Example:
public static void main(String[] args) {
Cat cat = new Cat();
cat.setName("Tom");
cat.setBread("British Shorthair");
cat.setColor("white");
cat.setLikesToCatchMice(true);
Dog dog = new Dog();
dog.setName("Max");
dog.setBread("German Shepherd");
dog.setColor("brown");
dog.setCommands(Stream.of("Sit", "Stey", "Wait").collect(Collectors.toSet()));
List<Animal> animals = new ArrayList<>();
animals.add(cat);
animals.add(dog);
for (Animal animal : animals) {
System.out.println(animal.speak());
}
}
Output:
meow
woof-woof
You can use a constructor instead of setters if you like this style more.
What is an Interface in Java?
An interface is a group of related methods without implementation.
The class can implement as many interfaces as you want.
But since Java 8 you can write default methods and since Java 9 these methods even could be private.
But let’s try to understand what is it step-by-step.
For example, we want to add a Robot
class and it can speak as well.
Let’s implement speak()
method:
package com.explainjava;
public class Robot {
public String speak() {
return "I'm T-1000";
}
}
The problem here is: we can’t add a robot to our list to speak with animals.
What can we do? Extract speak()
method to an interface.
Example:
package com.explainjava;
public interface Speakable {
String speak();
}
By default, all methods are public abstract
and all fields are constants (public static final
) in the interface.
Let’s make Cat
, Dog
, and Robot
implementing Speakable
interface.
In case of Dog and Cat it’s enough to make Animal class implementing Speakable and remove its own speak() method.
package com.explainjava;
public abstract class Animal implements Speakable {
// fields, setters and getters here
}
And more or less the same for a Robot
:
package com.explainjava;
public class Robot implements Speakable {
@Override
public String speak() {
return "I'm T-1000";
}
}
Since all of our objects implement Speakable we can build a list of that objects and ask they them speak:
public static void main(String[] args) {
Cat cat = new Cat();
cat.setName("Tom");
cat.setBread("British Shorthair");
cat.setColor("white");
cat.setLikesToCatchMice(true);
Dog dog = new Dog();
dog.setName("Max");
dog.setBread("German Shepherd");
dog.setColor("brown");
dog.setCommands(Stream.of("Sit", "Stey", "Wait").collect(Collectors.toSet()));
Robot robot = new Robot();
List<Speakable> speakables = new ArrayList<>();
speakables.add(cat);
speakables.add(dog);
speakables.add(robot);
for (Speakable speakable : speakables) {
System.out.println(speakable.speak());
}
}
Output:
meow
woof-woof
I'm T-1000
I mentioned about default methods in the interface since Java 8, let’s take a look what is it.
For example, we want that by default all Speakable
objects speak “Hello”.
We need to change our interface a little bit:
package com.explainjava;
public interface Speakable {
default String speak() {
return "A-a-a-a-a";
}
}
As you see speak()
method is marked as default
and has its own implementation.
Let’s create a Human
class that implements Speakable
:
package com.explainjava;
public class Human implements Speakable {
}
Java doesn’t force you to implement speak()
method because it has a default implementation.
Of course, you can override it if it’s necessary for you.
If 2 interfaces have a default method with the same signature it’s not possible to compile the target class, you have to override this method explicitly.
Since Java 9 you can define private methods in the interface:
package com.explainjava;
public interface Speakable {
default String speak() {
return Aaaaaa();
}
private String Aaaaaa() {
return "A-a-a-a-a";
}
}
It could be useful if you want to extract common logic of 2 methods to avoid code duplication.
Abstract Class vs Interface in Java
Sometimes it’s really hard to make choice what’s better.
Let’s take a look what is a difference between abstract class and interface and when to use both of them.
Difference between Class and Interface
You can say: “Since Java 9 abstract class and interface looks almost the same, what is a difference?”.
Nowadays differences between abstract class and interface are:
- You cannot define fields in the interface, so it doesn’t hold a state.
- It’s not possible to extend few classes, but you can implement as many interfaces as you can.
If you’re talking about Java 8 you can’t define private methods.
Before Java 8 you cannot even define a default method implementation.
When to Use Abstract Class and When to Use Interface
First of all, you should understand differences described above.
Abstract classes it’s a defining what your class is, interfaces it’s defining what your class can do (behavior).
Personally, I don’t like default methods in the interfaces, that’s why I’m creating abstract classes when:
- I need to define default behavior, e.g. template method design pattern.
- It’s necessary to extract common fields.
- Your class and subclass should follow is-a relationship (read below).
In all other cases, I’m taking an interface.
In the same time, you should keep in mind that Java doesn’t support multiple inheritances, but you can implement as many interfaces as you want.
Is-a and Has-a Relationships (Inheritance vs Composition)
The composition is a way to combine simple objects into a complex object.
A Car
contains an Engine
, Wheels
etc, so we combine simple objects (engine, wheels) into more complex (car).
Every book about programming best practices will say to you: “Prefer composition over inheritance”.
But sometimes it’s complicated to decide what to use.
In such cases, you can use “is-a” and “has-a” relationship rules.
If you can say “BMW is a Car”, “Audi is a Car” – use inheritance.
If you can say “Car has an engine”, “Car has a wheel” – use composition.
Interview Questions
As usual, I’m writing questions only, answers you can find in the article’s body.
The most popular interview questions are:
- What is an abstraction in Java and what are abstraction layers?
- Is-a and has-a relationships: what is it and how to use it?
- What do you prefer inheritance or composition?
- How to define an abstract class?
- What is a difference between abstract class and interface?
- When you to use abstract class and when interface?
- What is a default method in the interface?
- Since what versions of Java you can define default and private methods in the interface?
- What is template method design pattern?
You can find a huge list of interview questions in my post, answers are in Java tutorials section.
That’s it! Any question? Please, feel free to ask me.