Object Oriented Programming System (OOPS)
The object-oriented programming system (OOPS) is a fundamental programming paradigm that relies on the concept of classes and objects rather than functions and procedures. It is used to structure a software program into simple, reusable pieces of code. This concept aims to implement real-world entities in programs. Simula and Smalltalk are considered the first object-oriented programming languages.
OOPS is the most popular programming paradigm used by nearly every developer and is taught as the standard way to code for most programmers. Without having an idea about OOPS concepts, you will not be able to design systems in the object-oriented programming model. It simplifies software development and maintenance.
Why do we use object-oriented programming?
- Make the development and maintenance of projects easier.
- OOPs provide the feature of data hiding, which is good for security concerns.
- We can provide the solution to real-world problems if we are using object-oriented programming.
Building blocks of OOPS
- Classes
- Objects
- Methods
- Attributes
The core concepts of OOPs
- Class
- Object
- Inheritance
- Abstraction
- Encapsulation
- Polymorphism
Class
In Java programming, a class is basically a template or blueprint from which objects are created. Every class defines the properties and behaviors of an object. In other words, A “class” is a group of objects which have common properties and behaviors.
Example: Let us consider two objects, the Samsung Galaxy and the iPhone.
Samsung Galaxy has properties like width = 6 cm, height = 13 cm, OS = Android, and price = $1000, as well as actions like call(), sendMessage(), browse(), share(), and takePicture().
The iPhone has some properties such as width = 7.7 cm, height = 13.2 cm, OS = iOS, price = $1200, and actions such as call(), sendMessage(), browse(), and share().
Both objects have some different properties and actions, but the type is the same: “Phone.” The type “Phone” is the class.
Class is a logical entity that does not occupy any space or memory and contains:
- Fields
- Methods
- Constructors
- Blocks
- Nested class and interface
// syntax for class
class <class_name> {
field;
method;
}
Object
An object is an instance of a class. Each object has its own unique identity, behavior, and state. An object is a runtime entity.
- State: It is represented by the attributes of an object.
- Behavior: It is represented by the methods of an object.
- Identity: It gives a unique name to an object.
The class as a blueprint specifies what an object will look like. Consider a class called “Mobiles” and Samsung and Nokia mobiles as objects of the class Mobiles.
Note: Memory is allocated when we create objects of a class type.
We can create an object by using the new keyword. The new keyword is used to allocate memory for an object dynamically and return a reference to it.
// The syntax for creating an object is:
ClassName object = new ClassName();
There are three ways to initialize an object:
- By reference variable
- By method
- By constructor
Example for class and object:
public class Main { // Main is the class name
int x = 5; // fields (variables)
public static void main(String[] args) {
Main myObj = new Main(); // myObj is an object
System.out.println(myObj.x);
}
}
// Output: 5
Four Principles of OOPS
- Inheritance.
- Abstraction.
- Encapsulation.
- Polymorphism.
Inheritance
Inheritance is a mechanism by which an object acquires all the properties and behaviors of its parent. In inheritance, there are two classes: the parent class, or super class, and the child class, or sub class. The keyword “extends” is used by the subclass to inherit the features of the superclass. Inheritance represents the IS-A relationship, which is also known as a parent-child relationship.
Uses of Inheritance
- Increase the reusability of code
- For method overriding (so runtime polymorphism can be achieved)
- Remove code duplication, which indirectly helps in bug-free code.
Types of Inheritance
- Single Inheritance
When a class inherits properties from another class, this is known as a single inheritance. The class that inherits another class is termed a “derived class,” whereas the class from which it’s extended is termed a “base class.”
The diagram represents that a class named B extends from a single class, which is A. In this, A is the superclass, and B is the subclass.
// Superclass (Parent class)
class Animal {
void eat() {
System.out.println("The animal eats food.");
}
}
// Subclass (Child class) inheriting from Animal
class Dog extends Animal {
void bark() {
System.out.println("The dog barks.");
}
}
class Main {
public static void main(String[] args) {
// Create an instance of the Dog class
Dog myDog = new Dog();
// Call methods from both the Animal and Dog classes
myDog.eat(); // Inherited from Animal class
myDog.bark(); // Defined in Dog class
// You can also create an Animal reference to a Dog object
//Animal myAnimal = myDog;
// myAnimal.eat(); // Still calls the eat method from Animal class
}
}
2. Multi-Level Inheritance
When there is a chain of inheritance, it is known as multilevel inheritance. In multilevel inheritance, a subclass extends from a superclass, and then the same subclass acts as a superclass for another class. For example,
3. Hierarchical Inheritance
When two or more classes inherit a single class, it is known as “hierarchical inheritance.” In hierarchical inheritance, multiple subclasses extend from a single superclass. For example,
4. Multiple Inheritance
In multiple inheritance, a single subclass extends from multiple super classes. To reduce the complexity and simplify the language, Java doesn’t support multiple inheritance in classes because it can lead to the “diamond problem.” However, we can achieve multiple inheritance using interfaces.
The reason why Java doesn’t support multiple inheritance is:
Consider that if a child class inherits from more than one parent, the compiler may be unsure whether to call the function from class A or class B. Therefore, to prevent the ambiguity of the “Diamond” problem, Java doesn’t support multiple inheritance. But we can use interfaces to achieve the same purpose.
Interface (The blueprint of the class)
An interface is a contract for a number of classes, which is a mechanism to achieve abstraction and multiple inheritance in Java. Like a class, an interface can have methods and variables, but the methods declared in an interface are abstract by default.
In inheritance, a class extends another class, an interface extends another interface, but a class implements an interface.
Points to remember for Interface:
- Access modifiers for methods declared in interfaces are public abstract by default.
- Access modifiers for variables and fields declared in interfaces are by default public static final.
- There are no constructors in Interface.
- We never create objects for the interface.
As a result, consider interface to be a fully abstract class. It includes a group of abstract methods (methods without a body).
interface Language {
public void getType();
public void getVersion();
}
Here, language is an interface. It has methods like getType() and grtVersion().
Implementation for Multiple Inheritance:
class A
void msg(){
System.out.println("Hello");}
}
class B
void msg(){
System.out.println("welcome");}
}
class C extends A,B {
public static void main(String args[]){
C obj = new C();
obj.msg();
}}
// Output: Compile-time Error
Implementation for Interface:
interface Animal {
public void animalSound(); // interface method (does not have a body)
public void sleep(); // interface method (does not have a body)
}
class Pig implements Animal {
public void animalSound() {
System.out.println("The pig says: wee wee");
}
public void sleep() {
System.out.println("Zzz");
}
}
class Main {
public static void main(String[] args) {
Pig myPig = new Pig(); // Create a Pig object
myPig.animalSound();
myPig.sleep();
}
}
Output: /* The pig says: wee wee
Zzz */
Abstraction
Abstraction is the process of hiding implementation details from the user and displaying only functionality. i.e., it shows only the essential things to the user and hides the internal details. For example, when sending SMS, you are unaware of the internal processing that occurs during message delivery.
Ways to achieve Abstraction:
There are two ways to achieve abstraction in Java.
- Abstract class (0 to 100%)
- Interface (100%)
Abstract Class (incomplete class; no object creation)
A class that is declared abstract is known as an abstract class. A class can be abstract even if there are no abstract methods. It can have abstract and non-abstract methods. We cannot create objects for an abstract class. It can also have final methods, static methods, and constructors.
Abstract Methods
A method that is declared abstract and does not have an implement is known as an abstract method. If a method is declared abstract, then the class of the method must also be abstract. An abstract method cannot be private. If abstract methods are private, then they will not be inherited by subclasses and will not get enhanced. A class can be abstract even if there are no abstract methods.
Implementation for abstract classes:
abstract class Bike {
abstract void run();
}
class Honda extends Bike {
void run() {
System.out.println("running safely");}
}
public class Main {
public static void main(String args[]) {
Honda obj = new Honda();
obj.run();
}}
// Output: running safely
In this example, Bike is an abstract class that contains only one abstract method, run. The Honda class provides its implementation.
Implementation using an interface:
interface I {
void eat();
}
class B implements I {
public void eat() {
System.out.println("Hello");
}
public static void main(String args[]) {
B obj = new B();
obj.eat();
}}
// Output: Hello
By using an interface, we can achieve 100% abstraction.
Accesses abstract class constructors
We can access the constructor of an abstract class from a subclass using the super keyword.
abstract class animal {
Animal() {
.....
}}
class Dog extends Animal {
Dog() {
super();
.....
}
}
Advantages of abstraction
- It helps reduce the complexity of the design and implementation processes of software.
- It avoids code duplication.
Encapsulation
The process of wrapping up the implementation of data and methods(binding of the data member and member functions/methods) into a single unit is called encapsulation. In other words, encapsulation is a protective shield that prevents data from reaching the outside of the shield. To ensure the security of the code, we can use encapsulation.
Every Java class is an example of encapsulation because we write everything within the class, which binds variables and methods together and hides their complexity from other classes.
As an example, we all use strong passwords to protect our phones and computers. This prevents unauthorized access to our data present on the phone or computer.
We can achieve or implement encapsulation in two ways:
- Declaring the instance variable of a class as private so that it cannot be accessed directly from outside the class Therefore, it is also called “data hiding.”
- Provide public setter and getter methods to set or modify the values of the variable or fields.
package encapsulation;
class Test {
private int a;
int getValue() {
return a;
}
void setValue(int x) {
a = x;
}
}
public class Encapsulation {
public static void main(String[] args) {
Test obj = new Test();
obj.setValue(10); // getter & setter is used to call indirectly
int b = obj.getValue(); // intermediater = binds
System.out.println(b);
}
}
// Output: 10
Polymorphism
In Greek, the term “polymorphism” means many forms. Poly = many; morphs = different forms. Polymorphism is the ability of an entity to take on multiple forms. i.e., one task is performed in different ways.
Note: Entities can be an object, variable, function, etc.
In Java, polymorphism is implemented using inheritance, method overloading, and method overriding.
Example:
A boy starts to love a girl with the word “friendship,” but the girl ends the love with the same word “friendship.”
The word is the same, but the attitude is different. This beautiful concept is called polymorphism.
There are two types of polymorphism in java:
- Compile-time(Static) polymorphism (Overloading)
- Run-time(Dynamic) polymorphism (Overriding)
Compile-time Polymorphism
Compile-time polymorphism, also called static polymorphism, is a type of polymorphism that happens at compile-time. It has two types.
- Method Overloading
- Operator Overloading
Method Overloading
Method overloading is the ability to create multiple methods with the same name but different parameters.
Rules for Method Overloading:
- The method name must be the same, but the parameters can be different.
- The parameters can be changed in one of the following three ways:
1. Data types of parameters (The data type should be different in both methods.) Example:
void add(int a, int b);
void add(int a, float b); // It is a valid case of method overloading.
2. Number of parameters (The number of parameters is different, but the data type is the same.) Example:
void sum(int a, int b);
void sum(int a, int b, int c); // It is also a valid case of method overloading.
3. Sequence of Data type of parameters is different. Example:
void sub(int a, double b);
void sub(double a, float a); // This case is also valid for method overloading
Example of method overloading:
public class Addition {
void sum(int a, int b)
{
int s = a + b;
System.out.println("Sum of two numbers: " +s);
}
void sum(int a, int b, int c)
{
int t = a + b + c;
System.out.println("Sum of three numbers: " +t);
}
public static void main(String args[]) {
Addition a = new Addition();
a.sum(10, 20);
a.sum(50, 23, 46);
}
}
/* Output: Sum of two numbers: 30
Sum of three numbers: 119 */
In this example, the add(sum) method is overloaded with two different versions, one that takes two arguments and one that takes three arguments.
Operator Overloading
The ability to redefine the functionality of the operators is referred to as “operator overloading.” Programming languages like C++ support operator overloading.
Java does not support operator overloading to avoid ambiguities.
The functionality of operator overloading can be achieved in Java using method overloading in a simple, error-free, and clean manner.
Runtime Polymorphism
Dynamic polymorphism is another name for runtime polymorphism. In Java, method overriding is a technique for implementing runtime polymorphism. It is also sometimes known as the “dynamic method of dispatch.”
Method Overriding
Method overriding is the ability to create a method in a subclass with the same name and parameters as a method in the superclass and then provide a different implementation for the method in the subclass.
Rules of Method Overriding:
- The child class method must have the same name as in the parent class.
- The child class method must have the same parameter as in the parent class.
- There must be an IS-A relationship (inheritance)
Example of method overriding:
class Human {
public void eat()
{
System.out.println("Human is eating");
}
}
class Boy extends Human {
public void eat()
{
System.out.println("Boy is eating");
}
public static void main(String args[]) {
Boy obj = new Boy();
// Human obj = new Boy(); // Upcasting
obj.eat();
}
}
// Output: Boy is eating
Difference Between Upcasting & Downcasting : -
class EmmaBeforeCollege {
public void looks() {
System.out.println("Emma's natural looks");
}
public void love() {
System.out.println("Emma's Deep love with Harry");
}
}
class EmmaAfterCollege extends EmmaBeforeCollege {
public void looks() {
System.out.println("Emma applies foundation and lipstick.");
}
public void love() {
System.out.println("Emma's Deep love with Harry and dated Peter");
}
}
public class Main {
public static void main(String[] args) {
EmmaAfterCollege emma = new EmmaAfterCollege();
emma.looks(); // Output: Emma applies foundation and lipstick.
emma.love(); // Output: Emma's Deep love with Harry and dated Peter
}
}
// parent class methods are overridden.