There are 4 major principles that make an language Object Oriented. These are Encapsulation, Data Abstraction, Polymorphism and Inheritance. These are also called as four pillars of Object Oriented Programming.
What
Why
How
Example
Encapsulation is the mechanism of hiding of data implementation by restricting access to public methods. Instance variables are kept private and GetterSetter methods are made public to achieve this.
For example, we are hiding the name
and dob
attributes of person class in the below code snippet.
Encapsulation — private instance variable and public GetterSetter methods.
public class Employee {
private String name;
private Date dob;
public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public Date getDob() {
return dob;
} public void setDob(Date dob) {
this.dob = dob;
}
}
Abstract means a concept or an Idea which is not associated with any particular instance. Using abstract class/Interface we express the intent of the class rather than the actual implementation. In a way, one class should not know the inner details of another in order to use it, just knowing the interfaces should be good enough.
Using Inheritance, Derived Classes we can reuse the properties and methods of existing Super Classes. Inheritances expresses “is-a” relationship between two objects. . In Java, concept of “is-a” is based on class inheritance (using extends
) or interface implementation (using implements
).
Why use inheritance in java
For Method Overriding (so runtime polymorphism can be achieved).
For Code Reusability.
Polymorphism in Java is a concept by which we can perform a single action in different ways. It means one name many forms. It is further of two types — static and dynamic.
There are two types of polymorphism in Java: compile-time polymorphism and runtime polymorphism. We can perform polymorphism in java by method overloading and method overriding.
If you overload a static method in Java, it is the example of compile time polymorphism.
Runtime polymorphism is about an overridden method is called through the reference variable of a superclass. The determination of the method to be called is based on the object being referred to by the reference variable.
For example: interface work{ void work();}
class Programmer implement work{
void work(){
print("Coding");
}
}
different classes implement work have different working action.
Java collections framework has an interface called java.util.Collection
, ArrayList
and TreeSet
are two different implementation of this interface. ArrayList maintains the insertion order of elements while TreeSet
orders its elements by their natural order
or comparator
(if supplied). Now if we write a method that accepts a collection and prints its elements, the actual object (ArrayList or TreeSet) at runtime will decide the behavior of this method.
Polymorphic print method
public void print(Collection<String> collection) {
for (String s : collection) {
System.out.println("s = " + s);
}
}
Passing an ArrayList
Collection<String> collection1 = new ArrayList<>();
collection1.add("A");
collection1.add("D");
collection1.add("B");
collection1.add("C");
print(collection1); //elements will be printed as per the insertion order of elements into arraylist
Program output
s = A
s = D
s = B
s = C
Passing an TreeSet
Collection<String> collection2 = new TreeSet<>();
collection2.add("A");
collection2.add("D");
collection2.add("B");
collection2.add("C");
print(collection2); //elements will be printed as per the natural order
Program output
s = A
s = B
s = C
s = D
We just saw that print()
method’s behavior is determined by the actual type of object passed to it at run time. That’s polymorphism!
Important Facts
java.lang.Object
, all java objects are polymorphic i.e. they pass the IS-A test for their own type as well as for class Object
.print()
method can only invoke methods that are listed on Collection
interface irrespective the type of actual object passed to this method.