ALL OOPs Concepts Using Java with 1 Tiny Program – Explained!

Learn OOPs concepts using Java with 1 real-life program example. ALL oops features used in this program are explained.

PROGRAM: ENJOY COFFEE IN THE CAR!The application is: Choose your luxury car and enjoy coffee or tea as per your choice while driving.

First, you need to have a look at the complete program, and then come back while reading the concepts given after it, if required.

TABLE OF CONTENT:

  • Complete program in java
  • Class and Object
  • Class constructor
  • Polymorphism
  • Method overloading
  • Method overriding
  • Inheritance
  • Interface
  • Abstract class
  • Abstraction and Encapsulation
  • Composition and Aggregation
  • Generalization and Specialization

Complete program in java

//Driver class with driver’s name and Drive

//functionality

import java.util.Scanner;

class Driver {
	String name;
	int license;
	int mobile;

	public Driver() {
		this.name = "Car Owner";
		this.license = 11111;
		this.mobile = 11111;
	}

	public void drive() {
		System.out.println("Drive started..." + "Have a nice drive!");
	}

	public void profile(String name) {
		this.name = name;
	}

	public void profile(String name, int license) {
		this.name = name;
		this.license = license;
	}

	public void profile(String name, int license, int mobile) {
		this.name = name;
		this.license = license;
		this.mobile = mobile;
	}

	public String getName() {
		return name;
	}
}

// Car class aggregated with driver and
// composed with in built feature beverages
// Tea and Coffee.

class Car {
	Driver driver;
	Beverages b;
	String carChoice;

	Car() {
		this.carChoice = "SUV";
	}

	Car(String carChoice) {
		this.carChoice = carChoice;
	}

	void GetInTheCar(Driver driver) {
		System.out.println("Hey " + driver.getName()
				+ " Enjoy driving with your " + this.carChoice + " Car");
		driver.drive();
	}

	void EnjobyBeverages() {
		System.out
				.println("Want Beverage?" + " Enter 1 for Tea/ 2 for Coffee!");
		Scanner s = new Scanner(System.in);
		int choice = s.nextInt();
		if (choice == 1) {
			b = new Tea();
		}
		if (choice == 2) {
			b = new Coffee();
		}

		b.getBeverage();
	}
}


// Beverages abstract class.

abstract class Beverages {

	private void addHotWater() {
		System.out.println("Adding hot water");
	}

	private void addMilk() {
		System.out.println("Adding hot milk");
	}

	private void addSugar() {
		System.out.println("Adding Sugar");
	}

	public void getMixture() {
		System.out.println("Your Beverage is " + "getting ready...");
		addHotWater();
		addMilk();
		addSugar();
	}

	public abstract void getBeverage();

	public abstract void addIngredients();
}


// 2 subclasses Tea and Coffee and an Interface to enforce subclasses to implement
// cleaning tea and coffee pot.

interface Clean {
	void cleanPot();
}

class Tea extends Beverages implements Clean {

	@Override
	public void addIngredients() {
		System.out.println("Tea Bag added");
	}

	@Override
	public void getBeverage() {
		cleanPot();
		getMixture();
		addIngredients();
		System.out.println("Tea's Ready! Enjoy");
	}

	@Override
	public void cleanPot() {
		System.out.println("Cleaning tea pot...");
	}
}

class Coffee extends Beverages implements Clean {

	@Override
	public void addIngredients() {
		System.out.println("Coffee Bag added");
	}

	@Override
	public void getBeverage() {
		cleanPot();
		getMixture();
		addIngredients();
		System.out.println("Coffee's Ready! Enjoy");
	}

	@Override
	public void cleanPot() {
		System.out.println("Cleaning Coffee pot...");

	}
}

// SAMPLE CLIENT PROGRAM

public class Sample {

	public static void main(String[] args) {
		System.out.println("Welcome for a nice Drive!");
		Scanner s = new Scanner(System.in);
		Driver peter = new Driver();
		peter.profile("peter");
		Car c;

		System.out.println("Want to Choose Car? "
				+ "Press 0 for NO / 1 for YES");
		int carType = s.nextInt();
		if (carType == 1) {
			System.out.println("Enter Car name");
			String carName = s.next();
			c = new Car(carName);
		} else {
			c = new Car();
		}

		c.GetInTheCar(peter);
		c.EnjobyBeverages();
	}

}


