0% found this document useful (0 votes)
25 views416 pages

JavaMain 1

Uploaded by

Maruf Remon
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
25 views416 pages

JavaMain 1

Uploaded by

Maruf Remon
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 416

Free Courses

on YouTube
Channel

175K
Subscribers

Java main() Method Interview Questions with


Answers
author: Ramesh Fadatare

CORE JAVA INTERVIEW

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

In this article, we will discuss frequently asked Java main() method interview questions with answers

for both freshers and experienced.

As we know that Java main() method is the entry point of any Java program. Its syntax is always

public static void main(String[] args).


YouTube Video
Top 8 Java main() Method Interview Questions with Answers
Share

Watch on

Java main() method interview Questions with


Answers
We will discuss below 8 Java main() interview questions and answers:

1. Why the main() method is public static?

2. Can we overload the main() method in Java?

3. Can we declare the main() method as private or protected or with no access modifier?

4. Can we declare the main() method as a non-static?

5. Can we change the return type of the main() method?

6. Can the main() method take an argument other than String array?

7. Can we run define Java Class without the main() method?

8. Can we make the main final in Java?

I will demonstrate all the above questions with examples.

1. Why the main() method is public static?


First, let's see why the main() method is static in Java?
The main() method is static in Java, so the JVM can directly invoke it without instantiating the class’s
object.

If the main() method is non-static, then JVM needs to create an instance of the class, and there would
be ambiguity if the constructor of that class takes an argument – which constructor should be called
by JVM and what parameters should be passed? We know that JVM can’t instantiate a Java class

without calling a constructor method.

The following example demonstrates why the main() method is static in Java.

package net.javaguides.corejava;

public class MainMethodDemo {

public MainMethodDemo(int arg0) {


//One argument constructor
}

public MainMethodDemo(int arg0, int arg1) {


//Two arguments constructor
}

public MainMethodDemo(String arg[]) {

public void main(String...args) {


//Non Static main method
}
}

Now, let's see why the main() method is public?

We know that anyone can access/invoke a method having public access specifier. The main()

method is public in Java because it has to be invoked by the JVM. So, if main() is not public in Java,
the JVM won’t call it.

2. Can we overload the main() method in Java?


Yes, We can overload the main() method. A Java class can have any number of main() methods.
But to run the java class, the class should have a main() method with signature as public static void

main(String[] args).

The diagram below demonstrates that the main() method can be overloaded:

Let's see a simple example to demonstrate main() can be overloaded:

package net.javaguides.corejava;

import java.util.Arrays;

public class MainMethodDemo {

/** Actual main method with String[] args**/


public static void main(String[] args) {
System.out.println("String[] args main method called");
main(new Double[] {
1.0,
2.0,
3.0
});
}

/** Overloaded main method with Double[] args**/


public static void main(Double[] args) {
System.out.println("Double[] args main method called");
System.out.println(Arrays.toString(args));
}
}

Output:

String[] args main method called


Double[] args main method called
[1.0, 2.0, 3.0]

3. Can we declare the main() method as private


or protected or with no access modifier?
No, the main() method must be public. You can’t define the main() method as private or

protected or with no access modifier. This is because to make the main() method accessible to

JVM.

The below diagram shows a runtime error if you define the main() method other than public.

4. Can we declare the main() method as a non-


static?
No, the main() method must be declared as static so that JVM can call the main() method without

instantiating its class. If you remove ‘static’ from the main() method signature, the compilation will

be successful but the program fails at runtime.

The below diagram demonstrates that the main() method should be static otherwise JVM will throw

a runtime error:
5. Can we change the return type of the main()
method?
No, the return type of the main() method must be void only. Any other type is not acceptable.

The diagram below demonstrates that the main() method should have a void return type:

6. Can the main() method take an argument


other than String array?
No, the argument of the main method must be a String array. But, from the introduction of var args,

you can pass var args of string type as an argument to the main() method. Again, var args are

nothing but the arrays.

The below diagram demonstrates that the main() method should have an argument as String array
or var args:

7. Can we run define Java Class without the


main() method?
No, we cannot define a class without the main() method starting from Java 7. In the previous release

of Java, we can have Static Initializers as an alternative:

public class MainMethodDemo


{
static
{
System.out.println("Static Initalizer");
System.exit(0);
}
}

Output: (From JDK 7)

Error: Main method not found in class Test, please define the main method as:
public static void main(String[] args)
or a JavaFX application class must extend javafx.application.Application

Output: (JDK 6)

Static Initalizer

8. Can we make the main final in Java?


Yes, you can make the main() method final.

The diagram below demonstrates that we can have the main method as the final in Java.

Related Java Interview Articles


Spring Boot Interview Questions
Java Tricky Coding Interview Questions

Java String Interview Questions


Java String Tricky Coding Questions

Java main() Method Interview Questions


Java 8 Interview Questions

Top 10 Spring MVC Interview Questions

Java Array Interview Questions and Answers


Java OOPS Tricky Coding Questions

Java Programs Asked in an Interview


OOPS Interview Questions and Answers

Hibernate Interview Questions

JPA Interview Questions and Answers


Java Design Patterns Interview Questions

Spring Core Interview Questions


Java Exception Handling Interview

Related Java Interview Guides:


Free Courses
on YouTube
Channel

175K
Subscribers

Java Array Interview Questions and Answers for


Freshers
author: Ramesh Fadatare

INTERVIEW JAVA JAVA ARRAYS

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

In this article, we will discuss a few frequently asked Java Array interview questions with answers for
beginners.

YouTube Video

Java Array Interview Questions and Answers for Freshers


Share
Watch on

1. What is an Array?
An Array is a data structure that defines an index-based collection of a fixed number of homogeneous
data elements. This means that all elements in the array have the same data type and Array a starts
from index 0.

For example, This is an array of 10 elements. All the elements are integers and homogeneous.

The size of an array is fixed and cannot be changed after the array has been created.

In Java, arrays are objects. Arrays can be of primitive data types or reference types.

The main use of Array is used to store multiple values in a single variable, instead of declaring
separate variables for each value.

For example:

int[] array = { 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000 };
2. What Is the Advantage and Disadvantage of
an Array?
Advantage of an Array

-> The main use of Array is used to store multiple values in a single variable, instead of
declaring separate variables for each value.

For example:

int[] array = { 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000 };

-> We can access any element randomly by using indexes provided by arrays.

For example:

// initialize primitive one dimensional array


int[] anArray = new int[5];

anArray[0] = 10; // initialize first element


anArray[1] = 20; // initialize second element
anArray[2] = 30; // and so forth
anArray[3] = 40;
anArray[4] = 50;

// Each array element is accessed by its numerical index:


System.out.println("Element 1 at index 0: " + anArray[0]);
System.out.println("Element 2 at index 1: " + anArray[1]);
System.out.println("Element 3 at index 2: " + anArray[2]);
System.out.println("Element 4 at index 3: " + anArray[3]);
System.out.println("Element 5 at index 4: " + anArray[4]);

Output:

Element 1 at index 0: 10
Element 2 at index 1: 20
Element 3 at index 2: 30
Element 4 at index 3: 40
Element 5 at index 4: 50
-> We can sort multiple elements of Array at the same time.

The disadvantage of an Array


Size Limit: We can store the only fixed size of elements in the array. It doesn't grow its size at
runtime.

Arrays are Strongly Typed: This means that all elements in the array have the same data type. We
can not store different types of data in an Array.

3. What are the Types of Array in Java?


There are two types of array.

1. Single Dimensional Array

2. Multidimensional Array

Single Dimensional Array


A single-dimensional array of Java is a normal array where the array contains sequential elements (of

the same type).

For example:

int[] array = { 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000 };

The following program creates an array of integers, puts some values in the array, and prints each

value to standard output.

public class ArrayBasics {


public static void main(String[] args) {
// declares an array of integers
int[] anArray;

// allocates memory for 10 integers


anArray = new int[10];

// initialize first element


anArray[0] = 100;
// initialize second element
anArray[1] = 200;
// and so forth
anArray[2] = 300;
anArray[3] = 400;
anArray[4] = 500;
anArray[5] = 600;
anArray[6] = 700;
anArray[7] = 800;
anArray[8] = 900;
anArray[9] = 1000;

for (int i = 0; i < anArray.length; i++) {


System.out.println("Element at index " + i + ": " +anArray[i]);
}
}
}

Output:

Element at index 0: 100


Element at index 1: 200
Element at index 2: 300
Element at index 3: 400
Element at index 4: 500
Element at index 5: 600
Element at index 6: 700
Element at index 7: 800
Element at index 8: 900
Element at index 9: 1000

Multidimensional Array
A multi-dimensional array in Java is an array of arrays. A two-dimensional array is an array of one-

dimensional arrays and a three-dimensional array is an array of two-dimensional arrays.

Example for two-dimensional array:

class MultiDimArrayDemo {

public static void main(String[] args){


String[][] names = {
{"Mr. ","Mrs. ","Ms. "},
{"Smith","Jones"}};

// Mr. Smith
System.out.println(names[0][0] +
names[1][0]);
// Ms. Jones
System.out.println(names[0][2] +
names[1][1]);
}
}

Output:

Mr. Smith
Ms. Jones

4. Can You Pass the Negative Number in Array


Size?
No, you can not pass the negative number as Array size. If you pass a negative number in Array size

then you will not get the compiler error. Instead, you will get the NegativeArraySizeException at run
time.

5. When ArrayIndexOutOfBoundsException
occurs?
ArrayOutOfBoundsException is thrown when an attempt is made to access the Array with an illegal

index. For example, an illegal index means if the index is either negative or greater than or equal to
the size of the Array.

For example 1: Below program tries to access the element at index 5 but the array index starts from

index 0. The index 5 is equal to the size of an Array hence throwing ArrayOutOfBoundsException :

public class Main {


public static void main(String[] args) {
int[] array = { 100, 200, 300, 400, 500 };
int element = array[5];

System.out.println(element);
}
}

Output:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for


at com.java.sms.Main.main(Main.java:7)

For example 2: Access array with negative index to Array leads to throwing
ArrayOutOfBoundsException :

public class Main {


public static void main(String[] args) {
int[] array = { 100, 200, 300, 400, 500 };

System.out.println("Array length -> " + array.length);

int element = array[-2];

System.out.println(element);
}
}

Output:

Array length -> 5


Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index -2 out of bounds fo
at com.java.sms.Main.main(Main.java:9)

6. Difference of Array and ArrayList


1. An Array is static in nature i.e. of fixed length. The size of an array is fixed and cannot be changed

after the array has been created. ArrayList is dynamic in nature. If you add elements to an ArrayList, it

will automatically increase its size.


2. An Array can contain both primitive and Object data types. ArrayList does not contain primitive
data types (but contains primitive Wrapper classes). It only contains object entries.

3. Java provides add() method to insert an element into ArrayList and we can use the assignment

operator to store elements into Array.

ArrayList.add() method:

List<String> animals = new ArrayList<>();


// Adding new elements to the ArrayList
animals.add("Lion");
animals.add("Tiger");

Assignment operator to store elements into Array:

// initialize primitive one dimensional array


int[] anArray = new int[5];

anArray[0] = 10; // initialize first element


anArray[1] = 20; // initialize second element
anArray[2] = 30; // and so forth

4. We can not use Generics along with Array whereas ArrayList allows you to use Generics to ensure
type safety.

5. Length of the ArrayList is provided by the size() method while Each array object has the length

variable which returns the length of the array.

Example 1: find the length of the ArrayList using the size() method:

import java.util.ArrayList;
import java.util.List;

public class Main {


public static void main(String[] args) {
// Creating an ArrayList of String using
List<String> animals = new ArrayList<>();
// Adding new elements to the ArrayList
animals.add("Lion");
animals.add("Tiger");
animals.add("Cat");
animals.add("Dog");
System.out.println(animals.size());
}
}

Output:

Example 2: find the length of an Array using the length variable:

public class Main {


public static void main(String[] args) {
int[] array = { 100, 200, 300, 400, 500 };
System.out.println("Array length -> " + array.length);
}
}

Output:

Array length -> 5

6. The performance of Array and ArrayList depends on the operation you are performing :
resize() operation: Automatic resize of ArrayList will slow down the performance as it will use a

temporary array to copy elements from the old array to the new array.

add() or get() operation: adding an element or retrieving an element from the array or ArrayList
object has almost the same performance, as for ArrayList object these operations run in constant time.

7. Can You Declare an Array Without Array


Size?
No, you can not declare an Array without an Array size. You will get a compile-time error.
8. Where Does Array Store in JVM Memory?
As we know that Array is an object in java. So, Array is stored in heap memory in JVM.

9. What is ArrayStoreException? When this


exception is thrown?
ArrayStoreException is a runtime exception. The array must contain the same data type elements.

This exception is thrown to indicate that an attempt has been made to store the wrong type of object
in an array of objects. In other words, if you want to store the integer Object in an Array of String you

will get ArrayStoreException .

The following code throws ArrayStoreException :

public class Main {


public static void main(String[] args) {
Object x[] = new Employee[3];
x[0] = new String("javaguides");
}
}
class Employee{

Output:

Exception in thread "main" java.lang.ArrayStoreException: java.lang.String


at com.java.sms.Main.main(Main.java:6)

10. What is the Difference Between


ArrayStoreException and
ArrayOutOfBoundsException?
ArrayStoreException is thrown if you are trying to add an incompatible data type. For example, if

you try to add an integer object to String Array, then ArrayStoreException is thrown.

ArrayOutOfBoundsException is thrown when an attempt is made to access the Array with an illegal

index. For example, an illegal index means if the index is either negative or greater than or equal to

the size of the Array.

11. What is an Anonymous Array in Java? Give


an Example?
An array without any name (or reference) is called an Anonymous Array. They are useful for scenarios

where we need one-time usage of Array.

For example:

public class Main {


public static void main(String[] args)
{
// anonymous array
sum(new int[]{ 1, 2, 3 });
}
public static void sum(int[] a)
{
int total = 0;

// using for-each loop


for (int i : a)
total = total + i;

System.out.println("The sum is:" + total);


}
}

Output:

The sum is:6


12. Are arrays mutable or immutable in Java?
Arrays are mutable. The size of the array is fixed, but the elements can be changed.

int[] arr = {1, 2, 3};


arr[0] = 10; // This modifies the first element of the array from 1 to 10.

In the example above, we've changed the first element of the array, demonstrating the mutability of
arrays in Java.

13. Java Array Programs Asked in Interviews


1. Java Program to Reverse an Array Without Using Another Array

2. Java Program to Find Duplicate Elements in an Array

3. Java Program to Find Largest Number in an Array

4. Java Program to Check the Equality of Two Arrays

14. Related Java Interview Articles


Spring Boot Interview Questions
Java Tricky Coding Interview Questions

Java String Interview Questions

Java String Tricky Coding Questions

Java main() Method Interview Questions

Java 8 Interview Questions


Top 10 Spring MVC Interview Questions

Java OOPS Tricky Coding Questions

Java Programs Asked in Interview

OOPS Interview Questions and Answers

Hibernate Interview Questions


JPA Interview Questions and Answers

Java Design Patterns Interview Questions

Spring Core Interview Questions


Free Courses
on YouTube
Channel

175K
Subscribers

Java String Interview Questions And Answers


author: Ramesh Fadatare

CORE JAVA INTERVIEW STRING HANDLING

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

In this article, we will discuss some important Java String Interview Questions and Answers for
beginners as well as experienced candidates.

Before we get started, check out Complete guide to Java String, StringBuilder, and
StringBuffer methods

I would like to share my experience with Java String Interview questions. I have listed these most
commonly asked interview questions and answers regarding String handling in Java.
YouTube Video

Java String Interview Questions and Answers | Frequently Asked Java …


Share

Watch on

1. What is String in Java?


A String is a sequence of characters. In the Java programming language, strings are objects. A String is

immutable so once a String object is created, its content can't be changed.

From Java API, the String is a Java Class defined in java.lang package. It’s not a primitive data

type like int and long .

Below is the String Class hierarchy diagram for quick reference -


2. Is String a primitive type or an object in
Java?
The String is an object in Java, not a primitive type.

3. What are the different ways to create String


Objects?
There are two ways to create a String object:

1. By string literal

2. By new keyword

1. Using String Literal

We can create a String literal using double quotes in Java:

For Example:

String s="javaguides";

2. Using new Keyword


We can create a String object using a new keyword in Java:

String str = new String("Java Guides");

4. What do you mean by mutable and


immutable objects?
Immutable objects are like constants. You can’t modify them once they are created. They are final in
nature. Where mutable objects are concerned, you can perform modifications to them.

For example, String is immutable in Java, once you created a String object then you can't modify it.
Any modification leads to a new String object being created.

String str = "Hello";


str.concat(" World"); // Returns a new string, the original 'str' is unchanged.

Whereas StringBuilder or StringBuffer is a mutable in Java so once you create an object


of StringBuilder or StringBuffer class then you can modify it.

StringBuilder builder = new StringBuilder("Hello");


builder.append(" World"); // Modifies the original object.

5. What is String Constant Pool?


String Constant Pool is a pool of string literals stored in the Java Heap memory. When a string literal is
created, Java checks the String Constant Pool first. If the string already exists, it returns a reference to
the pooled instance; otherwise, it creates a new String and places it in the pool.

Read more at String Constant Pool

6. How String Constant Pool Works


When a string is created in Java, the JVM first checks the string constant pool. If a string with the same
value already exists in the pool, a reference to that string is returned. Otherwise, a new string object is
created in the pool, and a reference to this new object is returned. This process is called "interning."

For example:

String str1 = "JavaGuides"; // These two strings are both references


String str2 = "JavaGuides"; // to the same object in the constant pool

In the above example, the JVM will only create one object in the string constant pool. Both str1 and

str2 will point to the same object in the pool.

Read more at String Constant Pool

7. Does String is thread-safe in Java?


Yes, Strings are immutable in Java so once we create a String object then we can't change its content.
Hence it’s thread-safe and can be safely used in a multi-threaded environment.

8. Difference between == and equals() method


in Java
In Java, the == operator is used to compare the references of objects, i.e., it checks if two variables

point to the same memory location.

On the other hand, the equals() method is used to compare the content or values of objects, and it

is usually overridden by classes to provide custom comparison logic.

public class Test {


public static void main(String[] args)
{
String s1 = new String("HELLO");
String s2 = new String("HELLO");
System.out.println(s1 == s2);
System.out.println(s1.equals(s2));
}
}

Output:

false
true

9. Difference between String and StringBuilder?


1. A String is immutable in Java, while a StringBuilder is mutable in Java

2. A String is thread-safe, whereas StringBuilder is not a thread-safe

3. The performance of the String is slower than StringBuilder in the case of multiple concatenation
operations. This is because the string is immutable in Java, and the concatenation of two string

objects involves creating a new object

4. A String class overrides the equals() method of the Object class. So you can compare the

contents of two strings by the equals() method. StringBuilder class doesn't override the

equals() method of an Object class.


10. Difference between String and StringBuffer
1. A String class is immutable and whereas the StringBuffer class is mutable.
2. A String is slow and consumes more memory when you perform too many concatenation String

operations because every time it creates a new instance. But StringBuffer is fast and consumes
less memory when you cancat strings.

3. A String class overrides the equals() method of an Object class. So you can compare the

contents of two strings by the equals() method. StringBuffer class doesn't override the

equals() method of an Object class.

4. String class uses a String constant pool to store the objects whereas StringBuffer class uses heap

memory to store its objects.

11. Difference between StringBuilder and


StringBuffer?
1. A StringBuilder is not a thread-safe, whereas StringBuffer is a thread-safe
2. A StringBuffer is slower than StringBuilder. Because StringBuffer is a thread-safe implementation

and therefore slower than the StringBuilder.

12. String vs StringBuilder vs StringBuffer in


Java
Here is the summary of the differences between String, StringBuilder and StringBuffer in Java
13. What does the String intern() method do?
The method intern() creates an exact copy of a String object in the heap memory and stores it in

the String constant pool.

Note that, if another String with the same contents exists in the String constant pool, then a new

object won't be created and the new reference will point to the other String.

We can call the intern() method to tell the JVM to add it to the string pool if it doesn't already exist

there, and return a reference of that interned string:

String s1 = "abc";
String s2 = new String("abc");
String s3 = new String("foo");
String s4 = s1.intern();
String s5 = s2.intern();

System.out.println(s3 == s4);
System.out.println(s1 == s5);

Output:

false
true

15. Why String is a popular HashMap key in


Java?
Since String is immutable, its hashcode is cached at the time of creation and it doesn’t need to be
calculated again. This makes it a great candidate for keys in a Map and its processing is fast than

other HashMap key objects. This is why String is mostly used Object as HashMap keys.

15. How many objects will be created in the


following code and where they will be stored?
String s1 = new String("javaguides");

String s2 = "javaguides";

Answer:
Two objects will be created. Here's the breakdown:

When the code encounters the string literal "javaguides", it ensures there's an instance of it in the

String Pool. If not already present, one is created. This is our first object.

Using the new keyword forces Java to create a new String object in the heap memory, regardless of

whether the content is already present in the String Pool or not. This is our second object.

For s2 , no new object is created. Instead, the reference from the String Pool (from our first object) is

simply assigned to s2 .

To summarize:

1 object is stored in the String Pool (part of the heap).

1 object is directly stored in the heap memory (outside the StringPool).

16. How many objects will be created in the


following code and where they will be stored?

String s1 = new String("javaguides");

String s2 = new String("javaguides");

Answer:

Three objects will be created. Here's the breakdown:

String Literal "javaguides": When the code encounters the string literal "javaguides", it ensures
there's an instance of it in the String Pool. If not already present, one is created. This is our first

object.
new String("javaguides") for s1: Using the new keyword forces Java to create a new String object in

the heap memory, regardless of whether the content is already present in the String Pool or not. This

is our second object.

new String("javaguides") for s2: Again, using the new keyword causes another separate String

object to be created in the heap memory. This is our third object.

To summarize:

1 object is stored in the StringPool (part of the heap).

2 objects are directly stored in the heap memory (outside the StringPool).

17. How do you concatenate two strings in


Java?
In Java, you can concatenate two strings using either the + operator or the concat() method of the

String class.

Example: Using the + operator:

String result = "Hello" + " World";

Using the concat() method:

String result = "Hello".concat(" World");

Both approaches will produce the string "Hello World".

18. What are the methods to compare two


strings in Java?
In Java, you can compare two strings using the following methods:

equals(): Compares the content of two strings. Returns true if they have the same content, false

otherwise.
equalsIgnoreCase(): Compares the content of two strings, ignoring case differences.

compareTo(): Lexicographically compares two strings. Returns 0 if they are the same, a negative

integer if the first string comes before the second, or a positive integer if the first string comes after
the second.

For example:

String str1 = "Hello";


String str2 = "hello";

boolean isEqual = str1.equals(str2); // false


boolean isEqualIgnoreCase = str1.equalsIgnoreCase(str2); // true
int comparisonResult = str1.compareTo(str2); // -32 (because 'H' is 32 units away from 'h

19. Java String Programs Asked in the


Interviews
All these Java String programs have step-by-step explanations along with their output.

1. Java Program to Find the First Non-repeated Character in a String


2. Java Program to Check Palindrome String

3. Java Program to Find Duplicate Characters in a String


4. Java Program to Find Duplicate Words in a String

5. Java Program to Find All the Permutations of a String

6. Java Program to Count Occurrences of Words in a String


7. Java Program to Count the Occurrences of Each Character

8. Java Program to Count Vowels and Consonants in a String


9. Java program to Count the Number of Duplicate Words in a String

10. Java Program to Count Number of Words in Given String

11. Java Program to Count the Number of Occurrences of Substring in a String

12. Java Program to Count the Occurrences of Each Character in String


13. Java Program to Merge Two String Arrays

14. Java Program to Remove Duplicate Words from String

15. Java Program to Reverse a String(5 ways)

16. Java Program to Reverse Each Word of a String


Free Courses
on YouTube
Channel

175K
Subscribers

Java String: A Guide to String Basics, Methods,


Immutability, Performance, and Best Practices
author: Ramesh Fadatare

CORE JAVA JAVA STRING HANDLING

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

In this blog post, we will learn what is String, how to use it, its important methods with an example,
why String is immutable, and the best practices to use Strings in Java.

1. What is a String?
In Java, a string is a sequence of characters. The String class provides methods to manipulate these

characters, like concatenating two strings, converting characters to uppercase, and so on.
Key Features of String
Immutability: Strings are immutable in Java, meaning once created, they cannot be changed. Any

modification to a string results in a new object, leaving the original string unaltered.

String Pool: Java uses a special memory area known as the String Pool to store string literals. This

helps in saving memory, as multiple references to the same string literally point to the same object in
the pool.

String Creation: Strings can be created using either string literals or the new keyword. Creating

strings with literals promotes reusing existing objects from the String Pool, whereas the new keyword

forces a new object's creation.

Concatenation: Strings can be concatenated using the + operator or the concat() method.

Concatenation creates a new string object since strings are immutable.

Comparison: Strings can be compared using the equals() method for content comparison or ==

for reference comparison. The equalsIgnoreCase() method can be used for case-insensitive content

comparisons.

Case Handling: Methods like t oLowerCase() and toUpperCase() allow conversion between

different cases.

Substring & Character Access: Methods like substring() , charAt() , and indexOf() help in

accessing specific parts or characters of a string.

Trimming & Replacing: trim() is used to remove leading and trailing whitespace. replace() and

replaceAll() help in replacing specific characters or sequences within a string.

Converting to Other Types: Strings can be converted to arrays of characters using toCharArray() .

Various parsing methods like Integer.parseInt() can convert a string to numerical types.

Performance Consideration: Since strings are immutable, frequent modifications can lead to
performance issues. In scenarios with intense string manipulation, consider using StringBuilder or
StringBuffer.
2. Creating String Objects
There are two ways to create a String object:

1. By string literal
2. By new keyword

1. Using String Literal

Java String literal is created by using double quotes.

For Example:

String s="javaguides";

Each time you create a string literal, the JVM checks the string constant pool first. If the string already
exists in the pool, a reference to the pooled instance is returned. If a string doesn't exist in the pool, a
new string instance is created and placed in the pool.

For example:

String s1="javaguides";
String s2="javaguides";
//will not create new instance

To know more detail about how the String Pool works on Guide to Java String Constant Pool

Now the question is why Java uses a concept of a string literal?

It's simple, to make Java more memory efficient because no new objects are created if it exists already
in the string constant pool.

2. Using a new Keyword

Let's create a simple example to demonstrate by creating String objects using the new keyword.

public static void main(String[] args) {


String str = new String("Java Guides");
// create String object using new Keyword
int length = str.length();
System.out.println(" length of the string '" + str + "' is :: " + length);
}

Output:

length of the string 'Java Guides' is:: 11

From the above example, JVM will create a new string object in normal(non-pool) heap memory, and
the literal "Java Guides" will be placed in the string constant pool. The variable str will refer to the

object in the heap(non-pool).

To create a String initialized by an array of characters, Here is an example:

char chars[] = {
'a',
'b',
'c'
}

;
String s = new String(chars);

3. Important String Class Methods


Java's String class, part of the java.lang package provides various methods to perform different

operations on strings, such as trimming, replacing, converting, comparing, and more. Let's explore the
important methods of the String class in Java and illustrates how they can be used.

1. length(): Finding the Length

This method returns the length of the string, i.e., the number of characters in it.

String name = "JavaGuides";


int len = name.length();
System.out.println("Length: " + len); // Output: Length: 10

2. concat(): Concatenating Strings


The concat() method appends one string to the end of another.

String first = "Java";


String second = "Guides";
String full = first.concat(second);
System.out.println(full); // Output: JavaGuides

3. charAt(): Accessing Specific Characters

The charAt() method returns the character at a specific index in the string.

String word = "JavaGuides";


char letter = word.charAt(4);
System.out.println(letter); // Output: G

4. substring(): Extracting Substrings

This method returns a part of the string.

String word = "JavaGuides";


String part = word.substring(4, 9);
System.out.println(part); // Output: Guide

5. toLowerCase() and toUpperCase(): Changing Case


These methods convert the string to lowercase and uppercase, respectively.

String mixed = "JavaGuides";


System.out.println(mixed.toLowerCase()); // Output: javaguides
System.out.println(mixed.toUpperCase()); // Output: JAVAGUIDES

6. trim(): Removing Whitespace


The trim() method eliminates leading and trailing spaces.

String spaced = " JavaGuides ";


System.out.println(spaced.trim()); // Output: JavaGuides

7. replace(): Replacing Characters


This method replaces occurrences of a specific character or character sequence.
String original = "JavaGuides";
String replaced = original.replace("Java", "Spring");
System.out.println(replaced); // Output: SpringGuides

8. equals(): Comparing Strings


The equals() method checks if two strings are the same.

String one = "JavaGuides";


String two = "javaguides";
boolean isEqual = one.equals(two); // false

9. indexOf() and lastIndexOf(): Finding Occurrences


These methods return the index of the first and last occurrence of a character or substring.

String example = "JavaGuides";


int firstIndex = example.indexOf('a'); // 1
int lastIndex = example.lastIndexOf('a'); // 3

4. Why String is Immutable in Java


In Java, strings are immutable, meaning that once a string object is created, its content cannot be

altered. Instead, any operation that seems to change the content of a string actually results in a new

string object. The original string remains unchanged.

Here's why string immutability is a design feature in Java:


1. Security: Immutable objects are inherently thread-safe since they cannot be modified after

creation. This property eliminates synchronization issues in multithreaded applications, making string

handling more secure.

2. Performance Optimization through String Pooling: Since strings are immutable, Java can cache
them in a special memory region called the String Pool. If the same string literal is used elsewhere in

the program, both references will point to the same object in the pool. This saves memory and boosts

performance.

3. Hashcode Caching: Strings in Java often act as keys in collections like HashMap and HashSet. The
hashcode of an object, once calculated, can be cached as long as the object is not modified. Since

strings are immutable, their hashcode remains constant, allowing for efficient retrieval from

collections.

4. Integrity and Reliability: Immutability ensures that once a string object is created, it will not be
changed by any part of the code, intentionally or unintentionally. This behavior makes the code more

predictable and maintains the integrity of the data.

5. Simplifies Complex Systems: In a large and complex application, tracking and controlling object

modification can be cumbersome. Immutability alleviates this problem, simplifying code


understanding and maintenance.

6. Class Loading and Security Concerns: Strings are used in various parts of Java's Class Loading
mechanism, including specifying the classpath. Mutable strings could pose security risks and create

unpredictable behaviors within the JVM's security model.

5. Java String Best Practices


1. Use String Literals Where Possible:
String literals are managed in the String Pool, allowing for efficient memory usage. Compare using
equals instead of ==:

String str1 = "JavaGuides";


String str2 = "JavaGuides";
// Use equals for content comparison
if (str1.equals(str2)) { /*...*/ }

2. Avoid Concatenation in Loops:


String concatenation inside a loop can lead to performance issues due to the creation of multiple

objects. Use StringBuilder instead:

StringBuilder builder = new StringBuilder();


for (int i = 0; i < 100; i++) {
builder.append(i);
}
String result = builder.toString();
3. Use String Formatting:

For complex string creation, the String.format provides a more readable approach:

String formatted = String.format("Order %d: %s", orderId, orderName);

4. Avoid Using == for String Comparison:


The == operator compares object references, not content. Use equals() :

if (str1.equals(str2)) { /*...*/ }

5. Use equalsIgnoreCase for Case-Insensitive Comparison:

if (str1.equalsIgnoreCase(str2)) { /*...*/ }

6. Prefer isEmpty Over length() Check for Emptiness:

if (str.isEmpty()) { /*...*/ }

7. Use StringBuilder Over StringBuffer for Single-Threaded


Operations:
StringBuilder provides better performance as it doesn't synchronize every operation like

StringBuffer.

8. Handle null Strings Carefully:

Consider using Objects.equals(str1, str2) to avoid NullPointerException .

9. Utilize String Methods for Cleaning and Parsing:

Make use of methods like trim(), split(), toLowerCase(), toUpperCase(), etc., to manipulate strings
without reinventing the wheel.

10. Be Careful with Character Encoding:


If working with different character encodings, be conscious of the encoding used, especially when

reading or writing strings to files or over a network.

6. Java String Best Practices - Cheat Sheet

Conclusion
In this blog post, we have learned what is String, key points about String, different ways to create
String objects, important String class methods with examples, we discussed why String is immutable in

Java, and finally, we learned String best practices.

Related Java String Posts


1. Java Program to Count Number of Duplicate Words in String
2. Java Program to Count Number of Words in Given String
Free Courses
on YouTube
Channel

175K
Subscribers

Java String Constant Pool


author: Ramesh Fadatare

CORE JAVA STRING HANDLING

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

🧠 Introduction
If you're learning Java, you’ve probably used String values like this:

String name = "Ramesh";

But did you know this string is stored differently than using new String("Ramesh")?

This is because of something called the String Constant Pool.


In this article, we’ll explore:

What the String Constant Pool is


Why Java uses it
How it improves memory usage

Key examples and interview tips

📌 What is the String Constant Pool?


In Java, the String Constant Pool (also called the String Intern Pool) is a special memory area in the
Java Heap that stores string literals.

✅ Simply put:

It’s a memory optimization technique that avoids creating duplicate String objects
with the same value.

🔍 How It Works
When you create a string like this:

String str1 = "Java";

➡️Java stores "Java" in the String Pool. If you later write:

String str2 = "Java";

➡️Java doesn’t create a new object — it simply points str2 to the same "Java" instance in the
pool.

But if you do:

String str3 = new String("Java");

➡️It creates a new object in the heap, even if "Java" already exists in the pool.
✅ Why Does Java Do This?
Strings are immutable, meaning they can’t be changed once created.
Many programs use the same string values repeatedly (like "yes", "no", "OK").

So instead of creating multiple "yes" strings, Java reuses the same one in the pool, saving

memory.

🔄 String Pool vs. Heap


Creation Type Stored In New Object Created?

String s = "Java" String Constant Pool ❌ No (if already exists)

String s = new String("Java") Java Heap ✅ Yes

💡 Code Example: String Pool in Action

public class StringPoolDemo {


public static void main(String[] args) {
String s1 = "Hello";
String s2 = "Hello";
String s3 = new String("Hello");

System.out.println(s1 == s2); // true - same reference from pool


System.out.println(s1 == s3); // false - different objects
System.out.println(s1.equals(s3)); // true - same value
}
}

Output:

true
false
true

🧠 What is intern() Method?


Java provides a method called intern() to manually add a string to the pool or get the existing

one.
String s4 = new String("World").intern();
String s5 = "World";

System.out.println(s4 == s5); // true

✅ Benefits of String Constant Pool


💾 Memory-efficient: Reuses string objects
⚡ Faster comparisons: Using == for references is faster than .equals()
🧘 Safe to reuse: Since strings are immutable

⚠️Things to Remember
Only string literals are automatically added to the pool.
new String("value") always creates a new object.

Use intern() if you want to move a runtime string into the pool.

Too many string literals in large applications can still fill up memory — use wisely!

📋 Interview Tip
Q: What's the difference between == and .equals() in String comparison?

A:

== compares references (memory addresses)

.equals() compares actual values

So in String Pool:

String a = "Java";
String b = "Java";
System.out.println(a == b); // true

But with new String:

String x = new String("Java");


System.out.println(a == x); // false

✅ Summary
Concept Explanation

String Pool Special memory area to store string literals

Immutable Strings Safe to share references

"Java" vs new String("Java")First reuses, second creates a new object

intern() Manually adds a string to the pool

Final Thoughts

The String Constant Pool is a powerful concept that improves both performance and memory
usage in Java applications. By understanding how it works, you can write better, more efficient Java
code.

CORE JAVA STRING HANDLING

To leave a comment, click the button below to sign in with Google.

SIGN IN WITH GOOGLE


Free Courses
on YouTube
Channel

175K
Subscribers

Java StringBuffer Class API Guide


author: Ramesh Fadatare

JAVA.LANG PACKAGE STRING HANDLING

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

Introduction
The StringBuffer class in Java is used to create mutable strings. Unlike the String class, which

creates immutable strings, StringBuffer allows you to modify the string without creating a new

object. This makes StringBuffer useful for applications where you need to perform many

modifications to a string.

Table of Contents

1. Constructors
2. Important Methods

append()

insert()

replace()

delete()

deleteCharAt()

reverse()

capacity()

length()

charAt()

setCharAt()

substring()

3. Complete Example Program

4. Conclusion

1. Constructors
The StringBuffer class provides several constructors to initialize a StringBuffer object.

Examples:

public class StringBufferConstructorsExample {


public static void main(String[] args) {
// Default constructor with initial capacity 16
StringBuffer sb1 = new StringBuffer();
System.out.println("sb1: " + sb1 + ", capacity: " + sb1.capacity());

// Constructor with initial string


StringBuffer sb2 = new StringBuffer("java guides");
System.out.println("sb2: " + sb2 + ", capacity: " + sb2.capacity());

// Constructor with specified capacity


StringBuffer sb3 = new StringBuffer(50);
System.out.println("sb3: " + sb3 + ", capacity: " + sb3.capacity());
}
}

Output:
sb1: , capacity: 16
sb2: java guides, capacity: 27
sb3: , capacity: 50

2. Important() Methods

append()

The append() method adds the specified string to the end of the existing string.

Syntax:

public synchronized StringBuffer append(String str)

Example:

public class StringBufferAppendExample {


public static void main(String[] args) {
StringBuffer sb = new StringBuffer("java");
sb.append(" guides");
System.out.println("After append: " + sb);
}
}

Output:

After append: java guides

insert()

The insert() method inserts the specified string at the specified position.

Syntax:

public synchronized StringBuffer insert(int offset, String str)

Example:
public class StringBufferInsertExample {
public static void main(String[] args) {
StringBuffer sb = new StringBuffer("java guides");
sb.insert(5, "programming ");
System.out.println("After insert: " + sb);
}
}

Output:

After insert: java programming guides

replace()

The replace() method replaces the characters in a substring of the string with the specified string.

Syntax:

public synchronized StringBuffer replace(int start, int end, String str)

Example:

public class StringBufferReplaceExample {


public static void main(String[] args) {
StringBuffer sb = new StringBuffer("java guides");
sb.replace(5, 11, "tutorial");
System.out.println("After replace: " + sb);
}
}

Output:

After replace: java tutorial

delete()
The delete() method removes the characters in a substring of the string.

Syntax:

public synchronized StringBuffer delete(int start, int end)

Example:

public class StringBufferDeleteExample {


public static void main(String[] args) {
StringBuffer sb = new StringBuffer("java guides");
sb.delete(5, 11);
System.out.println("After delete: " + sb);
}
}

Output:

After delete: java

deleteCharAt()

The deleteCharAt() method removes the character at the specified position.

Syntax:

public synchronized StringBuffer deleteCharAt(int index)

Example:

public class StringBufferDeleteCharAtExample {


public static void main(String[] args) {
StringBuffer sb = new StringBuffer("java guides");
sb.deleteCharAt(4);
System.out.println("After deleteCharAt: " + sb);
}
}
Output:

After deleteCharAt: java guides

reverse()

The reverse() method reverses the characters in the string.

Syntax:

public synchronized StringBuffer reverse()

Example:

public class StringBufferReverseExample {


public static void main(String[] args) {
StringBuffer sb = new StringBuffer("java guides");
sb.reverse();
System.out.println("After reverse: " + sb);
}
}

Output:

After reverse: seduig avaj

capacity()

The capacity() method returns the current capacity of the string buffer.

Syntax:

public synchronized int capacity()

Example:
public class StringBufferCapacityExample {
public static void main(String[] args) {
StringBuffer sb = new StringBuffer("java guides");
System.out.println("Capacity: " + sb.capacity());
}
}

Output:

Capacity: 27

length()

The length() method returns the length (number of characters) of the string buffer.

Syntax:

public synchronized int length()

Example:

public class StringBufferLengthExample {


public static void main(String[] args) {
StringBuffer sb = new StringBuffer("java guides");
System.out.println("Length: " + sb.length());
}
}

Output:

Length: 11

charAt()

The charAt() method returns the character at the specified index.


Syntax:

public synchronized char charAt(int index)

Example:

public class StringBufferCharAtExample {


public static void main(String[] args) {
StringBuffer sb = new StringBuffer("java guides");
char ch = sb.charAt(5);
System.out.println("Character at index 5: " + ch);
}
}

Output:

Character at index 5: g

setCharAt()

The setCharAt() method sets the character at the specified index to the given character.

Syntax:

public synchronized void setCharAt(int index, char ch)

Example:

public class StringBufferSetCharAtExample {


public static void main(String[] args) {
StringBuffer sb = new StringBuffer("java guides");
sb.setCharAt(5, 'G');
System.out.println("After setCharAt: " + sb);
}
}

Output:
After setCharAt: java Guides

substring()

The substring() method returns a new string that is a substring of the original string buffer. It can

take one or two arguments: the start index and optionally the end index.

Syntax:

public synchronized String substring(int start)


public synchronized String substring(int start, int end)

Example:

public class StringBufferSubstringExample {


public static void main(String[] args) {
StringBuffer sb = new StringBuffer("java guides");
String substr1 = sb.substring(5);
String substr2 = sb.substring(0, 4);

System.out.println("Substring from index 5: " + substr1);


System.out.println("Substring from index 0 to 4: " + substr2);
}
}

Output:

Substring from index 5: guides


Substring from index 0 to 4: java

3. Complete Example Program


Here is a complete program that demonstrates the various methods of the StringBuffer class.

Example Code:
public class StringBufferExample {
public static void main(String[] args) {
// Create a new StringBuffer with initial string
StringBuffer sb = new StringBuffer("java guides");

// append() method
sb.append(" tutorial");
System.out.println("After append: " + sb);

// insert() method
sb.insert(5, "programming ");
System.out.println("After insert: " + sb);

// replace() method
sb.replace(5, 16, "learning");
System.out.println("After replace: " + sb);

// delete() method
sb.delete(5, 13);
System.out.println("After delete: " + sb);

// deleteCharAt() method
sb.deleteCharAt(4);
System.out.println("After deleteCharAt: " + sb);

// reverse() method
sb.reverse();
System.out.println("After reverse: " + sb);

// capacity() method
System.out.println("Capacity: " + sb.capacity());

// length() method
System.out.println("Length: " + sb.length());

// charAt() method
char ch = sb.charAt(5);
System.out.println("Character at index 5: " + ch);

// setCharAt() method
sb.setCharAt(5, 'G');
System.out.println("After setCharAt: " + sb);

// substring() method
String substr1 = sb.substring(5);
String substr2 = sb.substring(0, 4);
System.out.println("Substring from index 5: " + substr1);
System.out.println("Substring from index 0 to 4: " + substr2);
}
}

Output:

After append: java guides tutorial


After insert: java programming guides tutorial
After replace: java learning guides tutorial
After delete: java guides tutorial
After deleteCharAt: java guides tutorial
After reverse: lairotut sediug avaj
Capacity: 46
Length: 21
Character at index 5: t
After setCharAt: lairoGut sediug avaj
Substring from index 5: ut sediug avaj
Substring from index 0 to 4: lair

4. Conclusion
The StringBuffer class in Java provides a variety of methods to manipulate and modify strings

efficiently. Understanding and utilizing these methods allows you to perform complex string

operations with ease. This tutorial has covered the most important methods of the StringBuffer

class, providing examples and explanations for each.


Free Courses
on YouTube
Channel

175K
Subscribers

Java HashMap
author: Ramesh Fadatare

COLLECTIONS FRAMEWORK CORE JAVA JAVA COLLECTIONS GUIDE

JAVA.UTIL PACKAGE

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

Introduction

In this article, you will learn what is a HashMap, how to create a HashMap, how to add new key-value
pairs to a HashMap, how to remove keys from a HashMap, how to iterate over a HashMap, and how

to create and store user-defined objects as keys in a HashMap, and much more.

The HashMap class in Java is part of the Java Collections Framework and implements the Map interface.
It provides the basic implementation of the Map interface of Java and is used to store data in the form

of key-value pairs, which are known as entries.

HashMap uses a technique called Hashing, which allows us to access elements directly by calculating a

unique key from their content. This unique key is the index at which the specific value is stored,
making retrieval efficient.

Key Points About Java HashMap

Key-Value Pairs

HashMap stores data in key-value pairs. The key is used as an index to store data. The value is the

actual object that the key is mapped to.

Null Keys and Values

HashMap allows one null key and multiple null values in a collection.

Non-Synchronized
HashMap is not synchronized, which means it is not thread-safe. If it is used in a multi-threaded
environment, then it must be synchronized externally.

Insertion Order Not Preserved

The order in which keys or values are inserted into a HashMap is not necessarily the order in which
they are iterated.

Unordered

HashMap does not guarantee any specific order of entries.

HashCode Method

The keys of HashMap are objects. Hence, these objects must implement the equals method and the
hashCode method in order to follow the contract of the Map interface.

Performance

HashMap offers constant time performance for the basic operations get and put, assuming the hash

function disperses the elements properly among the buckets.

Capacity and Load Factor

The capacity is the number of buckets in the hash table, and the initial capacity is simply the capacity
at the time the hash table is created. Load factor is a measure of how full the hash table is allowed to
get before its capacity is automatically increased.

Implements

HashMap implements the Map interface and extends the AbstractMap class in Java.

Fail-Fast Iterator

The iterator of HashMap is fail-fast, meaning any structural modification (insertion or removal) after
the creation of the iterator, will throw ConcurrentModificationException.

Creating a HashMap

Creating a HashMap in Java is straightforward. Here's an example:

HashMap<String, Integer> map = new HashMap<>();


Adding Elements
You can add entries to the HashMap using the put() method. The put() method takes two

parameters: the key and the corresponding value.

map.put("Apple", 10);
map.put("Orange", 20);
map.put("Banana", 30);

Here's the complete code with output:

import java.util.HashMap;

public class Main {


public static void main(String[] args) {
HashMap<String, Integer> map = new HashMap<>();
map.put("Apple", 10);
map.put("Orange", 20);
map.put("Banana", 30);

System.out.println(map);
}
}

Output:

{Apple=10, Banana=30, Orange=20}

Note: The order in which entries are printed here does not represent the order in which they were
inserted into the HashMap. This is because HashMap does not preserve the order of inserted entries.

HashMap Contains Null Key and Null Values

Here is an example that demonstrates how a HashMap can store null keys and null values:

import java.util.HashMap;
public class Main {
public static void main(String[] args) {
// Creating a HashMap object
HashMap<String, String> map = new HashMap<>();

// Adding key-value pairs, including a null key and null values


map.put("Apple", "Red");
map.put(null, "Orange");
map.put("Banana", null);
map.put("Mango", "Yellow");
map.put("Pear", null);

System.out.println("HashMap: " + map);


}
}

In this program, a HashMap is created and then key-value pairs are added to it. Note the use of null

as a key and null as values. The HashMap can store one null key and multiple null values.

When you run this program, you might see output like the following:

Output:

HashMap: {null=Orange, Pear=null, Apple=Red, Banana=null, Mango=Yellow}

Remember, the order of the elements in a HashMap is not guaranteed, so the order of the elements
in your output may be different.

Access Elements in HashMap

To access elements in a HashMap, you can use the get() method. The get() method takes the key

as an argument and returns the corresponding value.

import java.util.HashMap;

public class Main {


public static void main(String[] args) {
HashMap<String, Integer> map = new HashMap<>();
map.put("Apple", 10);
map.put("Orange", 20);
map.put("Banana", 30);
// Access the value corresponding to the key "Apple"
Integer appleValue = map.get("Apple");
System.out.println("Value for 'Apple': " + appleValue);

// Access the value corresponding to the key "Orange"


Integer orangeValue = map.get("Orange");
System.out.println("Value for 'Orange': " + orangeValue);

// Access the value corresponding to the key "Banana"


Integer bananaValue = map.get("Banana");
System.out.println("Value for 'Banana': " + bananaValue);
}
}

Output:

Value for 'Apple': 10


Value for 'Orange': 20
Value for 'Banana': 30

This output shows the values associated with the keys "Apple", "Orange", and "Banana" in the
HashMap.

Note: If you attempt to access a key that does not exist in the HashMap using the get method, it will

return null.

Remove Elements from HashMap


To remove an element from the HashMap, use the remove() method. The remove() method

removes the mapping for a key from this map if it is present.

Here is the complete example:

import java.util.HashMap;

public class Main {


public static void main(String[] args) {
// Create a HashMap object
HashMap<String, Integer> map = new HashMap<>();

// Add key-value pairs to the HashMap


map.put("Apple", 10);
map.put("Orange", 20);
map.put("Banana", 30);

System.out.println("Original HashMap: " + map);

// Remove the key-value pair with key "Apple"


map.remove("Apple");

System.out.println("HashMap after removing 'Apple': " + map);

// Remove the key-value pair with key "Orange"


map.remove("Orange");

System.out.println("HashMap after removing 'Orange': " + map);


}
}

This program creates a HashMap, adds some key-value pairs to it, and then removes some of these

pairs. The remove() method takes a key as an argument and removes the corresponding key-value

pair from the HashMap.

When you run this program, you should see the following output:

Output:

Original HashMap: {Orange=20, Banana=30, Apple=10}


HashMap after removing 'Apple': {Orange=20, Banana=30}
HashMap after removing 'Orange': {Banana=30}

HashMap Size
We can get the size of the HashMap using the size() method.

Here's a simple example of how to get the size of a HashMap in Java:

import java.util.HashMap;

public class Main {


public static void main(String[] args) {
// Creating a HashMap object
HashMap<String, String> map = new HashMap<>();
// Adding key-value pairs to the map
map.put("Apple", "Red");
map.put("Orange", "Orange");
map.put("Banana", "Yellow");
map.put("Mango", "Yellow");

System.out.println("Original HashMap: " + map);

// Getting the size of the map


int size = map.size();

System.out.println("Size of the HashMap: " + size);


}
}

Output:

Original HashMap: {Mango=Yellow, Orange=Orange, Banana=Yellow, Apple=Red}


Size of the HashMap: 4

Iterate or Loop Through a HashMap

There are different ways we can loop through a HashMap:

1. Using entrySet and a for-each loop

2. Using keySet and a for-each loop

3. Using values and a for-each loop

4. Using an Iterator

5. Using Java 8's forEach method

Let's create a program that demonstrates the different ways to iterate over a HashMap in Java:

import java.util.*;

public class Main {


public static void main(String[] args) {
// Creating a HashMap
HashMap<String, String> map = new HashMap<>();
map.put("Apple", "Red");
map.put("Orange", "Orange");
map.put("Banana", "Yellow");
// Using `entrySet` and a `for-each` loop:
System.out.println("Using `entrySet` and a `for-each` loop:");
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue())
}
System.out.println();

// Using `keySet` and a `for-each` loop:


System.out.println("Using `keySet` and a `for-each` loop:");
for (String key : map.keySet()) {
System.out.println("Key = " + key + ", Value = " + map.get(key));
}
System.out.println();

// Using `values` and a `for-each` loop:


System.out.println("Using `values` and a `for-each` loop:");
for (String value : map.values()) {
System.out.println("Value = " + value);
}
System.out.println();

// Using an `Iterator`:
System.out.println("Using an `Iterator`:");
Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, String> entry = iterator.next();
System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue())
}
System.out.println();

// Using Java 8's `forEach` method:


System.out.println("Using Java 8's `forEach` method:");
map.forEach((key, value) -> System.out.println("Key = " + key + ", Value = " + valu
}
}

Output:

Using `entrySet` and a `for-each` loop:


Key = Apple, Value = Red
Key = Orange, Value = Orange
Key = Banana, Value = Yellow
Using `keySet` and a `for-each` loop:
Key = Apple, Value = Red
Key = Orange, Value = Orange
Key = Banana, Value = Yellow

Using `values` and a `for-each` loop:


Value = Red
Value = Orange
Value = Yellow

Using an `Iterator`:
Key = Apple, Value = Red
Key = Orange, Value = Orange
Key = Banana, Value = Yellow

Using Java 8's `forEach` method:


Key = Apple, Value = Red
Key = Orange, Value = Orange
Key = Banana, Value = Yellow

Java HashMap with User-Defined Objects


If you are using user-defined objects as keys in your HashMap, you should make sure that these

objects implement the equals() and hashCode() methods appropriately. If they do not, then your

HashMap may not function as expected because it relies on these methods to store and retrieve

objects.

Let's create a simple class named Employee:

class Employee {
private String id;
private String name;

Employee(String id, String name) {


this.id = id;
this.name = name;
}

public String getId(){


return this.id;
}

public String getName(){


return this.name;
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null || getClass() != obj.getClass())
return false;
Employee employee = (Employee) obj;
return Objects.equals(id, employee.id) &&
Objects.equals(name, employee.name);
}

@Override
public int hashCode() {
return Objects.hash(id, name);
}

@Override
public String toString() {
return "Employee{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
'}';
}
}

And here is how to use Employee objects as keys in a HashMap:

import java.util.*;

public class Main {


public static void main(String[] args) {
HashMap<Employee, String> employeeMap = new HashMap<>();

Employee e1 = new Employee("1", "John");


Employee e2 = new Employee("2", "Tom");

employeeMap.put(e1, e1.getName());
employeeMap.put(e2, e2.getName());

for (Map.Entry<Employee, String> entry : employeeMap.entrySet()) {


System.out.println(entry.getKey() + " : " + entry.getValue());
}
}
}

Output:

Employee{id='1', name='John'} : John


Employee{id='2', name='Tom'} : Tom

Conclusion
Congratulations folks! In this article, you learned what is a HashMap, how to create a HashMap, how to

add new key-value pairs to a HashMap, how to remove keys from a HashMap, how to iterate over a

HashMap, and how to create and store user-defined objects as keys in a HashMap.

COLLECTIONS FRAMEWORK CORE JAVA JAVA COLLECTIONS GUIDE JAVA.UTIL PACKAGE

To leave a comment, click the button below to sign in with Google.

SIGN IN WITH GOOGLE


Free Courses
on YouTube
Channel

175K
Subscribers

String vs StringBuffer in Java with Example


(Performance Analysis)
author: Ramesh Fadatare

CORE JAVA INTERVIEW JAVA STRING HANDLING X VS Y

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

In this blog post, let's explore the differences between String and StringBuffer in Java with examples.
We also see the performance analysis with an example.

1. Immutability
String

The String class in Java is immutable, meaning once a String object is created, it cannot be
changed. Any modification to a String results in a new String object.

String str = "Java";


str = str + " Guides"; // Creates a new String object

StringBuffer

On the other hand, StringBuffer is mutable, meaning that its content can be changed without
creating a new object.

StringBuffer strBuffer = new StringBuffer("Java");


strBuffer.append(" Guides"); // Modifies the existing object

2. Performance
Performance differences between String and StringBuffer in Java can be significant, especially when
you're dealing with a large number of string manipulations. Let's explore this with an example that

demonstrates the performance of both classes.

Concatenating Strings in a Loop

Consider a scenario where we need to concatenate a short string to an existing string repeatedly,
many times.

Using String

public class StringPerformanceTest {


public static void main(String[] args) {
long startTime = System.currentTimeMillis();

String str = "";


for (int i = 0; i < 100000; i++) {
str += "a"; // Creates a new String object on each iteration
}

long endTime = System.currentTimeMillis();


System.out.println("Time taken using String: " + (endTime - startTime) + " milliseco
}
}
Output:

Time taken using String: 441 milliseconds

Using StringBuffer

public class StringBufferPerformanceTest {


public static void main(String[] args) {
long startTime = System.currentTimeMillis();

StringBuffer strBuffer = new StringBuffer();


for (int i = 0; i < 100000; i++) {
strBuffer.append("a"); // Modifies the existing object
}

long endTime = System.currentTimeMillis();


System.out.println("Time taken using StringBuffer: " + (endTime - startTime) + " mil
}
}

Output:

Time taken using StringBuffer: 5 milliseconds

StringBuffer being mutable, simply modifies the existing object. This leads to much better
performance.

Performance Analysis
When you run these above two examples, you will typically see a substantial difference in the

execution time:

Time taken using String: 441 milliseconds

Time taken using StringBuffer: 5 milliseconds


Note: The actual times will vary depending on the system and environment.

So use String for short, simple, and infrequent string manipulations where immutability is desired.

Use StringBuffer when dealing with complex or frequent string manipulations, especially in a loop, to
gain significant performance benefits.

3. Synchronization
String

String Being Immutable, synchronization is not a concern with String objects. Multiple threads can
access a String without risk of concurrent modification, as any changes will result in new, separate

objects.

StringBuffer

All the methods in StringBuffer that change the content are synchronized. This means that only one
thread at a time can execute these methods on a given StringBuffer object. If multiple threads try to
modify the same StringBuffer object concurrently, synchronization ensures that only one can do so

at a time, thus preventing data inconsistency.

4. Method Availability
String and StringBuffer both provide methods for various operations, but StringBuffer has additional
methods like append() , insert() , reverse() , etc., to modify the content.

StringBuffer class methods example:

StringBuffer sb = new StringBuffer("Java");


sb.append(" Programming"); // Appends " Programming"
sb.insert(5, "Language "); // Inserts "Language " at the 5th index
sb.reverse(); // Reverses the content
System.out.println(sb.toString()); // Output: "gnimmargorP eganguaL avaJ"

The append method is used to add content to the end of the StringBuffer.

The reverse method reverses the content of the StringBuffer.

The insert method inserts content at a specified position in the StringBuffer.


String vs StringBuffer - Cheat Sheet

Conclusion
While String and StringBuffer might seem interchangeable, their distinct characteristics make them
suitable for different scenarios.

Use String when you need a fixed, immutable sequence of characters, and you are sure that the
content won't change frequently.

Use StringBuffer when you need to perform frequent modifications to the text content, especially in
a multithreaded environment.

Understanding these differences will help you choose the right class for your specific use case,
balancing performance, safety, and functionality.

Related Java Interview Guides:


Java Career Roadmap: How To Level Up From Junior To Senior Developer

How To Crack Java Developer Interviews Like A Pro Spring Vs Spring MVC Vs Spring Boot

Java Spring Boot Vs. Go (Golang) For Backend Development In 2025


Free Courses
on YouTube
Channel

175K
Subscribers

String vs StringBuilder vs StringBuffer in Java


author: Ramesh Fadatare

CORE JAVA INTERVIEW JAVA STRING HANDLING X VS Y

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

Hey everyone — welcome back.

Today we’re going to talk about one of those classic Java questions that every developer faces at
some point. What is the difference between String, StringBuilder, and StringBuffer? At first glance,
they all seem to just handle text. But under the hood, they behave very differently. And understanding

those differences can help you write cleaner, faster, and more efficient code.

Let’s break this down step-by-step.


Immutability

First, let’s start with immutability.

A String in Java is immutable. That means once a String object is created, you can’t change its value.

Any time you try to modify it, Java actually creates a brand new object. So even something as simple
as adding a word to an existing string creates a completely new one in memory. This makes Strings
thread-safe by default, but also inefficient if you’re changing them a lot.

Now compare that with StringBuilder and StringBuffer. Both of these are mutable. You can change
their content as many times as you want — no new object is created. That makes them much better
for situations where strings are modified frequently, like building large text outputs or processing

input in loops.

Thread Safety
Next up — thread safety.

String, again, is naturally thread-safe because you can’t change it. Once it exists, nothing can modify
it. So it works fine in multi-threaded environments.
StringBuilder, on the other hand, is not thread-safe. It doesn’t have any internal synchronization. This
makes it faster, but also means that if you use it across multiple threads, you might run into problems.

StringBuffer solves that by being synchronized. Every method in StringBuffer is designed to be thread-
safe. So it’s safe to use even when multiple threads are accessing it at the same time. But all that
synchronization comes at a performance cost. So it’s a trade-off between safety and speed.

Performance
And that brings us to performance.

When it comes to frequent modifications — like adding or updating text inside a loop — String is the
slowest option. Because it keeps creating new objects again and again, your memory usage goes up,

and performance drops.

StringBuilder is usually the fastest in single-threaded programs because it's lightweight and avoids

unnecessary object creation.

StringBuffer is just a little slower than StringBuilder because it has to handle synchronization for

thread safety. Still, it performs well in situations where you truly need safe access across multiple
threads.

Storage

Let’s talk about where these objects live in memory.

String objects are stored in a special area of memory called the String pool. This helps Java reuse
string literals and optimize memory use.

StringBuilder and StringBuffer don’t use this pool. They’re regular objects stored on the heap. So
there's no built-in memory optimization for repeated values like there is with Strings.

This might not matter much for short programs, but it becomes very important when working on
applications that handle large datasets or run for long periods.

Concatenation

Now here’s where you often notice the difference.


Concatenating Strings — like joining first name, last name, and email into one sentence — can be
very expensive with regular Strings. Because each join operation creates a new object, it generates
more garbage in memory and slows your application down.

StringBuilder and StringBuffer both avoid that by offering an append method. This lets you keep
adding text to the same object without creating new ones. It’s fast, efficient, and more predictable —

especially when building dynamic content like HTML or reports.

Which One Should You Use?

So what should you use, and when?

Use String when the text doesn’t change, or when you're working with fixed values like configuration

keys, user roles, or simple labels. It’s simple, safe, and memory-efficient — as long as you’re not
constantly modifying it.

Use StringBuilder when you’re in a single-threaded environment and need to build or update strings
frequently. It gives you great performance without the overhead of thread safety.

Use StringBuffer when you’re in a multi-threaded application and different threads might update the
same string. You pay a little performance cost, but your data stays safe and consistent.

Wrap Up

So that’s it.

Strings are simple and safe — but slow to change. StringBuilder is fast and efficient — but only safe in
single-threaded code. And StringBuffer is safe across threads — but just a little heavier to use.

Knowing these differences helps you choose the right one depending on what your code needs to do.

Related Java Interview Guides:


Java Career Roadmap: How To Level Up From Junior To Senior Developer

How To Crack Java Developer Interviews Like A Pro Spring Vs Spring MVC Vs Spring Boot

Java Spring Boot Vs. Go (Golang) For Backend Development In 2025

Is Java Compiled Or Interpreted? Let’s Clear The Confusion!


Free Courses
on YouTube
Channel

175K
Subscribers

Java Exception Handling Interview Questions and


Answers
author: Ramesh Fadatare

CORE JAVA EXCEPTION HANDLING INTERVIEW

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

In this article, we will discuss important Java Exception Handling interview questions and answers.

1. What is an Exception in Java?

An exception in Java is an event that occurs during the execution of a program, disrupting the normal
flow of instructions. Exceptions are objects that encapsulate information about an error condition that
has occurred within a method or block of code.
2. How does Exception Handling Work in Java?
Java exception handling works by using a combination of try, catch, finally, throw, and throws

keywords. When an exception occurs in a try block, it is thrown to the corresponding catch block. If

the exception is not caught, it propagates up the call stack. The finally block is executed regardless

of whether an exception was thrown or caught. The throw keyword is used to explicitly throw an

exception, while the throws keyword is used to declare that a method might throw one or more

exceptions.

3. What are the Exception Handling Keywords in Java?


The exception-handling keywords in Java are:

try

catch

finally

throw

throws

4. What is the purpose of the throw and throws keywords?

throw: Used to explicitly throw an exception in a method or block of code.

throws: Used in a method signature to declare that the method might throw one or more

exceptions.

5. How can you handle an exception?

You can handle an exception using a try-catch block. Place the code that might throw an exception

inside the try block, and handle the exception in the catch block. Optionally, you can use a finally

block to execute code regardless of whether an exception was thrown or caught.

Example:

try {
// Code that might throw an exception
} catch (ExceptionType e) {
// Code to handle the exception
} finally {
// Code that will always execute
}
6. Explain Java Exception Hierarchy?
The exception hierarchy in Java is as follows:

java.lang.Object
└── java.lang.Throwable
├── java.lang.Exception
│ ├── java.io.IOException
│ ├── java.sql.SQLException
│ └── java.lang.RuntimeException
│ ├── java.lang.NullPointerException
│ ├── java.lang.ArrayIndexOutOfBoundsException
│ └── java.lang.ArithmeticException
└── java.lang.Error
├── java.lang.OutOfMemoryError
├── java.lang.StackOverflowError
└── java.lang.VirtualMachineError

7. How can you catch multiple exceptions?


You can catch multiple exceptions by using multiple catch blocks or a single catch block that

handles multiple exception types (Java 7 and later).

Example:

try {
// Code that might throw multiple exceptions
} catch (IOException | SQLException e) {
// Code to handle IOException or SQLException
} catch (Exception e) {
// Code to handle other exceptions
}

8. What is the difference between Checked and Unchecked


Exceptions in Java?

Checked Exceptions: Checked at compile-time. Must be either caught or declared in the


method signature using the throws keyword. Examples: IOException, SQLException.

Unchecked Exceptions: Not checked at compile-time. They are subclasses of


RuntimeException. Examples: NullPointerException, ArrayIndexOutOfBoundsException.

9. What is the difference between the throw and throws


keywords in Java?

throw: Used to explicitly throw an exception. Example:

throw new IllegalArgumentException("Invalid argument");

throws: Used in a method signature to declare that the method might throw one or more

exceptions. Example:

public void method() throws IOException, SQLException {


// Method body
}

10. What is the difference between an exception and an error?


Exception: Represents conditions that a program might want to catch and handle. They are

recoverable conditions.
Error: Represents serious issues that a reasonable application should not try to catch. They are
usually external to the application and indicate problems with the environment, such as the Java
Virtual Machine (JVM) running out of memory.

11. What is OutOfMemoryError in Java?

OutOfMemoryError is an error that occurs when the Java Virtual Machine (JVM) cannot allocate an

object because it is out of memory. The JVM throws this error to indicate that the heap memory has

been exhausted.

12. What are Chained Exceptions in Java?

Chained exceptions allow you to relate one exception with another, forming a chain of exceptions.
This is useful when an exception occurs as a direct result of another exception. You can create a
chained exception by passing the original exception as a parameter to the constructor of the new

exception.

Example:
public class ChainedExceptionDemo {
public static void main(String[] args) {
try {
method1();
} catch (Exception e) {
e.printStackTrace();
}
}

public static void method1() throws Exception {


try {
method2();
} catch (Exception e) {
throw new Exception("Exception in method1", e);
}
}

public static void method2() throws Exception {


throw new Exception("Exception in method2");
}
}

13. How to write custom exceptions in Java?


You can create custom exceptions by extending the Exception class or any of its subclasses. Custom

exceptions are useful for specific error conditions relevant to your application.

Example:

class InvalidAgeException extends Exception {


public InvalidAgeException(String message) {
super(message);
}
}

public class CustomExceptionExample {


public static void main(String[] args) {
try {
validateAge(15);
} catch (InvalidAgeException e) {
System.out.println("Caught custom exception: " + e.getMessage());
}
}
public static void validateAge(int age) throws InvalidAgeException {
if (age < 18) {
throw new InvalidAgeException("Age must be 18 or older.");
}
System.out.println("Age is valid.");
}
}

14. What is the difference between final, finally, and finalize in


Java?
final: A keyword used to define constants, prevent inheritance, and prevent method overriding.

finally: A block that is executed after the try-catch block, regardless of whether an exception

was thrown or caught.

finalize: A method called by the garbage collector before an object is destroyed. It is used to
perform cleanup operations.

15. What happens when an exception is thrown by the main


method?
If an exception is thrown by the main method and not caught within the main method, the JVM

handles it by printing the stack trace to the standard error stream and terminating the program.

16. What is a try-with-resources statement?

The try-with-resources statement is a try statement that declares one or more resources. A

resource is an object that must be closed after the program is finished with it. The try-with-

resources statement ensures that each resource is closed at the end of the statement.

Example:

try (BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {


String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
17. What is a stack trace and how does it relate to an
exception?

A stack trace is a list of method calls that the application was in the middle of when an exception was
thrown. It provides information about the sequence of method calls that led to the exception, helping

developers debug the error by showing the exact point where the exception occurred.

18. What are the Advantages of Java Exceptions?


Separation of Error Handling Code from Regular Code: Improves readability and

maintainability of code.
Propagating Errors Up the Call Stack: Allows a method to catch and handle exceptions thrown

by methods it calls.
Grouping and Differentiating Error Types: Provides a way to handle different types of errors

in different ways.

19. Can you throw any exception inside a lambda expression’s


body?
Yes, you can throw exceptions inside a lambda expression's body. However, if the exception is a

checked exception, the functional interface method that the lambda expression implements must
declare that it throws the exception.

Example:

@FunctionalInterface
interface ThrowingConsumer<T> {
void accept(T t) throws Exception;
}

public class LambdaExceptionDemo {


public static void main(String[] args) {
ThrowingConsumer<Integer> consumer = (Integer i) -> {
if (i < 0) {
throw new Exception("Negative value not allowed");
}
System.out.println(i);
};

try {
consumer.accept(-1);
} catch (Exception e) {
System.out.println("Caught exception: " + e.getMessage());
}
}
}

20. What are the rules we need to follow when overriding a


method that throws an exception?

When overriding a method that throws an exception:

The overridden method can only throw the same exceptions or subclasses of the exceptions

declared by the parent method.


The overridden method cannot throw new or broader checked exceptions than those declared

by the parent method

Example:

class Parent {
public void method() throws IOException {
// Method body
}
}

class Child extends Parent {


@Override
public void method() throws FileNotFoundException {
// Method body
}
}

21. Java Exception Handling Best Practices


Catch Specific Exceptions: Catch the most specific exception first to handle known error

conditions.

Use Finally Block for Cleanup: Ensure that resources are properly closed using the finally

block or try-with-resources.

Log Exceptions: Log exceptions with sufficient details to help with debugging.
Throw Custom Exceptions for Business Logic Errors: Create custom exceptions for specific

error conditions relevant to your application.


Avoid Swallowing Exceptions: Do not catch exceptions without handling them or rethrowing

them.

Example of Best Practices:

public class ExceptionHandlingBestPractices {


public static void main(String[] args) {
try (BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (FileNotFoundException e) {
System.err.println("File not found: " + e.getMessage());
} catch (IOException e) {
System.err.println("I/O error: " + e.getMessage());
}
}
}

By following these best practices, you can write robust and maintainable code that handles exceptions

effectively, ensuring your application can recover gracefully from unexpected errors.

Related Java Interview Guides:


Java Career Roadmap: How To Level Up From Junior To Senior Developer

How To Crack Java Developer Interviews Like A Pro Spring Vs Spring MVC Vs Spring Boot

Java Spring Boot Vs. Go (Golang) For Backend Development In 2025

Is Java Compiled Or Interpreted? Let’s Clear The Confusion!

Java JIT Compiler: Explained In Simple Words What Is JVM, JDK, And JRE?

Why Java Is The Platform Independent? (Interview Question And Answer)

Is Java A Pure Object-Oriented Language? (Java Interview Question And Answer)🤔

Is Java Case Sensitive? (Java Interview Question And Answer)


Free Courses
on YouTube
Channel

175K
Subscribers

OOPs Interview Questions and Answers


author: Ramesh Fadatare

CORE JAVA INTERVIEW OOPS

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

Introduction
Object-Oriented Programming (OOP) is a programming paradigm that uses objects and classes to

structure software in a way that is both modular and reusable. Below are some common OOP
interview questions and their answers with additional explanations and real-world examples.

What is OOP?

Answer: Object-Oriented Programming (OOP) is a programming paradigm that uses objects and
classes to create models based on real-world entities. OOP promotes better software design, making
code more modular, reusable, and maintainable.

What are Core OOP Concepts?

Answer: The core OOP concepts are:

1. Abstraction
2. Encapsulation

3. Inheritance
4. Polymorphism

What is an Object?

Answer: An object is an instance of a class that contains attributes (data) and methods (functions) to
represent real-world entities or concepts. It encapsulates both state and behavior.

Real-world example: A car is an object. It has attributes like color, model, and speed, and methods
like drive() and brake().

Read more: What Is Object in Java with Programming Examples

What is Class?

Answer: A class is a blueprint or template for creating objects. It defines the attributes and behaviors
that the objects created from the class can have.

Real-world example: A car class can have attributes like color and model, and methods like drive()
and brake().

Read more: What is a Class in Java with Programming Examples

What are the advantages of OOP concepts?

Answer:

1. Modularity: The source code for an object can be written and maintained independently of the
source code for other objects.
2. Reusability: Objects can be reused across programs.

3. Scalability: OOP allows for programs to grow in complexity while maintaining readability and
structure.
4. Maintainability: Changes to objects can be made independently without affecting other parts
of the system.

What is the difference between Procedural programming and


OOP?

Answer: Procedural programming is based on functions, while OOP is based on objects and classes.
Procedural programming follows a top-down approach, whereas OOP follows a bottom-up approach.

What is Abstraction and give real-world examples?

Answer: Abstraction is the process of hiding the complex implementation details and showing only
the essential features of the object.

Real-world example: A car's dashboard. The driver interacts with the steering wheel, pedals, and
buttons without needing to understand the internal mechanics of the car.

Read more: Abstraction in Java with Example

What is Encapsulation and give real-world examples?


Answer: Encapsulation is the technique of bundling the data (attributes) and methods (functions) that
operate on the data into a single unit or class, and restricting access to some of the object's
components.

Real-world example: A capsule in medicine. It encapsulates the drug inside it and only exposes the
outer shell to the user.

Read more: Encapsulation in Java with Example

What is Polymorphism?

Answer: Polymorphism allows objects to be treated as instances of their parent class rather than their
actual class. It allows one interface to be used for a general class of actions.

Real-world example: A person who can act as a student, an employee, and a customer, depending
on the context.

Explain different types of Polymorphism in Java.

Answer: There are two types of polymorphism in Java:

1. Compile-time polymorphism (Method Overloading): Methods with the same name but
different parameters.
2. Runtime polymorphism (Method Overriding): Methods with the same name and parameters

but defined in different classes related by inheritance.

Read more: Polymorphism in Java with Example

What is Inheritance and give real-world examples?

Answer: Inheritance is the mechanism by which one class (child/subclass) can inherit the attributes
and methods of another class (parent/superclass).

Real-world example: A child inherits traits from their parents, such as eye color or hair color.

Read more: Inheritance in Java with Example

What is the difference between Abstraction and Encapsulation?

Answer:

Abstraction focuses on hiding the complex implementation details and showing only the
essential features.
Encapsulation involves bundling the data and methods that operate on the data into a single
unit and restricting access to some of the object's components.

What is multiple inheritance?


Answer: Multiple inheritance is a feature in which a class can inherit attributes and methods from
more than one parent class. Java does not support multiple inheritance with classes to avoid
complexity and ambiguity.

What is the diamond problem in inheritance?

Answer: The diamond problem occurs when two classes B and C inherit from A, and class D inherits
from both B and C. If A has a method, and B and C override it, D will have two inherited versions of
the method, leading to ambiguity.

Why Java does not support multiple inheritance?

Answer: Java does not support multiple inheritance to avoid the diamond problem and to keep the
language simple and easier to understand.
What is Static Binding and Dynamic Binding?

Answer:

Static Binding: The method call is resolved at compile time. Method overloading is an example
of static binding.
Dynamic Binding: The method call is resolved at runtime. Method overriding is an example of

dynamic binding.

What is Composition?

Answer: Composition is a design principle where a class is composed of one or more objects of other
classes rather than inheriting from them. It allows for more flexible designs and code reuse.

Read more: Composition in Java with Example

What is Aggregation?
Answer: Aggregation is a special form of association where one class is a part of another class but

can exist independently. It represents a "has-a" relationship.

Read more: Aggregation in Java with Example

What is an Association?

Answer: Association represents a relationship between two separate classes that are set up through
their objects. It can be one-to-one, one-to-many, many-to-one, or many-to-many.

Read more: Association in Java with Example

What is Cohesion?

Answer: Cohesion refers to how closely related and focused the responsibilities of a single class are.
High cohesion within classes means that the class does a well-defined job.

Read more: Cohesion in Java with Example

What is Coupling?
Answer: Coupling refers to the degree of direct knowledge that one class has of another. Low

coupling means that classes are largely independent and changes in one class are less likely to affect
other classes.
Read more: Coupling in Java with Example

What is Delegation?

Answer: Delegation is a design pattern where an object handles a request by delegating to a second
object (the delegate).

Read more: Delegation in Java with Example

What are SOLID OOP Principles?

Answer: SOLID is an acronym for five principles of object-oriented programming and design:

1. Single Responsibility Principle

2. Open/Closed Principle
3. Liskov Substitution Principle

4. Interface Segregation Principle

5. Dependency Inversion Principle

Read more: Design Principles

What is the Single Responsibility Principle?


Answer: A class should have only one reason to change, meaning it should have only one job or

responsibility.

Read more: Single Responsibility Principle

What is the Open Closed Principle?

Answer: Software entities should be open for extension but closed for modification. This means that
a class should be extendable without modifying its source code.

Read more: Open Closed Principle

What is the Liskov Substitution Principle?

Answer: Objects of a superclass should be replaceable with objects of a subclass without affecting
the correctness of the program.

Read more: Liskov Substitution Principle


What is the Interface Segregation Principle?
Answer: No client should be forced to

depend on methods it does not use. Instead of one large interface, many smaller and more specific

interfaces are preferred.

Read more: Interface Segregation Principle

What is the Dependency Inversion Principle?

Answer: High-level modules should not depend on low-level modules. Both should depend on
abstractions.

Read more: Dependency Inversion Principle

What are All the Different Ways to Create an Object in Java?


Answer:

1. Using the new keyword: ClassName obj = new ClassName();

2. Using Class.forName: ClassName obj = (ClassName)

Class.forName("ClassName").newInstance();

3. Using clone method: ClassName obj2 = (ClassName) obj1.clone();

4. Using deserialization: ObjectInputStream inStream = new ObjectInputStream(new

FileInputStream("file.ser")); ClassName obj = (ClassName)

inStream.readObject();

5. Using factory methods: ClassName obj = ClassNameFactory.createClassName();

Read more: What Are All the Different Ways to Create an Object in Java?

Conclusion

Understanding OOP principles and concepts is crucial for software development in Java. These
interview questions cover a broad range of topics that are fundamental to object-oriented

programming and design.

Related Java Interview Guides:


Java Career Roadmap: How To Level Up From Junior To Senior Developer
Free Courses
on YouTube
Channel

175K
Subscribers

What is an Object in Java with Example


author: Ramesh Fadatare

CORE JAVA OOPS

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

Introduction
In Java, an object is a fundamental entity in object-oriented programming (OOP). An object is an

instance of a class that encapsulates both state (attributes) and behavior (methods). Objects interact
with one another through methods, providing a way to model real-world entities and their

interactions.

What is an Object?
An object is an instance of a class that represents a real-world entity or concept. It is created based on

the blueprint provided by the class and has its own identity, state, and behavior.

Identity: Each object has a unique identity, which differentiates it from other objects.

State: The state of an object is represented by its attributes (fields or properties).


Behavior: The behavior of an object is represented by its methods (functions or operations).

Key Points:

Objects are instances of classes.

They encapsulate state and behavior.


Objects are created using the new keyword in Java.

Syntax for Creating an Object

The syntax for creating an object in Java is:

ClassName objectName = new ClassName();

Example:

Car myCar = new Car("Red", "Toyota Corolla");

Different Ways to Create Objects in Java

1. Using the new Keyword

This is the most common way to create an object. It invokes the constructor of the class.

Car myCar = new Car("Red", "Toyota Corolla");

2. Using Class.forName()

This method is used for dynamic class loading. It can throw a ClassNotFoundException.

Car myCar = (Car) Class.forName("Car").newInstance();


3. Using clone()

This method creates a new object by copying the existing object's data. It requires the class to

implement the Cloneable interface.

Car myCar = new Car("Red", "Toyota Corolla");


Car clonedCar = (Car) myCar.clone();

4. Using Object Deserialization

This method creates an object from a serialized form (a byte stream). It requires the class to
implement the Serializable interface.

FileInputStream fileIn = new FileInputStream("car.ser");


ObjectInputStream in = new ObjectInputStream(fileIn);
Car myCar = (Car) in.readObject();
in.close();
fileIn.close();

5. Using a Factory Method

A factory method is a static method that returns an instance of a class. It encapsulates the object
creation process.

public class CarFactory {


public static Car createCar(String color, String model) {
return new Car(color, model);
}
}

// Using the factory method


Car myCar = CarFactory.createCar("Red", "Toyota Corolla");

Diagram

Class: Car
+---------------------------+
| Car |
+---------------------------+
| - color: String |
| - model: String |
| - speed: int |
+---------------------------+
| + Car(color, model) |
| + start(): void |
| + accelerate(int): void |
| + brake(): void |
| + getColor(): String |
| + getModel(): String |
| + getSpeed(): int |
+---------------------------+

Object: myCar
+---------------------------+
| myCar |
+---------------------------+
| - color: "Red" |
| - model: "Toyota Corolla" |
| - speed: 0 |
+---------------------------+
| + start() |
| + accelerate(int) |
| + brake() |
| + getColor() |
| + getModel() |
| + getSpeed() |
+---------------------------+

Example: Creating and Using an Object in Java

Let's consider a real-world example: a Car class. We will define a Car class with attributes such as

color, model, and speed, and methods such as start(), accelerate(), and brake(). Then, we will

create an instance of the Car class and use it.

Step 1: Define the Car Class

public class Car {


// Attributes (state)
private String color;
private String model;
private int speed;
// Constructor
public Car(String color, String model) {
this.color = color;
this.model = model;
this.speed = 0; // Initially, the car is stationary
}

// Methods (behavior)
public void start() {
System.out.println(model + " is starting.");
speed = 10; // Starting speed
}

public void accelerate(int increment) {


speed += increment;
System.out.println(model + " is accelerating. Speed: " + speed + " km/h");
}

public void brake() {


speed = 0;
System.out.println(model + " has stopped.");
}

// Getters
public String getColor() {
return color;
}

public String getModel() {


return model;
}

public int getSpeed() {


return speed;
}
}

Step 2: Create and Use an Instance of the Car Class

public class Main {


public static void main(String[] args) {
// Creating an object of the Car class
Car myCar = new Car("Red", "Toyota Corolla");
// Using the object
myCar.start();
myCar.accelerate(20);
myCar.brake();

// Accessing the object's attributes


System.out.println("Car Model: " + myCar.getModel());
System.out.println("Car Color: " + myCar.getColor());
System.out.println("Car Speed: " + myCar.getSpeed() + " km/h");
}
}

Explanation:

1. Defining the Car Class:

The Car class has three attributes: color, model, and speed.

It has a constructor to initialize the color and model attributes, and the speed is initially

set to 0.

The class has three methods: start(), accelerate(int increment), and brake(),

representing the behavior of the car.

The class also includes getter methods to access the attributes of the car.

2. Creating and Using an Object:

In the Main class, we create an instance of the Car class using the new keyword.

We then call the methods start(), accelerate(int increment), and brake() on the

myCar object to simulate the car's behavior.

We access the attributes of the myCar object using the getter methods and print their

values.

Conclusion
In Java, objects are instances of classes that encapsulate state and behavior. They are fundamental to
object-oriented programming and provide a way to model real-world entities and their interactions.

By creating and using objects, we can design modular and reusable code that is easier to manage and
maintain.
Free Courses
on YouTube
Channel

175K
Subscribers

What is Class in Java with Examples


author: Ramesh Fadatare

CORE JAVA OOPS

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

Introduction
In Java, a class is a blueprint or template that defines the structure and behavior (attributes and

methods) that the objects created from the class can have. A class encapsulates data for the object
and methods to manipulate that data. It serves as the fundamental building block in object-oriented

programming (OOP) in Java.

What is a Class?
A class in Java is a user-defined data type that serves as a blueprint for creating objects. It defines the
attributes (data fields) and behaviors (methods) that the objects created from the class can possess.

Key Points:

A class is a blueprint for objects.


It defines attributes and methods.

Objects are instances of a class.

Syntax of a Class
The basic syntax to define a class in Java is as follows:

class ClassName {
// Attributes (data fields)
dataType attributeName;

// Constructor
public ClassName(parameters) {
// Initialize attributes
}

// Methods
returnType methodName(parameters) {
// Method body
}
}

Example: Defining and Using a Class


Let's consider a real-world example: a Car class. We will define a Car class with attributes such as

color, model, and speed, and methods such as start(), accelerate(), and brake(). Then, we will

create an instance of the Car class and use it.

Step 1: Define the Car Class

public class Car {


// Attributes (state)
private String color;
private String model;
private int speed;
// Constructor
public Car(String color, String model) {
this.color = color;
this.model = model;
this.speed = 0; // Initially, the car is stationary
}

// Methods (behavior)
public void start() {
System.out.println(model + " is starting.");
speed = 10; // Starting speed
}

public void accelerate(int increment) {


speed += increment;
System.out.println(model + " is accelerating. Speed: " + speed + " km/h");
}

public void brake() {


speed = 0;
System.out.println(model + " has stopped.");
}

// Getters
public String getColor() {
return color;
}

public String getModel() {


return model;
}

public int getSpeed() {


return speed;
}
}

Step 2: Create and Use an Instance of the Car Class

public class Main {


public static void main(String[] args) {
// Creating an object of the Car class
Car myCar = new Car("Red", "Toyota Corolla");
// Using the object
myCar.start();
myCar.accelerate(20);
myCar.brake();

// Accessing the object's attributes


System.out.println("Car Model: " + myCar.getModel());
System.out.println("Car Color: " + myCar.getColor());
System.out.println("Car Speed: " + myCar.getSpeed() + " km/h");
}
}

Explanation:

1. Defining the Car Class:

The Car class has three attributes: color, model, and speed.

It has a constructor to initialize the color and model attributes, and the speed is initially

set to 0.

The class has three methods: start(), accelerate(int increment), and brake(),

representing the behavior of the car.

The class also includes getter methods to access the attributes of the car.

2. Creating and Using an Object:

In the Main class, we create an instance of the Car class using the new keyword.

We then call the methods start(), accelerate(int increment), and brake() on the

myCar object to simulate the car's behavior.

We access the attributes of the myCar object using the getter methods and print their

values.

Text-based Diagram

Class: Car
+---------------------------+
| Car |
+---------------------------+
| - color: String |
| - model: String |
| - speed: int |
+---------------------------+
| + Car(color, model) |
| + start(): void |
| + accelerate(int): void |
| + brake(): void |
| + getColor(): String |
| + getModel(): String |
| + getSpeed(): int |
+---------------------------+

Object: myCar
+---------------------------+
| myCar |
+---------------------------+
| - color: "Red" |
| - model: "Toyota Corolla" |
| - speed: 0 |
+---------------------------+
| + start() |
| + accelerate(int) |
| + brake() |
| + getColor() |
| + getModel() |
| + getSpeed() |
+---------------------------+

Conclusion
In Java, a class is a blueprint for creating objects. It defines the attributes and methods that the

objects created from the class can possess. By using classes and objects, we can model real-world
entities and their interactions, making our code more modular, reusable, and maintainable.
Free Courses
on YouTube
Channel

175K
Subscribers

Abstraction in Java with Example


author: Ramesh Fadatare

OOP FUNDAMENTALS OOPS

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

Introduction
Abstraction is one of the four fundamental principles of Object-Oriented Programming (OOP). It is the

concept of hiding the complex implementation details and showing only the essential features of the
object.

Table of Contents

1. What is Abstraction?
2. Benefits of Abstraction
3. Real-World Examples of Abstraction
4. Abstract Class

5. Interface
6. Abstract Class vs Interface
7. Example: Abstraction with Abstract Class

8. Example: Abstraction with Interface


9. Example 1: Employee, Contractor, and FullTimeEmployee Example
10. Conclusion

1. What is Abstraction?
Abstraction is the process of hiding the implementation details and showing only the functionality to

the user. It focuses on what the object does instead of how it does it. Abstraction allows you to
manage complexity by breaking down complex systems into simpler components.

In Java, abstraction is achieved using abstract classes and interfaces.

2. Benefits of Abstraction
Reduces complexity: By hiding unnecessary details, abstraction makes the system easier to

understand and use.


Improves code readability: Abstraction allows you to focus on an object's high-level behavior
without getting bogged down by implementation details.

Enhances maintainability: Abstraction helps to encapsulate changes, so modifications in the


implementation do not affect other parts of the system.

Facilitates code reuse: Abstract components can be reused across different parts of the
application or even in different applications.

3. Real-World Examples of Abstraction

Example: Man Driving a Car

Consider a man driving a car. The man knows what each pedal and steering wheel does, but he
doesn't know how the car does these things internally. He doesn't know about the inner mechanisms
that empower these things. This is an example of abstraction.

Example: ATM Machine

Another real-world example is an ATM Machine. All users perform operations on the ATM machine
like cash withdrawal, money transfer, retrieving mini-statements, etc., but they do not know the
internal details about the ATM. This is another example of abstraction.

4. Abstract Class

An abstract class in Java is a class that cannot be instantiated and may contain abstract methods,
which are methods without a body. Subclasses of the abstract class are responsible for providing
implementations for these abstract methods.

Syntax:

abstract class AbstractClassName {


// Abstract method (no body)
abstract void abstractMethod();

// Regular method
void regularMethod() {
// Method body
}
}

5. Interface

An interface in Java is a reference type, similar to a class, that can contain only constants, method
signatures, default methods, static methods, and nested types. Interfaces cannot contain instance
fields or constructors.

Syntax:

interface InterfaceName {
// Abstract method (implicitly public and abstract)
void abstractMethod();

// Default method
default void defaultMethod() {
// Method body
}

// Static method
static void staticMethod() {
// Method body
}
}

6. Abstract Class vs Interface

Feature Abstract Class Interface

Can have both abstract and concrete


Methods Only abstract methods (until Java 8)
methods

Can only have static and final


Fields Can have instance variables
variables

Multiple
Does not support multiple inheritance Supports multiple inheritance
Inheritance

Access Modifiers Can have any access modifier Methods are implicitly public

Constructor Can have constructors Cannot have constructors

7. Example: Abstraction with Abstract Class


Example:

// Abstract class
abstract class Animal {
// Abstract method
abstract void makeSound();

// Regular method
void eat() {
System.out.println("This animal is eating.");
}
}

// Subclass
class Dog extends Animal {
@Override
void makeSound() {
System.out.println("Bark");
}
}

// Usage
public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
dog.makeSound(); // Output: Bark
dog.eat(); // Output: This animal is eating.
}
}

Explanation:

Animal: Abstract class with an abstract method makeSound and a regular method eat.

Dog: Subclass of Animal that provides an implementation for the makeSound method.

8. Example: Abstraction with Interface

Example:

// Interface
interface Animal {
void makeSound();
void eat();
}

// Class implementing the interface


class Dog implements Animal {
@Override
public void makeSound() {
System.out.println("Bark");
}

@Override
public void eat() {
System.out.println("This animal is eating.");
}
}

// Usage
public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
dog.makeSound(); // Output: Bark
dog.eat(); // Output: This animal is eating.
}
}
Explanation:

Animal: Interface with abstract methods makeSound and eat.

Dog: Class that implements the Animal interface and provides implementations for the

makeSound and eat methods.

9. Example 1: Employee, Contractor, and FullTimeEmployee


Example
Example:

// Abstract class
abstract class Employee {
private String name;
private int employeeId;

public Employee(String name, int employeeId) {


this.name = name;
this.employeeId = employeeId;
}

public String getName() {


return name;
}

public int getEmployeeId() {


return employeeId;
}

// Abstract method
abstract void calculatePay();
}

// FullTimeEmployee class
class FullTimeEmployee extends Employee {
private double salary;

public FullTimeEmployee(String name, int employeeId, double salary) {


super(name, employeeId);
this.salary = salary;
}

@Override
void calculatePay() {
System.out.println("FullTimeEmployee Pay: " + salary);
}
}

// Contractor class
class Contractor extends Employee {
private double hourlyRate;
private int hoursWorked;

public Contractor(String name, int employeeId, double hourlyRate, int hoursWorked) {


super(name, employeeId);
this.hourlyRate = hourlyRate;
this.hoursWorked = hoursWorked;
}

@Override
void calculatePay() {
System.out.println("Contractor Pay: " + (hourlyRate * hoursWorked));
}
}

// Usage
public class Main {
public static void main(String[] args) {
Employee fullTimeEmployee = new FullTimeEmployee("Alice", 101, 60000);
fullTimeEmployee.calculatePay(); // Output: FullTimeEmployee Pay: 60000.0

Employee contractor = new Contractor("Bob", 102, 50, 160);


contractor.calculatePay(); // Output: Contractor Pay: 8000.0
}
}

Explanation:

Employee: Abstract class with common properties and an abstract method calculatePay.

FullTimeEmployee: Subclass of Employee that provides an implementation for the

calculatePay method.

Contractor: Subclass of Employee that provides an implementation for the calculatePay

method.

10. Conclusion
Abstraction in Java is a powerful concept that allows you to hide the implementation details and focus
on the functionality. It can be achieved using abstract classes and interfaces. Abstract classes are used

when you want to share code among several closely related classes, while interfaces are used to
define a contract that can be implemented by any class, regardless of its position in the class

hierarchy. Real-world examples like a man driving a car or using an ATM machine illustrate the
concept of abstraction. Understanding and applying abstraction helps to manage complexity, improve

code readability, and enhance maintainability.

Happy coding!

OOP FUNDAMENTALS OOPS

Anonymous 24 December 2018 at 22:55


Examples are very good with explanation.

Ramesh Fadatare 27 December 2018 at 21:21


Thank you. You can learn complete Core Java at Java Tutorial for Beginners

REPLY
Free Courses
on YouTube
Channel

175K
Subscribers

Encapsulation in Java with Example


author: Ramesh Fadatare

OOP FUNDAMENTALS OOPS

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

Introduction
Encapsulation is one of the fundamental principles of Object-Oriented Programming (OOP). It

involves bundling the data (variables) and the methods (functions) that operate on the data into a
single unit, usually a class. Encapsulation also restricts direct access to some of an object's

components, which prevents unintended interference and misuse of the data.

Table of Contents
1. What is Encapsulation?
2. Benefits of Encapsulation
3. Encapsulation in Java

4. Access Modifiers
5. Real-World Examples of Encapsulation
6. Example: Encapsulation in Java

7. Conclusion

1. What is Encapsulation?
Encapsulation is the technique of making the fields in a class private and providing access to them via

public methods. It restricts direct access to certain components of an object and protects the integrity
of the data by controlling modifications.

2. Benefits of Encapsulation

Improved Maintainability: Encapsulation allows for the modularization of code, making it


easier to maintain and modify.

Enhanced Security: Encapsulation helps protect data from unauthorized access and
modification by restricting access to an object's internal state.
Controlled Access: Encapsulation provides control over the data by exposing only the necessary

methods to interact with it, ensuring that the data is used in a controlled manner.
Flexibility and Reusability: Encapsulation allows changes to the implementation without

affecting the users of the class, making the code more flexible and reusable.

3. Encapsulation in Java
In Java, encapsulation is achieved by:

1. Declaring the fields of a class as private.


2. Providing public getter and setter methods to access and modify the fields.

4. Access Modifiers

Java provides four types of access modifiers to control the visibility of class members:

private: The member is accessible only within the same class.

default (no modifier): The member is accessible only within the same package.
protected: The member is accessible within the same package and subclasses.
public: The member is accessible from any other class.
5. Real-World Examples of Encapsulation

Example 1: Medical Records

In a hospital management system, patient data should be encapsulated to ensure that it is accessed
and modified only through authorized methods, maintaining the integrity and confidentiality of the
information.

Example 2: Banking System

In a banking application, account details such as account balance should be encapsulated to prevent
unauthorized access and modification, ensuring the security and consistency of the data.

6. Example: Encapsulation in Java


Example:

public class Person {


// Private fields
private String name;
private int age;

// Public getter method for name


public String getName() {
return name;
}

// Public setter method for name


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

// Public getter method for age


public int getAge() {
return age;
}

// Public setter method for age


public void setAge(int age) {
if (age > 0) {
this.age = age;
} else {
System.out.println("Age cannot be negative or zero");
}
}

public static void main(String[] args) {


Person person = new Person();
person.setName("John Doe");
person.setAge(30);

System.out.println("Name: " + person.getName()); // Output: Name: John Doe


System.out.println("Age: " + person.getAge()); // Output: Age: 30

person.setAge(-5); // Output: Age cannot be negative or zero


}
}

Explanation:

Private Fields: name and age are private fields, meaning they cannot be accessed directly from

outside the class.

Public Getter and Setter Methods: Methods getName, setName, getAge, and setAge are

public, providing controlled access to the private fields.

Validation in Setter Method: The setAge method includes validation to ensure that the age is

not set to a negative value, demonstrating encapsulation's role in maintaining data integrity.

7. Conclusion

Encapsulation in Java is a powerful concept that helps to protect an object's internal state and
provides controlled access to it. By making fields private and exposing public methods to interact with

them, encapsulation ensures that data is used in a controlled and secure manner. This approach
improves maintainability, enhances security, and promotes code reusability and flexibility.
Understanding and applying encapsulation is essential for effective Java programming and building
robust, maintainable software.

Happy coding!
Free Courses
on YouTube
Channel

175K
Subscribers

Polymorphism in Java with Example


author: Ramesh Fadatare

OOP FUNDAMENTALS OOPS

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

Introduction
Polymorphism is one of the core concepts of Object-Oriented Programming (OOP). It allows methods

to do different things based on the object it is acting upon, even though they share the same name.
Polymorphism provides a way to perform a single action in different forms. In Java, polymorphism can

be achieved through method overloading and method overriding.

Table of Contents
1. What is Polymorphism?
2. Types of Polymorphism
3. Method Overloading

4. Method Overriding
5. Real-World Examples of Polymorphism
6. Example: Polymorphism with Method Overloading

7. Example: Polymorphism with Method Overriding


8. Example: Payment Processing Example
9. Conclusion

1. What is Polymorphism?
Polymorphism means "many shapes" or "many forms." In Java, it refers to the ability of a single

method or class to take on multiple forms. This is achieved through method overloading (compile-
time polymorphism) and method overriding (runtime polymorphism).

2. Types of Polymorphism

Compile-time Polymorphism (Method Overloading): This type of polymorphism is resolved


during compile time. Method overloading allows a class to have more than one method with the
same name, provided their parameter lists are different.

Runtime Polymorphism (Method Overriding): This type of polymorphism is resolved during


runtime. Method overriding allows a subclass to provide a specific implementation of a method

that is already defined in its superclass.

3. Method Overloading
Method overloading occurs when a class has multiple methods with the same name but different
parameter lists (different types or numbers of parameters).

Example:

public class MathUtils {


public int add(int a, int b) {
return a + b;
}

public double add(double a, double b) {


return a + b;
}
public int add(int a, int b, int c) {
return a + b + c;
}
}

4. Method Overriding

Method overriding occurs when a subclass provides a specific implementation of a method that is
already defined in its superclass.

Example:

class Animal {
public void makeSound() {
System.out.println("Animal makes a sound");
}
}

class Dog extends Animal {


@Override
public void makeSound() {
System.out.println("Dog barks");
}
}

class Cat extends Animal {


@Override
public void makeSound() {
System.out.println("Cat meows");
}
}

5. Real-World Examples of Polymorphism

Example 1: Different Behaviors of a Person

Suppose you are in a classroom, you behave like a student. When you are in the market, you behave
like a customer. When you are at home, you behave like a son or daughter. Here, one person exhibits
different behaviors in different contexts.
Example 2: Payment Processing System

In a payment processing system, different payment methods such as credit card, debit card, and

PayPal have different processing steps.

6. Example: Polymorphism with Method Overloading

Example:

public class Printer {


public void print(String message) {
System.out.println(message);
}

public void print(int number) {


System.out.println(number);
}

public void print(double number) {


System.out.println(number);
}

public static void main(String[] args) {


Printer printer = new Printer();
printer.print("Hello, World!"); // Output: Hello, World!
printer.print(123); // Output: 123
printer.print(3.14); // Output: 3.14
}
}
Explanation:

Printer: Class with overloaded print methods to handle different types of input.

Main method: Demonstrates the use of overloaded print methods.

7. Example: Polymorphism with Method Overriding

Example:

class Animal {
public void makeSound() {
System.out.println("Animal makes a sound");
}
}

class Dog extends Animal {


@Override
public void makeSound() {
System.out.println("Dog barks");
}
}

class Cat extends Animal {


@Override
public void makeSound() {
System.out.println("Cat meows");
}
}

public class Main {


public static void main(String[] args) {
Animal myDog = new Dog();
Animal myCat = new Cat();

myDog.makeSound(); // Output: Dog barks


myCat.makeSound(); // Output: Cat meows
}
}

Explanation:

Animal: Base class with a makeSound method.


Dog and Cat: Subclasses that override the makeSound method.

Main method: Demonstrates runtime polymorphism by calling the overridden methods on Dog

and Cat objects.

8. Example: Payment Processing Example

Class Diagram

Code Example:

Payment Interface:

interface Payment {
void pay();
}

CashPayment Class:

class CashPayment implements Payment {


@Override
public void pay() {
System.out.println("Payment made using cash.");
}
}

CreditPayment Class:

class CreditPayment implements Payment {


@Override
public void pay() {
System.out.println("Payment made using credit card.");
}
}

Client Class:

public class Polymorphism {


public static void main(String[] args) {
Payment payment;

payment = new CashPayment();


payment.pay(); // Output: Payment made using cash.

payment = new CreditPayment();


payment.pay(); // Output: Payment made using credit card.
}
}

Explanation:

Payment: Interface defining the pay method.

CashPayment and CreditPayment: Classes implementing the Payment interface and providing

their own implementations of the pay method.

Polymorphism: Client class demonstrating polymorphism by using the Payment interface to call

the pay method on different types of payment objects.

9. Conclusion
Polymorphism in Java is a powerful concept that allows methods to perform different tasks based on
the object they are acting upon. It enhances flexibility and maintainability in code by allowing a single

method or class to take on multiple forms. Method overloading and method overriding are two ways
to achieve polymorphism in Java. Real-world examples like different behaviors of a person in different

contexts and various payment processing methods further illustrate the usefulness of polymorphism.

Happy coding!
Free Courses
on YouTube
Channel

175K
Subscribers

Inheritance in Java with Example


author: Ramesh Fadatare

OOP FUNDAMENTALS OOPS

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

Introduction
Inheritance is one of the four fundamental principles of Object-Oriented Programming (OOP). It

allows a class to inherit properties and behaviors (fields and methods) from another class. The class
that inherits the properties is called the subclass (or derived class), and the class from which

properties are inherited is called the superclass (or base class). Inheritance promotes code reusability
and establishes a natural hierarchical relationship between classes.

Table of Contents
1. What is Inheritance?
2. Benefits of Inheritance

3. Types of Inheritance
4. Single Inheritance
5. Multilevel Inheritance

6. Hierarchical Inheritance
7. Real-World Examples of Inheritance
8. Example: Single Inheritance

9. Example: Multilevel Inheritance


10. Example: Hierarchical Inheritance

11. Conclusion

1. What is Inheritance?
Inheritance is a mechanism wherein a new class is derived from an existing class. The derived class

(child class) inherits the attributes and methods of the base class (parent class), allowing code reuse
and the creation of a natural hierarchy.

2. Benefits of Inheritance

Code Reusability: Inheritance allows a class to reuse the fields and methods of another class.
Method Overriding: Subclasses can provide specific implementations for methods that are

defined in the parent class.


Polymorphism: Inheritance supports polymorphism, allowing objects to be treated as instances
of their parent class.

3. Types of Inheritance

Single Inheritance: A class inherits from one superclass.


Multilevel Inheritance: A class inherits from a superclass, and another class inherits from this
derived class.
Hierarchical Inheritance: Multiple classes inherit from a single superclass.
Multiple Inheritance: A class inherits from more than one superclass. Java does not support

multiple inheritance directly to avoid complexity and ambiguity. However, it can be achieved
using interfaces.

4. Single Inheritance
In a single inheritance, a class inherits from one superclass.

Example:

class Animal {
void eat() {
System.out.println("This animal eats food.");
}
}

class Dog extends Animal {


void bark() {
System.out.println("The dog barks.");
}
}

5. Multilevel Inheritance

In multilevel inheritance, a class inherits from a superclass, and another


class inherits from this derived class.

Example:

class Animal {
void eat() {
System.out.println("This animal eats food.");
}
}

class Dog extends Animal {


void bark() {
System.out.println("The dog barks.");
}
}

class Puppy extends Dog {


void weep() {
System.out.println("The puppy weeps.");
}
}

6. Hierarchical Inheritance
In hierarchical inheritance, multiple classes inherit from a single superclass.

Example:

class Animal {
void eat() {
System.out.println("This animal eats food.");
}
}

class Dog extends Animal {


void bark() {
System.out.println("The dog barks.");
}
}

class Cat extends Animal {


void meow() {
System.out.println("The cat meows.");
}
}

Multiple Inheritance (Through Interfaces)

In Multiple inheritances, one class can have more than one superclass and inherit features from all
parent classes.

Please note that Java does not support multiple inheritances with classes. In Java, we can achieve

multiple inheritances only through Interfaces.

In the image below, Class C is derived from Class A and Class B.


7. Real-World Examples of Inheritance

Example 1: Vehicle Hierarchy

Consider a vehicle hierarchy where Vehicle is the base class. Car and Bike can be derived classes

that inherit properties and methods from Vehicle.

Example 2: Employee Hierarchy

In an employee management system, Employee can be the base class. Manager and Developer can

be derived classes that inherit from Employee.

Example 3: Number hierarchy from java.lang library

The Java library extensively uses inheritance. The figure below shows an inheritance hierarchy

from java.lang library. The Number class abstracts various numerical (reference) types such

as Byte , Integer , Float , Double , Short , and BigDecimal .

8. Example: Single Inheritance


Example:

class Animal {
void eat() {
System.out.println("This animal eats food.");
}
}

class Dog extends Animal {


void bark() {
System.out.println("The dog barks.");
}
}

public class Main {


public static void main(String[] args) {
Dog dog = new Dog();
dog.eat(); // Output: This animal eats food.
dog.bark(); // Output: The dog barks.
}
}

Explanation:

Animal: Superclass with a method eat.

Dog: Subclass that inherits from Animal and adds a method bark.

9. Example: Multilevel Inheritance


Example:

class Animal {
void eat() {
System.out.println("This animal eats food.");
}
}

class Dog extends Animal {


void bark() {
System.out.println("The dog barks.");
}
}
class Puppy extends Dog {
void weep() {
System.out.println("The puppy weeps.");
}
}

public class Main {


public static void main(String[] args) {
Puppy puppy = new Puppy();
puppy.eat(); // Output: This animal eats food.
puppy.bark(); // Output: The dog barks.
puppy.weep(); // Output: The puppy weeps.
}
}

Explanation:

Animal: Superclass with a method eat.

Dog: Subclass that inherits from Animal and adds a method bark.

Puppy: Subclass that inherits from Dog and adds a method weep.

10. Example: Hierarchical Inheritance


Example:

class Animal {
void eat() {
System.out.println("This animal eats food.");
}
}

class Dog extends Animal {


void bark() {
System.out.println("The dog barks.");
}
}

class Cat extends Animal {


void meow() {
System.out.println("The cat meows.");
}
}
public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
dog.eat(); // Output: This animal eats food.
dog.bark(); // Output: The dog barks.

Cat cat = new Cat();


cat.eat(); // Output: This animal eats food.
cat.meow(); // Output: The cat meows.
}
}

Explanation:

Animal: Superclass with a method eat.

Dog and Cat: Subclasses that inherit from Animal and add methods bark and meow,

respectively.

11. Conclusion
Inheritance in Java is a powerful concept that promotes code reusability and establishes a natural

hierarchical relationship between classes. By using inheritance, you can create a base class with
common properties and methods and then create derived classes that inherit these properties and

methods while adding specific features. Understanding and applying inheritance helps to build a
structured and organized codebase, making it easier to maintain and extend.

Happy coding!
Free Courses
on YouTube
Channel

175K
Subscribers

Composition in Java with Example


author: Ramesh Fadatare

OOP FUNDAMENTALS OOPS

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

Introduction
Composition is a fundamental concept in Object-Oriented Programming (OOP) that allows a class to

contain objects of other classes to achieve code reuse and establish a has-a relationship. Unlike
inheritance, which represents an is-a relationship, composition models a relationship where one

object is made up of one or more objects.

Table of Contents
1. What is Composition?
2. Benefits of Composition
3. Composition vs Inheritance

4. Example: Composition in Java


5. Real-World Examples of Composition
6. Conclusion

1. What is Composition?

Composition is a design principle where a class contains references to one or more objects of other
classes. This allows the class to use the functionality of the composed objects and delegate tasks to

them. Composition is often preferred over inheritance because it promotes greater flexibility and
modularity in the design.

Example: A university consists of several departments. Whenever a university object is destroyed


automatically, all the department objects will be destroyed. Without an existing university object,

there is no chance of an existing dependent object; hence, these are strongly associated, and this
relationship is called composition.

2. Benefits of Composition

Reusability: Composition allows for code reuse by including instances of other classes.
Flexibility: Changes to composed objects can be made independently of the class that uses
them.
Encapsulation: Composition encapsulates the functionality of composed objects, reducing

dependencies.
Better Modeling: Composition better represents real-world relationships where objects are
made up of other objects.
3. Composition vs Inheritance

Feature Composition Inheritance


Relationship Has-a (one object contains another object) Is-a (one class is a type of another)

Flexibility More flexible, allows runtime behavior changesLess flexible, fixed at compile time
Coupling Loosely coupled Tightly coupled
Reusability Promotes high reusability Limited reusability
EncapsulationBetter encapsulation Exposes implementation details

4. Example: Composition in Java

Example:

Let's create a Library class that contains multiple Book objects using composition.

Step 1: Define the Book Class

public class Book {


private String title;
private String author;

public Book(String title, String author) {


this.title = title;
this.author = author;
}

public String getTitle() {


return title;
}

public String getAuthor() {


return author;
}
}

Step 2: Define the Library Class

import java.util.ArrayList;
import java.util.List;
public class Library {
private List<Book> books;

public Library() {
this.books = new ArrayList<>();
}

public void addBook(Book book) {


books.add(book);
}

public void showBooks() {


for (Book book : books) {
System.out.println("Title: " + book.getTitle() + ", Author: " + book.getAuthor(
}
}
}

Step 3: Main Class to Demonstrate Composition

public class Main {


public static void main(String[] args) {
Book book1 = new Book("1984", "George Orwell");
Book book2 = new Book("To Kill a Mockingbird", "Harper Lee");

Library library = new Library();


library.addBook(book1);
library.addBook(book2);

library.showBooks();
// Output:
// Title: 1984, Author: George Orwell
// Title: To Kill a Mockingbird, Author: Harper Lee
}
}

Explanation:

Book: A simple class with title and author attributes.

Library: A class that uses composition to include multiple Book objects. The Library class

manages a list of books and provides methods to add and display books.
Main: A class to demonstrate the use of composition by creating Book objects and adding them

to the Library.

5. Real-World Examples of Composition

Example 1: Car and Engine

A Car class can use composition to include an Engine object. The Car class can delegate the starting

and stopping functionalities to the Engine class.

class Engine {
public void start() {
System.out.println("Engine started.");
}

public void stop() {


System.out.println("Engine stopped.");
}
}

class Car {
private Engine engine;

public Car() {
this.engine = new Engine();
}

public void startCar() {


engine.start();
System.out.println("Car started.");
}

public void stopCar() {


engine.stop();
System.out.println("Car stopped.");
}
}

public class Main {


public static void main(String[] args) {
Car car = new Car();
car.startCar(); // Output: Engine started. Car started.
car.stopCar(); // Output: Engine stopped. Car stopped.
}
}

Example 2: Computer and Components

A Computer class can use composition to include CPU, RAM, and HardDrive objects. The Computer

class can delegate the functionalities to these components.

class CPU {
public void process() {
System.out.println("CPU processing...");
}
}

class RAM {
public void load() {
System.out.println("RAM loading...");
}
}

class HardDrive {
public void readData() {
System.out.println("HardDrive reading data...");
}
}

class Computer {
private CPU cpu;
private RAM ram;
private HardDrive hardDrive;

public Computer() {
this.cpu = new CPU();
this.ram = new RAM();
this.hardDrive = new HardDrive();
}

public void startComputer() {


cpu.process();
ram.load();
hardDrive.readData();
System.out.println("Computer started.");
}
}
public class Main {
public static void main(String[] args) {
Computer computer = new Computer();
computer.startComputer();
// Output:
// CPU processing...
// RAM loading...
// HardDrive reading data...
// Computer started.
}
}

6. Conclusion
Composition in Java is a powerful concept that promotes code reuse and modularity by allowing a

class to contain objects of other classes. It models a has-a relationship, which is more flexible and
encapsulated than inheritance. By using composition, developers can build complex systems that are

easy to maintain and extend. Understanding and applying composition effectively is essential for
designing robust and scalable Java applications.

Happy coding!

OOP FUNDAMENTALS OOPS


Free Courses
on YouTube
Channel

175K
Subscribers

Aggregation in Java with Example


author: Ramesh Fadatare

OOP FUNDAMENTALS OOPS

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

Introduction
Aggregation is a type of association that represents a "has-a" relationship with a whole-part hierarchy.

In aggregation, the child object can exist independently of the parent object, implying a weak
relationship between the parent and child. Aggregation allows one class to contain another class

without owning its lifecycle.

Table of Contents
1. What is Aggregation?
2. Benefits of Aggregation
3. Aggregation vs Composition

4. Example: Aggregation in Java


5. Real-World Examples of Aggregation
6. Conclusion

1. What is Aggregation?

Aggregation is a special type of association that represents a whole-part relationship where the child
(part) can exist independently of the parent (whole). It is used to model relationships where the

contained objects are not strongly dependent on the lifecycle of the container object.

2. Benefits of Aggregation
Reusability: Aggregated objects can be reused across different parts of the application.

Flexibility: Aggregated objects can exist independently of the parent object, providing flexibility
in design.

Modularity: Aggregation promotes modularity by separating the responsibilities of different


classes.
Maintainability: Changes to the aggregated object do not necessarily affect the parent object,

enhancing maintainability.

3. Aggregation vs Composition

Feature Aggregation Composition


RelationshipWhole-part (has-a) Whole-part (has-a)
Dependenc Child cannot exist independently of the
Child can exist independently of the parent
y parent

Parent and child have independent


Lifecycle Parent and child have dependent lifecycles
lifecycles
Coupling Loosely coupled Tightly coupled

4. Example: Aggregation in Java

Example:

Let's create a Department class that aggregates multiple Employee objects using aggregation.

Step 1: Define the Employee Class


public class Employee {
private String name;
private int id;

public Employee(String name, int id) {


this.name = name;
this.id = id;
}

public String getName() {


return name;
}

public int getId() {


return id;
}
}

Step 2: Define the Department Class

import java.util.ArrayList;
import java.util.List;

public class Department {


private String name;
private List<Employee> employees;

public Department(String name) {


this.name = name;
this.employees = new ArrayList<>();
}

public void addEmployee(Employee employee) {


employees.add(employee);
}

public void showEmployees() {


for (Employee employee : employees) {
System.out.println("Employee ID: " + employee.getId() + ", Name: " + employee.g
}
}
public String getName() {
return name;
}
}

Step 3: Main Class to Demonstrate Aggregation

public class Main {


public static void main(String[] args) {
Employee employee1 = new Employee("John Doe", 101);
Employee employee2 = new Employee("Jane Smith", 102);

Department department = new Department("IT Department");


department.addEmployee(employee1);
department.addEmployee(employee2);

System.out.println("Department: " + department.getName());


department.showEmployees();
// Output:
// Department: IT Department
// Employee ID: 101, Name: John Doe
// Employee ID: 102, Name: Jane Smith
}
}

Explanation:

Employee: A simple class with name and id attributes.

Department: A class that uses aggregation to include multiple Employee objects. The

Department class can add and display employees.

Main: A class to demonstrate the use of aggregation by creating Employee objects and adding

them to the Department.

5. Real-World Examples of Aggregation

Example 1: School and Student

A School class can aggregate multiple Student objects. The Student objects can exist independently

of the School.
Student Class

public class Student {


private String name;
private int rollNumber;

public Student(String name, int rollNumber) {


this.name = name;
this.rollNumber = rollNumber;
}

public String getName() {


return name;
}

public int getRollNumber() {


return rollNumber;
}
}

School Class

import java.util.ArrayList;
import java.util.List;

public class School {


private String name;
private List<Student> students;

public School(String name) {


this.name = name;
this.students = new ArrayList<>();
}

public void addStudent(Student student) {


students.add(student);
}

public void showStudents() {


for (Student student : students) {
System.out.println("Student Roll Number: " + student.getRollNumber() + ", Name:
}
}
public String getName() {
return name;
}
}

Example 2: Library and Book

A Library class can aggregate multiple Book objects. The Book objects can exist independently of

the Library.

Book Class

public class Book {


private String title;
private String author;

public Book(String title, String author) {


this.title = title;
this.author = author;
}

public String getTitle() {


return title;
}

public String getAuthor() {


return author;
}
}

Library Class

import java.util.ArrayList;
import java.util.List;

public class Library {


private String name;
private List<Book> books;

public Library(String name) {


this.name = name;
this.books = new ArrayList<>();
}

public void addBook(Book book) {


books.add(book);
}

public void showBooks() {


for (Book book : books) {
System.out.println("Title: " + book.getTitle() + ", Author: " + book.getAuthor(
}
}

public String getName() {


return name;
}
}

6. Conclusion
Aggregation in Java is a powerful concept that allows classes to model a whole-part relationship

where the parts can exist independently of the whole. This promotes modularity, reusability, and
maintainability in the design of software systems. By understanding and using aggregation correctly,

developers can create flexible and robust applications.

Happy coding!
Free Courses
on YouTube
Channel

175K
Subscribers

Association in Java with Example


author: Ramesh Fadatare

OOP FUNDAMENTALS OOPS

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

Introduction
Association is a relationship between two classes that establishes a connection between their objects.

It defines how objects of one class are connected to objects of another class. Association can be of
different types: unidirectional, bidirectional, one-to-one, one-to-many, many-to-one, and many-to-

many. Understanding association is essential for modeling relationships in object-oriented design.

Table of Contents
1. What is Association?
2. Types of Association
3. Benefits of Association

4. Example: Unidirectional Association


5. Example: Bidirectional Association
6. Real-World Examples of Association

7. Conclusion

1. What is Association?
Association is a structural relationship that represents how objects of one class are related to objects

of another class. Unlike inheritance, which defines an is-a relationship, association defines a has-a
relationship. It indicates that one object uses or interacts with another object.

2. Types of Association

Unidirectional Association: One class knows about the other class, but not vice versa.
Bidirectional Association: Both classes know about each other.

One-to-One Association: One object of a class is associated with one object of another class.
One-to-Many Association: One object of a class is associated with many objects of another
class.

Many-to-One Association: Many objects of a class are associated with one object of another
class.

Many-to-Many Association: Many objects of a class are associated with many objects of
another class.

3. Benefits of Association
Reusability: Promotes code reuse by establishing relationships between classes.

Flexibility: Allows classes to interact and collaborate without being tightly coupled.
Modularity: Helps in creating modular designs by defining clear relationships between classes.
Improved Design: Facilitates better design by modeling real-world relationships.

4. Example: Unidirectional Association


In a unidirectional association, one class knows about the other class, but not vice versa.

Example:

Let's create a Library class that is associated with multiple Book objects using unidirectional
association.

Step 1: Define the Book Class

public class Book {


private String title;
private String author;

public Book(String title, String author) {


this.title = title;
this.author = author;
}

public String getTitle() {


return title;
}

public String getAuthor() {


return author;
}
}

Step 2: Define the Library Class

import java.util.ArrayList;
import java.util.List;

public class Library {


private List<Book> books;

public Library() {
this.books = new ArrayList<>();
}

public void addBook(Book book) {


books.add(book);
}

public void showBooks() {


for (Book book : books) {
System.out.println("Title: " + book.getTitle() + ", Author: " + book.getAuthor(
}
}
}

Step 3: Main Class to Demonstrate Unidirectional Association

public class Main {


public static void main(String[] args) {
Book book1 = new Book("1984", "George Orwell");
Book book2 = new Book("To Kill a Mockingbird", "Harper Lee");

Library library = new Library();


library.addBook(book1);
library.addBook(book2);

library.showBooks();
// Output:
// Title: 1984, Author: George Orwell
// Title: To Kill a Mockingbird, Author: Harper Lee
}
}

Explanation:

Book: A simple class with title and author attributes.

Library: A class that uses unidirectional association to include multiple Book objects. The

Library class can add and display books.

Main: A class to demonstrate the use of unidirectional association by creating Book objects and

adding them to the Library.

5. Example: Bidirectional Association


In a bidirectional association, both classes know about each other.

Example:

Let's create a Person class and an Address class with a bidirectional association.

Step 1: Define the Address Class

public class Address {


private String street;
private String city;
private Person person; // Bidirectional association

public Address(String street, String city) {


this.street = street;
this.city = city;
}

public String getStreet() {


return street;
}

public String getCity() {


return city;
}

public void setPerson(Person person) {


this.person = person;
}

public Person getPerson() {


return person;
}
}

Step 2: Define the Person Class

public class Person {


private String name;
private Address address; // Bidirectional association

public Person(String name) {


this.name = name;
}

public String getName() {


return name;
}

public void setAddress(Address address) {


this.address = address;
address.setPerson(this); // Set the reverse association
}
public Address getAddress() {
return address;
}
}

Step 3: Main Class to Demonstrate Bidirectional Association

public class Main {


public static void main(String[] args) {
Person person = new Person("John Doe");
Address address = new Address("123 Main St", "Springfield");

person.setAddress(address);

System.out.println("Person: " + person.getName());


System.out.println("Address: " + person.getAddress().getStreet() + ", " + person.ge
System.out.println("Resident: " + address.getPerson().getName());
// Output:
// Person: John Doe
// Address: 123 Main St, Springfield
// Resident: John Doe
}
}

Explanation:

Address: A class with street, city, and a reference to a Person object.

Person: A class with name and a reference to an Address object.

Main: A class to demonstrate bidirectional association by creating Person and Address objects

and setting up their association.

6. Real-World Examples of Association

Example 1: University and Student

In a university system, a University class can have multiple Student objects. This can be modeled

using unidirectional or bidirectional association.

University Class
import java.util.ArrayList;
import java.util.List;

public class University {


private String name;
private List<Student> students;

public University(String name) {


this.name = name;
this.students = new ArrayList<>();
}

public void addStudent(Student student) {


students.add(student);
}

public List<Student> getStudents() {


return students;
}

public String getName() {


return name;
}
}

Student Class

public class Student {


private String name;
private University university; // Bidirectional association

public Student(String name) {


this.name = name;
}

public String getName() {


return name;
}

public void setUniversity(University university) {


this.university = university;
}
public University getUniversity() {
return university;
}
}

Example 2: Department and Employee

In a company, a Department can have multiple Employee objects, and an Employee can belong to a

single Department.

Department Class

import java.util.ArrayList;
import java.util.List;

public class Department {


private String name;
private List<Employee> employees;

public Department(String name) {


this.name = name;
this.employees = new ArrayList<>();
}

public void addEmployee(Employee employee) {


employees.add(employee);
}

public List<Employee> getEmployees() {


return employees;
}

public String getName() {


return name;
}
}

Employee Class

public class Employee {


private String name;
private Department department; // Bidirectional association
public Employee(String name) {
this.name = name;
}

public String getName() {


return name;
}

public void setDepartment(Department department) {


this.department = department;
}

public Department getDepartment() {


return department;
}
}

7. Conclusion
Association in Java is a powerful concept that allows modeling relationships between classes. By

understanding and using association correctly, developers can create flexible, modular, and
maintainable systems. Association can be unidirectional or bidirectional and can represent one-to-

one, one-to-many, many-to-one, or many-to-many relationships.

Happy coding!
Free Courses
on YouTube
Channel

175K
Subscribers

Cohesion in Java with Example


author: Ramesh Fadatare

OOP FUNDAMENTALS OOPS

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

Introduction
Cohesion is a measure of how closely related and focused the responsibilities of a single module or

class are. In Object-Oriented Programming (OOP), a highly cohesive class is one that performs a single
task or a group of related tasks, making the class easier to maintain and understand. High cohesion

often correlates with low coupling, leading to a more modular and maintainable codebase.

Table of Contents
1. What is Cohesion?
2. Benefits of High Cohesion
3. Types of Cohesion

4. Example: Low Cohesion vs High Cohesion


5. Real-World Examples of Cohesion
6. Conclusion

1. What is Cohesion?

Cohesion refers to the degree to which the elements inside a module or class belong together. It
describes how well the methods and properties of a class are related to each other. High cohesion

means that a class is responsible for only one thing or a group of related things, while low cohesion
means that a class has many unrelated responsibilities.

2. Benefits of High Cohesion

Improved Maintainability: High cohesion makes classes easier to maintain and update
because each class has a clear and focused responsibility.

Enhanced Readability: Classes with high cohesion are easier to understand and reason about.
Increased Reusability: Highly cohesive classes are more likely to be reused in different parts of
an application or in different projects.

Simplified Testing: Testing is easier for highly cohesive classes since they perform a single task
or a group of related tasks.

3. Types of Cohesion

1. Low cohesion
2. High Cohesion

4. Example: Low Cohesion vs High Cohesion

Example of Low Cohesion

In a class with low cohesion, responsibilities are scattered and unrelated, making the class difficult to
maintain and understand.

public class LowCohesionClass {


// Unrelated methods grouped together

public void calculateSalary() {


// Calculate employee salary
}

public void printReport() {


// Print employee report
}

public void sendEmail() {


// Send email to employee
}
}

Example of High Cohesion

In a class with high cohesion, responsibilities are related and focused, making the class easier to

maintain and understand.

Employee Class

public class Employee {


private String name;
private double salary;

public Employee(String name, double salary) {


this.name = name;
this.salary = salary;
}

public String getName() {


return name;
}

public double getSalary() {


return salary;
}

public void setSalary(double salary) {


this.salary = salary;
}
}

SalaryCalculator Class
public class SalaryCalculator {
public double calculateAnnualSalary(Employee employee) {
return employee.getSalary() * 12;
}
}

ReportPrinter Class

public class ReportPrinter {


public void printEmployeeReport(Employee employee) {
System.out.println("Employee Report: " + employee.getName() + ", Salary: " + employ
}
}

EmailService Class

public class EmailService {


public void sendEmail(String email, String message) {
System.out.println("Sending email to: " + email + ", Message: " + message);
}
}

Explanation

LowCohesionClass: Contains methods that perform unrelated tasks such as calculating salary,
printing reports, and sending emails. This makes the class difficult to understand and maintain.
High Cohesion Example: Responsibilities are divided into separate classes: Employee,

SalaryCalculator, ReportPrinter, and EmailService. Each class has a single responsibility,

making the code more modular and easier to maintain.

5. Real-World Examples of Cohesion

Example 1: Library System

In a library system, you can have classes like Book, LibraryMember, LibraryCatalog, and

LoanService. Each class has a specific responsibility, such as managing book details, handling

member information, maintaining the catalog, and managing book loans, respectively.
Book Class

public class Book {


private String title;
private String author;
private String isbn;

// Constructors, getters, and setters


}

LibraryMember Class

public class LibraryMember {


private String memberId;
private String name;

// Constructors, getters, and setters


}

LibraryCatalog Class

public class LibraryCatalog {


private List<Book> books;

public void addBook(Book book) {


books.add(book);
}

public Book findBookByIsbn(String isbn) {


for (Book book : books) {
if (book.getIsbn().equals(isbn)) {
return book;
}
}
return null;
}
}

LoanService Class
public class LoanService {
public void loanBook(LibraryMember member, Book book) {
// Logic to loan a book to a member
}
}

Example 2: E-commerce System

In an e-commerce system, you can have classes like Product, ShoppingCart, Order, and

PaymentProcessor. Each class is responsible for a specific part of the system.

Product Class

public class Product {


private String name;
private double price;

// Constructors, getters, and setters


}

ShoppingCart Class

public class ShoppingCart {


private List<Product> products;

public void addProduct(Product product) {


products.add(product);
}

public double calculateTotal() {


double total = 0;
for (Product product : products) {
total += product.getPrice();
}
return total;
}
}

Order Class
public class Order {
private List<Product> products;

// Constructors, getters, and setters


}

PaymentProcessor Class

public class PaymentProcessor {


public void processPayment(Order order, String paymentDetails) {
// Logic to process payment
}
}

6. Conclusion
Cohesion is a critical concept in software design that affects the maintainability, readability, and

reusability of a system. High cohesion within classes leads to a more modular and understandable
codebase, making it easier to manage and extend. By focusing on creating highly cohesive classes,

developers can build robust and scalable software systems.

Happy coding!
Free Courses
on YouTube
Channel

175K
Subscribers

Coupling in Java with Example


author: Ramesh Fadatare

OOP FUNDAMENTALS OOPS

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

Introduction
Coupling refers to the degree of direct knowledge that one class has about another class. In software

design, coupling is an essential concept that impacts the modularity and maintainability of a system.
Lower coupling between classes usually leads to a system that is easier to maintain and extend, while

higher coupling can make the system more rigid and harder to manage.

Table of Contents
1. What is Coupling?

2. Types of Coupling
3. Benefits of Low Coupling

4. Example: Tight Coupling


5. Example: Loose Coupling
6. Conclusion

1. What is Coupling?

Coupling describes the degree of dependency between classes or modules. It indicates how closely
connected different classes or modules are, and how much they rely on each other. There are two

main types of coupling:

Tight Coupling: High dependency between classes. Changes in one class often require changes

in the coupled class.


Loose Coupling: Low dependency between classes. Classes interact through well-defined

interfaces, reducing the impact of changes.

2. Types of Coupling

Tight Coupling

Tight coupling occurs when a class is highly dependent on the specifics of another class. This often

happens when one class creates an instance of another class and directly accesses its methods and
fields.

Loose Coupling

Loose coupling occurs when classes are less dependent on the specifics of other classes. This can be
achieved by using interfaces, abstract classes, or dependency injection, allowing classes to interact
without knowing the implementation details of each other.

3. Benefits of Low Coupling

Improved Maintainability: Changes in one class have minimal impact on other classes.
Enhanced Reusability: Loosely coupled classes can be reused in different contexts.
Better Testability: Independent classes are easier to test in isolation.

Flexibility: Systems with low coupling are more adaptable to change.


4. Example: Tight Coupling

In a tightly coupled system, changes in one class can significantly affect other classes.

Example:

class Engine {
public void start() {
System.out.println("Engine started.");
}
}

class Car {
private Engine engine;

public Car() {
this.engine = new Engine(); // Direct instantiation
}

public void start() {


engine.start();
}
}

public class Main {


public static void main(String[] args) {
Car car = new Car();
car.start(); // Output: Engine started.
}
}

Explanation:

Car class is tightly coupled with the Engine class.

The Car class directly creates an instance of Engine and calls its start method.

Any change in the Engine class, such as a change in the method signature, would require

changes in the Car class.

5. Example: Loose Coupling

In a loosely coupled system, classes interact through interfaces, reducing dependency.


Example:

interface Engine {
void start();
}

class DieselEngine implements Engine {


@Override
public void start() {
System.out.println("Diesel Engine started.");
}
}

class ElectricEngine implements Engine {


@Override
public void start() {
System.out.println("Electric Engine started.");
}
}

class Car {
private Engine engine;

public Car(Engine engine) {


this.engine = engine;
}

public void start() {


engine.start();
}
}

public class Main {


public static void main(String[] args) {
Engine dieselEngine = new DieselEngine();
Car carWithDieselEngine = new Car(dieselEngine);
carWithDieselEngine.start(); // Output: Diesel Engine started.

Engine electricEngine = new ElectricEngine();


Car carWithElectricEngine = new Car(electricEngine);
carWithElectricEngine.start(); // Output: Electric Engine started.
}
}
Explanation:

Engine is an interface that defines the start method.

DieselEngine and ElectricEngine are implementations of the Engine interface.


Car class depends on the Engine interface rather than a concrete implementation.

The Car class can work with any implementation of the Engine interface, promoting loose
coupling.

6. Conclusion

Coupling is a critical concept in software design that affects the modularity, maintainability, and
flexibility of a system. Tight coupling leads to a system where classes are highly dependent on each

other, making it hard to maintain and extend. Loose coupling, on the other hand, reduces
dependencies, making the system easier to manage and adapt to changes. By using interfaces,
abstract classes, and dependency injection, developers can achieve loose coupling and build more
robust and flexible systems.

Happy coding!

OOP FUNDAMENTALS OOPS


Free Courses
on YouTube
Channel

175K
Subscribers

Delegation in Java with Example


author: Ramesh Fadatare

OOP FUNDAMENTALS OOPS

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

Introduction
Delegation is an object-oriented design pattern in which an object passes a task to another object

instead of performing it itself. This concept allows for polymorphism and code reuse, leading to more
maintainable and flexible code. Delegation helps maintain a loosely coupled system, which is easier to

maintain and extend.

Table of Contents
1. What is Delegation?
2. Benefits of Delegation
3. Example 1: Ticket Booking System

4. Example 2: Printers Implementation


5. Conclusion

1. What is Delegation?

Delegation is a technique in which an object delegates responsibilities to another helper object.


Instead of doing the work itself, it passes the task to another object. This helps achieve polymorphism
and ensures that tasks are handled by the most appropriate class.

2. Benefits of Delegation

Loosely Coupled Code: Delegation reduces the coupling between classes.


Code Reusability: Common functionalities can be reused by multiple classes.

Enhanced Flexibility: Changes to the delegated class do not affect the delegator class.
Improved Maintainability: Easier to maintain and extend as the code is modular.

3. Example 1: Ticket Booking System

Step-by-Step Implementation

Step 1: Create a TravelBooking Interface

interface TravelBooking {
void bookTicket();
}

The TravelBooking interface defines a single method bookTicket(), which will be implemented by

various travel booking classes.

Step 2: TrainBooking Class

class TrainBooking implements TravelBooking {


@Override
public void bookTicket() {
System.out.println("Train ticket booked");
}
}
The TrainBooking class implements the TravelBooking interface and provides a specific

implementation for booking train tickets.

Step 3: AirBooking Class

class AirBooking implements TravelBooking {


@Override
public void bookTicket() {
System.out.println("Flight ticket booked");
}
}

The AirBooking class implements the TravelBooking interface and provides a specific

implementation for booking air tickets.

Step 4: TicketBookingByAgent Class

class TicketBookingByAgent implements TravelBooking {

private TravelBooking travelBooking;

public TicketBookingByAgent(TravelBooking travelBooking) {


this.travelBooking = travelBooking;
}

@Override
public void bookTicket() {
travelBooking.bookTicket();
}
}

The TicketBookingByAgent class also implements the TravelBooking interface but delegates the

actual booking task to another TravelBooking object. The delegation is achieved via the constructor

which accepts a TravelBooking object. The bookTicket() method calls the bookTicket() method

of the delegated TravelBooking object.

Step 5: DelegationDemonstration Class


public class DelegationDemonstration {
public static void main(String[] args) {
TicketBookingByAgent agent = new TicketBookingByAgent(new TrainBooking());
agent.bookTicket(); // Output: Train ticket booked

agent = new TicketBookingByAgent(new AirBooking());


agent.bookTicket(); // Output: Flight ticket booked
}
}

In the DelegationDemonstration class, we create an instance of TicketBookingByAgent and pass

it different TravelBooking implementations. The bookTicket() method of TicketBookingByAgent

delegates the call to the appropriate booking class (either TrainBooking or AirBooking).

How Delegation Works in the Ticket Booking System

In this example, the TicketBookingByAgent class does not handle the actual ticket booking process.

Instead, it delegates this responsibility to the classes that implement the TravelBooking interface

(TrainBooking and AirBooking). This allows TicketBookingByAgent to dynamically choose which

booking implementation to use at runtime, promoting flexibility and code reuse.

4. Example 2: Printers Implementation

Step-by-Step Implementation

Step 1: Printer Interface

public interface Printer {


void print(String message);
}

The Printer interface defines a single method print(), which will be implemented by various
printer classes.

Step 2: CanonPrinter Class

public class CanonPrinter implements Printer {


@Override
public void print(String message) {
System.out.println("Canon Printer: " + message);
}
}

The CanonPrinter class implements the Printer interface and provides a specific implementation

for printing a message.

Step 3: EpsonPrinter Class

public class EpsonPrinter implements Printer {


@Override
public void print(String message) {
System.out.println("Epson Printer: " + message);
}
}

The EpsonPrinter class implements the Printer interface and provides a specific implementation

for printing a message.

Step 4: HpPrinter Class

public class HpPrinter implements Printer {


@Override
public void print(String message) {
System.out.println("HP Printer: " + message);
}
}

The HpPrinter class implements the Printer interface and provides a specific implementation for

printing a message.

Step 5: PrinterController Class


public class PrinterController implements Printer {

private final Printer printer;

public PrinterController(Printer printer) {


this.printer = printer;
}

@Override
public void print(String message) {
printer.print(message);
}
}

The PrinterController class also implements the Printer interface but delegates the actual

printing task to another Printer object. The delegation is achieved via the constructor which accepts

a Printer object. The print() method calls the print() method of the delegated Printer object.

Step 6: App Class to Test Delegation

public class App {

public static final String MESSAGE_TO_PRINT = "hello world";

public static void main(String[] args) {


PrinterController hpPrinterController = new PrinterController(new HpPrinter());
PrinterController canonPrinterController = new PrinterController(new CanonPrinter()
PrinterController epsonPrinterController = new PrinterController(new EpsonPrinter()

hpPrinterController.print(MESSAGE_TO_PRINT); // Output: HP Printer: hello world


canonPrinterController.print(MESSAGE_TO_PRINT); // Output: Canon Printer: hello wor
epsonPrinterController.print(MESSAGE_TO_PRINT); // Output: Epson Printer: hello wor
}
}

How Delegation Works in the Printers Implementation

In this example, the PrinterController class does not handle the actual printing process. Instead, it

delegates this responsibility to the classes that implement the Printer interface (CanonPrinter,
EpsonPrinter, and HpPrinter). This allows PrinterController to dynamically choose which

printer implementation to use at runtime, promoting flexibility and code reuse.

5. Conclusion

Delegation is a powerful design pattern that allows objects to delegate tasks to other objects,
promoting code reuse and modularity. By using delegation, you can create more flexible and

maintainable systems. In this article, we explored two examples: a ticket booking system and a printer

implementation, to demonstrate how delegation can be effectively used in Java.

Happy coding!

OOP FUNDAMENTALS OOPS

Anonymous 24 December 2018 at 00:15


class diagram is wrong. +CanonPrinter() in all the different printer class

Java Technology 24 December 2018 at 02:28


Class diagram is not wrong. The content CononPrinter is typo in all subclasses.You
can fix this.
Free Courses
on YouTube
Channel

175K
Subscribers

Single Responsibility Principle in Java with Example


author: Ramesh Fadatare

JAVA BEST PRACTICES OBJECT ORIENTED DESIGN OOPS SOLID PRINCIPLES

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

Introduction
The Single Responsibility Principle (SRP) is one of the five SOLID principles of object-oriented design.

SRP states that a class should have only one reason to change, meaning it should have only one
responsibility or job. This principle helps in creating more maintainable and understandable code by

ensuring that each class addresses only one concern.

Table of Contents
1. What is the Single Responsibility Principle?
2. Benefits of the Single Responsibility Principle
3. Example: Violation of SRP

4. Example: Adherence to SRP


5. Real-World Example
6. Conclusion

1. What is the Single Responsibility Principle?

The Single Responsibility Principle (SRP) asserts that a class should only have one reason to change,
implying it should have only one responsibility or purpose. This principle helps in building classes that

are easier to understand, test, and maintain by ensuring each class is focused on a single aspect of the
application.

2. Benefits of the Single Responsibility Principle

Improved Maintainability: Changes to a single responsibility affect only one class, making the
codebase easier to maintain.

Enhanced Readability: Classes with a single responsibility are easier to read and understand.
Increased Reusability: Classes focused on a single responsibility can be reused in different
contexts without modification.

Simplified Testing: Testing is more straightforward for classes with a single responsibility.

3. Example: Violation of SRP

In this example, a User class is responsible for both user management and email sending, violating

SRP.

public class User {


private String name;
private String email;

public User(String name, String email) {


this.name = name;
this.email = email;
}

public void saveUser() {


// Code to save user to database
System.out.println("User saved to database.");
}
public void sendEmail(String message) {
// Code to send email
System.out.println("Email sent to " + email + " with message: " + message);
}

public String getName() {


return name;
}

public String getEmail() {


return email;
}
}

public class Main {


public static void main(String[] args) {
User user = new User("John Doe", "[email protected]");
user.saveUser();
user.sendEmail("Welcome to our platform!");
}
}

Issues:

The User class is responsible for both saving the user and sending emails.

Any change in email sending logic will require changes in the User class, violating SRP.

4. Example: Adherence to SRP


By splitting responsibilities into separate classes, we adhere to SRP.

Step 1: Define the User Class

public class User {


private String name;
private String email;

public User(String name, String email) {


this.name = name;
this.email = email;
}

public String getName() {


return name;
}

public String getEmail() {


return email;
}
}

Step 2: Define the UserRepository Class

public class UserRepository {


public void saveUser(User user) {
// Code to save user to database
System.out.println("User " + user.getName() + " saved to database.");
}
}

Step 3: Define the EmailService Class

public class EmailService {


public void sendEmail(User user, String message) {
// Code to send email
System.out.println("Email sent to " + user.getEmail() + " with message: " + message
}
}

Step 4: Main Class to Demonstrate SRP

public class Main {


public static void main(String[] args) {
User user = new User("John Doe", "[email protected]");

UserRepository userRepository = new UserRepository();


userRepository.saveUser(user);

EmailService emailService = new EmailService();


emailService.sendEmail(user, "Welcome to our platform!");
}
}
Explanation:

User: Class only responsible for storing user details.


UserRepository: Class responsible for saving the user to the database.
EmailService: Class responsible for sending emails to users.
Main: Class demonstrating the use of SRP by separating concerns into different classes.

5. Real-World Example

Example: Library System

In a library management system, consider separating the responsibilities of book management,


member management, and loan management into different classes.

Book Class

public class Book {


private String title;
private String author;

public Book(String title, String author) {


this.title = title;
this.author = author;
}

public String getTitle() {


return title;
}

public String getAuthor() {


return author;
}
}

Member Class

public class Member {


private String name;
private String memberId;
public Member(String name, String memberId) {
this.name = name;
this.memberId = memberId;
}

public String getName() {


return name;
}

public String getMemberId() {


return memberId;
}
}

LoanService Class

public class LoanService {


public void loanBook(Member member, Book book) {
// Code to loan book to member
System.out.println("Book '" + book.getTitle() + "' loaned to member " + member.getN
}
}

Explanation:

Book: Class responsible for storing book details.


Member: Class responsible for storing member details.

LoanService: Class responsible for managing book loans.


Main: Class demonstrating the use of SRP by separating concerns into different classes.

Conclusion

The Single Responsibility Principle (SRP) is a fundamental concept in object-oriented design that
promotes high cohesion and low coupling by ensuring that each class has only one responsibility or

reason to change. By adhering to SRP, developers can create more maintainable, understandable, and
flexible code. This principle is critical for building robust and scalable applications.

Happy coding!
Free Courses
on YouTube
Channel

175K
Subscribers

Open/Closed Principle in Java with Example


author: Ramesh Fadatare

JAVA BEST PRACTICES OBJECT ORIENTED DESIGN OOPS SOLID PRINCIPLES

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

Introduction
The Open/Closed Principle (OCP) is one of the five SOLID principles of object-oriented design. It

states that software entities (such as classes, modules, and functions) should be open for extension
but closed for modification. This means that the behavior of a module can be extended without

modifying its source code.

Table of Contents
1. What is the Open/Closed Principle?
2. Benefits of the Open/Closed Principle
3. Example: Violation of OCP

4. Example: Adherence to OCP


5. Real-World Example
6. Conclusion

1. What is the Open/Closed Principle?

The Open/Closed Principle (OCP) asserts that a class should be open for extension but closed for
modification. This means you should be able to add new functionality to a class by extending it,

without changing the existing code.

2. Benefits of the Open/Closed Principle


Enhanced Maintainability: Reduces the risk of introducing bugs when adding new

functionality.
Improved Flexibility: New features can be added without modifying existing code.

Increased Reusability: Classes that adhere to OCP are more likely to be reusable in different
contexts.

3. Example: Violation of OCP

In this example, we'll create a Shape class and a AreaCalculator class that violates OCP by requiring

modification to add new shapes.

Example:

class Circle {
private double radius;

public Circle(double radius) {


this.radius = radius;
}

public double getRadius() {


return radius;
}
}

class Rectangle {
private double width;
private double height;

public Rectangle(double width, double height) {


this.width = width;
this.height = height;
}

public double getWidth() {


return width;
}

public double getHeight() {


return height;
}
}

class AreaCalculator {
public double calculateArea(Object shape) {
if (shape instanceof Circle) {
Circle circle = (Circle) shape;
return Math.PI * circle.getRadius() * circle.getRadius();
} else if (shape instanceof Rectangle) {
Rectangle rectangle = (Rectangle) shape;
return rectangle.getWidth() * rectangle.getHeight();
}
return 0;
}
}

public class Main {


public static void main(String[] args) {
Circle circle = new Circle(5);
Rectangle rectangle = new Rectangle(4, 5);

AreaCalculator calculator = new AreaCalculator();


System.out.println("Circle area: " + calculator.calculateArea(circle)); // Output:
System.out.println("Rectangle area: " + calculator.calculateArea(rectangle)); // Ou
}
}

Issues:

The AreaCalculator class must be modified to support new shapes, violating OCP.

Adding new shapes requires changes to the calculateArea method, making the code less
maintainable.

4. Example: Adherence to OCP

To adhere to OCP, we can use polymorphism and interfaces to allow the AreaCalculator to work

with any shape without modification.

Example:

Step 1: Define the Shape Interface

interface Shape {
double calculateArea();
}

Step 2: Implement Specific Shape Classes

class Circle implements Shape {


private double radius;

public Circle(double radius) {


this.radius = radius;
}

@Override
public double calculateArea() {
return Math.PI * radius * radius;
}
}

class Rectangle implements Shape {


private double width;
private double height;

public Rectangle(double width, double height) {


this.width = width;
this.height = height;
}

@Override
public double calculateArea() {
return width * height;
}
}

Step 3: Update the AreaCalculator Class

class AreaCalculator {
public double calculateArea(Shape shape) {
return shape.calculateArea();
}
}

Step 4: Main Class to Demonstrate OCP

public class Main {


public static void main(String[] args) {
Shape circle = new Circle(5);
Shape rectangle = new Rectangle(4, 5);

AreaCalculator calculator = new AreaCalculator();


System.out.println("Circle area: " + calculator.calculateArea(circle)); // Output:
System.out.println("Rectangle area: " + calculator.calculateArea(rectangle)); // Ou
}
}

Explanation:

Shape: An interface that defines the calculateArea method.

Circle and Rectangle: Implementations of the Shape interface that provide specific area

calculations.
AreaCalculator: A class that calculates the area of any Shape without needing modification.

Main: Demonstrates the use of OCP by adding new shapes without changing the
AreaCalculator class.

5. Real-World Example

Example: Notification System

Consider a notification system where different types of notifications (e.g., email, SMS) need to be sent.
Step 1: Define the Notification Interface

interface Notification {
void send(String message);
}

Step 2: Implement Specific Notification Classes

class EmailNotification implements Notification {


@Override
public void send(String message) {
System.out.println("Sending email: " + message);
}
}

class SMSNotification implements Notification {


@Override
public void send(String message) {
System.out.println("Sending SMS: " + message);
}
}

Step 3: Update the NotificationService Class

class NotificationService {
private List<Notification> notifications;

public NotificationService() {
this.notifications = new ArrayList<>();
}

public void addNotification(Notification notification) {


notifications.add(notification);
}

public void sendAll(String message) {


for (Notification notification : notifications) {
notification.send(message);
}
}
}
Step 4: Main Class to Demonstrate OCP

public class Main {


public static void main(String[] args) {
NotificationService service = new NotificationService();
service.addNotification(new EmailNotification());
service.addNotification(new SMSNotification());

service.sendAll("Hello, World!");
// Output:
// Sending email: Hello, World!
// Sending SMS: Hello, World!
}
}

Explanation:

Notification: An interface that defines the send method.

EmailNotification and SMSNotification: Implementations of the Notification interface that

provide specific sending mechanisms.


NotificationService: A class that sends notifications without needing modification for new

types of notifications.
Main: Demonstrates the use of OCP by adding new notification types without changing the

NotificationService class.

6. Conclusion
The Open/Closed Principle (OCP) is a fundamental concept in object-oriented design that promotes

the extension of software entities without modifying their source code. By adhering to OCP,
developers can create more maintainable, flexible, and reusable code. Understanding and applying

OCP is essential for building robust and scalable Java applications.

Happy coding!
Free Courses
on YouTube
Channel

175K
Subscribers

Liskov Substitution Principle in Java with Example


author: Ramesh Fadatare

JAVA BEST PRACTICES OBJECT ORIENTED DESIGN OOPS SOLID PRINCIPLES

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

Introduction
The Liskov Substitution Principle (LSP) is one of the five SOLID principles of object-oriented design. It

states that objects of a superclass should be replaceable with objects of a subclass without affecting
the correctness of the program. This principle ensures that a subclass can stand in for its superclass

without altering the desirable properties of the program (correctness, task performed, etc.).

Table of Contents
1. What is the Liskov Substitution Principle?
2. Benefits of the Liskov Substitution Principle
3. Example: Violation of LSP

4. Example: Adherence to LSP


5. Real-World Example
6. Conclusion

1. What is the Liskov Substitution Principle?

The Liskov Substitution Principle (LSP) asserts that if S is a subtype of T, then objects of type T may be

replaced with objects of type S (i.e., objects of type S may substitute objects of type T) without

altering any of the desirable properties of the program. This means that subclasses should extend the

functionality of the parent class without changing its behavior.

2. Benefits of the Liskov Substitution Principle


Enhanced Reusability: Ensures subclasses can be used interchangeably with their parent

classes.
Improved Maintainability: Reduces the risk of introducing bugs when extending classes.
Increased Flexibility: Allows for more flexible and modular code design.

3. Example: Violation of LSP


In this example, we'll create a superclass Bird and a subclass Penguin that violates LSP.

Example:

class Bird {
public void fly() {
System.out.println("Bird is flying");
}
}

class Sparrow extends Bird {


@Override
public void fly() {
System.out.println("Sparrow is flying");
}
}

class Penguin extends Bird {


@Override
public void fly() {
throw new UnsupportedOperationException("Penguins can't fly");
}
}

public class Main {


public static void main(String[] args) {
Bird bird = new Sparrow();
bird.fly(); // Output: Sparrow is flying

bird = new Penguin();


bird.fly(); // Throws UnsupportedOperationException
}
}

Issues:

The Penguin class violates LSP because it changes the behavior of the fly method by throwing

an exception.
This breaks the expected behavior of the Bird class and can lead to runtime errors.

4. Example: Adherence to LSP

To adhere to LSP, we can introduce a more appropriate class hierarchy where flying ability is modeled
differently.

Example:

abstract class Bird {


public abstract void eat();
}

class Sparrow extends Bird {


@Override
public void eat() {
System.out.println("Sparrow is eating");
}

public void fly() {


System.out.println("Sparrow is flying");
}
}
class Penguin extends Bird {
@Override
public void eat() {
System.out.println("Penguin is eating");
}

public void swim() {


System.out.println("Penguin is swimming");
}
}

public class Main {


public static void main(String[] args) {
Bird sparrow = new Sparrow();
sparrow.eat(); // Output: Sparrow is eating
((Sparrow) sparrow).fly(); // Output: Sparrow is flying

Bird penguin = new Penguin();


penguin.eat(); // Output: Penguin is eating
((Penguin) penguin).swim(); // Output: Penguin is swimming
}
}

Explanation:

Bird: An abstract class that provides a common interface for all bird types.
Sparrow and Penguin: Subclasses that extend Bird without changing its behavior.

Main: Demonstrates the use of LSP by allowing subclasses to be used interchangeably with the
parent class.

5. Real-World Example

Example: Payment Processing System

Consider a payment processing system where different payment methods (e.g., credit card, PayPal)
should adhere to the Liskov Substitution Principle.

Step 1: Define the Payment Class

abstract class Payment {


public abstract void processPayment(double amount);
}
class CreditCardPayment extends Payment {
@Override
public void processPayment(double amount) {
System.out.println("Processing credit card payment of $" + amount);
}
}

class PayPalPayment extends Payment {


@Override
public void processPayment(double amount) {
System.out.println("Processing PayPal payment of $" + amount);
}
}

Step 2: Main Class to Demonstrate LSP

public class Main {


public static void main(String[] args) {
Payment payment = new CreditCardPayment();
payment.processPayment(100.0); // Output: Processing credit card payment of $100.0

payment = new PayPalPayment();


payment.processPayment(200.0); // Output: Processing PayPal payment of $200.0
}
}

Explanation:

Payment: An abstract class that provides a common interface for all payment methods.

CreditCardPayment and PayPalPayment: Subclasses that extend Payment without changing its

behavior.

Main: Demonstrates the use of LSP by allowing different payment methods to be used

interchangeably.

6. Conclusion

The Liskov Substitution Principle (LSP) is a fundamental concept in object-oriented design that
ensures subclasses can replace their parent classes without altering the correctness of the program.

By adhering to LSP, developers can create more flexible, reusable, and maintainable code.
Free Courses
on YouTube
Channel

175K
Subscribers

Interface Segregation Principle in Java with Example


author: Ramesh Fadatare

JAVA BEST PRACTICES OBJECT ORIENTED DESIGN OOPS SOLID PRINCIPLES

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

Introduction
The Interface Segregation Principle (ISP) is one of the five SOLID principles of object-oriented design.

ISP states that no client should be forced to depend on methods they do not use. This principle
promotes the creation of smaller, more specific interfaces instead of larger, general-purpose

interfaces, ensuring that classes implement only the methods that are relevant to them.

Table of Contents
1. What is the Interface Segregation Principle?
2. Benefits of the Interface Segregation Principle
3. Example: Violation of ISP

4. Example: Adherence to ISP


5. Real-World Example
6. Conclusion

1. What is the Interface Segregation Principle?

The Interface Segregation Principle (ISP) asserts that clients should not be forced to depend on
interfaces they do not use. In other words, an interface should not include methods that are not

relevant to the implementing class. Instead, interfaces should be small and focused on specific sets of
behaviors.

2. Benefits of the Interface Segregation Principle

Improved Maintainability: Smaller interfaces are easier to implement, maintain, and


understand.

Enhanced Flexibility: Changes in one part of the system are less likely to affect other parts.
Increased Reusability: Classes can implement only the interfaces they need, promoting reuse.

3. Example: Violation of ISP

In this example, we'll create an interface Worker that violates ISP by including methods not relevant to

all implementing classes.

Example:

interface Worker {
void work();
void eat();
}

class Developer implements Worker {


@Override
public void work() {
System.out.println("Developer is coding.");
}

@Override
public void eat() {
System.out.println("Developer is eating.");
}
}

class Robot implements Worker {


@Override
public void work() {
System.out.println("Robot is working.");
}

@Override
public void eat() {
// Robot does not eat
throw new UnsupportedOperationException("Robot does not eat.");
}
}

public class Main {


public static void main(String[] args) {
Worker developer = new Developer();
developer.work(); // Output: Developer is coding.
developer.eat(); // Output: Developer is eating.

Worker robot = new Robot();


robot.work(); // Output: Robot is working.
robot.eat(); // Throws UnsupportedOperationException
}
}

Issues:

The Robot class is forced to implement the eat method, which is not applicable to it.

This leads to a violation of ISP as the Robot class depends on a method it does not use.

4. Example: Adherence to ISP

To adhere to ISP, we can split the Worker interface into more specific interfaces.

Example:

Step 1: Define Specific Interfaces

interface Workable {
void work();
}

interface Eatable {
void eat();
}

Step 2: Implement the Specific Interfaces

class Developer implements Workable, Eatable {


@Override
public void work() {
System.out.println("Developer is coding.");
}

@Override
public void eat() {
System.out.println("Developer is eating.");
}
}

class Robot implements Workable {


@Override
public void work() {
System.out.println("Robot is working.");
}
}

Step 3: Main Class to Demonstrate ISP

public class Main {


public static void main(String[] args) {
Workable developer = new Developer();
developer.work(); // Output: Developer is coding.

Eatable eatableDeveloper = (Eatable) developer;


eatableDeveloper.eat(); // Output: Developer is eating.

Workable robot = new Robot();


robot.work(); // Output: Robot is working.
}
}
Explanation:

Workable: An interface with the work method.

Eatable: An interface with the eat method.

Developer: A class that implements both Workable and Eatable interfaces.

Robot: A class that implements only the Workable interface.

Main: Demonstrates the use of ISP by allowing classes to implement only the methods they
need.

5. Real-World Example

Example: Document Printing System

Consider a document printing system where different devices have different capabilities.

Step 1: Define Specific Interfaces

interface Printable {
void print();
}

interface Scannable {
void scan();
}

interface Faxable {
void fax();
}

Step 2: Implement the Specific Interfaces

class Printer implements Printable {


@Override
public void print() {
System.out.println("Printing document.");
}
}

class Scanner implements Scannable {


@Override
public void scan() {
System.out.println("Scanning document.");
}
}

class AllInOnePrinter implements Printable, Scannable, Faxable {


@Override
public void print() {
System.out.println("Printing document.");
}

@Override
public void scan() {
System.out.println("Scanning document.");
}

@Override
public void fax() {
System.out.println("Faxing document.");
}
}

Step 3: Main Class to Demonstrate ISP

public class Main {


public static void main(String[] args) {
Printable printer = new Printer();
printer.print(); // Output: Printing document.

Scannable scanner = new Scanner();


scanner.scan(); // Output: Scanning document.

AllInOnePrinter allInOnePrinter = new AllInOnePrinter();


allInOnePrinter.print(); // Output: Printing document.
allInOnePrinter.scan(); // Output: Scanning document.
allInOnePrinter.fax(); // Output: Faxing document.
}
}

Explanation:

Printable, Scannable, Faxable: Interfaces with specific methods.


Printer: A class that implements the Printable interface.
Scanner: A class that implements the Scannable interface.

AllInOnePrinter: A class that implements Printable, Scannable, and Faxable interfaces.

Main: Demonstrates the use of ISP by allowing devices to implement only the capabilities they
support.

6. Conclusion
The Interface Segregation Principle (ISP) is a fundamental concept in object-oriented design that
promotes the creation of small, specific interfaces rather than large, general-purpose ones. By

adhering to ISP, developers can create more flexible, maintainable, and reusable code. Understanding
and applying ISP is essential for building robust and scalable Java applications.

Happy coding!

JAVA BEST PRACTICES OBJECT ORIENTED DESIGN OOPS SOLID PRINCIPLES

To leave a comment, click the button below to sign in with Google.

SIGN IN WITH GOOGLE


Free Courses
on YouTube
Channel

175K
Subscribers

Dependency Inversion Principle in Java with Example


author: Ramesh Fadatare

JAVA BEST PRACTICES OBJECT ORIENTED DESIGN OOPS SOLID PRINCIPLES

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

Introduction
The Dependency Inversion Principle (DIP) is one of the five SOLID principles of object-oriented design.

It states that high-level modules should not depend on low-level modules. Both should depend on
abstractions. Furthermore, abstractions should not depend on details. Details should depend on

abstractions. This principle promotes loose coupling between software components.

Table of Contents
1. What is the Dependency Inversion Principle?

2. Benefits of the Dependency Inversion Principle


3. Example: Violation of DIP

4. Example: Adherence to DIP


5. Real-World Example
6. Conclusion

1. What is the Dependency Inversion Principle?

The Dependency Inversion Principle (DIP) asserts that:

High-level modules should not depend on low-level modules. Both should depend on
abstractions.
Abstractions should not depend on details. Details should depend on abstractions.

This principle ensures that the system's high-level policy does not depend on the low-level details but
rather on an abstraction.

2. Benefits of the Dependency Inversion Principle

Loose Coupling: Promotes loose coupling between classes and components.


Flexibility: Enhances flexibility and makes it easier to change or replace components.

Reusability: Encourages the development of reusable components.


Testability: Improves testability by allowing dependencies to be easily mocked or stubbed.

3. Example: Violation of DIP

In this example, we'll create a LightBulb class and a Switch class that violates DIP by depending

directly on LightBulb.

Example:

class LightBulb {
public void turnOn() {
System.out.println("LightBulb is turned on");
}

public void turnOff() {


System.out.println("LightBulb is turned off");
}
}
class Switch {
private LightBulb lightBulb;

public Switch(LightBulb lightBulb) {


this.lightBulb = lightBulb;
}

public void flip(boolean on) {


if (on) {
lightBulb.turnOn();
} else {
lightBulb.turnOff();
}
}
}

public class Main {


public static void main(String[] args) {
LightBulb lightBulb = new LightBulb();
Switch lightSwitch = new Switch(lightBulb);
lightSwitch.flip(true); // Output: LightBulb is turned on
lightSwitch.flip(false); // Output: LightBulb is turned off
}
}

Issues:

The Switch class depends directly on the LightBulb class, creating tight coupling.

Any change in the LightBulb class requires changes in the Switch class.

4. Example: Adherence to DIP

To adhere to DIP, we can introduce an abstraction for the LightBulb class and make the Switch class

depend on this abstraction.

Example:

Step 1: Define the Switchable Interface

interface Switchable {
void turnOn();
void turnOff();
}

Step 2: Implement the LightBulb Class

class LightBulb implements Switchable {


@Override
public void turnOn() {
System.out.println("LightBulb is turned on");
}

@Override
public void turnOff() {
System.out.println("LightBulb is turned off");
}
}

Step 3: Implement the Switch Class

class Switch {
private Switchable switchable;

public Switch(Switchable switchable) {


this.switchable = switchable;
}

public void flip(boolean on) {


if (on) {
switchable.turnOn();
} else {
switchable.turnOff();
}
}
}

Step 4: Main Class to Demonstrate DIP

public class Main {


public static void main(String[] args) {
Switchable lightBulb = new LightBulb();
Switch lightSwitch = new Switch(lightBulb);
lightSwitch.flip(true); // Output: LightBulb is turned on
lightSwitch.flip(false); // Output: LightBulb is turned off
}
}

Explanation:

Switchable: An interface that defines the turnOn and turnOff methods.

LightBulb: A class that implements the Switchable interface.

Switch: A class that depends on the Switchable interface rather than the LightBulb class.

Main: Demonstrates the use of DIP by creating a Switch object that depends on the

Switchable interface.

5. Real-World Example

Example: Payment Processing System

Consider a payment processing system where different payment methods (e.g., credit card, PayPal)

need to be processed.

Step 1: Define the PaymentProcessor Interface

interface PaymentProcessor {
void processPayment(double amount);
}

Step 2: Implement Specific Payment Classes

class CreditCardPaymentProcessor implements PaymentProcessor {


@Override
public void processPayment(double amount) {
System.out.println("Processing credit card payment of $" + amount);
}
}

class PayPalPaymentProcessor implements PaymentProcessor {


@Override
public void processPayment(double amount) {
System.out.println("Processing PayPal payment of $" + amount);
}
}

Step 3: Implement the PaymentService Class

class PaymentService {
private PaymentProcessor paymentProcessor;

public PaymentService(PaymentProcessor paymentProcessor) {


this.paymentProcessor = paymentProcessor;
}

public void makePayment(double amount) {


paymentProcessor.processPayment(amount);
}
}

Step 4: Main Class to Demonstrate DIP

public class Main {


public static void main(String[] args) {
PaymentProcessor creditCardPayment = new CreditCardPaymentProcessor();
PaymentService paymentService = new PaymentService(creditCardPayment);
paymentService.makePayment(100.0); // Output: Processing credit card payment of $10

PaymentProcessor paypalPayment = new PayPalPaymentProcessor();


paymentService = new PaymentService(paypalPayment);
paymentService.makePayment(200.0); // Output: Processing PayPal payment of $200.0
}
}

Explanation:

PaymentProcessor: An interface that defines the processPayment method.

CreditCardPaymentProcessor and PayPalPaymentProcessor: Classes that implement the


PaymentProcessor interface.

PaymentService: A class that depends on the PaymentProcessor interface.

Main: Demonstrates the use of DIP by creating a PaymentService object that depends on the

PaymentProcessor interface.
6. Conclusion

The Dependency Inversion Principle (DIP) is a fundamental concept in object-oriented design that
promotes loose coupling between high-level and low-level modules by depending on abstractions

rather than concrete implementations. By adhering to DIP, developers can create more maintainable,
flexible, and testable code. Understanding and applying DIP is essential for building robust and

scalable Java applications.

Happy coding!

JAVA BEST PRACTICES OBJECT ORIENTED DESIGN OOPS SOLID PRINCIPLES

To leave a comment, click the button below to sign in with Google.

SIGN IN WITH GOOGLE


Free Courses
on YouTube
Channel

175K
Subscribers

5 Different Ways to Create Objects in Java


author: Ramesh Fadatare

CORE JAVA INTERVIEW OOPS

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

There are several ways to create objects in Java. In this article, we will discuss five different ways to
create objects in Java. We will understand each method with an example and its output.

1. Using the new Keyword


This is the most common way to create an object. It involves calling the constructor of the class using

the new keyword.

Example:
public class Car {
private String color;
private String model;

public Car(String color, String model) {


this.color = color;
this.model = model;
}

public void displayInfo() {


System.out.println("Car Model: " + model + ", Color: " + color);
}

public static void main(String[] args) {


Car myCar = new Car("Red", "Toyota Corolla");
myCar.displayInfo();
}
}

Output:

Car Model: Toyota Corolla, Color: Red

2. Using Class.forName()
This method is used for dynamic class loading. It can throw a ClassNotFoundException.

Example:

public class Car {


private String color;
private String model;

public Car() {
this.color = "Blue";
this.model = "Honda Civic";
}

public void displayInfo() {


System.out.println("Car Model: " + model + ", Color: " + color);
}
public static void main(String[] args) {
try {
Car myCar = (Car) Class.forName("Car").newInstance();
myCar.displayInfo();
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e
e.printStackTrace();
}
}
}

Output:

Car Model: Honda Civic, Color: Blue

3. Using clone()

This method creates a new object by copying the existing object's data. It requires the class to
implement the Cloneable interface.

Example:

public class Car implements Cloneable {


private String color;
private String model;

public Car(String color, String model) {


this.color = color;
this.model = model;
}

public void displayInfo() {


System.out.println("Car Model: " + model + ", Color: " + color);
}

@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}

public static void main(String[] args) {


try {
Car originalCar = new Car("Green", "BMW X5");
Car clonedCar = (Car) originalCar.clone();
clonedCar.displayInfo();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}

Output:

Car Model: BMW X5, Color: Green

4. Using Object Deserialization

This method creates an object from a serialized form (a byte stream). It requires the class to
implement the Serializable interface.

Example:

import java.io.*;

public class Car implements Serializable {


private static final long serialVersionUID = 1L;
private String color;
private String model;

public Car(String color, String model) {


this.color = color;
this.model = model;
}

public void displayInfo() {


System.out.println("Car Model: " + model + ", Color: " + color);
}

public static void main(String[] args) {


try {
// Serialize the object
Car carToSerialize = new Car("Black", "Audi A4");
FileOutputStream fileOut = new FileOutputStream("car.ser");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(carToSerialize);
out.close();
fileOut.close();

// Deserialize the object


FileInputStream fileIn = new FileInputStream("car.ser");
ObjectInputStream in = new ObjectInputStream(fileIn);
Car deserializedCar = (Car) in.readObject();
in.close();
fileIn.close();

deserializedCar.displayInfo();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}

Output:

Car Model: Audi A4, Color: Black

5. Using a Factory Method


A factory method is a static method that returns an instance of a class. It encapsulates the object

creation process.

Example:

public class Car {


private String color;
private String model;

private Car(String color, String model) {


this.color = color;
this.model = model;
}

public void displayInfo() {


System.out.println("Car Model: " + model + ", Color: " + color);
}
public static class CarFactory {
public static Car createCar(String color, String model) {
return new Car(color, model);
}
}

public static void main(String[] args) {


Car myCar = Car.CarFactory.createCar("White", "Mercedes-Benz C-Class");
myCar.displayInfo();
}
}

Output:

Car Model: Mercedes-Benz C-Class, Color: White

Conclusion

These are five different ways to create objects in Java. Each method has its use cases and advantages,
and understanding these methods is crucial for effective Java programming.

Related Java Interview Guides:


Java Career Roadmap: How To Level Up From Junior To Senior Developer

How To Crack Java Developer Interviews Like A Pro Spring Vs Spring MVC Vs Spring Boot

Java Spring Boot Vs. Go (Golang) For Backend Development In 2025

Is Java Compiled Or Interpreted? Let’s Clear The Confusion!

Java JIT Compiler: Explained In Simple Words What Is JVM, JDK, And JRE?

Why Java Is The Platform Independent? (Interview Question And Answer)

Is Java A Pure Object-Oriented Language? (Java Interview Question And Answer)🤔

Is Java Case Sensitive? (Java Interview Question And Answer)

Why Is Java Secure? (Java Interview Question And Answer)

💪 Why Is Java Robust? (Java Interview Question And Answer)


Free Courses
on YouTube
Channel

175K
Subscribers

What is an Object in Java with Example


author: Ramesh Fadatare

CORE JAVA OOPS

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

Introduction
In Java, an object is a fundamental entity in object-oriented programming (OOP). An object is an

instance of a class that encapsulates both state (attributes) and behavior (methods). Objects interact
with one another through methods, providing a way to model real-world entities and their

interactions.

What is an Object?
An object is an instance of a class that represents a real-world entity or concept. It is created based on

the blueprint provided by the class and has its own identity, state, and behavior.

Identity: Each object has a unique identity, which differentiates it from other objects.

State: The state of an object is represented by its attributes (fields or properties).


Behavior: The behavior of an object is represented by its methods (functions or operations).

Key Points:

Objects are instances of classes.

They encapsulate state and behavior.


Objects are created using the new keyword in Java.

Syntax for Creating an Object

The syntax for creating an object in Java is:

ClassName objectName = new ClassName();

Example:

Car myCar = new Car("Red", "Toyota Corolla");

Different Ways to Create Objects in Java

1. Using the new Keyword

This is the most common way to create an object. It invokes the constructor of the class.

Car myCar = new Car("Red", "Toyota Corolla");

2. Using Class.forName()

This method is used for dynamic class loading. It can throw a ClassNotFoundException.

Car myCar = (Car) Class.forName("Car").newInstance();


3. Using clone()

This method creates a new object by copying the existing object's data. It requires the class to

implement the Cloneable interface.

Car myCar = new Car("Red", "Toyota Corolla");


Car clonedCar = (Car) myCar.clone();

4. Using Object Deserialization

This method creates an object from a serialized form (a byte stream). It requires the class to
implement the Serializable interface.

FileInputStream fileIn = new FileInputStream("car.ser");


ObjectInputStream in = new ObjectInputStream(fileIn);
Car myCar = (Car) in.readObject();
in.close();
fileIn.close();

5. Using a Factory Method

A factory method is a static method that returns an instance of a class. It encapsulates the object
creation process.

public class CarFactory {


public static Car createCar(String color, String model) {
return new Car(color, model);
}
}

// Using the factory method


Car myCar = CarFactory.createCar("Red", "Toyota Corolla");

Diagram

Class: Car
+---------------------------+
| Car |
+---------------------------+
| - color: String |
| - model: String |
| - speed: int |
+---------------------------+
| + Car(color, model) |
| + start(): void |
| + accelerate(int): void |
| + brake(): void |
| + getColor(): String |
| + getModel(): String |
| + getSpeed(): int |
+---------------------------+

Object: myCar
+---------------------------+
| myCar |
+---------------------------+
| - color: "Red" |
| - model: "Toyota Corolla" |
| - speed: 0 |
+---------------------------+
| + start() |
| + accelerate(int) |
| + brake() |
| + getColor() |
| + getModel() |
| + getSpeed() |
+---------------------------+

Example: Creating and Using an Object in Java

Let's consider a real-world example: a Car class. We will define a Car class with attributes such as

color, model, and speed, and methods such as start(), accelerate(), and brake(). Then, we will

create an instance of the Car class and use it.

Step 1: Define the Car Class

public class Car {


// Attributes (state)
private String color;
private String model;
private int speed;
// Constructor
public Car(String color, String model) {
this.color = color;
this.model = model;
this.speed = 0; // Initially, the car is stationary
}

// Methods (behavior)
public void start() {
System.out.println(model + " is starting.");
speed = 10; // Starting speed
}

public void accelerate(int increment) {


speed += increment;
System.out.println(model + " is accelerating. Speed: " + speed + " km/h");
}

public void brake() {


speed = 0;
System.out.println(model + " has stopped.");
}

// Getters
public String getColor() {
return color;
}

public String getModel() {


return model;
}

public int getSpeed() {


return speed;
}
}

Step 2: Create and Use an Instance of the Car Class

public class Main {


public static void main(String[] args) {
// Creating an object of the Car class
Car myCar = new Car("Red", "Toyota Corolla");
// Using the object
myCar.start();
myCar.accelerate(20);
myCar.brake();

// Accessing the object's attributes


System.out.println("Car Model: " + myCar.getModel());
System.out.println("Car Color: " + myCar.getColor());
System.out.println("Car Speed: " + myCar.getSpeed() + " km/h");
}
}

Explanation:

1. Defining the Car Class:

The Car class has three attributes: color, model, and speed.

It has a constructor to initialize the color and model attributes, and the speed is initially

set to 0.

The class has three methods: start(), accelerate(int increment), and brake(),

representing the behavior of the car.

The class also includes getter methods to access the attributes of the car.

2. Creating and Using an Object:

In the Main class, we create an instance of the Car class using the new keyword.

We then call the methods start(), accelerate(int increment), and brake() on the

myCar object to simulate the car's behavior.

We access the attributes of the myCar object using the getter methods and print their

values.

Conclusion
In Java, objects are instances of classes that encapsulate state and behavior. They are fundamental to
object-oriented programming and provide a way to model real-world entities and their interactions.

By creating and using objects, we can design modular and reusable code that is easier to manage and
maintain.
Free Courses
on YouTube
Channel

175K
Subscribers

What is Class in Java with Examples


author: Ramesh Fadatare

CORE JAVA OOPS

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

Introduction
In Java, a class is a blueprint or template that defines the structure and behavior (attributes and

methods) that the objects created from the class can have. A class encapsulates data for the object
and methods to manipulate that data. It serves as the fundamental building block in object-oriented

programming (OOP) in Java.

What is a Class?
A class in Java is a user-defined data type that serves as a blueprint for creating objects. It defines the
attributes (data fields) and behaviors (methods) that the objects created from the class can possess.

Key Points:

A class is a blueprint for objects.


It defines attributes and methods.

Objects are instances of a class.

Syntax of a Class
The basic syntax to define a class in Java is as follows:

class ClassName {
// Attributes (data fields)
dataType attributeName;

// Constructor
public ClassName(parameters) {
// Initialize attributes
}

// Methods
returnType methodName(parameters) {
// Method body
}
}

Example: Defining and Using a Class


Let's consider a real-world example: a Car class. We will define a Car class with attributes such as

color, model, and speed, and methods such as start(), accelerate(), and brake(). Then, we will

create an instance of the Car class and use it.

Step 1: Define the Car Class

public class Car {


// Attributes (state)
private String color;
private String model;
private int speed;
// Constructor
public Car(String color, String model) {
this.color = color;
this.model = model;
this.speed = 0; // Initially, the car is stationary
}

// Methods (behavior)
public void start() {
System.out.println(model + " is starting.");
speed = 10; // Starting speed
}

public void accelerate(int increment) {


speed += increment;
System.out.println(model + " is accelerating. Speed: " + speed + " km/h");
}

public void brake() {


speed = 0;
System.out.println(model + " has stopped.");
}

// Getters
public String getColor() {
return color;
}

public String getModel() {


return model;
}

public int getSpeed() {


return speed;
}
}

Step 2: Create and Use an Instance of the Car Class

public class Main {


public static void main(String[] args) {
// Creating an object of the Car class
Car myCar = new Car("Red", "Toyota Corolla");
// Using the object
myCar.start();
myCar.accelerate(20);
myCar.brake();

// Accessing the object's attributes


System.out.println("Car Model: " + myCar.getModel());
System.out.println("Car Color: " + myCar.getColor());
System.out.println("Car Speed: " + myCar.getSpeed() + " km/h");
}
}

Explanation:

1. Defining the Car Class:

The Car class has three attributes: color, model, and speed.

It has a constructor to initialize the color and model attributes, and the speed is initially

set to 0.

The class has three methods: start(), accelerate(int increment), and brake(),

representing the behavior of the car.

The class also includes getter methods to access the attributes of the car.

2. Creating and Using an Object:

In the Main class, we create an instance of the Car class using the new keyword.

We then call the methods start(), accelerate(int increment), and brake() on the

myCar object to simulate the car's behavior.

We access the attributes of the myCar object using the getter methods and print their

values.

Text-based Diagram

Class: Car
+---------------------------+
| Car |
+---------------------------+
| - color: String |
| - model: String |
| - speed: int |
+---------------------------+
| + Car(color, model) |
| + start(): void |
| + accelerate(int): void |
| + brake(): void |
| + getColor(): String |
| + getModel(): String |
| + getSpeed(): int |
+---------------------------+

Object: myCar
+---------------------------+
| myCar |
+---------------------------+
| - color: "Red" |
| - model: "Toyota Corolla" |
| - speed: 0 |
+---------------------------+
| + start() |
| + accelerate(int) |
| + brake() |
| + getColor() |
| + getModel() |
| + getSpeed() |
+---------------------------+

Conclusion
In Java, a class is a blueprint for creating objects. It defines the attributes and methods that the

objects created from the class can possess. By using classes and objects, we can model real-world
entities and their interactions, making our code more modular, reusable, and maintainable.
Free Courses
on YouTube
Channel

175K
Subscribers

Abstraction in Java with Example


author: Ramesh Fadatare

OOP FUNDAMENTALS OOPS

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

Introduction
Abstraction is one of the four fundamental principles of Object-Oriented Programming (OOP). It is the

concept of hiding the complex implementation details and showing only the essential features of the
object.

Table of Contents

1. What is Abstraction?
2. Benefits of Abstraction
3. Real-World Examples of Abstraction
4. Abstract Class

5. Interface
6. Abstract Class vs Interface
7. Example: Abstraction with Abstract Class

8. Example: Abstraction with Interface


9. Example 1: Employee, Contractor, and FullTimeEmployee Example
10. Conclusion

1. What is Abstraction?
Abstraction is the process of hiding the implementation details and showing only the functionality to

the user. It focuses on what the object does instead of how it does it. Abstraction allows you to
manage complexity by breaking down complex systems into simpler components.

In Java, abstraction is achieved using abstract classes and interfaces.

2. Benefits of Abstraction
Reduces complexity: By hiding unnecessary details, abstraction makes the system easier to

understand and use.


Improves code readability: Abstraction allows you to focus on an object's high-level behavior
without getting bogged down by implementation details.

Enhances maintainability: Abstraction helps to encapsulate changes, so modifications in the


implementation do not affect other parts of the system.

Facilitates code reuse: Abstract components can be reused across different parts of the
application or even in different applications.

3. Real-World Examples of Abstraction

Example: Man Driving a Car

Consider a man driving a car. The man knows what each pedal and steering wheel does, but he
doesn't know how the car does these things internally. He doesn't know about the inner mechanisms
that empower these things. This is an example of abstraction.

Example: ATM Machine

Another real-world example is an ATM Machine. All users perform operations on the ATM machine
like cash withdrawal, money transfer, retrieving mini-statements, etc., but they do not know the
internal details about the ATM. This is another example of abstraction.

4. Abstract Class

An abstract class in Java is a class that cannot be instantiated and may contain abstract methods,
which are methods without a body. Subclasses of the abstract class are responsible for providing
implementations for these abstract methods.

Syntax:

abstract class AbstractClassName {


// Abstract method (no body)
abstract void abstractMethod();

// Regular method
void regularMethod() {
// Method body
}
}

5. Interface

An interface in Java is a reference type, similar to a class, that can contain only constants, method
signatures, default methods, static methods, and nested types. Interfaces cannot contain instance
fields or constructors.

Syntax:

interface InterfaceName {
// Abstract method (implicitly public and abstract)
void abstractMethod();

// Default method
default void defaultMethod() {
// Method body
}

// Static method
static void staticMethod() {
// Method body
}
}

6. Abstract Class vs Interface

Feature Abstract Class Interface

Can have both abstract and concrete


Methods Only abstract methods (until Java 8)
methods

Can only have static and final


Fields Can have instance variables
variables

Multiple
Does not support multiple inheritance Supports multiple inheritance
Inheritance

Access Modifiers Can have any access modifier Methods are implicitly public

Constructor Can have constructors Cannot have constructors

7. Example: Abstraction with Abstract Class


Example:

// Abstract class
abstract class Animal {
// Abstract method
abstract void makeSound();

// Regular method
void eat() {
System.out.println("This animal is eating.");
}
}

// Subclass
class Dog extends Animal {
@Override
void makeSound() {
System.out.println("Bark");
}
}

// Usage
public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
dog.makeSound(); // Output: Bark
dog.eat(); // Output: This animal is eating.
}
}

Explanation:

Animal: Abstract class with an abstract method makeSound and a regular method eat.

Dog: Subclass of Animal that provides an implementation for the makeSound method.

8. Example: Abstraction with Interface

Example:

// Interface
interface Animal {
void makeSound();
void eat();
}

// Class implementing the interface


class Dog implements Animal {
@Override
public void makeSound() {
System.out.println("Bark");
}

@Override
public void eat() {
System.out.println("This animal is eating.");
}
}

// Usage
public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
dog.makeSound(); // Output: Bark
dog.eat(); // Output: This animal is eating.
}
}
Explanation:

Animal: Interface with abstract methods makeSound and eat.

Dog: Class that implements the Animal interface and provides implementations for the

makeSound and eat methods.

9. Example 1: Employee, Contractor, and FullTimeEmployee


Example
Example:

// Abstract class
abstract class Employee {
private String name;
private int employeeId;

public Employee(String name, int employeeId) {


this.name = name;
this.employeeId = employeeId;
}

public String getName() {


return name;
}

public int getEmployeeId() {


return employeeId;
}

// Abstract method
abstract void calculatePay();
}

// FullTimeEmployee class
class FullTimeEmployee extends Employee {
private double salary;

public FullTimeEmployee(String name, int employeeId, double salary) {


super(name, employeeId);
this.salary = salary;
}

@Override
void calculatePay() {
System.out.println("FullTimeEmployee Pay: " + salary);
}
}

// Contractor class
class Contractor extends Employee {
private double hourlyRate;
private int hoursWorked;

public Contractor(String name, int employeeId, double hourlyRate, int hoursWorked) {


super(name, employeeId);
this.hourlyRate = hourlyRate;
this.hoursWorked = hoursWorked;
}

@Override
void calculatePay() {
System.out.println("Contractor Pay: " + (hourlyRate * hoursWorked));
}
}

// Usage
public class Main {
public static void main(String[] args) {
Employee fullTimeEmployee = new FullTimeEmployee("Alice", 101, 60000);
fullTimeEmployee.calculatePay(); // Output: FullTimeEmployee Pay: 60000.0

Employee contractor = new Contractor("Bob", 102, 50, 160);


contractor.calculatePay(); // Output: Contractor Pay: 8000.0
}
}

Explanation:

Employee: Abstract class with common properties and an abstract method calculatePay.

FullTimeEmployee: Subclass of Employee that provides an implementation for the

calculatePay method.

Contractor: Subclass of Employee that provides an implementation for the calculatePay

method.

10. Conclusion
Abstraction in Java is a powerful concept that allows you to hide the implementation details and focus
on the functionality. It can be achieved using abstract classes and interfaces. Abstract classes are used

when you want to share code among several closely related classes, while interfaces are used to
define a contract that can be implemented by any class, regardless of its position in the class

hierarchy. Real-world examples like a man driving a car or using an ATM machine illustrate the
concept of abstraction. Understanding and applying abstraction helps to manage complexity, improve

code readability, and enhance maintainability.

Happy coding!

OOP FUNDAMENTALS OOPS

Anonymous 24 December 2018 at 22:55


Examples are very good with explanation.

Ramesh Fadatare 27 December 2018 at 21:21


Thank you. You can learn complete Core Java at Java Tutorial for Beginners

REPLY
Free Courses
on YouTube
Channel

175K
Subscribers

Encapsulation in Java with Example


author: Ramesh Fadatare

OOP FUNDAMENTALS OOPS

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

Introduction
Encapsulation is one of the fundamental principles of Object-Oriented Programming (OOP). It

involves bundling the data (variables) and the methods (functions) that operate on the data into a
single unit, usually a class. Encapsulation also restricts direct access to some of an object's

components, which prevents unintended interference and misuse of the data.

Table of Contents
1. What is Encapsulation?
2. Benefits of Encapsulation
3. Encapsulation in Java

4. Access Modifiers
5. Real-World Examples of Encapsulation
6. Example: Encapsulation in Java

7. Conclusion

1. What is Encapsulation?
Encapsulation is the technique of making the fields in a class private and providing access to them via

public methods. It restricts direct access to certain components of an object and protects the integrity
of the data by controlling modifications.

2. Benefits of Encapsulation

Improved Maintainability: Encapsulation allows for the modularization of code, making it


easier to maintain and modify.

Enhanced Security: Encapsulation helps protect data from unauthorized access and
modification by restricting access to an object's internal state.
Controlled Access: Encapsulation provides control over the data by exposing only the necessary

methods to interact with it, ensuring that the data is used in a controlled manner.
Flexibility and Reusability: Encapsulation allows changes to the implementation without

affecting the users of the class, making the code more flexible and reusable.

3. Encapsulation in Java
In Java, encapsulation is achieved by:

1. Declaring the fields of a class as private.


2. Providing public getter and setter methods to access and modify the fields.

4. Access Modifiers

Java provides four types of access modifiers to control the visibility of class members:

private: The member is accessible only within the same class.

default (no modifier): The member is accessible only within the same package.
protected: The member is accessible within the same package and subclasses.
public: The member is accessible from any other class.
5. Real-World Examples of Encapsulation

Example 1: Medical Records

In a hospital management system, patient data should be encapsulated to ensure that it is accessed
and modified only through authorized methods, maintaining the integrity and confidentiality of the
information.

Example 2: Banking System

In a banking application, account details such as account balance should be encapsulated to prevent
unauthorized access and modification, ensuring the security and consistency of the data.

6. Example: Encapsulation in Java


Example:

public class Person {


// Private fields
private String name;
private int age;

// Public getter method for name


public String getName() {
return name;
}

// Public setter method for name


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

// Public getter method for age


public int getAge() {
return age;
}

// Public setter method for age


public void setAge(int age) {
if (age > 0) {
this.age = age;
} else {
System.out.println("Age cannot be negative or zero");
}
}

public static void main(String[] args) {


Person person = new Person();
person.setName("John Doe");
person.setAge(30);

System.out.println("Name: " + person.getName()); // Output: Name: John Doe


System.out.println("Age: " + person.getAge()); // Output: Age: 30

person.setAge(-5); // Output: Age cannot be negative or zero


}
}

Explanation:

Private Fields: name and age are private fields, meaning they cannot be accessed directly from

outside the class.

Public Getter and Setter Methods: Methods getName, setName, getAge, and setAge are

public, providing controlled access to the private fields.

Validation in Setter Method: The setAge method includes validation to ensure that the age is

not set to a negative value, demonstrating encapsulation's role in maintaining data integrity.

7. Conclusion

Encapsulation in Java is a powerful concept that helps to protect an object's internal state and
provides controlled access to it. By making fields private and exposing public methods to interact with

them, encapsulation ensures that data is used in a controlled and secure manner. This approach
improves maintainability, enhances security, and promotes code reusability and flexibility.
Understanding and applying encapsulation is essential for effective Java programming and building
robust, maintainable software.

Happy coding!
Free Courses
on YouTube
Channel

175K
Subscribers

Polymorphism in Java with Example


author: Ramesh Fadatare

OOP FUNDAMENTALS OOPS

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

Introduction
Polymorphism is one of the core concepts of Object-Oriented Programming (OOP). It allows methods

to do different things based on the object it is acting upon, even though they share the same name.
Polymorphism provides a way to perform a single action in different forms. In Java, polymorphism can

be achieved through method overloading and method overriding.

Table of Contents
1. What is Polymorphism?
2. Types of Polymorphism
3. Method Overloading

4. Method Overriding
5. Real-World Examples of Polymorphism
6. Example: Polymorphism with Method Overloading

7. Example: Polymorphism with Method Overriding


8. Example: Payment Processing Example
9. Conclusion

1. What is Polymorphism?
Polymorphism means "many shapes" or "many forms." In Java, it refers to the ability of a single

method or class to take on multiple forms. This is achieved through method overloading (compile-
time polymorphism) and method overriding (runtime polymorphism).

2. Types of Polymorphism

Compile-time Polymorphism (Method Overloading): This type of polymorphism is resolved


during compile time. Method overloading allows a class to have more than one method with the
same name, provided their parameter lists are different.

Runtime Polymorphism (Method Overriding): This type of polymorphism is resolved during


runtime. Method overriding allows a subclass to provide a specific implementation of a method

that is already defined in its superclass.

3. Method Overloading
Method overloading occurs when a class has multiple methods with the same name but different
parameter lists (different types or numbers of parameters).

Example:

public class MathUtils {


public int add(int a, int b) {
return a + b;
}

public double add(double a, double b) {


return a + b;
}
public int add(int a, int b, int c) {
return a + b + c;
}
}

4. Method Overriding

Method overriding occurs when a subclass provides a specific implementation of a method that is
already defined in its superclass.

Example:

class Animal {
public void makeSound() {
System.out.println("Animal makes a sound");
}
}

class Dog extends Animal {


@Override
public void makeSound() {
System.out.println("Dog barks");
}
}

class Cat extends Animal {


@Override
public void makeSound() {
System.out.println("Cat meows");
}
}

5. Real-World Examples of Polymorphism

Example 1: Different Behaviors of a Person

Suppose you are in a classroom, you behave like a student. When you are in the market, you behave
like a customer. When you are at home, you behave like a son or daughter. Here, one person exhibits
different behaviors in different contexts.
Example 2: Payment Processing System

In a payment processing system, different payment methods such as credit card, debit card, and

PayPal have different processing steps.

6. Example: Polymorphism with Method Overloading

Example:

public class Printer {


public void print(String message) {
System.out.println(message);
}

public void print(int number) {


System.out.println(number);
}

public void print(double number) {


System.out.println(number);
}

public static void main(String[] args) {


Printer printer = new Printer();
printer.print("Hello, World!"); // Output: Hello, World!
printer.print(123); // Output: 123
printer.print(3.14); // Output: 3.14
}
}
Explanation:

Printer: Class with overloaded print methods to handle different types of input.

Main method: Demonstrates the use of overloaded print methods.

7. Example: Polymorphism with Method Overriding

Example:

class Animal {
public void makeSound() {
System.out.println("Animal makes a sound");
}
}

class Dog extends Animal {


@Override
public void makeSound() {
System.out.println("Dog barks");
}
}

class Cat extends Animal {


@Override
public void makeSound() {
System.out.println("Cat meows");
}
}

public class Main {


public static void main(String[] args) {
Animal myDog = new Dog();
Animal myCat = new Cat();

myDog.makeSound(); // Output: Dog barks


myCat.makeSound(); // Output: Cat meows
}
}

Explanation:

Animal: Base class with a makeSound method.


Dog and Cat: Subclasses that override the makeSound method.

Main method: Demonstrates runtime polymorphism by calling the overridden methods on Dog

and Cat objects.

8. Example: Payment Processing Example

Class Diagram

Code Example:

Payment Interface:

interface Payment {
void pay();
}

CashPayment Class:

class CashPayment implements Payment {


@Override
public void pay() {
System.out.println("Payment made using cash.");
}
}

CreditPayment Class:

class CreditPayment implements Payment {


@Override
public void pay() {
System.out.println("Payment made using credit card.");
}
}

Client Class:

public class Polymorphism {


public static void main(String[] args) {
Payment payment;

payment = new CashPayment();


payment.pay(); // Output: Payment made using cash.

payment = new CreditPayment();


payment.pay(); // Output: Payment made using credit card.
}
}

Explanation:

Payment: Interface defining the pay method.

CashPayment and CreditPayment: Classes implementing the Payment interface and providing

their own implementations of the pay method.

Polymorphism: Client class demonstrating polymorphism by using the Payment interface to call

the pay method on different types of payment objects.

9. Conclusion
Polymorphism in Java is a powerful concept that allows methods to perform different tasks based on
the object they are acting upon. It enhances flexibility and maintainability in code by allowing a single

method or class to take on multiple forms. Method overloading and method overriding are two ways
to achieve polymorphism in Java. Real-world examples like different behaviors of a person in different

contexts and various payment processing methods further illustrate the usefulness of polymorphism.

Happy coding!
Free Courses
on YouTube
Channel

175K
Subscribers

Inheritance in Java with Example


author: Ramesh Fadatare

OOP FUNDAMENTALS OOPS

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

Introduction
Inheritance is one of the four fundamental principles of Object-Oriented Programming (OOP). It

allows a class to inherit properties and behaviors (fields and methods) from another class. The class
that inherits the properties is called the subclass (or derived class), and the class from which

properties are inherited is called the superclass (or base class). Inheritance promotes code reusability
and establishes a natural hierarchical relationship between classes.

Table of Contents
1. What is Inheritance?
2. Benefits of Inheritance

3. Types of Inheritance
4. Single Inheritance
5. Multilevel Inheritance

6. Hierarchical Inheritance
7. Real-World Examples of Inheritance
8. Example: Single Inheritance

9. Example: Multilevel Inheritance


10. Example: Hierarchical Inheritance

11. Conclusion

1. What is Inheritance?
Inheritance is a mechanism wherein a new class is derived from an existing class. The derived class

(child class) inherits the attributes and methods of the base class (parent class), allowing code reuse
and the creation of a natural hierarchy.

2. Benefits of Inheritance

Code Reusability: Inheritance allows a class to reuse the fields and methods of another class.
Method Overriding: Subclasses can provide specific implementations for methods that are

defined in the parent class.


Polymorphism: Inheritance supports polymorphism, allowing objects to be treated as instances
of their parent class.

3. Types of Inheritance

Single Inheritance: A class inherits from one superclass.


Multilevel Inheritance: A class inherits from a superclass, and another class inherits from this
derived class.
Hierarchical Inheritance: Multiple classes inherit from a single superclass.
Multiple Inheritance: A class inherits from more than one superclass. Java does not support

multiple inheritance directly to avoid complexity and ambiguity. However, it can be achieved
using interfaces.

4. Single Inheritance
In a single inheritance, a class inherits from one superclass.

Example:

class Animal {
void eat() {
System.out.println("This animal eats food.");
}
}

class Dog extends Animal {


void bark() {
System.out.println("The dog barks.");
}
}

5. Multilevel Inheritance

In multilevel inheritance, a class inherits from a superclass, and another


class inherits from this derived class.

Example:

class Animal {
void eat() {
System.out.println("This animal eats food.");
}
}

class Dog extends Animal {


void bark() {
System.out.println("The dog barks.");
}
}

class Puppy extends Dog {


void weep() {
System.out.println("The puppy weeps.");
}
}

6. Hierarchical Inheritance
In hierarchical inheritance, multiple classes inherit from a single superclass.

Example:

class Animal {
void eat() {
System.out.println("This animal eats food.");
}
}

class Dog extends Animal {


void bark() {
System.out.println("The dog barks.");
}
}

class Cat extends Animal {


void meow() {
System.out.println("The cat meows.");
}
}

Multiple Inheritance (Through Interfaces)

In Multiple inheritances, one class can have more than one superclass and inherit features from all
parent classes.

Please note that Java does not support multiple inheritances with classes. In Java, we can achieve

multiple inheritances only through Interfaces.

In the image below, Class C is derived from Class A and Class B.


7. Real-World Examples of Inheritance

Example 1: Vehicle Hierarchy

Consider a vehicle hierarchy where Vehicle is the base class. Car and Bike can be derived classes

that inherit properties and methods from Vehicle.

Example 2: Employee Hierarchy

In an employee management system, Employee can be the base class. Manager and Developer can

be derived classes that inherit from Employee.

Example 3: Number hierarchy from java.lang library

The Java library extensively uses inheritance. The figure below shows an inheritance hierarchy

from java.lang library. The Number class abstracts various numerical (reference) types such

as Byte , Integer , Float , Double , Short , and BigDecimal .

8. Example: Single Inheritance


Example:

class Animal {
void eat() {
System.out.println("This animal eats food.");
}
}

class Dog extends Animal {


void bark() {
System.out.println("The dog barks.");
}
}

public class Main {


public static void main(String[] args) {
Dog dog = new Dog();
dog.eat(); // Output: This animal eats food.
dog.bark(); // Output: The dog barks.
}
}

Explanation:

Animal: Superclass with a method eat.

Dog: Subclass that inherits from Animal and adds a method bark.

9. Example: Multilevel Inheritance


Example:

class Animal {
void eat() {
System.out.println("This animal eats food.");
}
}

class Dog extends Animal {


void bark() {
System.out.println("The dog barks.");
}
}
class Puppy extends Dog {
void weep() {
System.out.println("The puppy weeps.");
}
}

public class Main {


public static void main(String[] args) {
Puppy puppy = new Puppy();
puppy.eat(); // Output: This animal eats food.
puppy.bark(); // Output: The dog barks.
puppy.weep(); // Output: The puppy weeps.
}
}

Explanation:

Animal: Superclass with a method eat.

Dog: Subclass that inherits from Animal and adds a method bark.

Puppy: Subclass that inherits from Dog and adds a method weep.

10. Example: Hierarchical Inheritance


Example:

class Animal {
void eat() {
System.out.println("This animal eats food.");
}
}

class Dog extends Animal {


void bark() {
System.out.println("The dog barks.");
}
}

class Cat extends Animal {


void meow() {
System.out.println("The cat meows.");
}
}
public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
dog.eat(); // Output: This animal eats food.
dog.bark(); // Output: The dog barks.

Cat cat = new Cat();


cat.eat(); // Output: This animal eats food.
cat.meow(); // Output: The cat meows.
}
}

Explanation:

Animal: Superclass with a method eat.

Dog and Cat: Subclasses that inherit from Animal and add methods bark and meow,

respectively.

11. Conclusion
Inheritance in Java is a powerful concept that promotes code reusability and establishes a natural

hierarchical relationship between classes. By using inheritance, you can create a base class with
common properties and methods and then create derived classes that inherit these properties and

methods while adding specific features. Understanding and applying inheritance helps to build a
structured and organized codebase, making it easier to maintain and extend.

Happy coding!
Free Courses
on YouTube
Channel

175K
Subscribers

Composition in Java with Example


author: Ramesh Fadatare

OOP FUNDAMENTALS OOPS

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

Introduction
Composition is a fundamental concept in Object-Oriented Programming (OOP) that allows a class to

contain objects of other classes to achieve code reuse and establish a has-a relationship. Unlike
inheritance, which represents an is-a relationship, composition models a relationship where one

object is made up of one or more objects.

Table of Contents
1. What is Composition?
2. Benefits of Composition
3. Composition vs Inheritance

4. Example: Composition in Java


5. Real-World Examples of Composition
6. Conclusion

1. What is Composition?

Composition is a design principle where a class contains references to one or more objects of other
classes. This allows the class to use the functionality of the composed objects and delegate tasks to

them. Composition is often preferred over inheritance because it promotes greater flexibility and
modularity in the design.

Example: A university consists of several departments. Whenever a university object is destroyed


automatically, all the department objects will be destroyed. Without an existing university object,

there is no chance of an existing dependent object; hence, these are strongly associated, and this
relationship is called composition.

2. Benefits of Composition

Reusability: Composition allows for code reuse by including instances of other classes.
Flexibility: Changes to composed objects can be made independently of the class that uses
them.
Encapsulation: Composition encapsulates the functionality of composed objects, reducing

dependencies.
Better Modeling: Composition better represents real-world relationships where objects are
made up of other objects.
3. Composition vs Inheritance

Feature Composition Inheritance


Relationship Has-a (one object contains another object) Is-a (one class is a type of another)

Flexibility More flexible, allows runtime behavior changesLess flexible, fixed at compile time
Coupling Loosely coupled Tightly coupled
Reusability Promotes high reusability Limited reusability
EncapsulationBetter encapsulation Exposes implementation details

4. Example: Composition in Java

Example:

Let's create a Library class that contains multiple Book objects using composition.

Step 1: Define the Book Class

public class Book {


private String title;
private String author;

public Book(String title, String author) {


this.title = title;
this.author = author;
}

public String getTitle() {


return title;
}

public String getAuthor() {


return author;
}
}

Step 2: Define the Library Class

import java.util.ArrayList;
import java.util.List;
public class Library {
private List<Book> books;

public Library() {
this.books = new ArrayList<>();
}

public void addBook(Book book) {


books.add(book);
}

public void showBooks() {


for (Book book : books) {
System.out.println("Title: " + book.getTitle() + ", Author: " + book.getAuthor(
}
}
}

Step 3: Main Class to Demonstrate Composition

public class Main {


public static void main(String[] args) {
Book book1 = new Book("1984", "George Orwell");
Book book2 = new Book("To Kill a Mockingbird", "Harper Lee");

Library library = new Library();


library.addBook(book1);
library.addBook(book2);

library.showBooks();
// Output:
// Title: 1984, Author: George Orwell
// Title: To Kill a Mockingbird, Author: Harper Lee
}
}

Explanation:

Book: A simple class with title and author attributes.

Library: A class that uses composition to include multiple Book objects. The Library class

manages a list of books and provides methods to add and display books.
Main: A class to demonstrate the use of composition by creating Book objects and adding them

to the Library.

5. Real-World Examples of Composition

Example 1: Car and Engine

A Car class can use composition to include an Engine object. The Car class can delegate the starting

and stopping functionalities to the Engine class.

class Engine {
public void start() {
System.out.println("Engine started.");
}

public void stop() {


System.out.println("Engine stopped.");
}
}

class Car {
private Engine engine;

public Car() {
this.engine = new Engine();
}

public void startCar() {


engine.start();
System.out.println("Car started.");
}

public void stopCar() {


engine.stop();
System.out.println("Car stopped.");
}
}

public class Main {


public static void main(String[] args) {
Car car = new Car();
car.startCar(); // Output: Engine started. Car started.
car.stopCar(); // Output: Engine stopped. Car stopped.
}
}

Example 2: Computer and Components

A Computer class can use composition to include CPU, RAM, and HardDrive objects. The Computer

class can delegate the functionalities to these components.

class CPU {
public void process() {
System.out.println("CPU processing...");
}
}

class RAM {
public void load() {
System.out.println("RAM loading...");
}
}

class HardDrive {
public void readData() {
System.out.println("HardDrive reading data...");
}
}

class Computer {
private CPU cpu;
private RAM ram;
private HardDrive hardDrive;

public Computer() {
this.cpu = new CPU();
this.ram = new RAM();
this.hardDrive = new HardDrive();
}

public void startComputer() {


cpu.process();
ram.load();
hardDrive.readData();
System.out.println("Computer started.");
}
}
public class Main {
public static void main(String[] args) {
Computer computer = new Computer();
computer.startComputer();
// Output:
// CPU processing...
// RAM loading...
// HardDrive reading data...
// Computer started.
}
}

6. Conclusion
Composition in Java is a powerful concept that promotes code reuse and modularity by allowing a

class to contain objects of other classes. It models a has-a relationship, which is more flexible and
encapsulated than inheritance. By using composition, developers can build complex systems that are

easy to maintain and extend. Understanding and applying composition effectively is essential for
designing robust and scalable Java applications.

Happy coding!

OOP FUNDAMENTALS OOPS


Free Courses
on YouTube
Channel

175K
Subscribers

Aggregation in Java with Example


author: Ramesh Fadatare

OOP FUNDAMENTALS OOPS

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

Introduction
Aggregation is a type of association that represents a "has-a" relationship with a whole-part hierarchy.

In aggregation, the child object can exist independently of the parent object, implying a weak
relationship between the parent and child. Aggregation allows one class to contain another class

without owning its lifecycle.

Table of Contents
1. What is Aggregation?
2. Benefits of Aggregation
3. Aggregation vs Composition

4. Example: Aggregation in Java


5. Real-World Examples of Aggregation
6. Conclusion

1. What is Aggregation?

Aggregation is a special type of association that represents a whole-part relationship where the child
(part) can exist independently of the parent (whole). It is used to model relationships where the

contained objects are not strongly dependent on the lifecycle of the container object.

2. Benefits of Aggregation
Reusability: Aggregated objects can be reused across different parts of the application.

Flexibility: Aggregated objects can exist independently of the parent object, providing flexibility
in design.

Modularity: Aggregation promotes modularity by separating the responsibilities of different


classes.
Maintainability: Changes to the aggregated object do not necessarily affect the parent object,

enhancing maintainability.

3. Aggregation vs Composition

Feature Aggregation Composition


RelationshipWhole-part (has-a) Whole-part (has-a)
Dependenc Child cannot exist independently of the
Child can exist independently of the parent
y parent

Parent and child have independent


Lifecycle Parent and child have dependent lifecycles
lifecycles
Coupling Loosely coupled Tightly coupled

4. Example: Aggregation in Java

Example:

Let's create a Department class that aggregates multiple Employee objects using aggregation.

Step 1: Define the Employee Class


public class Employee {
private String name;
private int id;

public Employee(String name, int id) {


this.name = name;
this.id = id;
}

public String getName() {


return name;
}

public int getId() {


return id;
}
}

Step 2: Define the Department Class

import java.util.ArrayList;
import java.util.List;

public class Department {


private String name;
private List<Employee> employees;

public Department(String name) {


this.name = name;
this.employees = new ArrayList<>();
}

public void addEmployee(Employee employee) {


employees.add(employee);
}

public void showEmployees() {


for (Employee employee : employees) {
System.out.println("Employee ID: " + employee.getId() + ", Name: " + employee.g
}
}
public String getName() {
return name;
}
}

Step 3: Main Class to Demonstrate Aggregation

public class Main {


public static void main(String[] args) {
Employee employee1 = new Employee("John Doe", 101);
Employee employee2 = new Employee("Jane Smith", 102);

Department department = new Department("IT Department");


department.addEmployee(employee1);
department.addEmployee(employee2);

System.out.println("Department: " + department.getName());


department.showEmployees();
// Output:
// Department: IT Department
// Employee ID: 101, Name: John Doe
// Employee ID: 102, Name: Jane Smith
}
}

Explanation:

Employee: A simple class with name and id attributes.

Department: A class that uses aggregation to include multiple Employee objects. The

Department class can add and display employees.

Main: A class to demonstrate the use of aggregation by creating Employee objects and adding

them to the Department.

5. Real-World Examples of Aggregation

Example 1: School and Student

A School class can aggregate multiple Student objects. The Student objects can exist independently

of the School.
Student Class

public class Student {


private String name;
private int rollNumber;

public Student(String name, int rollNumber) {


this.name = name;
this.rollNumber = rollNumber;
}

public String getName() {


return name;
}

public int getRollNumber() {


return rollNumber;
}
}

School Class

import java.util.ArrayList;
import java.util.List;

public class School {


private String name;
private List<Student> students;

public School(String name) {


this.name = name;
this.students = new ArrayList<>();
}

public void addStudent(Student student) {


students.add(student);
}

public void showStudents() {


for (Student student : students) {
System.out.println("Student Roll Number: " + student.getRollNumber() + ", Name:
}
}
public String getName() {
return name;
}
}

Example 2: Library and Book

A Library class can aggregate multiple Book objects. The Book objects can exist independently of

the Library.

Book Class

public class Book {


private String title;
private String author;

public Book(String title, String author) {


this.title = title;
this.author = author;
}

public String getTitle() {


return title;
}

public String getAuthor() {


return author;
}
}

Library Class

import java.util.ArrayList;
import java.util.List;

public class Library {


private String name;
private List<Book> books;

public Library(String name) {


this.name = name;
this.books = new ArrayList<>();
}

public void addBook(Book book) {


books.add(book);
}

public void showBooks() {


for (Book book : books) {
System.out.println("Title: " + book.getTitle() + ", Author: " + book.getAuthor(
}
}

public String getName() {


return name;
}
}

6. Conclusion
Aggregation in Java is a powerful concept that allows classes to model a whole-part relationship

where the parts can exist independently of the whole. This promotes modularity, reusability, and
maintainability in the design of software systems. By understanding and using aggregation correctly,

developers can create flexible and robust applications.

Happy coding!
Free Courses
on YouTube
Channel

175K
Subscribers

Association in Java with Example


author: Ramesh Fadatare

OOP FUNDAMENTALS OOPS

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

Introduction
Association is a relationship between two classes that establishes a connection between their objects.

It defines how objects of one class are connected to objects of another class. Association can be of
different types: unidirectional, bidirectional, one-to-one, one-to-many, many-to-one, and many-to-

many. Understanding association is essential for modeling relationships in object-oriented design.

Table of Contents
1. What is Association?
2. Types of Association
3. Benefits of Association

4. Example: Unidirectional Association


5. Example: Bidirectional Association
6. Real-World Examples of Association

7. Conclusion

1. What is Association?
Association is a structural relationship that represents how objects of one class are related to objects

of another class. Unlike inheritance, which defines an is-a relationship, association defines a has-a
relationship. It indicates that one object uses or interacts with another object.

2. Types of Association

Unidirectional Association: One class knows about the other class, but not vice versa.
Bidirectional Association: Both classes know about each other.

One-to-One Association: One object of a class is associated with one object of another class.
One-to-Many Association: One object of a class is associated with many objects of another
class.

Many-to-One Association: Many objects of a class are associated with one object of another
class.

Many-to-Many Association: Many objects of a class are associated with many objects of
another class.

3. Benefits of Association
Reusability: Promotes code reuse by establishing relationships between classes.

Flexibility: Allows classes to interact and collaborate without being tightly coupled.
Modularity: Helps in creating modular designs by defining clear relationships between classes.
Improved Design: Facilitates better design by modeling real-world relationships.

4. Example: Unidirectional Association


In a unidirectional association, one class knows about the other class, but not vice versa.

Example:

Let's create a Library class that is associated with multiple Book objects using unidirectional
association.

Step 1: Define the Book Class

public class Book {


private String title;
private String author;

public Book(String title, String author) {


this.title = title;
this.author = author;
}

public String getTitle() {


return title;
}

public String getAuthor() {


return author;
}
}

Step 2: Define the Library Class

import java.util.ArrayList;
import java.util.List;

public class Library {


private List<Book> books;

public Library() {
this.books = new ArrayList<>();
}

public void addBook(Book book) {


books.add(book);
}

public void showBooks() {


for (Book book : books) {
System.out.println("Title: " + book.getTitle() + ", Author: " + book.getAuthor(
}
}
}

Step 3: Main Class to Demonstrate Unidirectional Association

public class Main {


public static void main(String[] args) {
Book book1 = new Book("1984", "George Orwell");
Book book2 = new Book("To Kill a Mockingbird", "Harper Lee");

Library library = new Library();


library.addBook(book1);
library.addBook(book2);

library.showBooks();
// Output:
// Title: 1984, Author: George Orwell
// Title: To Kill a Mockingbird, Author: Harper Lee
}
}

Explanation:

Book: A simple class with title and author attributes.

Library: A class that uses unidirectional association to include multiple Book objects. The

Library class can add and display books.

Main: A class to demonstrate the use of unidirectional association by creating Book objects and

adding them to the Library.

5. Example: Bidirectional Association


In a bidirectional association, both classes know about each other.

Example:

Let's create a Person class and an Address class with a bidirectional association.

Step 1: Define the Address Class

public class Address {


private String street;
private String city;
private Person person; // Bidirectional association

public Address(String street, String city) {


this.street = street;
this.city = city;
}

public String getStreet() {


return street;
}

public String getCity() {


return city;
}

public void setPerson(Person person) {


this.person = person;
}

public Person getPerson() {


return person;
}
}

Step 2: Define the Person Class

public class Person {


private String name;
private Address address; // Bidirectional association

public Person(String name) {


this.name = name;
}

public String getName() {


return name;
}

public void setAddress(Address address) {


this.address = address;
address.setPerson(this); // Set the reverse association
}
public Address getAddress() {
return address;
}
}

Step 3: Main Class to Demonstrate Bidirectional Association

public class Main {


public static void main(String[] args) {
Person person = new Person("John Doe");
Address address = new Address("123 Main St", "Springfield");

person.setAddress(address);

System.out.println("Person: " + person.getName());


System.out.println("Address: " + person.getAddress().getStreet() + ", " + person.ge
System.out.println("Resident: " + address.getPerson().getName());
// Output:
// Person: John Doe
// Address: 123 Main St, Springfield
// Resident: John Doe
}
}

Explanation:

Address: A class with street, city, and a reference to a Person object.

Person: A class with name and a reference to an Address object.

Main: A class to demonstrate bidirectional association by creating Person and Address objects

and setting up their association.

6. Real-World Examples of Association

Example 1: University and Student

In a university system, a University class can have multiple Student objects. This can be modeled

using unidirectional or bidirectional association.

University Class
import java.util.ArrayList;
import java.util.List;

public class University {


private String name;
private List<Student> students;

public University(String name) {


this.name = name;
this.students = new ArrayList<>();
}

public void addStudent(Student student) {


students.add(student);
}

public List<Student> getStudents() {


return students;
}

public String getName() {


return name;
}
}

Student Class

public class Student {


private String name;
private University university; // Bidirectional association

public Student(String name) {


this.name = name;
}

public String getName() {


return name;
}

public void setUniversity(University university) {


this.university = university;
}
public University getUniversity() {
return university;
}
}

Example 2: Department and Employee

In a company, a Department can have multiple Employee objects, and an Employee can belong to a

single Department.

Department Class

import java.util.ArrayList;
import java.util.List;

public class Department {


private String name;
private List<Employee> employees;

public Department(String name) {


this.name = name;
this.employees = new ArrayList<>();
}

public void addEmployee(Employee employee) {


employees.add(employee);
}

public List<Employee> getEmployees() {


return employees;
}

public String getName() {


return name;
}
}

Employee Class

public class Employee {


private String name;
private Department department; // Bidirectional association
public Employee(String name) {
this.name = name;
}

public String getName() {


return name;
}

public void setDepartment(Department department) {


this.department = department;
}

public Department getDepartment() {


return department;
}
}

7. Conclusion
Association in Java is a powerful concept that allows modeling relationships between classes. By

understanding and using association correctly, developers can create flexible, modular, and
maintainable systems. Association can be unidirectional or bidirectional and can represent one-to-

one, one-to-many, many-to-one, or many-to-many relationships.

Happy coding!
Free Courses
on YouTube
Channel

175K
Subscribers

Cohesion in Java with Example


author: Ramesh Fadatare

OOP FUNDAMENTALS OOPS

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

Introduction
Cohesion is a measure of how closely related and focused the responsibilities of a single module or

class are. In Object-Oriented Programming (OOP), a highly cohesive class is one that performs a single
task or a group of related tasks, making the class easier to maintain and understand. High cohesion

often correlates with low coupling, leading to a more modular and maintainable codebase.

Table of Contents
1. What is Cohesion?
2. Benefits of High Cohesion
3. Types of Cohesion

4. Example: Low Cohesion vs High Cohesion


5. Real-World Examples of Cohesion
6. Conclusion

1. What is Cohesion?

Cohesion refers to the degree to which the elements inside a module or class belong together. It
describes how well the methods and properties of a class are related to each other. High cohesion

means that a class is responsible for only one thing or a group of related things, while low cohesion
means that a class has many unrelated responsibilities.

2. Benefits of High Cohesion

Improved Maintainability: High cohesion makes classes easier to maintain and update
because each class has a clear and focused responsibility.

Enhanced Readability: Classes with high cohesion are easier to understand and reason about.
Increased Reusability: Highly cohesive classes are more likely to be reused in different parts of
an application or in different projects.

Simplified Testing: Testing is easier for highly cohesive classes since they perform a single task
or a group of related tasks.

3. Types of Cohesion

1. Low cohesion
2. High Cohesion

4. Example: Low Cohesion vs High Cohesion

Example of Low Cohesion

In a class with low cohesion, responsibilities are scattered and unrelated, making the class difficult to
maintain and understand.

public class LowCohesionClass {


// Unrelated methods grouped together

public void calculateSalary() {


// Calculate employee salary
}

public void printReport() {


// Print employee report
}

public void sendEmail() {


// Send email to employee
}
}

Example of High Cohesion

In a class with high cohesion, responsibilities are related and focused, making the class easier to

maintain and understand.

Employee Class

public class Employee {


private String name;
private double salary;

public Employee(String name, double salary) {


this.name = name;
this.salary = salary;
}

public String getName() {


return name;
}

public double getSalary() {


return salary;
}

public void setSalary(double salary) {


this.salary = salary;
}
}

SalaryCalculator Class
public class SalaryCalculator {
public double calculateAnnualSalary(Employee employee) {
return employee.getSalary() * 12;
}
}

ReportPrinter Class

public class ReportPrinter {


public void printEmployeeReport(Employee employee) {
System.out.println("Employee Report: " + employee.getName() + ", Salary: " + employ
}
}

EmailService Class

public class EmailService {


public void sendEmail(String email, String message) {
System.out.println("Sending email to: " + email + ", Message: " + message);
}
}

Explanation

LowCohesionClass: Contains methods that perform unrelated tasks such as calculating salary,
printing reports, and sending emails. This makes the class difficult to understand and maintain.
High Cohesion Example: Responsibilities are divided into separate classes: Employee,

SalaryCalculator, ReportPrinter, and EmailService. Each class has a single responsibility,

making the code more modular and easier to maintain.

5. Real-World Examples of Cohesion

Example 1: Library System

In a library system, you can have classes like Book, LibraryMember, LibraryCatalog, and

LoanService. Each class has a specific responsibility, such as managing book details, handling

member information, maintaining the catalog, and managing book loans, respectively.
Book Class

public class Book {


private String title;
private String author;
private String isbn;

// Constructors, getters, and setters


}

LibraryMember Class

public class LibraryMember {


private String memberId;
private String name;

// Constructors, getters, and setters


}

LibraryCatalog Class

public class LibraryCatalog {


private List<Book> books;

public void addBook(Book book) {


books.add(book);
}

public Book findBookByIsbn(String isbn) {


for (Book book : books) {
if (book.getIsbn().equals(isbn)) {
return book;
}
}
return null;
}
}

LoanService Class
public class LoanService {
public void loanBook(LibraryMember member, Book book) {
// Logic to loan a book to a member
}
}

Example 2: E-commerce System

In an e-commerce system, you can have classes like Product, ShoppingCart, Order, and

PaymentProcessor. Each class is responsible for a specific part of the system.

Product Class

public class Product {


private String name;
private double price;

// Constructors, getters, and setters


}

ShoppingCart Class

public class ShoppingCart {


private List<Product> products;

public void addProduct(Product product) {


products.add(product);
}

public double calculateTotal() {


double total = 0;
for (Product product : products) {
total += product.getPrice();
}
return total;
}
}

Order Class
public class Order {
private List<Product> products;

// Constructors, getters, and setters


}

PaymentProcessor Class

public class PaymentProcessor {


public void processPayment(Order order, String paymentDetails) {
// Logic to process payment
}
}

6. Conclusion
Cohesion is a critical concept in software design that affects the maintainability, readability, and

reusability of a system. High cohesion within classes leads to a more modular and understandable
codebase, making it easier to manage and extend. By focusing on creating highly cohesive classes,

developers can build robust and scalable software systems.

Happy coding!
Free Courses
on YouTube
Channel

175K
Subscribers

Coupling in Java with Example


author: Ramesh Fadatare

OOP FUNDAMENTALS OOPS

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

Introduction
Coupling refers to the degree of direct knowledge that one class has about another class. In software

design, coupling is an essential concept that impacts the modularity and maintainability of a system.
Lower coupling between classes usually leads to a system that is easier to maintain and extend, while

higher coupling can make the system more rigid and harder to manage.

Table of Contents
1. What is Coupling?

2. Types of Coupling
3. Benefits of Low Coupling

4. Example: Tight Coupling


5. Example: Loose Coupling
6. Conclusion

1. What is Coupling?

Coupling describes the degree of dependency between classes or modules. It indicates how closely
connected different classes or modules are, and how much they rely on each other. There are two

main types of coupling:

Tight Coupling: High dependency between classes. Changes in one class often require changes

in the coupled class.


Loose Coupling: Low dependency between classes. Classes interact through well-defined

interfaces, reducing the impact of changes.

2. Types of Coupling

Tight Coupling

Tight coupling occurs when a class is highly dependent on the specifics of another class. This often

happens when one class creates an instance of another class and directly accesses its methods and
fields.

Loose Coupling

Loose coupling occurs when classes are less dependent on the specifics of other classes. This can be
achieved by using interfaces, abstract classes, or dependency injection, allowing classes to interact
without knowing the implementation details of each other.

3. Benefits of Low Coupling

Improved Maintainability: Changes in one class have minimal impact on other classes.
Enhanced Reusability: Loosely coupled classes can be reused in different contexts.
Better Testability: Independent classes are easier to test in isolation.

Flexibility: Systems with low coupling are more adaptable to change.


4. Example: Tight Coupling

In a tightly coupled system, changes in one class can significantly affect other classes.

Example:

class Engine {
public void start() {
System.out.println("Engine started.");
}
}

class Car {
private Engine engine;

public Car() {
this.engine = new Engine(); // Direct instantiation
}

public void start() {


engine.start();
}
}

public class Main {


public static void main(String[] args) {
Car car = new Car();
car.start(); // Output: Engine started.
}
}

Explanation:

Car class is tightly coupled with the Engine class.

The Car class directly creates an instance of Engine and calls its start method.

Any change in the Engine class, such as a change in the method signature, would require

changes in the Car class.

5. Example: Loose Coupling

In a loosely coupled system, classes interact through interfaces, reducing dependency.


Example:

interface Engine {
void start();
}

class DieselEngine implements Engine {


@Override
public void start() {
System.out.println("Diesel Engine started.");
}
}

class ElectricEngine implements Engine {


@Override
public void start() {
System.out.println("Electric Engine started.");
}
}

class Car {
private Engine engine;

public Car(Engine engine) {


this.engine = engine;
}

public void start() {


engine.start();
}
}

public class Main {


public static void main(String[] args) {
Engine dieselEngine = new DieselEngine();
Car carWithDieselEngine = new Car(dieselEngine);
carWithDieselEngine.start(); // Output: Diesel Engine started.

Engine electricEngine = new ElectricEngine();


Car carWithElectricEngine = new Car(electricEngine);
carWithElectricEngine.start(); // Output: Electric Engine started.
}
}
Explanation:

Engine is an interface that defines the start method.

DieselEngine and ElectricEngine are implementations of the Engine interface.


Car class depends on the Engine interface rather than a concrete implementation.

The Car class can work with any implementation of the Engine interface, promoting loose
coupling.

6. Conclusion

Coupling is a critical concept in software design that affects the modularity, maintainability, and
flexibility of a system. Tight coupling leads to a system where classes are highly dependent on each

other, making it hard to maintain and extend. Loose coupling, on the other hand, reduces
dependencies, making the system easier to manage and adapt to changes. By using interfaces,
abstract classes, and dependency injection, developers can achieve loose coupling and build more
robust and flexible systems.

Happy coding!

OOP FUNDAMENTALS OOPS


Free Courses
on YouTube
Channel

175K
Subscribers

Delegation in Java with Example


author: Ramesh Fadatare

OOP FUNDAMENTALS OOPS

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

Introduction
Delegation is an object-oriented design pattern in which an object passes a task to another object

instead of performing it itself. This concept allows for polymorphism and code reuse, leading to more
maintainable and flexible code. Delegation helps maintain a loosely coupled system, which is easier to

maintain and extend.

Table of Contents
1. What is Delegation?
2. Benefits of Delegation
3. Example 1: Ticket Booking System

4. Example 2: Printers Implementation


5. Conclusion

1. What is Delegation?

Delegation is a technique in which an object delegates responsibilities to another helper object.


Instead of doing the work itself, it passes the task to another object. This helps achieve polymorphism
and ensures that tasks are handled by the most appropriate class.

2. Benefits of Delegation

Loosely Coupled Code: Delegation reduces the coupling between classes.


Code Reusability: Common functionalities can be reused by multiple classes.

Enhanced Flexibility: Changes to the delegated class do not affect the delegator class.
Improved Maintainability: Easier to maintain and extend as the code is modular.

3. Example 1: Ticket Booking System

Step-by-Step Implementation

Step 1: Create a TravelBooking Interface

interface TravelBooking {
void bookTicket();
}

The TravelBooking interface defines a single method bookTicket(), which will be implemented by

various travel booking classes.

Step 2: TrainBooking Class

class TrainBooking implements TravelBooking {


@Override
public void bookTicket() {
System.out.println("Train ticket booked");
}
}
The TrainBooking class implements the TravelBooking interface and provides a specific

implementation for booking train tickets.

Step 3: AirBooking Class

class AirBooking implements TravelBooking {


@Override
public void bookTicket() {
System.out.println("Flight ticket booked");
}
}

The AirBooking class implements the TravelBooking interface and provides a specific

implementation for booking air tickets.

Step 4: TicketBookingByAgent Class

class TicketBookingByAgent implements TravelBooking {

private TravelBooking travelBooking;

public TicketBookingByAgent(TravelBooking travelBooking) {


this.travelBooking = travelBooking;
}

@Override
public void bookTicket() {
travelBooking.bookTicket();
}
}

The TicketBookingByAgent class also implements the TravelBooking interface but delegates the

actual booking task to another TravelBooking object. The delegation is achieved via the constructor

which accepts a TravelBooking object. The bookTicket() method calls the bookTicket() method

of the delegated TravelBooking object.

Step 5: DelegationDemonstration Class


public class DelegationDemonstration {
public static void main(String[] args) {
TicketBookingByAgent agent = new TicketBookingByAgent(new TrainBooking());
agent.bookTicket(); // Output: Train ticket booked

agent = new TicketBookingByAgent(new AirBooking());


agent.bookTicket(); // Output: Flight ticket booked
}
}

In the DelegationDemonstration class, we create an instance of TicketBookingByAgent and pass

it different TravelBooking implementations. The bookTicket() method of TicketBookingByAgent

delegates the call to the appropriate booking class (either TrainBooking or AirBooking).

How Delegation Works in the Ticket Booking System

In this example, the TicketBookingByAgent class does not handle the actual ticket booking process.

Instead, it delegates this responsibility to the classes that implement the TravelBooking interface

(TrainBooking and AirBooking). This allows TicketBookingByAgent to dynamically choose which

booking implementation to use at runtime, promoting flexibility and code reuse.

4. Example 2: Printers Implementation

Step-by-Step Implementation

Step 1: Printer Interface

public interface Printer {


void print(String message);
}

The Printer interface defines a single method print(), which will be implemented by various
printer classes.

Step 2: CanonPrinter Class

public class CanonPrinter implements Printer {


@Override
public void print(String message) {
System.out.println("Canon Printer: " + message);
}
}

The CanonPrinter class implements the Printer interface and provides a specific implementation

for printing a message.

Step 3: EpsonPrinter Class

public class EpsonPrinter implements Printer {


@Override
public void print(String message) {
System.out.println("Epson Printer: " + message);
}
}

The EpsonPrinter class implements the Printer interface and provides a specific implementation

for printing a message.

Step 4: HpPrinter Class

public class HpPrinter implements Printer {


@Override
public void print(String message) {
System.out.println("HP Printer: " + message);
}
}

The HpPrinter class implements the Printer interface and provides a specific implementation for

printing a message.

Step 5: PrinterController Class


public class PrinterController implements Printer {

private final Printer printer;

public PrinterController(Printer printer) {


this.printer = printer;
}

@Override
public void print(String message) {
printer.print(message);
}
}

The PrinterController class also implements the Printer interface but delegates the actual

printing task to another Printer object. The delegation is achieved via the constructor which accepts

a Printer object. The print() method calls the print() method of the delegated Printer object.

Step 6: App Class to Test Delegation

public class App {

public static final String MESSAGE_TO_PRINT = "hello world";

public static void main(String[] args) {


PrinterController hpPrinterController = new PrinterController(new HpPrinter());
PrinterController canonPrinterController = new PrinterController(new CanonPrinter()
PrinterController epsonPrinterController = new PrinterController(new EpsonPrinter()

hpPrinterController.print(MESSAGE_TO_PRINT); // Output: HP Printer: hello world


canonPrinterController.print(MESSAGE_TO_PRINT); // Output: Canon Printer: hello wor
epsonPrinterController.print(MESSAGE_TO_PRINT); // Output: Epson Printer: hello wor
}
}

How Delegation Works in the Printers Implementation

In this example, the PrinterController class does not handle the actual printing process. Instead, it

delegates this responsibility to the classes that implement the Printer interface (CanonPrinter,
EpsonPrinter, and HpPrinter). This allows PrinterController to dynamically choose which

printer implementation to use at runtime, promoting flexibility and code reuse.

5. Conclusion

Delegation is a powerful design pattern that allows objects to delegate tasks to other objects,
promoting code reuse and modularity. By using delegation, you can create more flexible and

maintainable systems. In this article, we explored two examples: a ticket booking system and a printer

implementation, to demonstrate how delegation can be effectively used in Java.

Happy coding!

OOP FUNDAMENTALS OOPS

Anonymous 24 December 2018 at 00:15


class diagram is wrong. +CanonPrinter() in all the different printer class

Java Technology 24 December 2018 at 02:28


Class diagram is not wrong. The content CononPrinter is typo in all subclasses.You
can fix this.
Free Courses
on YouTube
Channel

175K
Subscribers

Single Responsibility Principle in Java with Example


author: Ramesh Fadatare

JAVA BEST PRACTICES OBJECT ORIENTED DESIGN OOPS SOLID PRINCIPLES

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

Introduction
The Single Responsibility Principle (SRP) is one of the five SOLID principles of object-oriented design.

SRP states that a class should have only one reason to change, meaning it should have only one
responsibility or job. This principle helps in creating more maintainable and understandable code by

ensuring that each class addresses only one concern.

Table of Contents
1. What is the Single Responsibility Principle?
2. Benefits of the Single Responsibility Principle
3. Example: Violation of SRP

4. Example: Adherence to SRP


5. Real-World Example
6. Conclusion

1. What is the Single Responsibility Principle?

The Single Responsibility Principle (SRP) asserts that a class should only have one reason to change,
implying it should have only one responsibility or purpose. This principle helps in building classes that

are easier to understand, test, and maintain by ensuring each class is focused on a single aspect of the
application.

2. Benefits of the Single Responsibility Principle

Improved Maintainability: Changes to a single responsibility affect only one class, making the
codebase easier to maintain.

Enhanced Readability: Classes with a single responsibility are easier to read and understand.
Increased Reusability: Classes focused on a single responsibility can be reused in different
contexts without modification.

Simplified Testing: Testing is more straightforward for classes with a single responsibility.

3. Example: Violation of SRP

In this example, a User class is responsible for both user management and email sending, violating

SRP.

public class User {


private String name;
private String email;

public User(String name, String email) {


this.name = name;
this.email = email;
}

public void saveUser() {


// Code to save user to database
System.out.println("User saved to database.");
}
public void sendEmail(String message) {
// Code to send email
System.out.println("Email sent to " + email + " with message: " + message);
}

public String getName() {


return name;
}

public String getEmail() {


return email;
}
}

public class Main {


public static void main(String[] args) {
User user = new User("John Doe", "[email protected]");
user.saveUser();
user.sendEmail("Welcome to our platform!");
}
}

Issues:

The User class is responsible for both saving the user and sending emails.

Any change in email sending logic will require changes in the User class, violating SRP.

4. Example: Adherence to SRP


By splitting responsibilities into separate classes, we adhere to SRP.

Step 1: Define the User Class

public class User {


private String name;
private String email;

public User(String name, String email) {


this.name = name;
this.email = email;
}

public String getName() {


return name;
}

public String getEmail() {


return email;
}
}

Step 2: Define the UserRepository Class

public class UserRepository {


public void saveUser(User user) {
// Code to save user to database
System.out.println("User " + user.getName() + " saved to database.");
}
}

Step 3: Define the EmailService Class

public class EmailService {


public void sendEmail(User user, String message) {
// Code to send email
System.out.println("Email sent to " + user.getEmail() + " with message: " + message
}
}

Step 4: Main Class to Demonstrate SRP

public class Main {


public static void main(String[] args) {
User user = new User("John Doe", "[email protected]");

UserRepository userRepository = new UserRepository();


userRepository.saveUser(user);

EmailService emailService = new EmailService();


emailService.sendEmail(user, "Welcome to our platform!");
}
}
Explanation:

User: Class only responsible for storing user details.


UserRepository: Class responsible for saving the user to the database.
EmailService: Class responsible for sending emails to users.
Main: Class demonstrating the use of SRP by separating concerns into different classes.

5. Real-World Example

Example: Library System

In a library management system, consider separating the responsibilities of book management,


member management, and loan management into different classes.

Book Class

public class Book {


private String title;
private String author;

public Book(String title, String author) {


this.title = title;
this.author = author;
}

public String getTitle() {


return title;
}

public String getAuthor() {


return author;
}
}

Member Class

public class Member {


private String name;
private String memberId;
public Member(String name, String memberId) {
this.name = name;
this.memberId = memberId;
}

public String getName() {


return name;
}

public String getMemberId() {


return memberId;
}
}

LoanService Class

public class LoanService {


public void loanBook(Member member, Book book) {
// Code to loan book to member
System.out.println("Book '" + book.getTitle() + "' loaned to member " + member.getN
}
}

Explanation:

Book: Class responsible for storing book details.


Member: Class responsible for storing member details.

LoanService: Class responsible for managing book loans.


Main: Class demonstrating the use of SRP by separating concerns into different classes.

Conclusion

The Single Responsibility Principle (SRP) is a fundamental concept in object-oriented design that
promotes high cohesion and low coupling by ensuring that each class has only one responsibility or

reason to change. By adhering to SRP, developers can create more maintainable, understandable, and
flexible code. This principle is critical for building robust and scalable applications.

Happy coding!
Free Courses
on YouTube
Channel

175K
Subscribers

Open/Closed Principle in Java with Example


author: Ramesh Fadatare

JAVA BEST PRACTICES OBJECT ORIENTED DESIGN OOPS SOLID PRINCIPLES

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

Introduction
The Open/Closed Principle (OCP) is one of the five SOLID principles of object-oriented design. It

states that software entities (such as classes, modules, and functions) should be open for extension
but closed for modification. This means that the behavior of a module can be extended without

modifying its source code.

Table of Contents
1. What is the Open/Closed Principle?
2. Benefits of the Open/Closed Principle
3. Example: Violation of OCP

4. Example: Adherence to OCP


5. Real-World Example
6. Conclusion

1. What is the Open/Closed Principle?

The Open/Closed Principle (OCP) asserts that a class should be open for extension but closed for
modification. This means you should be able to add new functionality to a class by extending it,

without changing the existing code.

2. Benefits of the Open/Closed Principle


Enhanced Maintainability: Reduces the risk of introducing bugs when adding new

functionality.
Improved Flexibility: New features can be added without modifying existing code.

Increased Reusability: Classes that adhere to OCP are more likely to be reusable in different
contexts.

3. Example: Violation of OCP

In this example, we'll create a Shape class and a AreaCalculator class that violates OCP by requiring

modification to add new shapes.

Example:

class Circle {
private double radius;

public Circle(double radius) {


this.radius = radius;
}

public double getRadius() {


return radius;
}
}

class Rectangle {
private double width;
private double height;

public Rectangle(double width, double height) {


this.width = width;
this.height = height;
}

public double getWidth() {


return width;
}

public double getHeight() {


return height;
}
}

class AreaCalculator {
public double calculateArea(Object shape) {
if (shape instanceof Circle) {
Circle circle = (Circle) shape;
return Math.PI * circle.getRadius() * circle.getRadius();
} else if (shape instanceof Rectangle) {
Rectangle rectangle = (Rectangle) shape;
return rectangle.getWidth() * rectangle.getHeight();
}
return 0;
}
}

public class Main {


public static void main(String[] args) {
Circle circle = new Circle(5);
Rectangle rectangle = new Rectangle(4, 5);

AreaCalculator calculator = new AreaCalculator();


System.out.println("Circle area: " + calculator.calculateArea(circle)); // Output:
System.out.println("Rectangle area: " + calculator.calculateArea(rectangle)); // Ou
}
}

Issues:

The AreaCalculator class must be modified to support new shapes, violating OCP.

Adding new shapes requires changes to the calculateArea method, making the code less
maintainable.

4. Example: Adherence to OCP

To adhere to OCP, we can use polymorphism and interfaces to allow the AreaCalculator to work

with any shape without modification.

Example:

Step 1: Define the Shape Interface

interface Shape {
double calculateArea();
}

Step 2: Implement Specific Shape Classes

class Circle implements Shape {


private double radius;

public Circle(double radius) {


this.radius = radius;
}

@Override
public double calculateArea() {
return Math.PI * radius * radius;
}
}

class Rectangle implements Shape {


private double width;
private double height;

public Rectangle(double width, double height) {


this.width = width;
this.height = height;
}

@Override
public double calculateArea() {
return width * height;
}
}

Step 3: Update the AreaCalculator Class

class AreaCalculator {
public double calculateArea(Shape shape) {
return shape.calculateArea();
}
}

Step 4: Main Class to Demonstrate OCP

public class Main {


public static void main(String[] args) {
Shape circle = new Circle(5);
Shape rectangle = new Rectangle(4, 5);

AreaCalculator calculator = new AreaCalculator();


System.out.println("Circle area: " + calculator.calculateArea(circle)); // Output:
System.out.println("Rectangle area: " + calculator.calculateArea(rectangle)); // Ou
}
}

Explanation:

Shape: An interface that defines the calculateArea method.

Circle and Rectangle: Implementations of the Shape interface that provide specific area

calculations.
AreaCalculator: A class that calculates the area of any Shape without needing modification.

Main: Demonstrates the use of OCP by adding new shapes without changing the
AreaCalculator class.

5. Real-World Example

Example: Notification System

Consider a notification system where different types of notifications (e.g., email, SMS) need to be sent.
Step 1: Define the Notification Interface

interface Notification {
void send(String message);
}

Step 2: Implement Specific Notification Classes

class EmailNotification implements Notification {


@Override
public void send(String message) {
System.out.println("Sending email: " + message);
}
}

class SMSNotification implements Notification {


@Override
public void send(String message) {
System.out.println("Sending SMS: " + message);
}
}

Step 3: Update the NotificationService Class

class NotificationService {
private List<Notification> notifications;

public NotificationService() {
this.notifications = new ArrayList<>();
}

public void addNotification(Notification notification) {


notifications.add(notification);
}

public void sendAll(String message) {


for (Notification notification : notifications) {
notification.send(message);
}
}
}
Step 4: Main Class to Demonstrate OCP

public class Main {


public static void main(String[] args) {
NotificationService service = new NotificationService();
service.addNotification(new EmailNotification());
service.addNotification(new SMSNotification());

service.sendAll("Hello, World!");
// Output:
// Sending email: Hello, World!
// Sending SMS: Hello, World!
}
}

Explanation:

Notification: An interface that defines the send method.

EmailNotification and SMSNotification: Implementations of the Notification interface that

provide specific sending mechanisms.


NotificationService: A class that sends notifications without needing modification for new

types of notifications.
Main: Demonstrates the use of OCP by adding new notification types without changing the

NotificationService class.

6. Conclusion
The Open/Closed Principle (OCP) is a fundamental concept in object-oriented design that promotes

the extension of software entities without modifying their source code. By adhering to OCP,
developers can create more maintainable, flexible, and reusable code. Understanding and applying

OCP is essential for building robust and scalable Java applications.

Happy coding!
Free Courses
on YouTube
Channel

175K
Subscribers

Liskov Substitution Principle in Java with Example


author: Ramesh Fadatare

JAVA BEST PRACTICES OBJECT ORIENTED DESIGN OOPS SOLID PRINCIPLES

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

Introduction
The Liskov Substitution Principle (LSP) is one of the five SOLID principles of object-oriented design. It

states that objects of a superclass should be replaceable with objects of a subclass without affecting
the correctness of the program. This principle ensures that a subclass can stand in for its superclass

without altering the desirable properties of the program (correctness, task performed, etc.).

Table of Contents
1. What is the Liskov Substitution Principle?
2. Benefits of the Liskov Substitution Principle
3. Example: Violation of LSP

4. Example: Adherence to LSP


5. Real-World Example
6. Conclusion

1. What is the Liskov Substitution Principle?

The Liskov Substitution Principle (LSP) asserts that if S is a subtype of T, then objects of type T may be

replaced with objects of type S (i.e., objects of type S may substitute objects of type T) without

altering any of the desirable properties of the program. This means that subclasses should extend the

functionality of the parent class without changing its behavior.

2. Benefits of the Liskov Substitution Principle


Enhanced Reusability: Ensures subclasses can be used interchangeably with their parent

classes.
Improved Maintainability: Reduces the risk of introducing bugs when extending classes.
Increased Flexibility: Allows for more flexible and modular code design.

3. Example: Violation of LSP


In this example, we'll create a superclass Bird and a subclass Penguin that violates LSP.

Example:

class Bird {
public void fly() {
System.out.println("Bird is flying");
}
}

class Sparrow extends Bird {


@Override
public void fly() {
System.out.println("Sparrow is flying");
}
}

class Penguin extends Bird {


@Override
public void fly() {
throw new UnsupportedOperationException("Penguins can't fly");
}
}

public class Main {


public static void main(String[] args) {
Bird bird = new Sparrow();
bird.fly(); // Output: Sparrow is flying

bird = new Penguin();


bird.fly(); // Throws UnsupportedOperationException
}
}

Issues:

The Penguin class violates LSP because it changes the behavior of the fly method by throwing

an exception.
This breaks the expected behavior of the Bird class and can lead to runtime errors.

4. Example: Adherence to LSP

To adhere to LSP, we can introduce a more appropriate class hierarchy where flying ability is modeled
differently.

Example:

abstract class Bird {


public abstract void eat();
}

class Sparrow extends Bird {


@Override
public void eat() {
System.out.println("Sparrow is eating");
}

public void fly() {


System.out.println("Sparrow is flying");
}
}
class Penguin extends Bird {
@Override
public void eat() {
System.out.println("Penguin is eating");
}

public void swim() {


System.out.println("Penguin is swimming");
}
}

public class Main {


public static void main(String[] args) {
Bird sparrow = new Sparrow();
sparrow.eat(); // Output: Sparrow is eating
((Sparrow) sparrow).fly(); // Output: Sparrow is flying

Bird penguin = new Penguin();


penguin.eat(); // Output: Penguin is eating
((Penguin) penguin).swim(); // Output: Penguin is swimming
}
}

Explanation:

Bird: An abstract class that provides a common interface for all bird types.
Sparrow and Penguin: Subclasses that extend Bird without changing its behavior.

Main: Demonstrates the use of LSP by allowing subclasses to be used interchangeably with the
parent class.

5. Real-World Example

Example: Payment Processing System

Consider a payment processing system where different payment methods (e.g., credit card, PayPal)
should adhere to the Liskov Substitution Principle.

Step 1: Define the Payment Class

abstract class Payment {


public abstract void processPayment(double amount);
}
class CreditCardPayment extends Payment {
@Override
public void processPayment(double amount) {
System.out.println("Processing credit card payment of $" + amount);
}
}

class PayPalPayment extends Payment {


@Override
public void processPayment(double amount) {
System.out.println("Processing PayPal payment of $" + amount);
}
}

Step 2: Main Class to Demonstrate LSP

public class Main {


public static void main(String[] args) {
Payment payment = new CreditCardPayment();
payment.processPayment(100.0); // Output: Processing credit card payment of $100.0

payment = new PayPalPayment();


payment.processPayment(200.0); // Output: Processing PayPal payment of $200.0
}
}

Explanation:

Payment: An abstract class that provides a common interface for all payment methods.

CreditCardPayment and PayPalPayment: Subclasses that extend Payment without changing its

behavior.

Main: Demonstrates the use of LSP by allowing different payment methods to be used

interchangeably.

6. Conclusion

The Liskov Substitution Principle (LSP) is a fundamental concept in object-oriented design that
ensures subclasses can replace their parent classes without altering the correctness of the program.

By adhering to LSP, developers can create more flexible, reusable, and maintainable code.
Free Courses
on YouTube
Channel

175K
Subscribers

Interface Segregation Principle in Java with Example


author: Ramesh Fadatare

JAVA BEST PRACTICES OBJECT ORIENTED DESIGN OOPS SOLID PRINCIPLES

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

Introduction
The Interface Segregation Principle (ISP) is one of the five SOLID principles of object-oriented design.

ISP states that no client should be forced to depend on methods they do not use. This principle
promotes the creation of smaller, more specific interfaces instead of larger, general-purpose

interfaces, ensuring that classes implement only the methods that are relevant to them.

Table of Contents
1. What is the Interface Segregation Principle?
2. Benefits of the Interface Segregation Principle
3. Example: Violation of ISP

4. Example: Adherence to ISP


5. Real-World Example
6. Conclusion

1. What is the Interface Segregation Principle?

The Interface Segregation Principle (ISP) asserts that clients should not be forced to depend on
interfaces they do not use. In other words, an interface should not include methods that are not

relevant to the implementing class. Instead, interfaces should be small and focused on specific sets of
behaviors.

2. Benefits of the Interface Segregation Principle

Improved Maintainability: Smaller interfaces are easier to implement, maintain, and


understand.

Enhanced Flexibility: Changes in one part of the system are less likely to affect other parts.
Increased Reusability: Classes can implement only the interfaces they need, promoting reuse.

3. Example: Violation of ISP

In this example, we'll create an interface Worker that violates ISP by including methods not relevant to

all implementing classes.

Example:

interface Worker {
void work();
void eat();
}

class Developer implements Worker {


@Override
public void work() {
System.out.println("Developer is coding.");
}

@Override
public void eat() {
System.out.println("Developer is eating.");
}
}

class Robot implements Worker {


@Override
public void work() {
System.out.println("Robot is working.");
}

@Override
public void eat() {
// Robot does not eat
throw new UnsupportedOperationException("Robot does not eat.");
}
}

public class Main {


public static void main(String[] args) {
Worker developer = new Developer();
developer.work(); // Output: Developer is coding.
developer.eat(); // Output: Developer is eating.

Worker robot = new Robot();


robot.work(); // Output: Robot is working.
robot.eat(); // Throws UnsupportedOperationException
}
}

Issues:

The Robot class is forced to implement the eat method, which is not applicable to it.

This leads to a violation of ISP as the Robot class depends on a method it does not use.

4. Example: Adherence to ISP

To adhere to ISP, we can split the Worker interface into more specific interfaces.

Example:

Step 1: Define Specific Interfaces

interface Workable {
void work();
}

interface Eatable {
void eat();
}

Step 2: Implement the Specific Interfaces

class Developer implements Workable, Eatable {


@Override
public void work() {
System.out.println("Developer is coding.");
}

@Override
public void eat() {
System.out.println("Developer is eating.");
}
}

class Robot implements Workable {


@Override
public void work() {
System.out.println("Robot is working.");
}
}

Step 3: Main Class to Demonstrate ISP

public class Main {


public static void main(String[] args) {
Workable developer = new Developer();
developer.work(); // Output: Developer is coding.

Eatable eatableDeveloper = (Eatable) developer;


eatableDeveloper.eat(); // Output: Developer is eating.

Workable robot = new Robot();


robot.work(); // Output: Robot is working.
}
}
Explanation:

Workable: An interface with the work method.

Eatable: An interface with the eat method.

Developer: A class that implements both Workable and Eatable interfaces.

Robot: A class that implements only the Workable interface.

Main: Demonstrates the use of ISP by allowing classes to implement only the methods they
need.

5. Real-World Example

Example: Document Printing System

Consider a document printing system where different devices have different capabilities.

Step 1: Define Specific Interfaces

interface Printable {
void print();
}

interface Scannable {
void scan();
}

interface Faxable {
void fax();
}

Step 2: Implement the Specific Interfaces

class Printer implements Printable {


@Override
public void print() {
System.out.println("Printing document.");
}
}

class Scanner implements Scannable {


@Override
public void scan() {
System.out.println("Scanning document.");
}
}

class AllInOnePrinter implements Printable, Scannable, Faxable {


@Override
public void print() {
System.out.println("Printing document.");
}

@Override
public void scan() {
System.out.println("Scanning document.");
}

@Override
public void fax() {
System.out.println("Faxing document.");
}
}

Step 3: Main Class to Demonstrate ISP

public class Main {


public static void main(String[] args) {
Printable printer = new Printer();
printer.print(); // Output: Printing document.

Scannable scanner = new Scanner();


scanner.scan(); // Output: Scanning document.

AllInOnePrinter allInOnePrinter = new AllInOnePrinter();


allInOnePrinter.print(); // Output: Printing document.
allInOnePrinter.scan(); // Output: Scanning document.
allInOnePrinter.fax(); // Output: Faxing document.
}
}

Explanation:

Printable, Scannable, Faxable: Interfaces with specific methods.


Printer: A class that implements the Printable interface.
Scanner: A class that implements the Scannable interface.

AllInOnePrinter: A class that implements Printable, Scannable, and Faxable interfaces.

Main: Demonstrates the use of ISP by allowing devices to implement only the capabilities they
support.

6. Conclusion
The Interface Segregation Principle (ISP) is a fundamental concept in object-oriented design that
promotes the creation of small, specific interfaces rather than large, general-purpose ones. By

adhering to ISP, developers can create more flexible, maintainable, and reusable code. Understanding
and applying ISP is essential for building robust and scalable Java applications.

Happy coding!

JAVA BEST PRACTICES OBJECT ORIENTED DESIGN OOPS SOLID PRINCIPLES

To leave a comment, click the button below to sign in with Google.

SIGN IN WITH GOOGLE


Free Courses
on YouTube
Channel

175K
Subscribers

Dependency Inversion Principle in Java with Example


author: Ramesh Fadatare

JAVA BEST PRACTICES OBJECT ORIENTED DESIGN OOPS SOLID PRINCIPLES

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

Introduction
The Dependency Inversion Principle (DIP) is one of the five SOLID principles of object-oriented design.

It states that high-level modules should not depend on low-level modules. Both should depend on
abstractions. Furthermore, abstractions should not depend on details. Details should depend on

abstractions. This principle promotes loose coupling between software components.

Table of Contents
1. What is the Dependency Inversion Principle?

2. Benefits of the Dependency Inversion Principle


3. Example: Violation of DIP

4. Example: Adherence to DIP


5. Real-World Example
6. Conclusion

1. What is the Dependency Inversion Principle?

The Dependency Inversion Principle (DIP) asserts that:

High-level modules should not depend on low-level modules. Both should depend on
abstractions.
Abstractions should not depend on details. Details should depend on abstractions.

This principle ensures that the system's high-level policy does not depend on the low-level details but
rather on an abstraction.

2. Benefits of the Dependency Inversion Principle

Loose Coupling: Promotes loose coupling between classes and components.


Flexibility: Enhances flexibility and makes it easier to change or replace components.

Reusability: Encourages the development of reusable components.


Testability: Improves testability by allowing dependencies to be easily mocked or stubbed.

3. Example: Violation of DIP

In this example, we'll create a LightBulb class and a Switch class that violates DIP by depending

directly on LightBulb.

Example:

class LightBulb {
public void turnOn() {
System.out.println("LightBulb is turned on");
}

public void turnOff() {


System.out.println("LightBulb is turned off");
}
}
class Switch {
private LightBulb lightBulb;

public Switch(LightBulb lightBulb) {


this.lightBulb = lightBulb;
}

public void flip(boolean on) {


if (on) {
lightBulb.turnOn();
} else {
lightBulb.turnOff();
}
}
}

public class Main {


public static void main(String[] args) {
LightBulb lightBulb = new LightBulb();
Switch lightSwitch = new Switch(lightBulb);
lightSwitch.flip(true); // Output: LightBulb is turned on
lightSwitch.flip(false); // Output: LightBulb is turned off
}
}

Issues:

The Switch class depends directly on the LightBulb class, creating tight coupling.

Any change in the LightBulb class requires changes in the Switch class.

4. Example: Adherence to DIP

To adhere to DIP, we can introduce an abstraction for the LightBulb class and make the Switch class

depend on this abstraction.

Example:

Step 1: Define the Switchable Interface

interface Switchable {
void turnOn();
void turnOff();
}

Step 2: Implement the LightBulb Class

class LightBulb implements Switchable {


@Override
public void turnOn() {
System.out.println("LightBulb is turned on");
}

@Override
public void turnOff() {
System.out.println("LightBulb is turned off");
}
}

Step 3: Implement the Switch Class

class Switch {
private Switchable switchable;

public Switch(Switchable switchable) {


this.switchable = switchable;
}

public void flip(boolean on) {


if (on) {
switchable.turnOn();
} else {
switchable.turnOff();
}
}
}

Step 4: Main Class to Demonstrate DIP

public class Main {


public static void main(String[] args) {
Switchable lightBulb = new LightBulb();
Switch lightSwitch = new Switch(lightBulb);
lightSwitch.flip(true); // Output: LightBulb is turned on
lightSwitch.flip(false); // Output: LightBulb is turned off
}
}

Explanation:

Switchable: An interface that defines the turnOn and turnOff methods.

LightBulb: A class that implements the Switchable interface.

Switch: A class that depends on the Switchable interface rather than the LightBulb class.

Main: Demonstrates the use of DIP by creating a Switch object that depends on the

Switchable interface.

5. Real-World Example

Example: Payment Processing System

Consider a payment processing system where different payment methods (e.g., credit card, PayPal)

need to be processed.

Step 1: Define the PaymentProcessor Interface

interface PaymentProcessor {
void processPayment(double amount);
}

Step 2: Implement Specific Payment Classes

class CreditCardPaymentProcessor implements PaymentProcessor {


@Override
public void processPayment(double amount) {
System.out.println("Processing credit card payment of $" + amount);
}
}

class PayPalPaymentProcessor implements PaymentProcessor {


@Override
public void processPayment(double amount) {
System.out.println("Processing PayPal payment of $" + amount);
}
}

Step 3: Implement the PaymentService Class

class PaymentService {
private PaymentProcessor paymentProcessor;

public PaymentService(PaymentProcessor paymentProcessor) {


this.paymentProcessor = paymentProcessor;
}

public void makePayment(double amount) {


paymentProcessor.processPayment(amount);
}
}

Step 4: Main Class to Demonstrate DIP

public class Main {


public static void main(String[] args) {
PaymentProcessor creditCardPayment = new CreditCardPaymentProcessor();
PaymentService paymentService = new PaymentService(creditCardPayment);
paymentService.makePayment(100.0); // Output: Processing credit card payment of $10

PaymentProcessor paypalPayment = new PayPalPaymentProcessor();


paymentService = new PaymentService(paypalPayment);
paymentService.makePayment(200.0); // Output: Processing PayPal payment of $200.0
}
}

Explanation:

PaymentProcessor: An interface that defines the processPayment method.

CreditCardPaymentProcessor and PayPalPaymentProcessor: Classes that implement the


PaymentProcessor interface.

PaymentService: A class that depends on the PaymentProcessor interface.

Main: Demonstrates the use of DIP by creating a PaymentService object that depends on the

PaymentProcessor interface.
6. Conclusion

The Dependency Inversion Principle (DIP) is a fundamental concept in object-oriented design that
promotes loose coupling between high-level and low-level modules by depending on abstractions

rather than concrete implementations. By adhering to DIP, developers can create more maintainable,
flexible, and testable code. Understanding and applying DIP is essential for building robust and

scalable Java applications.

Happy coding!

JAVA BEST PRACTICES OBJECT ORIENTED DESIGN OOPS SOLID PRINCIPLES

To leave a comment, click the button below to sign in with Google.

SIGN IN WITH GOOGLE


Free Courses
on YouTube
Channel

175K
Subscribers

5 Different Ways to Create Objects in Java


author: Ramesh Fadatare

CORE JAVA INTERVIEW OOPS

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

There are several ways to create objects in Java. In this article, we will discuss five different ways to
create objects in Java. We will understand each method with an example and its output.

1. Using the new Keyword


This is the most common way to create an object. It involves calling the constructor of the class using

the new keyword.

Example:
public class Car {
private String color;
private String model;

public Car(String color, String model) {


this.color = color;
this.model = model;
}

public void displayInfo() {


System.out.println("Car Model: " + model + ", Color: " + color);
}

public static void main(String[] args) {


Car myCar = new Car("Red", "Toyota Corolla");
myCar.displayInfo();
}
}

Output:

Car Model: Toyota Corolla, Color: Red

2. Using Class.forName()
This method is used for dynamic class loading. It can throw a ClassNotFoundException.

Example:

public class Car {


private String color;
private String model;

public Car() {
this.color = "Blue";
this.model = "Honda Civic";
}

public void displayInfo() {


System.out.println("Car Model: " + model + ", Color: " + color);
}
public static void main(String[] args) {
try {
Car myCar = (Car) Class.forName("Car").newInstance();
myCar.displayInfo();
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e
e.printStackTrace();
}
}
}

Output:

Car Model: Honda Civic, Color: Blue

3. Using clone()

This method creates a new object by copying the existing object's data. It requires the class to
implement the Cloneable interface.

Example:

public class Car implements Cloneable {


private String color;
private String model;

public Car(String color, String model) {


this.color = color;
this.model = model;
}

public void displayInfo() {


System.out.println("Car Model: " + model + ", Color: " + color);
}

@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}

public static void main(String[] args) {


try {
Car originalCar = new Car("Green", "BMW X5");
Car clonedCar = (Car) originalCar.clone();
clonedCar.displayInfo();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}

Output:

Car Model: BMW X5, Color: Green

4. Using Object Deserialization

This method creates an object from a serialized form (a byte stream). It requires the class to
implement the Serializable interface.

Example:

import java.io.*;

public class Car implements Serializable {


private static final long serialVersionUID = 1L;
private String color;
private String model;

public Car(String color, String model) {


this.color = color;
this.model = model;
}

public void displayInfo() {


System.out.println("Car Model: " + model + ", Color: " + color);
}

public static void main(String[] args) {


try {
// Serialize the object
Car carToSerialize = new Car("Black", "Audi A4");
FileOutputStream fileOut = new FileOutputStream("car.ser");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(carToSerialize);
out.close();
fileOut.close();

// Deserialize the object


FileInputStream fileIn = new FileInputStream("car.ser");
ObjectInputStream in = new ObjectInputStream(fileIn);
Car deserializedCar = (Car) in.readObject();
in.close();
fileIn.close();

deserializedCar.displayInfo();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}

Output:

Car Model: Audi A4, Color: Black

5. Using a Factory Method


A factory method is a static method that returns an instance of a class. It encapsulates the object

creation process.

Example:

public class Car {


private String color;
private String model;

private Car(String color, String model) {


this.color = color;
this.model = model;
}

public void displayInfo() {


System.out.println("Car Model: " + model + ", Color: " + color);
}
public static class CarFactory {
public static Car createCar(String color, String model) {
return new Car(color, model);
}
}

public static void main(String[] args) {


Car myCar = Car.CarFactory.createCar("White", "Mercedes-Benz C-Class");
myCar.displayInfo();
}
}

Output:

Car Model: Mercedes-Benz C-Class, Color: White

Conclusion

These are five different ways to create objects in Java. Each method has its use cases and advantages,
and understanding these methods is crucial for effective Java programming.

Related Java Interview Guides:


Java Career Roadmap: How To Level Up From Junior To Senior Developer

How To Crack Java Developer Interviews Like A Pro Spring Vs Spring MVC Vs Spring Boot

Java Spring Boot Vs. Go (Golang) For Backend Development In 2025

Is Java Compiled Or Interpreted? Let’s Clear The Confusion!

Java JIT Compiler: Explained In Simple Words What Is JVM, JDK, And JRE?

Why Java Is The Platform Independent? (Interview Question And Answer)

Is Java A Pure Object-Oriented Language? (Java Interview Question And Answer)🤔

Is Java Case Sensitive? (Java Interview Question And Answer)

Why Is Java Secure? (Java Interview Question And Answer)

💪 Why Is Java Robust? (Java Interview Question And Answer)


Free Courses
on YouTube
Channel

175K
Subscribers

Java Design Patterns Interview Questions and


Answers
author: Ramesh Fadatare

DESIGN PATTERNS INTERVIEW

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

In this article, we will discuss the Java design patterns interview questions asked for experienced Java
developers.

Let's discuss the most useful and frequently asked interview questions of Java/Java EE design patterns.

1. Can you name a few design patterns used in


the standard JDK library?
Here is a list of design patterns used in Java's core libraries.
Abstract factory
Provide an interface for creating families of related or dependent objects without specifying their

concrete classes.

javax.xml.parsers.DocumentBuilderFactory#newInstance()

javax.xml.transform.TransformerFactory#newInstance()
javax.xml.xpath.XPathFactory#newInstance()

Builder

Separate the construction of a complex object from its representation so that the same construction
process can create different representations.

java.lang.StringBuilder#append() (unsynchronized)
java.lang.StringBuffer#append() (synchronized)

java.nio.ByteBuffer#put() (also on CharBuffer, ShortBuffer, IntBuffer, LongBuffer,


FloatBuffer and DoubleBuffer)
javax.swing.GroupLayout.Group#addComponent()

All implementations of java.lang.Appendable

Factory method

Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory
Method lets a class defer instantiation to subclasses.

java.util.Calendar#getInstance()
java.util.ResourceBundle#getBundle()
java.text.NumberFormat#getInstance()
java.nio.charset.Charset#forName()

java.net.URLStreamHandlerFactory#createURLStreamHandler(String) (Returns singleton


object per protocol)
java.util.EnumSet#of()
javax.xml.bind.JAXBContext#createMarshaller() and other similar methods

Prototype
Specify the kinds of objects to create using a prototypical instance, and create new objects by copying
this prototype.

java.lang.Object#clone() (the class has to implement java.lang.Cloneable)

Singleton

Ensure a class only has one instance, and provide a global point of access to it.

java.lang.Runtime#getRuntime()
java.awt.Desktop#getDesktop()
java.lang.System#getSecurityManager()

Read the complete list of design patterns used in standard JDK libraries at Examples of GoF Design
Patterns in Java's core libraries

2. What design patterns are used in the Spring


framework?
Here is a list of a few known design patterns used in Spring Framework.
Read more about each of the above design patterns in-detail at Design Patterns used in Spring
Framework

3. What are design patterns used in Hibernate


Framework?
Here is a list of a few known design patterns used in Hibernate Framework.

Read more about each of the above design patterns in-detail at Design Patterns used in Hibernate
Framework

4. What are the design patterns used in your


current projects?
You can explain the design patterns you have been using in yours with real-time scenarios.

5. What is a Singleton design pattern in Java?


Write code for a thread-safe singleton in Java
Here is a Solution.

6. What are the advantages of the Factory


Pattern and when to use the Factory Pattern?
Advantages of the Factory Design Pattern

Factory Method Pattern allows the sub-classes to choose the type of objects to create.

It promotes the loose-coupling by eliminating the need to bind application-specific classes into
the code. That means the code interacts solely with the resultant interface or abstract class so
that it will work with any classes that implement that interface or that extend that abstract class.

Use the Factory Method pattern when

a class can't anticipate the class of objects it must create

a class wants its subclasses to specify the objects it creates

classes delegate responsibility to one of several helper subclasses, and you want to localize the
knowledge of which helper subclass is the delegate

Read more about Factory design pattern at Factory Design Pattern in Java with Examples

7. Name a few Object-Oriented Design


Principles
1. Encapsulate What Varies
2. Code to an Interface Rather Than to an Implementation

3. Delegation Principle

4. The Open-Closed Principle (OCP)


5. Dry- Don't Repeat Yourself

6. Single Responsibility Principle (SRP)


7. Liskov's Substitution Principle (LSP)

8. Interface Segregation Principle (ISP)

9. Dependency Injection or Inversion Principle


Read more at Object-Oriented Design Principles in Java

8. What is the use of Design Patterns?


Design patterns can speed up the development process by providing tested, proven
development paradigms. Effective software design requires considering issues that may not

become visible until later in the implementation. Reusing design patterns helps to prevent

subtle issues that can cause major problems and improves code readability for coders and
architects familiar with the patterns.

Often, people only understand how to apply certain software design techniques to certain
problems. These techniques are difficult to apply to a broader range of problems. Design

patterns provide general solutions, documented in a format that doesn't require specifics tied to
a particular problem.

In addition, patterns allow developers to communicate using well-known, well-understood


names for software interactions. Common design patterns can be improved over time, making

them more robust than ad-hoc designs.

9. Name a few GOF design patterns?


The GoF Design Patterns are broken into three categories:

1. Creational Patterns for the creation of objects;

2. Structural Patterns to provide relationships between objects

3. Behavioral Patterns to help define how objects interact.

1. Creational Patterns
In software engineering, creational design patterns are design patterns that deal with object creation
mechanisms, trying to create objects in a manner suitable to the situation.

Singleton Design Pattern

Factory Design Pattern

Abstract Factory Design Pattern

Builder Design Pattern

Prototype Design Pattern


Object Pool Design Pattern

2. Structural Patterns
In Software Engineering, Structural Design Patterns are Design Patterns that ease the design by
identifying a simple way to realize relationships between entities.

Adapter Design Pattern

Bridge Design Pattern

Composite Design Pattern

Decorator Design Pattern

Facade Design Pattern

Flyweight Design Pattern

Proxy Design Pattern

3. Behavioral Patterns
In software engineering, behavioral design patterns are design patterns that identify common
communication patterns between objects and realize these patterns. By doing so, these patterns
increase flexibility in carrying out this communication.

Chain of responsibility

Command Design Pattern

Iterator Design Pattern

Mediator Design Pattern

Memento Design Pattern

Observer Design Pattern

State Design Pattern

Strategy Design Pattern

Template Method Design Pattern

Delegation Pattern

10. Name a few Java EE desgin patterns


List of Core J2EE Design Patterns referred from book Core J2EE Patterns: Best Practices and Design

Strategies (2nd Edition).

Presentation Tier

Intercepting Filter Design Pattern in Java

Front Controller Design Pattern in Java


Application Controller Design Pattern in Java

View Helper Design Pattern in Java

Composite View Design Pattern in Java


Context Object Design Pattern in Java

Business Tier

Data Transfer Object Design Pattern in Java

Service Locator Design Pattern in Java


Business Delegate Design Pattern in Java

Converter Design Pattern in Java


Transfer Object Assembler Pattern in Java

Value List Handler Pattern in Java

Integration Tier

Data Access Object Pattern in Java

Service Activator Pattern in Java

11. What is Singleton's design pattern and


when to use it?
Definition

Ensure a class only has one instance, and provide a global point of access to it.

Use the Singleton pattern when

there must be exactly one instance of a class, and it must be accessible to clients from a well-
known access point.

when the sole instance should be extensible by subclassing, and clients should be able to use an
extended instance without modifying their code.

12. What is the Builder design pattern and


when to use it?
Definition

Separate the construction of a complex object from its representation so that the same construction

process can create different representations.

Use the Builder pattern when

the algorithm for creating a complex object should be independent of the parts that make up

the object and how they're assembled.

the construction process must allow different representations for the object that's constructed.

Related Java Interview Articles


Spring Boot Interview Questions

Java Tricky Coding Interview Questions

Java String Interview Questions


Java String Tricky Coding Questions

Java main() Method Interview Questions


Java 8 Interview Questions

Top 10 Spring MVC Interview Questions

Java Array Interview Questions and Answers


Java OOPS Tricky Coding Questions

Java Programs Asked in Interview


OOPS Interview Questions and Answers

Hibernate Interview Questions

JPA Interview Questions and Answers


Java Design Patterns Interview Questions

Spring Core Interview Questions


Java Exception Handling Interview

Related Java Interview Guides:


Free Courses
on YouTube
Channel

175K
Subscribers

Java OOPS Concepts Interview Questions and


Answers for Beginners and Experienced
author: Ramesh Fadatare

CORE JAVA INTERVIEW JAVA OOPS

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

In this article, we will discuss important Java OOPS (Object Oriented Programming) interview
questions and answers for freshers as well as experienced candidates.

Is Java a pure object-oriented programming


language?
There are a lot of arguments around whether Java is purely object-oriented or not. Well, Java is not a
pure OOP language due to two reasons:

The first reason is that the Object-oriented programming language should only have objects whereas

Java contains 8 primitive data types char, boolean, byte, short, int, long, float, and double which
are not objects. These primitive data types can be used without the use of any object.
For example:

public class IsJavaFullyOOPS {


public static void main(String[] args) {
int i = 10;
byte b = 20;
short s = 30;
long l = 100L;
double d = 100.10;
float f = 200f;
boolean flag = true;
char c = 'R';
System.out.println(i);
System.out.println(b);
System.out.println(s);
System.out.println(l);
System.out.println(d);
System.out.println(l);
System.out.println(d);
System.out.println(f);
System.out.println(flag);
System.out.println(c);
}
}

Output:

10
20
30
100
100.1
100
100.1
200.0
true
R
The second reason is related to the static keyword. In a pure object-oriented language, we should

access everything by message passing (through objects). But Java contains static variables and

methods that can be accessed directly without using objects.

For example:

public class IsJavaFullyOOPS {


private static String message = "hello";
public static void main(String[] args) {

// calling message instance variable without object


System.out.println(message);

// calling demo static method without object


demo();
}

private static String demo(){


return "hello from method";
}
}

What are Core OOPS Concepts?


Core OOPS concepts:

Object
Class
Abstraction

Encapsulation
Inheritance
Polymorphism

Advanced OOPS concepts:

Composition
Aggregation
Association
Cohesion
Coupling
Delegation

What is Method Overloading in OOP (Java)?


In Java, if the class has two or more methods having the same name but different parameters, this
process is known as Method Overloading.

Here is a simple example that illustrates method overloading:

package com.javaguides.corejava.basics.polymorphism;

public class MethodOverloading {


public static void main(String[] args) {
OverloadDemo ob = new OverloadDemo();
double result; // call all versions of test()
ob.test();
ob.test(10);
ob.test(10, 20);
result = ob.test(123.25);
System.out.println("Result of ob.test(123.25): " + result);
}
}

// Demonstrate method overloading.


class OverloadDemo {
void test() {
System.out.println("No parameters");
}

// Overload test for one integer parameter.


void test(int a) {
System.out.println("a: " + a);
}

// Overload test for two integer parameters.


void test(int a, int b) {
System.out.println("a and b: " + a + " " + b);
}

// Overload test for a double parameter


double test(double a) {
System.out.println("double a: " + a);
return a * a;
}
}

Output:

No parameters
a: 10
a and b: 10 20
double a: 123.25
Result of ob.test(123.25): 15190.5625

The compiler will resolve the call to a correct overloaded method depending on the actual number
and/or types of the passed parameters. We can use Method overloading to achieve Java compile-
time polymorphism.

The main advantage of method overloading increases the readability of the program.

There are four main rules that govern method overloading:

1. Method overloading is accomplished by changing the method parameters

2. Return type is not a part of method signature

3. We can overload private , static and final methods

4. We overload method within the same class.

A famous example of method overloading is System.out.println() .

The println() has several overloaded methods. For example:

public void println() {


// logic goes here
}

public void println(String x) {


// logic goes here
}

public void println(boolean x) {


// logic goes here
}

public void println(int x) {


// logic goes here
}
public void println(char x) {
// logic goes here
}

Read more about method overloading at Method Overloading in Java

What is Method Overriding in OOP (Java)?


In a Java class hierarchy, when a method in a subclass has the same name and type signature as a
method in its superclass, then the method in the subclass is said to override the method in the

superclass. Method overriding can be used in the presence of Inheritance or Runtime


Polymorphism.

Java decided at the runtime the actual method that should be called depending upon the type of
object we create. For example:

public class MethodOverriding {


public static void main(String args[]) {
SuperClass superClass = new SubClass();
superClass.method1("hello");
}
}

class SuperClass {
void method1(String message) {
System.out.println(message);
}
}
class SubClass extends SuperClass {
void method1(String message) {
message = message + " in SubClass";
System.out.println(message);
}
}
Output:

hello in SubClass

Another example:

class Shape {
void draw() {
System.out.println("drawing...");
}
}
class Rectangle extends Shape {
void draw() {
System.out.println("drawing rectangle...");
}
}
class Circle extends Shape {
void draw() {
System.out.println("drawing circle...");
}
}
class Triangle extends Shape {
void draw() {
System.out.println("drawing triangle...");
}
}
class TestPolymorphism2 {
public static void main(String args[]) {
Shape s;
s = new Rectangle();
s.draw();
s = new Circle();
s.draw();
s = new Triangle();
s.draw();
}
}

Output:

drawing rectangle...
drawing circle...
drawing triangle...
Here are the main rules that govern method overriding:
1. The name and signature of the method are the same in the superclass and subclass, or in the

interface and its implementations.


2. We can't override a method in the same class (but we can overload it in the same class)

3. We can't override private , static, and final methods

4. The overriding method cannot reduce the accessibility of the overridden method, but the opposite

is possible
5. The overriding method cannot throw checked exceptions that are higher in the exception

hierarchy than the checked exception thrown by the overridden method

6. Always use the @Override annotation for the overriding method.

How can the superclass overridden method be


called from the subclass overriding method?
We can call the superclass overridden method from the subclass overriding method via the Java
super keyword.

For example:

// Method overriding.
class A {
int i, j;
A(int a, int b) {
i = a;
j = b;
}
// display i and j
void show() {
System.out.println("i and j: " + i + " " + j);
}
}

class B extends A {
int k;
B(int a, int b, int c) {
super(a, b);
k = c;
}
void show() {
super.show(); // this calls A's show()
System.out.println("k: " + k);
}
}

Output:

i and j: 1 2
k: 3

Here, super.show( ) calls the superclass version of show( ) .

Can we override or overload the main()


method?
As we know that the main() method is static so we can overload it but we can't override it.

Because the static methods are resolved at compile-time, while the methods that we can override are

resolved at runtime depending upon the type of the object.

The below diagram demonstrates that the main() method can be overloaded:
Can we override a non-static method as static
in Java?
No. we cannot override a non-static method as a static one. If we try then it leads to a compilation

error:

Can you achieve Runtime Polymorphism by


data members?
No, we cannot achieve runtime polymorphism by data members. The method is overridden not the
data members, so runtime polymorphism can not be achieved by data members.

In the example given below, both the classes have a data member speedlimit , we are accessing the

data member by the reference variable of the Parent class which refers to the subclass object. Since

we are accessing the data member which is not overridden, hence it will access the data member of

the Parent class always.

Runtime polymorphism can't be achieved by data members

class Bike {
int speedlimit = 90;
}
class Honda extends Bike {
int speedlimit = 150;

public static void main(String args[]) {


Bike obj = new Honda();
System.out.println(obj.speedlimit); //90
}
}

Output:

90

What is Abstraction and give a real-world


example?
Abstraction exposes to the user only those things that are relevant to them and hides the remainder

of the details. In OOP terms, we say that an object should expose to the users only a set of high-level;

operations, while the internal implementation of those operations is hidden.

Abstraction is achieved in Java via abstract classes and interfaces

Let's consider a real-life example: a man driving a car. The man knows what each pedal does and what

the steering wheel does, but he doesn't know how these things are done internally by the car. He
doesn't know about the inner mechanisms that empower these things. This is known as abstraction.
Code example: Let's create a Car interface with high-level methods:

public interface Car {

public void speedUp();

public void slowDown();

public void turnRight();

public void turnLeft();

public String getCarType();


}

Next, each type of car should implement the Car interface and override these methods to provide

the implementation of these methods. This implementation is hidden from the user.

For example, here is the ElectricCar class implementation:

public class ElectricCar implements Car {

private final String carType;

public ElectricCar(String carType) {


this.carType = carType;
}

@Override
public void speedUp() {
System.out.println("Speed up the electric car");
}

@Override
public void slowDown() {
System.out.println("Slow down the electric car");
}

@Override
public void turnRight() {
System.out.println("Turn right the electric car");
}

@Override
public void turnLeft() {
System.out.println("Turn left the electric car");
}

@Override
public String getCarType() {
return this.carType;
}
}

The user of this class has access to these public methods without being aware of the implementation:

public class Main {

public static void main(String[] args) {

Car electricCar = new ElectricCar("BMW");

System.out.println("Driving the electric car: " + electricCar.getCarType() + "\n");


electricCar.speedUp();
electricCar.turnLeft();
electricCar.slowDown();
}
}

So, this was an example of abstraction via an interface.

What is Encapsulation and give a real-world


example?
Encapsulation refers to combining data and associated functions as a single unit. In OOP, data and

functions operating on that data are combined together to form a single unit, which is referred to as a

class.

Encapsulation is the technique whereby the object's state is hidden from the outer world and a set of
public methods for accessing this state are exposed. When each object keeps its state private inside a
class, we can say that encapsulation was achieved. This is why encapsulation is also referenced as the

data-hiding mechanism.

Encapsulation has a number of important advantages such as loosely coupled, reusable, secure, and

easy-to-test code.

In Java, encapsulation is implemented via the access modifiers - public, private, and protected.

Let's consider an example: a Cat class can have its state represented by fields such as mood,

hungry, and energy. While the code external to the Cat class cannot modify any of these fields

directly, it can call public methods play() , feed() , and sleep() that modify the Cat state

internally.

The Cat class may also have private methods that are not accessible outside the class, such as

meow() . This is encapsulation.

public class Cat {

private int mood = 50;


private int hungry = 50;
private int energy = 50;

public void sleep() {


System.out.println("Sleep ...");
energy++;
hungry++;
}

public void play() {


System.out.println("Play ...");
mood++;
energy--;
meow();
}

public void feed() {


System.out.println("Feed ...");
hungry--;
mood++;
meow();
}
private void meow() {
System.out.println("Meow!");
}

public int getMood() {


return mood;
}

public int getHungry() {


return hungry;
}

public int getEnergy() {


return energy;
}
}

The only way to modify the state (private fields) is via the public methods play() , feed() , and

sleep() , as in the following example:

public class Main {

public static void main(String[] args) {

Cat cat = new Cat();

cat.feed();
cat.play();
cat.feed();
cat.sleep();

System.out.println("Energy: " + cat.getEnergy());


System.out.println("Mood: " + cat.getMood());
System.out.println("Hungry: " + cat.getHungry());
}
}

The output will be as follows:

Feed ...
Meow!
Play ...
Meow!
Feed ...
Meow!
Sleep ...
Energy: 50
Mood: 53
Hungry: 49

What is Inheritance?
Inheritance is the process by which one object acquires the properties of another object.

Inheritance - IS-A relationship between a superclass and its subclasses. The process where one object

acquires the properties of another object plus it can have its own.

Let's consider a Dog, the Dog (subclass) is a type of Animal (superclass). So Dog can inherit (reuse)

members of the Animal class; plus it can have its own new behavior and properties.

In the Java library, you can see extensive use of inheritance. The below figure shows a partial
inheritance hierarchy from java.lang library. The Number class abstracts various numerical

(reference) types such as Byte , Integer , Float , Double , Short , and BigDecimal .

What is Composition?
A Composition is an association that represents a part of a whole relationship where a part cannot

exist without a whole. If a whole is deleted then all parts are deleted. It has a stronger relationship.
Read more about Composition with a complete example at Composition in Java with Example.

What is Aggregation?
Aggregation is an association that represents a part of a whole relationship where a part can exist
without a whole. It has a weaker relationship.

It is a specialized form of Association where all object has their own lifecycle but there is ownership.
This represents a “whole-part or a-part-of” relationship.

Let’s take an example of the relationship between the Department and the Teacher . A Teacher

may belong to multiple departments. Hence Teacher is a part of multiple departments. But if we

delete a Department then the Teacher Object will not destroy.

Read more at Aggregation in Java with Examples.

What is a SOLID OOPS Principle?


SOLID is one of the most popular sets of design principles in object-oriented software development.

It’s a mnemonic acronym for the following five design principles:

Single Responsibility Principle - A class should have only one reason to change

Open/Closed Principle - Software entities like classes, modules, and functions should be open
for extension but closed for modifications.

Liskov Substitution Principle - Derived types must be completely substitutable for their base

types.

Interface Segregation Principle - The Interface Segregation Principle states that clients should
not be forced to implement interfaces they don't use. ISP splits interfaces that are very large into

smaller and more specific ones so that clients will only have to know about the methods that are

of interest to them.

Dependency Inversion Principle - High-level modules should not depend on low-level modules.

Both should depend on abstractions.

What is the Single Responsibility Principle?


"A class should have only one reason to change". Every class should have a single responsibility, and

that responsibility should be entirely encapsulated by the class. There should never be more than one
reason for a class to change.

Read more about the Single Responsibility Principle with an example at Single Responsibility
Principle.

What is the Open-Closed Principle?


Software entities like classes, modules, and functions should be open for extension but closed for

modifications.

Read more about Open Closed Principle with an example at Open Closed Principle

What is the Liskov Substitution Principle?


Derived types must be completely substitutable for their base types.

Read more about Liskov Substitution Principle with an example of Liskov's Substitution Principle

What is the Interface Segregation Principle?


The Interface Segregation Principle states that clients should not be forced to implement interfaces
they don't use. ISP splits interfaces that are very large into smaller and more specific ones so that

clients will only have to know about the methods that are of interest to them.
Read more about Interface Segregation Principle with an example at Interface Segregation

Principle

What is the Dependency Inversion Principle?


Entities must depend on abstractions, not on concretions. It states that the high-level module must

not depend on the low-level module, but should depend on abstractions.

Related Java Interview Articles


Spring Boot Interview Questions

Java Tricky Coding Interview Questions

Java String Interview Questions


Java String Tricky Coding Questions

Java main() Method Interview Questions

Java 8 Interview Questions

Top 10 Spring MVC Interview Questions

Java OOPS Tricky Coding Questions


Java Programs Asked in Interview

OOPS Interview Questions and Answers

Hibernate Interview Questions

JPA Interview Questions and Answers

Java Design Patterns Interview Questions


Spring Core Interview Questions

Java Exception Handling Interview

Related Java Interview Guides:


Java Career Roadmap: How To Level Up From Junior To Senior Developer

How To Crack Java Developer Interviews Like A Pro Spring Vs Spring MVC Vs Spring Boot

Java Spring Boot Vs. Go (Golang) For Backend Development In 2025

Is Java Compiled Or Interpreted? Let’s Clear The Confusion!

Java JIT Compiler: Explained In Simple Words What Is JVM, JDK, And JRE?
Free Courses
on YouTube
Channel

175K
Subscribers

Top Java 11 Interview Questions


author: Ramesh Fadatare

INTERVIEW JAVA 11

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

Java 11, released in September 2018, brought a host of new features and enhancements that have
been crucial for developers. If you're preparing for a job interview that involves Java 11, it’s essential

to be familiar with its key features, improvements, and best practices. This blog post will cover some
of the most commonly asked Java 11 interview questions to help you prepare effectively.

1. What are the new features introduced in Java 11?

Answer: Java 11 introduced several new features and enhancements, including:


Local-Variable Syntax for Lambda Parameters: Allows the use of var in lambda expressions.

New String Methods: isBlank(), lines(), strip(), stripLeading(), stripTrailing(),

and repeat().

File Methods: readString() and writeString().

Optional Methods: isEmpty(), ifPresentOrElse(), or(), and stream().

HTTP Client: Standardized the HTTP Client API that was introduced in Java 9 as an incubator

module.
Nest-Based Access Control: Introduced to support the improved encapsulation of nested

classes.
Deprecation of Nashorn JavaScript Engine: Marked for removal.
Epsilon Garbage Collector: A no-op garbage collector for testing.

2. How do you use the var keyword in Java 11?


Answer: In Java 11, the var keyword can be used for local variable type inference in lambda

expressions. This means you can declare the type of lambda parameters using var, making the code

more concise and readable.

Example:

import java.util.List;

public class VarLambdaExample {


public static void main(String[] args) {
List<String> list = List.of("Java", "Kotlin", "Scala");

list.forEach((var item) -> System.out.println(item));


}
}

3. What are the new methods added to the String class in Java
11?
Answer: Java 11 introduced several new methods to the String class:

isBlank(): Returns true if the string is empty or contains only white space code points.

lines(): Returns a stream of lines extracted from the string, separated by line terminators.

strip(): Removes leading and trailing white space.

stripLeading(): Removes leading white space.


stripTrailing(): Removes trailing white space.

repeat(int count): Returns a string whose value is the concatenation of this string repeated

count times.

Example:

public class StringMethodsExample {


public static void main(String[] args) {
String str = " Java 11 ";
System.out.println(str.isBlank()); // false
System.out.println(str.strip()); // "Java 11"
System.out.println(str.stripLeading()); // "Java 11 "
System.out.println(str.stripTrailing()); // " Java 11"
System.out.println("Java\nKotlin\nScala".lines().count()); // 3
System.out.println("Hello ".repeat(3)); // "Hello Hello Hello "
}
}

4. Explain the new methods added to the Optional class in Java


11.

Answer: Java 11 added several new methods to the Optional class:

isEmpty(): Returns true if the value is not present.

ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction): If a value is

present, performs the given action with the value, otherwise performs the given empty-based
action.

or(Supplier<? extends Optional<? extends T>> supplier): If a value is present, returns

an Optional describing the value, otherwise returns an Optional produced by the supplying

function.
stream(): If a value is present, returns a sequential Stream containing only that value,

otherwise returns an empty Stream.

Example:

import java.util.Optional;

public class OptionalMethodsExample {


public static void main(String[] args) {
Optional<String> opt = Optional.of("Java 11");

System.out.println(opt.isEmpty()); // false

opt.ifPresentOrElse(
value -> System.out.println("Value: " + value),
() -> System.out.println("Value is absent")
);

Optional<String> orOpt = Optional.<String>empty().or(() -> Optional.of("Default"));


System.out.println(orOpt.get()); // "Default"

opt.stream().forEach(System.out::println); // "Java 11"


}
}

5. What is the HTTP Client API in Java 11, and how do you use
it?
Answer: The HTTP Client API, introduced in Java 9 as an incubator module and standardized in Java

11, provides a modern and easy-to-use HTTP client. It supports both synchronous and asynchronous
operations, and also HTTP/1.1 and HTTP/2.

Example:

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;

public class HttpClientExample {


public static void main(String[] args) throws Exception {
HttpClient client = HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_2)
.connectTimeout(Duration.ofSeconds(10))
.build();

HttpRequest request = HttpRequest.newBuilder()


.uri(new URI("https://postman-echo.com/get"))
.GET()
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofSt

System.out.println("Status Code: " + response.statusCode());


System.out.println("Response Body: " + response.body());
}
}

6. What is the Epsilon Garbage Collector, and when would you


use it?
Answer: The Epsilon Garbage Collector is a no-op garbage collector introduced in Java 11. It handles

memory allocation but does not reclaim any memory. It is mainly used for performance testing and
benchmarking where garbage collection overhead needs to be minimized.

Example Usage: To enable the Epsilon Garbage Collector, you can start your Java application with the
following JVM option:

java -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC -Xmx2g -Xms2g -jar myapp.jar

7. How do you read and write strings from/to files in Java 11?
Answer: Java 11 introduced Files.readString() and Files.writeString() methods for reading

and writing strings to files, simplifying file I/O operations.

Example:

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

public class FileReadWriteExample {


public static void main(String[] args) throws Exception {
Path path = Paths.get("example.txt");

// Writing a string to a file


Files.writeString(path, "Hello, Java 11!");

// Reading a string from a file


String content = Files.readString(path);
System.out.println(content); // "Hello, Java 11!"
}
}

8. What is Nest-Based Access Control in Java 11?

Answer: Nest-Based Access Control is a feature introduced in Java 11 that improves the access
control mechanism between nested classes. It allows nested classes to access private members of

other nested classes within the same outer class.

Example:

public class OuterClass {


private String outerField = "Outer";

class InnerClass {
private String innerField = "Inner";

private void innerMethod() {


System.out.println(outerField);
}
}

private void outerMethod() {


InnerClass inner = new InnerClass();
System.out.println(inner.innerField);
}
}

9. Explain the isBlank() method in Java 11.


Answer: The isBlank() method is a new method added to the String class in Java 11. It returns

true if the string is empty or contains only white space code points, otherwise false.

Example:

public class StringIsBlankExample {


public static void main(String[] args) {
String str1 = " ";
String str2 = "Java 11";

System.out.println(str1.isBlank()); // true
System.out.println(str2.isBlank()); // false
}
}

10. How does Java 11 improve the Optional class?

Answer: Java 11 improves the Optional class by adding several useful methods:

isEmpty(): Returns true if no value is present, otherwise false.

ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction): Performs the

given action with the value if present, otherwise performs the given empty-based action.
or(Supplier<? extends Optional<? extends T>> supplier): If a value is present, returns

an Optional describing the value, otherwise returns an Optional produced by the supplying

function.

stream(): If a value is present, returns a sequential Stream containing only that value,

otherwise returns an empty Stream.

Example:

import java.util.Optional;

public class OptionalMethodsExample {


public static void main(String[] args) {
Optional<String> opt = Optional.of("Java 11");

System.out.println

(opt.isEmpty()); // false

opt.ifPresentOrElse(
value -> System.out.println("Value: " + value),
() -> System.out.println("Value is absent")
);

Optional<String> orOpt = Optional.<String>empty().or(() -> Optional.of("Default"));


System.out.println(orOpt.get()); // "Default"

opt.stream().forEach(System.out::println); // "Java 11"


}
}
Conclusion
Java 11 brought many new features and improvements that enhance developer productivity and code

readability. Understanding these features is crucial for any Java developer, especially when preparing
for an interview. This blog post covered some of the most commonly asked Java 11 interview

questions, helping you prepare effectively for your next interview. By mastering these concepts, you
will be well-equipped to tackle any Java 11-related challenges you may encounter.

Related Java Interview Guides:


Java Career Roadmap: How To Level Up From Junior To Senior Developer

How To Crack Java Developer Interviews Like A Pro Spring Vs Spring MVC Vs Spring Boot

Java Spring Boot Vs. Go (Golang) For Backend Development In 2025

Is Java Compiled Or Interpreted? Let’s Clear The Confusion!

Java JIT Compiler: Explained In Simple Words What Is JVM, JDK, And JRE?

Why Java Is The Platform Independent? (Interview Question And Answer)

Is Java A Pure Object-Oriented Language? (Java Interview Question And Answer)🤔

Is Java Case Sensitive? (Java Interview Question And Answer)

Why Is Java Secure? (Java Interview Question And Answer)

💪 Why Is Java Robust? (Java Interview Question And Answer)

Why Is Java Architecture Neutral? (Java Interview Question And Answer)

Why Is Java Called Portable? Why Java Does Not Support Multiple Inheritance?

Why Java Does Not Support Pointers? Is Java Pass-By-Value Or Pass-By-Reference?

Why Is Main() Method Public Static In Java? (Here’s The Real Truth!)

Can We Overload The Main() Method In Java? (Java Interview Question And Answe

Can We Make The Main() Method Final In Java? (Java Interview Question And Answer)

What Is String Constant Pool In Java? | Explained With Examples


Free Courses
on YouTube
Channel

175K
Subscribers

Java 21 Interview Questions


author: Ramesh Fadatare

INTERVIEW JAVA

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

Java 21, the latest release in the Java platform, brings numerous new features, enhancements, and
performance improvements. If you're preparing for a job interview that involves Java 21, it's essential

to understand its core concepts, new features, and best practices. This blog post covers some of the
most commonly asked Java 21 interview questions and answers to help you prepare effectively.

1. What are the key new features introduced in Java 21?

Answer: Java 21 introduces several new features and enhancements, including:

Pattern Matching for switch: Enhanced pattern matching capabilities in switch statements.
Sequenced Collections: A new collection type that maintains insertion order.
Virtual Threads (Project Loom): Lightweight threads for better scalability in concurrent

applications.
Record Patterns: Improved pattern matching with records.
String Templates (Preview): Simplified string interpolation for creating formatted strings.

Foreign Function & Memory API: Enhanced support for interfacing with non-Java code and
memory.

Universal Generics (Preview): Enhanced generics that can work with primitives.

2. What is Pattern Matching for Switch in Java 21, and how


does it work?

Answer: Pattern Matching for a switch in Java 21 extends the switch statement and expression with
pattern matching capabilities. This allows more concise and readable code when working with

different types and conditions.

Example:

public String formatShape(Object shape) {


return switch (shape) {
case Circle c -> "Circle with radius " + c.radius();
case Rectangle r -> "Rectangle with width " + r.width() + " and height " + r.height
case null -> "Unknown shape";
default -> "Unknown shape type";
};
}

In this example, the switch statement matches the type of the shape variable and binds it to a variable

(c or r) if it matches the specified type.

3. What are Sequenced Collections in Java 21?

Answer: Sequenced Collections in Java 21 are a new type of collection that maintains the order of
elements based on their insertion order. They provide methods for accessing elements by their order

and for iterating over the elements in insertion order.

Example:
import java.util.SequencedCollection;
import java.util.SequencedHashSet;

SequencedCollection<String> sequencedCollection = new SequencedHashSet<>();


sequencedCollection.add("A");
sequencedCollection.add("B");
sequencedCollection.add("C");

for (String element : sequencedCollection) {


System.out.println(element); // Output: A B C
}

4. What are Virtual Threads in Java 21, and how do they


improve concurrency?

Answer: Virtual Threads, introduced as part of Project Loom in Java 21, are lightweight threads that
provide better scalability for concurrent applications. Unlike traditional platform threads, virtual
threads are managed by the Java runtime and can handle a large number of concurrent tasks with

lower overhead.

Example:

public void runConcurrentTasks() throws InterruptedException {


ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
List<Callable<String>> tasks = List.of(
() -> "Task 1",
() -> "Task 2",
() -> "Task 3"
);

List<Future<String>> results = executor.invokeAll(tasks);


for (Future<String> result : results) {
System.out.println(result.get()); // Output: Task 1 Task 2 Task 3
}
executor.shutdown();
}

5. What are Record Patterns in Java 21, and how are they used?
Answer: Record Patterns in Java 21 enhance pattern matching by allowing patterns to be used with

records. This simplifies the extraction of values from record instances.


Example:

public record Point(int x, int y) {}

public void printPoint(Object obj) {


if (obj instanceof Point(int x, int y)) {
System.out.println("Point coordinates: (" + x + ", " + y + ")");
} else {
System.out.println("Not a point");
}
}

Point point = new Point(1, 2);


printPoint(point); // Output: Point coordinates: (1, 2)

6. How do String Templates work in Java 21?

Answer: String Templates (introduced as a preview feature) simplify string interpolation by allowing
embedded expressions within string literals. This makes it easier to create formatted strings.

Example:

int x = 10;
int y = 20;
String message = STR."The sum of \{x} and \{y} is \{x + y}";
System.out.println(message); // Output: The sum of 10 and 20 is 30

7. What is the Foreign Function & Memory API in Java 21?


Answer: The Foreign Function & Memory API in Java 21 provides enhanced support for interfacing

with non-Java code and managing native memory. This API allows Java programs to call native
functions and manipulate native memory safely and efficiently.

Example:

import jdk.incubator.foreign.*;

public class ForeignMemoryExample {


public static void main(String[] args) {
try (MemorySegment segment = MemorySegment.allocateNative(100)) {
MemoryAccess.setIntAtOffset(segment, 0, 42);
int value = MemoryAccess.getIntAtOffset(segment, 0);
System.out.println("Value: " + value); // Output: Value: 42
}
}
}

8. What are Universal Generics in Java 21?

Answer: Universal Generics (introduced as a preview feature) enhance Java generics to work with both
reference types and primitive types. This allows for more flexible and efficient generic programming.

Example:

public class UniversalGenericExample {


public static <T> T identity(T value) {
return value;
}

public static void main(String[] args) {


int intValue = identity(42);
String stringValue = identity("Hello");
System.out.println("Int: " + intValue + ", String: " + stringValue); // Output: Int
}
}

9. What improvements have been made to the Java language in


Java 21?

Answer: Java 21 includes several language improvements, such as:

Enhanced Pattern Matching: Improved support for pattern matching in various constructs.

Sequenced Collections: Introduction of sequenced collections that maintain insertion order.


String Templates: Simplified string interpolation with embedded expressions.

Universal Generics: Enhanced generics for both reference and primitive types.
New and Enhanced APIs: Improvements to existing APIs and introduction of new APIs for

better functionality and performance.

10. How do you migrate a project to Java 21?


Answer: To migrate a project to Java 21, follow these steps:
1. Update JDK: Download and install the Java 21 JDK.
2. Update Build Tools: Ensure that your build tools (e.g., Maven, Gradle) are compatible with Java

21.
3. Update Project Settings: Update your project's settings to use the Java 21 JDK.

4. Refactor Code: Refactor your code to take advantage of new features and improvements in
Java 21.

5. Run Tests: Run your project's tests to ensure compatibility and correctness.

6. Address Deprecations: Address any deprecated APIs or features that have been removed or
changed in Java 21.

Example (Maven pom.xml update):

<properties>
<java.version>21</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>21</source>
<target>21</target>
</configuration>
</plugin>
</plugins>
</build>

Conclusion
Java 21 brings many new features and enhancements that improve the language's expressiveness,
performance, and ease of use. Understanding these new features and how to leverage them in your

projects is crucial for any Java developer. This blog post covered some of the most commonly asked

Java 21 interview questions, helping you prepare effectively for your next interview. By mastering
these concepts, you will be well-equipped to tackle any Java 21-related challenges you may

encounter.
Free Courses
on YouTube
Channel

175K
Subscribers

Java 8 Interview Questions and Answers


author: Ramesh Fadatare

INTERVIEW JAVA 8

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

In this article, we will discuss some important and frequently asked Java 8 Interview Questions and
Answers.

Learn everything about Java 8 at Java 8 Tutorial

YouTube Video
Java 8 Interview Questions and Answers ( Demonstrated with Live Exa…
Exa…
Share

Watch on

1. What new features were added in Java 8?


In Java 8, the following new features were added:

Lambda Expressions − lambda expression is a function that can be referenced and passed

around as an object

Method References − Method references are the references that use a function as a parameter
to request a method.

Optional − This class is to provide a type-level solution for representing optional values instead
of using null references.

Functional Interface – An Interface that contains exactly one abstract method

and implementation can be provided using a Lambda Expression

Default methods − give us the ability to add full implementations in interfaces besides abstract

methods

Stream API − Stream API provides a functional approach to processing collections of objects.

Date and Time API − an improved, immutable JodaTime-inspired Date API

Nashorn, JavaScript Engine − Java-based engine for executing and evaluating JavaScript code

Along with these new features, lots of feature enhancements are done under-the-hood, at both
compiler and JVM levels.

The below diagram shows all the Java 8 features and enhancements.
2. What is a Lambda Expression?
The lambda expression is simply a function without any name. It can even be used as a parameter in a

function. Lambda Expression facilitates functional programming and simplifies development a lot.

The main use of Lambda expression is to provide an implementation for functional interfaces.

For example, Lambda expression provides an implementation for a Printable functional interface
interface Printable {
void print(String msg);
}

public class JLEExampleSingleParameter {

public static void main(String[] args) {


// without lambda expression
Printable printable = new Printable() {
@Override
public void print(String msg) {
System.out.println(msg);
}
};
printable.print(" Print message to console....");

// with lambda expression


Printable withLambda = (msg) -> System.out.println(msg);
withLambda.print(" Print message to console....");
}
}

Output :

Print message to console....


Print message to console....

Example 2, Create a method that takes a lambda expression as a parameter:

interface StringFunction {
String run(String str);
}

public class Main {


public static void main(String[] args) {
StringFunction exclaim = (s) -> s + "!";
StringFunction ask = (s) -> s + "?";
printFormatted("Hello", exclaim);
printFormatted("Hello", ask);
}
public static void printFormatted(String str, StringFunction format) {
String result = format.run(str);
System.out.println(result);
}
}

Example 3, Pass lambda expression as an argument to the constructor

static Runnable runnableLambda = () -> {


System.out.println("Runnable Task 1");
System.out.println("Runnable Task 2");
};
//Pass lambda expression as argument
new Thread(runnableLambda).start();

Read more in detail about lambda expressions at Java 8 Lambda Expressions

3. Why use Lambda Expression?


1. Facilitates functional programming - Lambda Expression facilitates functional programming

and simplifies the development a lot.


2. To provide the implementation of the Java 8 Functional Interface.

3. Reduced Lines of Code - One of the clear benefits of using lambda expression is that the

amount of code is reduced, we have already seen how easily we can create instances of a
functional interface using lambda expression rather than using an anonymous class.

4. Passing Behaviors into methods - Lambda Expressions enable you to encapsulate a single unit
of behavior and pass it to other code. For example, to other methods or constructors.

Read more in detail about lambda expressions at Java 8 Lambda Expressions.

4. Explain Lambda Expression Syntax


Java Lambda Expression Syntax:

(argument-list) -> {body}

Java lambda expression consists of three components.

Argument list: It can be empty or non-empty as well.

Arrow-token: It is used to link arguments list and body of expression.

Body: It contains expressions and statements for the lambda expression.


For example, Consider we have a functional interface:

interface Addable{
int add(int a,int b);
}

Let's implement the above Addable functional interface using a lambda expression:

Addable withLambdaD = (int a,int b) -> (a+b);


System.out.println(withLambdaD.add(100,200));

Read more in detail about lambda expressions at Java 8 Lambda Expressions.

5. What is a functional interface?


An Interface that contains exactly one abstract method is known as a functional interface. It can
have any number of default, static methods but can contain only one abstract method. It can also

declare the methods of the object class.

Functional Interface is also known as Single Abstract Method Interfaces or SAM Interfaces. A

functional interface can extend another interface only when it does not have any abstract method.

Java 8 provides predefined functional interfaces to deal with functional programming by using

lambda and method references.

For example:

interface Printable {
void print(String msg);
}

public class JLEExampleSingleParameter {

public static void main(String[] args) {


// with lambda expression
Printable withLambda = (msg) -> System.out.println(msg);
withLambda.print(" Print message to console....");
}
}
Output :

Print message to console....

Read more at Java 8 Functional Interfaces with Examples.

6. Is it possible to define our own Functional


Interface? What is @FunctionalInterface? What
are the rules to define a Functional Interface?
Yes, it is possible to define our own Functional Interfaces. We use Java 8 to provide

the @FunctionalInterface annotation to mark an interface as a Functional Interface.

We need to follow these rules to define a Functional Interface:

Define an interface with one and only one abstract method.

We cannot define more than one abstract method.

Use @FunctionalInterface annotation in the interface definition.

We can define any number of other methods like default methods, static methods.

The below example illustrates defining our own Functional Interface:

Let's create a Sayable interface annotated with @FunctionalInterface annotation.

@FunctionalInterface
interface Sayable{
void say(String msg); // abstract method
}

Let's demonstrate a custom functional interface via the main( ) method.

public class FunctionalInterfacesExample {

public static void main(String[] args) {

Sayable sayable = (msg) -> {


System.out.println(msg);
};
sayable.say("Say something ..");
}
}

Read more at Java 8 Functional Interfaces with Examples.

7. Name some of the functional interfaces in


the standard library
In Java 8, there are a lot of functional interfaces introduced in the java.util.function package and

the more common ones include but are not limited to:

Function – it takes one argument and returns a result

Consumer – it takes one argument and returns no result (represents a side effect)

Supplier – it takes no argument and returns a result

Predicate – it takes one argument and returns a boolean

BiFunction – it takes two arguments and returns a result

BiConsumer - it takes two (reference type) input arguments and returns no result

BinaryOperator – it is similar to a BiFunction, taking two arguments and returning a result. The

two arguments and the result are all of the same types

UnaryOperator – it is similar to a Function, taking a single argument and returning a result of

the same type

Runnable : use to execute the instances of a class over another thread with no arguments and no

return value.

Callable : use to execute the instances of a class over another thread with no arguments and it

either returns a value or throws an exception.

Comparator : use to sort different objects in a user-defined order

Comparable : use to sort objects in the natural sort order

For more on functional interfaces, see the article at Java 8 Functional Interfaces
with Examples.

8. What is a method reference?


Method reference is used to refer method of the functional interface. It is a compact and easy form

of lambda expression. Each time when you are using a lambda expression to just referring a method,
you can replace your lambda expression with a method reference.

Below are a few examples of method references:

(o) -> o.toString();

can become:

Object::toString();

A method reference can be identified by a double colon separating a class or object name and the

name of the method. It has different variations such as constructor reference:

String::new;

Static method reference:

String::valueOf;

Bound instance method reference:

str::toString;

Unbound instance method reference:

String::toString;

You can read a detailed description of method references with full examples at Java 8 Method

References.

9. What are different kinds of Method


References?
There are four kinds of method references:
1. Reference to a static method. For example:

ContainingClass::staticMethodName

2. Reference to an instance method of a particular object. For example:

containingObject::instanceMethodName

3. Reference to an instance method of an arbitrary object of a particular type. For example:

ContainingType::methodName

4. Reference to a constructor. for example:

ClassName::new

You can read a detailed description of method references with full examples at Java 8 Method
References.

10. What is a Stream? How to create Streams in


Java?
A stream in Java represents a sequence of elements and supports different kinds of operations to

perform computations upon those elements. Streams are a core part of Java's functional

programming paradigm, introduced in Java 8.

Streams can be obtained in various ways from different sources such as collections, arrays, I/O

channels, etc. They don't change the original data structure; they just provide a view of this data

structure to allow bulk operations.

Key Characteristics of Streams:


No Storage: Streams have no storage for elements; they just convey elements from a source through
a pipeline of computational operations.

Functional in Nature: An operation on a stream produces a result, but it does not modify the source.
It returns a new stream that contains the result.

Laziness-Seeking: Many stream operations are "lazy," meaning that they do not process elements
until the result is needed.

Possibly Unbounded: Streams can represent sequences that are of an infinite size.

Consumable: The elements of a stream are consumed from the data source only when queried. Once

traversed, they are not revisited.

Creating Streams in Java


From a Collection:

List<String> myList = Arrays.asList("a1", "a2", "b1", "c2", "c1");


Stream<String> myStream = myList.stream();

From an Array:

int[] numbers = {1, 2, 3, 4, 5};


IntStream numberStream = Arrays.stream(numbers);

Using Stream.of():

Stream<String> stringStream = Stream.of("A", "B", "C");

Using Stream.iterate() for Infinite Streams:

Stream<Integer> infiniteStream = Stream.iterate(0, n -> n + 1);

Read more about streams at Java 8 Stream APIs with Examples.

11. Collection API vs Stream API?


Collection API Stream API

It’s available since Java 1.2 It is introduced in Java SE 8

It is used to store Data (A set of It is used to compute data (Computation on a set of


Collection API Stream API

Objects). Objects).

We can’t use Spliterator or Iterator to iterate


We can use both Spliterator and
elements. We can use forEach to perform an action for
Iterator to iterate elements.
each element of this stream.

It is used to store an unlimited


Stream API is used to process the elements of a Collection.
number of elements.

Typically, it uses the External


Stream API uses internal iteration to iterate Elements,
Iteration concept to iterate
using the forEach method.
Elements such as Iterators.

Collection Object is constructed


Stream Object is constructed Lazily.
Eagerly.

We add elements to the Collection We can add elements to Stream Object without any prior

object only after it is computed computation. That means Stream objects are computed

completely. on demand.

12. What is Optional in Java 8?


Optional is a container object which is used to contain not-null objects. An optional object is used to

represent null with an absent value.

The Optional class has various utility methods to facilitate code to handle values as 'available' or 'not

available' instead of checking null values.

The purpose of the Optional class is to provide a type-level solution for representing optional values

instead of using null references.

Read more about Optional Class with examples at Java 8 Optional Class with Examples.

13. What are the Advantages of Java 8


Optional?
Null checks are not required.
No more NullPointerException at run-time.

We can develop clean and neat APIs.

No more Boilerplate code

Read more about Optional Class with examples at Java 8 Optional Class with Examples.

14. What is a default method and when do we


use it?
A default method is a method with an implementation – which can be found in an interface.

We can use a default method to add new functionality to an interface while maintaining backward

compatibility with classes that are already implementing the interface:

public interface Vehicle {


String getBrand();

String speedUp();

String slowDown();

default String turnAlarmOn() {


return "Turning the vehice alarm on.";
}

default String turnAlarmOff() {


return "Turning the vehicle alarm off.";
}
}

Usually, when a new abstract method is added to an interface, all implementing classes will break until

they implement the new abstract method. In Java 8, this problem has been solved by the use of the

default method.

For example, the Collection interface does not have a forEach method declaration. Thus, adding such

a method would simply break the whole collections API.

Java 8 introduces the default method so that the Collection interface can have a default

implementation of the forEach method without requiring the classes implementing this interface to
implement the same.
Read more about Default Methods with examples at Java 8 Static and Default Methods in
Interface.

15. What is a Static Method? Why do we need


Static methods in Java 8 Interfaces?
A Static Method is a Utility method or Helper method, which is associated with a class (or interface). It

is not associated with any object.

We need Static Methods because of the following reasons:

We can keep Helper or Utility methods specific to an interface in the same interface rather than

in a separate Utility class.

We do not need separate Utility Classes like Collections, Arrays, etc to keep Utility methods.

Clear separation of Responsibilities. That is we do not need one Utility class to keep all Utility
methods of Collection API like Collections etc.

Easy to extend the API.

Easy to Maintain the API.

16. How will you call a default method of an


interface in a class?
Using the super keyword along with the interface name.

interface Vehicle {
default void print() {
System.out.println("I am a vehicle!");
}
}
class Car implements Vehicle {
public void print() {
Vehicle.super.print();
}
}

17. How will you call a static method of an


interface in a class?
Using the name of the interface.

interface Vehicle {
static void blowHorn() {
System.out.println("Blowing horn!!!");
}
}
class Car implements Vehicle {
public void print() {
Vehicle.blowHorn();
}
}

Related Java Interview Articles


Spring Boot Interview Questions

Java Tricky Coding Interview Questions

Java String Interview Questions


Java String Tricky Coding Questions

Java main() Method Interview Questions

Java 8 Interview Questions

Top 10 Spring MVC Interview Questions

Java Array Interview Questions and Answers


Java OOPS Tricky Coding Questions

Java Programs Asked in Interview

OOPS Interview Questions and Answers

Hibernate Interview Questions

JPA Interview Questions and Answers


Java Design Patterns Interview Questions

Spring Core Interview Questions

Java Exception Handling Interview

Related Java Interview Guides:


Java Career Roadmap: How To Level Up From Junior To Senior Developer

How To Crack Java Developer Interviews Like A Pro Spring Vs Spring MVC Vs Spring Boot
Free Courses
on YouTube
Channel

175K
Subscribers

Java Stream API Interview Questions and Answers


author: Ramesh Fadatare

INTERVIEW JAVA 8 STREAM API

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

Stream API is one of the most powerful features introduced in Java 8. It allows you to work with
collections in a declarative, functional way by chaining operations like filtering, mapping, and

reducing.
In this article, we’ll dive into the top 10 Java Stream API interview questions and answers asked in
2025.

1️⃣ What is Java Stream API and Why is it Useful?


Java Stream API allows you to process data from collections in a fluent, readable, and functional style.
Instead of writing for-loops and handling data manually, you can describe what needs to be done

using a pipeline of operations like map(), filter(), and collect().

Streams also support lazy evaluation, parallel processing, and method chaining, which makes code

cleaner and faster to execute. For example, if you want to get all employee names earning more than
₹50,000:

employees.stream()
.filter(e -> e.getSalary() > 50000)
.map(Employee::getName)
.collect(Collectors.toList());

2️⃣ What is the Difference Between Intermediate and Terminal


Operations?
In the Stream API, operations are divided into two categories:

1. intermediate operations
2. terminal operations

Intermediate operations return another stream, allowing you to chain more methods. These are lazy,
meaning they don’t execute until a terminal operation is invoked.

Terminal operations end the pipeline and produce a result such as a list, a count, or even just a side
effect. Without a terminal operation, the stream pipeline won’t run at all.
Here is the table that contains differences between Java 8 Stream Intermediate Vs Terminal
Operations:

3️⃣ How is map() Different from flatMap()?


Use map() when you want to transform individual elements in a stream. Use flatMap() when each

element itself is a collection or stream, and you want to flatten it into one combined stream.

Java Example: map() vs flatMap()


import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class StreamExample {


public static void main(String[] args) {

// List of sentences
List<String> sentences = Arrays.asList("Java Stream", "map vs flatMap", "Core Concepts

// Using map(): Each sentence becomes a list of words (nested list)


List<List<String>> mapped = sentences.stream()
.map(sentence -> Arrays.asList(sentence.split(" ")))
.collect(Collectors.toList());

System.out.println("Using map():");
System.out.println(mapped); // Output: [[Java, Stream], [map, vs, flatMap], [Core, Co

// Using flatMap(): All words are flattened into one list


List<String> flatMapped = sentences.stream()
.flatMap(sentence -> Arrays.stream(sentence.split(" ")))
.collect(Collectors.toList());

System.out.println("\nUsing flatMap():");
System.out.println(flatMapped); // Output: [Java, Stream, map, vs, flatMap, Core, Con
}
}
4️⃣ What is the Use of the filter() Method in Streams?
The filter() method is used to keep only those elements that satisfy a given condition. It’s a

powerful way to apply logic directly to a stream without needing an if-condition or manual removal.

For example, if you want only the even numbers from a list, you can write:

List<Integer> evenNumbers = numbers.stream()


.filter(n -> n % 2 == 0)
.collect(Collectors.toList());

This keeps your code readable and focused on the what, not the how.

5️⃣ What is the Difference Between collect() and toList()?


The collect() method is a terminal operation used to convert a stream into a collection like List,

Set, or Map using collectors provided by the Collectors utility class. It offers flexibility and supports

various operations like grouping, partitioning, joining, and summing.

The toList() method, introduced in Java 16, is a more concise alternative to

collect(Collectors.toList()). It creates an unmodifiable list, which is ideal when you just need

to collect stream results without any further modifications.

6️⃣ What Does reduce() Do in a Java Stream?


The reduce() method is used to combine stream elements into a single value using a binary

operation. You define an identity value and a function, and the stream applies that function
cumulatively to the elements.
It’s great for calculations like summing numbers, multiplying them, or creating comma-separated
strings. For example:

int total = numbers.stream().reduce(0, Integer::sum);

This will return the sum of all the integers in the list.

7️⃣ What is Lazy Evaluation in Java Streams?


Lazy evaluation means that stream operations are not executed immediately when the stream is
created. Instead, intermediate operations are stored and only run when a terminal operation is called.

This improves performance, especially when working with large datasets, because unnecessary
operations can be skipped. For example, this does nothing:

Stream<String> stream = list.stream().filter(s -> s.length() > 5);

But when you add a terminal operation:

stream.collect(Collectors.toList());

Only then is the filter condition applied.

8️⃣ How Can You Sort a List Using Streams?


Streams offer a convenient way to sort collections using the sorted() method. You can sort elements

naturally or define your own custom comparator.

For example, to sort names alphabetically:

list.stream().sorted().collect(Collectors.toList());

To sort employees by salary:

employees.stream()
.sorted(Comparator.comparing(Employee::getSalary))
.collect(Collectors.toList());

9️⃣ How to Remove Duplicates Using Streams?


Duplicates can be removed from a stream using the distinct() method. It ensures that only unique

elements are passed to the next stage of the stream pipeline.

For example:

List<String> names = List.of("Ravi", "Ravi", "Sita", "Geeta");


List<String> uniqueNames = names.stream().distinct().collect(Collectors.toList());

This results in: ["Ravi", "Sita", "Geeta"].

🔟 What are Parallel Streams and When Should You Use Them?
Parallel streams split the data into multiple chunks and process them in parallel using multiple

threads. This can boost performance for large data processing tasks.

You should use parallelStream() when the operations are independent, stateless, and CPU-

intensive. But be cautious—parallel streams may reduce performance for small data sets or IO-bound

tasks.

list.parallelStream()
.map(String::toUpperCase)
.collect(Collectors.toList());

11. How to Create Streams in Java?

Java provides several ways to create streams depending on your data source. You can create streams
from collections, arrays, individual values, or even from file/data generators.

✅ Example: Different Ways to Create Streams:

// 1. From a List or Set


List<String> names = List.of("Ravi", "Sita", "Amit");
Stream<String> stream1 = names.stream();

// 2. From an Array
String[] fruits = {"Apple", "Banana", "Mango"};
Stream<String> stream2 = Arrays.stream(fruits);

// 3. Using Stream.of()
Stream<Integer> stream3 = Stream.of(10, 20, 30);
// 4. Using Stream.builder()
Stream<String> stream4 = Stream.<String>builder()
.add("One").add("Two").add("Three")
.build();

// 5. Using Stream.generate() (infinite stream)


Stream<Double> stream5 = Stream.generate(Math::random).limit(5);

// 6. Using Stream.iterate() (infinite stream with pattern)


Stream<Integer> stream6 = Stream.iterate(1, n -> n + 2).limit(5);

// 7. From Files (using NIO)


Stream<String> lines = Files.lines(Path.of("data.txt"));

Each method serves a different purpose. For example, Stream.generate() and Stream.iterate()

are best for infinite sequences, while Stream.of() is great for quick static values.

12. Collections vs Streams

13. What does the Stream map() function do? why you use it?

The map() function is an intermediate function that is used to perform map functional operations in

Java. This means it can transform one type of object into another by applying a function.

Use the map() function to convert one object to another object.


For example, if you have a list of strings and want to convert it to a list of integers, you can use
map() to do so.

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Main


{
public static void main(String[] args)
{
List<String> listOfStrings = Arrays.asList("1", "2", "3", "4", "5");

List<Integer> listOfIntegers = listOfStrings.stream()


.map(Integer::valueOf)
.collect(Collectors.toList());

System.out.println(listOfIntegers);
}
}

Output:

[1, 2, 3, 4, 5]

14. What does the Stream filter() method do? when you use it?
Java stream provides a filter() method to filter stream elements on the basis of a given predicate.

This method takes a predicate as an argument and returns a stream consisting of the resulting

elements.

Example 1: Using the filter() method to filter a List of string objects:

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Tester {


public static void main(String[] args){
List<String> lines = Arrays.asList("java", "c", "python");
List<String> result = lines.stream() // convert list to stream
.filter(line -> !"c".equals(line)) // we dont like c
.collect(Collectors.toList()); // collect the output and convert streams

result.forEach(System.out::println);
}
}

Output:

java
python

Example 2: In this example, we will create a list of products and filter products whose price is greater
than 25k. We display a list of products using the forEach() method.

Let's first create a Product class:

class Product {
private int id;
private String name;
private float price;
// getters and setters
}

public class StreamFilterExample {


public static void main(String[] args) {

// using stream API


List < Product > filteredProducts = getProducts().stream()
.filter((product) -> product.getPrice() > 25000 f)
.collect(Collectors.toList());
filteredProducts.forEach(System.out::println);
}

private static List < Product > getProducts() {


List < Product > productsList = new ArrayList < Product > ();
productsList.add(new Product(1, "HP Laptop", 25000 f));
productsList.add(new Product(2, "Dell Laptop", 30000 f));
productsList.add(new Product(3, "Lenevo Laptop", 28000 f));
productsList.add(new Product(4, "Sony Laptop", 28000 f));
productsList.add(new Product(5, "Apple Laptop", 90000 f));
return productsList;
}
}

In the above example, we are using the filter() method to filter products whose price is greater

than 25k:

List < Product > filteredProducts = getProducts().stream()


.filter((product) -> product.getPrice() > 25000 f)
.collect(Collectors.toList());

15. What does the Stream flatmap() function do? why you
need it?
The Stream.flatMap() function, as the name suggests, is the combination of a map and a flat

operation. This means you first apply the map function and then flatten the result.

To understand what flattening a stream consists in, consider a structure like [ [1,2,3],[4,5,6],[7,8,9] ]

which has "two levels". It's basically a big List containing three more List. Flattening this means

transforming it in a "one level" structure e.g. [ 1,2,3,4,5,6,7,8,9 ] i.e. just one list.

For example, In the below program, you can see that we have three lists merged into one using a
flatMap() function.

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Main {


public static void main(String[] args)
{
List<Integer> evens = Arrays.asList(2, 4, 6);
List<Integer> odds = Arrays.asList(3, 5, 7);
List<Integer> primes = Arrays.asList(2, 3, 5, 7, 11);
List<Integer> numbers = Stream.of(evens, odds, primes)
.flatMap(list -> list.stream())
.collect(Collectors.toList());
System.out.println("flattend list: " + numbers);
}
}

Output:

flattend list: [2, 4, 6, 3, 5, 7, 2, 3, 5, 7, 11]

Related Java Interview Guides:


Java Career Roadmap: How To Level Up From Junior To Senior Developer

How To Crack Java Developer Interviews Like A Pro Spring Vs Spring MVC Vs Spring Boot

Java Spring Boot Vs. Go (Golang) For Backend Development In 2025

Is Java Compiled Or Interpreted? Let’s Clear The Confusion!

Java JIT Compiler: Explained In Simple Words What Is JVM, JDK, And JRE?

Why Java Is The Platform Independent? (Interview Question And Answer)

Is Java A Pure Object-Oriented Language? (Java Interview Question And Answer)🤔

Is Java Case Sensitive? (Java Interview Question And Answer)

Why Is Java Secure? (Java Interview Question And Answer)

💪 Why Is Java Robust? (Java Interview Question And Answer)

Why Is Java Architecture Neutral? (Java Interview Question And Answer)

Why Is Java Called Portable? Why Java Does Not Support Multiple Inheritance?

Why Java Does Not Support Pointers? Is Java Pass-By-Value Or Pass-By-Reference?

Why Is Main() Method Public Static In Java? (Here’s The Real Truth!)

Can We Overload The Main() Method In Java? (Java Interview Question And Answe
Free Courses
on YouTube
Channel

175K
Subscribers

Java Lambda Expressions Interview Questions and


Answers
author: Ramesh Fadatare

INTERVIEW JAVA 8

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

In this article, we will discuss some important and frequently asked Java Lambda Expressions
Interview Questions and Answers.

Learn Java 8 Lambda expressions with examples at Lambda Expressions guide.

1. What is a Lambda Expression?

A lambda expression is simply a function without any name. It can even be used as a parameter in a
function. Lambda Expression facilitates functional programming and simplifies development a lot.

The main use of Lambda expression is to provide an implementation for functional interfaces.

Syntax of Lambda Expression

The syntax of a lambda expression is characterized by the following three parts:

Parameters: A lambda expression can have zero or more parameters, enclosed in parentheses.

Arrow Token: The arrow token -> separates the parameters from the body of the lambda.

Body: The body of the lambda contains expressions or statements describing the method's

functionality.

(parameters) -> expression

Or

(parameters) -> { statements; }

Example

Consider a simple functional interface:

@FunctionalInterface
interface MyFunction {
int apply(int x, int y);
}

A lambda expression implementing this interface:

MyFunction add = (x, y) -> x + y;


int result = add.apply(5, 3); // result is 8

Read more in detail about lambda expressions at Java 8 Lambda Expressions

2. Why use Lambda Expression?

Lambda expressions in Java are a powerful feature that provides several key benefits:
Conciseness: Lambda expressions allow you to write instances of anonymous classes more concisely.
This makes the code easier to read and maintain.

Functional Programming: Lambda expressions enable functional programming concepts in Java. You
can pass functions as method arguments, return them as values, and perform operations like mapping
and filtering on collections more naturally.

Readability: By reducing boilerplate code, lambda expressions can make the main logic of a program
more apparent. The concise syntax allows for clear expression of the computation or action being
performed.

Parallel Execution Support: Lambdas work well with the Stream API, which supports parallel

execution. This makes it easier to write parallel code, leveraging multicore processors without having
to deal with low-level threading details.

Less Verbose: Unlike anonymous inner classes, lambda expressions are less verbose. You don't need
to name the class, declare the method, or even type the input parameters.

Strong Typing: Lambda expressions are strongly typed. The compiler infers the types of parameters,
return values, and exceptions, which can lead to more robust code.

Scope Flexibility: Lambda expressions have access to final variables or effectively final variables from

the surrounding scope, allowing more natural encapsulation of behavior.

Interoperability: Lambdas can be used wherever functional interfaces are expected, providing great
interoperability with existing code, libraries, and frameworks that use functional interfaces.

Read more in detail about lambda expressions at Java 8 Lambda Expressions.

3. Explain Lambda Expression Syntax


The syntax of a lambda expression is characterized by the following three parts:

Parameters: A lambda expression can have zero or more parameters, enclosed in parentheses.

Arrow Token: The arrow token -> separates the parameters from the body of the lambda.
Body: The body of the lambda contains expressions or statements describing the method's functionality.

(parameters) -> expression

Or

(parameters) -> { statements; }

For example, Consider we have a functional interface:

interface Addable{
int add(int a,int b);
}

Let's implement the above Addable functional interface using a lambda expression:

Addable withLambdaD = (int a,int b) -> (a+b);


System.out.println(withLambdaD.add(100,200));

Read more in detail about lambda expressions at Java 8 Lambda Expressions.

4. Which of the following are valid lambda expressions?


A.

String a, String b -> System.out.print(a+ b);

B.

() -> return;

C.

(int i) -> i;

D.

(int i) -> i++; return i;


Answer

The correct answer is C.

Explanation

Option C is valid. The body doesn't need to use the return keyword if it only has one statement.

5. Write a Java Lambda Expression to Create a Thread

Creating a thread using a lambda expression in Java is straightforward and concise. You can define the
task you want the thread to perform as a lambda and pass it to the Thread constructor.

Here's an example:

Runnable task = () -> {


for (int i = 0; i < 5; i++) {
System.out.println("Running inside the thread: " + i);
}
};

Thread myThread = new Thread(task);


myThread.start();

Or you can simplify it further by passing the lambda expression directly to the Thread constructor:

Thread myThread = new Thread(() -> {


for (int i = 0; i < 5; i++) {
System.out.println("Running inside the thread: " + i);
}
});
myThread.start();

Either way, this code creates a new thread and runs a simple loop inside it, printing a message five

times. Lambda expressions make this code cleaner and more concise by removing the need to create

an anonymous inner class or implement a separate class that implements Runnable .

6. How are Lambda Expressions and Functional Interfaces


related?
The main use of Lambda expression is to provide an implementation for functional interfaces.

A lambda expressions provide a compact and expressive way to create instances of functional

interfaces, implementing the interface's single abstract method with the body of the lambda. This
relationship promotes a more functional programming style in Java, allowing for more concise and

readable code.

For example, Lambda expression provides an implementation for a Printable functional interface:

interface Printable {
void print(String msg);
}

public class JLEExampleSingleParameter {

public static void main(String[] args) {


// without lambda expression
Printable printable = new Printable() {
@Override
public void print(String msg) {
System.out.println(msg);
}
};
printable.print(" Print message to console....");

// with lambda expression


Printable withLambda = (msg) -> System.out.println(msg);
withLambda.print(" Print message to console....");
}
}

Output :

Print message to console....


Print message to console....

7. Explain the Various Forms of Writing Lambda Expressions.


Lambda expressions in Java can be written in various forms, depending on the signature of the
functional interface's abstract method they are implementing. Here are some different ways to write
lambda expressions:

No Parameters, No Return Value:

If the abstract method takes no parameters and returns no value, the lambda expression can be

written with empty parentheses and a body:

() -> System.out.println("Hello, World!");

Single Parameter, No Type Declaration:

If the abstract method takes a single parameter, you can omit the parentheses around the parameter,
and the type can be inferred:

s -> System.out.println(s);

Single Parameter, With Type Declaration:

You can also explicitly declare the type of the parameter:

(String s) -> System.out.println(s);

Multiple Parameters:

If the abstract method takes multiple parameters, you must include parentheses around the

parameters. Types can be inferred or explicitly declared:

(a, b) -> a + b;
(int a, int b) -> a + b;

Return Statement:

If the body of the lambda consists of a single expression that returns a value, you can write it directly:

(int a, int b) -> a + b;

If the body consists of multiple statements, you must include braces and use a return statement:
(int a, int b) -> {
int sum = a + b;
return sum;
};

No Parameters, Return Value:

If the abstract method takes no parameters but returns a value, you can write it like this:

() -> 42;

Use Local Variables:

You can also access local variables from the enclosing scope within the lambda expression:

int factor = 2;
(int a) -> a * factor;

8. How is Lambda Expression Different from Anonymous Class?


Lambda expressions provide a more concise way to implement functional interfaces, whereas

anonymous classes are more verbose. Lambdas don’t create a separate class file or object.

Here’s a clear comparison:

9. Can Lambdas Access Local Variables?


Yes, lambda expressions can access final or effectively final local variables from the enclosing scope.

This means the variable should not be modified after it’s used inside the lambda.

Example:
String prefix = "Hello ";
Consumer<String> c = name -> System.out.println(prefix + name);
c.accept("Ravi");

If you try to change prefix later, the compiler will throw an error.

10. What is the Difference Between Lambda and Method


Reference?

Both lambda expressions and method references are used to provide implementations for functional
interfaces. A method reference is a shorter way to write certain lambdas that call existing methods.

Here’s a detailed comparison:

Related Java Interview Articles

Spring Boot Interview Questions


Java Tricky Coding Interview Questions

Java String Interview Questions


Java String Tricky Coding Questions

Java main() Method Interview Questions

Java 8 Interview Questions


Top 10 Spring MVC Interview Questions

Java OOPS Tricky Coding Questions


Java Programs Asked in an Interview

OOPS Interview Questions and Answers

Hibernate Interview Questions


JPA Interview Questions and Answers
Free Courses
on YouTube
Channel

175K
Subscribers

Java Functional Interface Interview Questions and


Answers
author: Ramesh Fadatare

INTERVIEW JAVA 8

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.

▶️Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube

In this article, we will discuss some important and frequently asked Java 8 Functional Interface
Interview Questions and Answers.

Check out Java 8 Interview Questions

1. What is a functional interface?


A functional interface in Java is an interface that has exactly one abstract method. Since functional

interfaces have only one abstract method, they can represent a single functionality that can be
implemented by a lambda expression, a method reference, or an anonymous class.

Introduced in Java 8, functional interfaces are a key feature that enables functional programming
concepts within the language. They allow you to use simple expressions to represent instances of
anonymous classes that implement the interface, making code more concise and readable.

Key points about functional interfaces:


Single Abstract Method (SAM): A functional interface must contain exactly one abstract method. It
can have more than one non-abstract method (default or static methods), but only one abstract

method is allowed.
@FunctionalInterface Annotation: While it's not required, it's good practice to annotate a functional

interface with @FunctionalInterface. This annotation ensures that the interface meets the
requirements of a functional interface at compile time. If you try to add a second abstract method, the
compiler will raise an error.

Built-in Functional Interfaces: Java 8 introduced several built-in functional interfaces within the

java.util.function package. Some common ones include Predicate<T>, Function<T, R>,

Supplier<T>, Consumer<T>, and others.


Lambda Expressions: Since functional interfaces have only one abstract method, you can use lambda

expressions to provide the implementation of that method directly within the code where it's needed.

Example:

@FunctionalInterface
public interface MyFunctionalInterface {
void execute();
}

// Using a lambda expression to implement the functional interface


MyFunctionalInterface implementation = () -> System.out.println("Executing...");
implementation.execute(); // Output: Executing...

Read more at Java 8 Functional Interfaces with Examples.


2. Is it possible to define our own Functional
Interface? What is @FunctionalInterface? What
are the rules to define a Functional Interface?
Yes, it is possible to define your own functional interface in Java, and the @FunctionalInterface

annotation is often used to mark an interface as a functional interface.

What is @FunctionalInterface?

The @FunctionalInterface annotation is used to indicate that an interface is intended to be a

functional interface. While it is not mandatory to use this annotation when defining a functional
interface, it's a good practice because it makes the intention clear and allows the compiler to generate
an error if the annotated interface does not satisfy the conditions of a functional interface.

Rules to Define a Functional Interface


Exactly One Abstract Method: The functional interface must contain exactly one abstract method.

Having more or fewer abstract methods will violate the functional interface contract.

Any Number of Default and Static Methods: You can have any number of default or static methods
in the functional interface.

@FunctionalInterface Annotation (Optional but Recommended): Using the @FunctionalInterface


annotation helps in indicating the purpose of the interface and ensures a compile-time check.

Inheritance: A functional interface can extend another interface only if it does not have any abstract
method itself.

Example of a Custom Functional Interface

@FunctionalInterface
interface MyFunctionalInterface {
// Single abstract method
void execute();

// Default method
default void defaultMethod() {
System.out.println("Default method");
}

// Static method
static void staticMethod() {
System.out.println("Static method");
}
}

Read more at Java 8 Functional Interfaces with Examples.

3. Name some of the functional interfaces in


the standard library
In Java 8, there are a lot of functional interfaces introduced in the java.util.function package and

the more common ones include but are not limited to:

1. Function<T, R>: Represents a function that takes an argument of type T and returns a result of
type R.
2. Consumer<T>: Represents an operation that takes a single input argument of type T and
returns no result (performs a side effect).
3. Supplier<T>: Represents a supplier of results, taking no arguments but providing a result of

type T.
4. Predicate<T>: Represents a boolean-valued function of one argument of type T. Commonly
used for filtering or matching.
5. UnaryOperator<T>: Represents a function that takes a single argument of type T and returns a
result of the same type. It extends Function<T, T>.

6. BinaryOperator<T>: Represents a function that takes two arguments of type T and returns a
result of the same type. It extends BiFunction<T, T, T>.
7. BiFunction<T, U, R>: Represents a function that takes two arguments of types T and U and
returns a result of type R.
8. BiConsumer<T, U>: Represents an operation that takes two input arguments of types T and U

and returns no result.


9. BiPredicate<T, U>: Represents a boolean-valued function that takes two arguments of types T
and U.
10. ToIntFunction<T>, ToLongFunction<T>, and ToDoubleFunction<T>: Represents functions
that take an argument of type T and return a primitive int, long, or double value, respectively.
11. IntFunction<R>, LongFunction<R>, DoubleFunction<R>: Represents functions that take a
primitive int, long, or double value and return a result of type R.

These functional interfaces are part of the java.util.function package, and they can be used with

lambda expressions, method references, or anonymous inner classes. They greatly enhance the ability
to write concise and functional-style code in Java.

4. What Is the Difference Between a Normal


and Functional Interface in Java?
In Java, the distinction between a normal interface and a functional interface is mainly related to the
number of abstract methods they contain and their intended usage.
Here's a breakdown of the differences:

Normal Interface:
Abstract Methods: A normal interface can have more than one abstract method. There are no

constraints on the number of abstract methods it can declare.

Static and Default Methods: It may contain static methods and default methods with

implementations.

Purpose: A normal interface serves the traditional role of defining a contract that implementing
classes must follow. It's used for multiple inheritance and polymorphism.

Usage with Lambda Expressions: You cannot use normal interfaces (with more than one abstract
method) with lambda expressions.

Functional Interface:
Abstract Methods: A functional interface has exactly one abstract method. This abstract method is

called the functional method.

Static and Default Methods: Like normal interfaces, functional interfaces can also contain static and

default methods with implementations.

Purpose: Functional interfaces are designed to facilitate functional programming in Java, allowing
methods to be used as first-class citizens, passed as arguments, and returned as values.

Usage with Lambda Expressions: Functional interfaces can be implemented using lambda
expressions, providing a concise way to implement the single abstract method.

Annotation: Although not mandatory, a functional interface can be annotated with

@FunctionalInterface. This annotation ensures that the interface will not compile if more than one

abstract method is declared.

5. What is a Function interface?


The Function is a functional interface introduced in Java 8; it takes an argument (object of type T)

and returns an object (object of type R). The argument and output can be of different types.

This is the internal implementation of the Function interface:

@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
}

T – Type of the input to the function.

R – Type of the result of the function.

Example:

Function < String, Integer > function = (t) -> t.length();


System.out.println(function.apply("Ramesh"));

Output:

Read more at Java 8 Function Interface Example

6. What is a Predicate interface?


The Predicate is a functional interface that can be used as an assignment target for a lambda

expression.

The Predicate interface represents an operation that takes a single input and returns a boolean

value.

This is the internal implementation of the Predicate interface:

@FunctionalInterface
public interface Predicate<T> {

/**
* Evaluates this predicate on the given argument.
*
* @param t the input argument
* @return {@code true} if the input argument matches the predicate,
* otherwise {@code false}
*/
boolean test(T t);
}

T – Type of the input to the predicate

Example:

Predicate < Integer > predicate = (t) -> {


if (t % 2 == 0) {
return true;
} else {
return false;
}
};

System.out.println(predicate.test(10));

Output:

true
Read more at Java 8 Predicate interface Example

7. What is the Consumer interface?


A Consumer is a functional interface in JDK 8, which represents an operation that accepts a single

input argument and returns no result.

This is the internal implementation of the Consumer interface:

@FunctionalInterface
public interface Consumer < T > {

/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);
}

Example:

Consumer < String > consumer = (t) -> System.out.println(t);


consumer.accept("Ramesh");

Output:

Ramesh

Read more at Java 8 Consumer Interface Example

8. What is the Supplier interface?


The Supplier is a functional interface that represents an operation that takes no argument and

returns a result.

This is the internal implementation of the Supplier interface:


@FunctionalInterface
public interface Supplier<T> {
T get();
}

Example:

Supplier < LocalDateTime > supplier = () -> LocalDateTime.now();


System.out.println(supplier.get());

Output:

2020-04-30T11:32:51.628

9. What is the BiFunction interface?


The BiFunction interface is a functional interface that represents a function that takes two

arguments of different types and produces a result of another type.

This is the internal implementation of the BiFunction interface:

@FunctionalInterface
public interface BiFunction<T, U, R> {
R apply(T t, U u); // Other default and static methods
// ...
}

Example:

// And with a lambda expression:


BiFunction < Integer, Integer, Integer > biFunction = (t, u) -> (t + u);

BiFunction < Integer, Integer, Integer > substraction = (t, u) -> (t - u);

BiFunction < Integer, Integer, Integer > multiplication = (t, u) -> (t * u);

BiFunction < Integer, Integer, Integer > division = (t, u) -> (t / u);
System.out.println(biFunction.apply(10, 20));
System.out.println(substraction.apply(200, 100));

System.out.println(multiplication.apply(200, 100));

System.out.println(division.apply(200, 100));

Output:

30
900
20000
2

Read more at Java 8 BiFunction Example

Related Java Interview Articles


Spring Boot Interview Questions
Java Tricky Coding Interview Questions

Java String Interview Questions


Java String Tricky Coding Questions

Java main() Method Interview Questions

Java 8 Interview Questions


Top 10 Spring MVC Interview Questions

Java OOPS Tricky Coding Questions


Java Programs Asked in Interview

OOPS Interview Questions and Answers

Hibernate Interview Questions


JPA Interview Questions and Answers
Java Design Patterns Interview Questions

Spring Core Interview Questions

Java Exception Handling Interview

Related Java Interview Guides:

You might also like