OUTPUT:

Welcome for a nice Drive!
Want to Choose Car? Press 0 for NO / 1 for YES
1
Enter Car name
Ferrari
Hey peter Enjoy driving with your Ferrari Car
Drive started...Have a nice drive!
Want Beverage? Enter 1 for Tea/ 2 for Coffee!
2
Cleaning Coffee pot...
Your Beverage is getting ready...
Adding hot water
Adding hot milk
Adding Sugar
Coffee Bag added
Coffee's Ready! Enjoy

Class and Object

A class is a blueprint or template from which you create multiple similar objects. For example, Peter, Jhon, and Linda, etc.

Form code:

Suppose we got a requirement to have a driver profile such as name, license and mobile number, and a functionality drive. Then you can create a template as a Driver class as shown in the program.

If you don’t have a template, then an object can try to put his/her age, gender, etc besides the name, license, and mobile, etc. Right?

Objects:

You can see multiple objects created in the code, e.g. for Driver, Tea and Coffee class, etc using the new keyword.

When you create an object using new, it gets created on heap memory. For example,

new Car();
c = new Car(carName);
Driver peter = new Driver();

NOTE:
1) “new Driver();” statement creates an object on the heap and assigns its reference to the variable peter which is on stack memory.
2)Note that a matching (empty or with parameter) constructor is always called when you create an object of a class.
3) If you don’t have a constructor in a class, the default one will be provided by the compiler. If you write a constructor even with a parameter only, the compiler will not provide any constructor. So, you’ve to write one with an empty parameter.

Class Constructor

Constructors have been used in the class Car and Driver to initialize objects. In other words, their class fields.

Here are the constructors for the classes Driver and Car and why they’re used:

The Driver class constructor is used to initialize with default values. So, if you don’t supply value from outside of the class, the default one will be used. Since, I wanted to give an option to set name, license, and mobile for the driver profile, I used a constructor to initialize the fields.

For example, if you only supply your name in the profile, your name will be used in the program. If you don’t then the default one will be used.

	public Driver() {
		this.name = "Car Owner";
		this.license = 11111;
		this.mobile = 11111;
	}

The Car class contains 2 constructors: 1) with empty parameter, 2) with one String type parameter.

NOTE: Having multiple constructors with different data types or different parameters is known as constructor overloading (compile-time) polymorphism.

From code: the Car class’s overloaded constructors are:

	Car() {
		this.carChoice = "SUV";
	}

	Car(String carChoice) {
		this.carChoice = carChoice;
	}

The matching constructors will be AUTOMATICALLY called, when the statements c = new Car(); and c = new Car(carName); executes in the Sample class.

Why used overloaded constructors in the Car class?

Because a driver has an option to choose a car. If he does not choose a Car and say NO, the default “SUV” car will be automatically selected.

	System.out.println("Want to Choose Car? "
				+ "Press 0 for NO / 1 for YES");
		int carType = s.nextInt();
		if (carType == 1) {
			System.out.println("Enter Car name");
			String carName = s.next();
			c = new Car(carName);
		} else {
			c = new Car();
		}

Polymorphism

“Simply, single functionality with the same name, with different implementation”.

  1. Constructor overloading – compile-time – already explained above.
  2. Method overloading – compile-time
  3. Method overriding – run-time

Method overloading

How you overloaded constructors, you can overload methods with the same name as well.

In the Driver class, we’ve 3 overloaded profile methods, because wanted to give options to users to use any of them. Users may want to set the only name, or name and license, etc.

Why overloaded methods, if you can write different methods with a different name?

Because, as an example, having 10 different method names for the same functionality is difficult to remember, but with the same name with different arguments is easier and readable.

From the below examples, you decide which one you’d love to use?

//overloaded methods
public void profile(String name)
public void profile(String name, int license)
public void profile(String name, int license, int mobile) 

//Methods with different name
public void profileWithName(String name)
public void profileWithNameAndLicense(String name, int license)
public void profileWithNameAndLIcenseAndMobile(String name, int license, int mobile) 

NOTE: Method overloading is a compile-time polymorphism, similar to constructor overloading.

Method overriding

You write a method with the same name in subclasses as present in the base class. It can be from base classes: interface, abstract class, a normal.

Form code:

We’ve overridden and implemented the cleanPot() method of interface Clean into the subclasses Tea and Coffee.

We’ve overridden getBeverage(); and addIngredients(); methods of the Beverages abstract class into the Tea and Coffee classes.

Same you can override the method from a normal base class and give it your definition into the child class if you want to use functionalities from the base class but don’t want to use some of them.

Inheritance

Re-use to functionalities of existing base class to save your time and efforts. And more…avail the feature of inheritance to implement an interface or use and implement the abstract class.

We’ve inherited and re-used the pre-built functionalities of the Beverages class like addHotWater(), addMilk(), and addSugar(), etc.

Interface

Simply, provide specifications (contracts) to child classes to implement them.

The Clean interface is used to provide clean pot specifications to subclasses Tea & Coffee to implement. In the program, it’s used to ENSURE that both the classes Tea and Coffee implement that as a mandatory cleaning process before preparing tea or coffee.

Abstract class

Abstract class acts as a base class and its primary purpose is to have common functionalities of all subclasses at one place in the base class and defer (postpone or force) some functionalities to subclasses to implement them.

In the given program, the Beverages abstract class has common functionalities like add hot water, add milk and add sugar, so the subclasses can inherit and use them. And the abstract class forces subclasses Tea and Coffee to implement getBeverage() and addIngredients() functionalities.

Abstraction and Encapsulation

Abstraction means providing only essentials to the users, and Encapsulation means hiding the complexities in whatever way you can hide.

Actually, abstraction is design-level concept where you decide what are necessary information’s to provide to users, and encapsulation is implementation level in object-oriented programming.

Form the code:

In the abstract class Beverages, we could have provided the functionalities addHotWater(), addMilk(), and addSugar() to the users, Tea, and Coffee subclasses.

But, I thought of abstraction, why give more responsibilities to users Tea and Coffee classes to call 3 functions? Can’t we reduce their responsibilities by providing only one getMixture() interface to them?

The abstraction says here: Only getMixture() method to users are enough.

So, I applied encapsulation at the implementation level design. Made all the 3 methods private and implemented one public method getMixture(). In this public method, I wrapped all the 3 methods.

Composition and Aggregation

The composition and aggregation are the relationship among the objects.

In composition, when the main object is destroyed, all the composed objects also MUST be destroyed whereas, in Aggregation, the composed object must not be destroyed.

These are the purely concepts and totally it’s up to you how you want to maintain relationships between objects, primarily to handle the memory uses occupied by the objects.

From the code:

In the program, the Car class composes the objects of Tea and Coffee. Give special attention that the object of Tea and Coffee is created using the new keyword inside the Car class in a method EnjobyBeverages(). So, when the Car class object is destroyed, immediately the Tea and coffee class object MUST also be destroyed.

In the Car class, the Driver is aggregated, its object is created using new outside of the class in the Sample class. So, when the car is destroyed, the Driver SHOULD NOT be destroyed.

Generalization and Specialization

Generalization means you move all the common functionalities of the child classed to a base class to avoid duplicate code and make code cleaner and readable.

All the child classes Tea and Coffee could have the methods add hot water, add milk and sugar. But they are generalized and move to the abstract class Beverages.

Specialization: The specialized functionalities are move to the child classes to implement their own way. For example, the getBeverage() and addIngredients() functionalities are given to the Tea and Coffee child classes of the Beverages class to implement their own way.

Hope you Enjoyed Reading!

RECOMMENDATION: You can make your Object-Oriented programming Concepts using Java rock solid with the book OOP Concepts booster, so you can stand out from the crowd in Job interviews or companies or college. Learn more about the book OOP Concepts Booster.

Leave a Comment