Friday 8 October 2021

Useful Java Interview Question and Answers

» Primitive Data Types in Java

integers (int, short, byte, long), fractions (float, double), characters (char), boolean (boolean)

String - This is one more non-primitive data type to declare string

» Method Overloading in Java

Inside a class you can have methods with same name as long as they differ in terms of Data Type, Order and Number of Arguments

Example:

public class MethodOverloading {

	// Inside a class you can have methods with same name as long as they differ in 
	// terms of Data Type, Order and Number of Arguments
			
	public void addition(int num1, int num2) {
		System.out.println(num1 + num2);
	}
	
	public void addition(double num1, double num2) {
		System.out.println(num1 + num2);
	}
	
	public void addition(int num1, double num2) {
		System.out.println(num1 + num2);
	}
	
	public void addition(double num1, int num2) {
		System.out.println(num1 + num2);
	}
	
	public void addition(int num1, int num2, int num3) {
		System.out.println(num1 + num2 + num3);
	}	
}

public class MainClass(){
	public static void main(String[] args){
		MethodOverloading m1 = new MethodOverloading();
		m1.addition(10,20);
		m1.addition(10.10,20.20);
		m1.addition(10,12.90);
		m1.addition(90.10,20);
		m1.addition(1,2,3);
	}
}

» Access Specifiers in Java

- Public Access

- Default Access / No Access Specifier

- Private Access

- Protected Access

» Constructor in Java

A block of code similar to method which gets executed when an instance (object) of the class is created

Generally used to initialize member variables of a class

Constructor name is same as that of class name

Constructor does not have return type (It does not return any value)

Default Constructor - The default constructor is the no-argument constructor created automatically unless you define another constructor

If we don't create any constructor in class then Java assumes it as default constructor class

Constructor is not a member of class which means you cannot call it from another methods like you call any explicit methods in the class

Constructor Overloading: Inside a class you can have multiple constructors as long as they distinguish in terms of arguments either by data type of arguments or number of arguments

Example:

// Class 1
package oopsprogramming
public class RoadToll {
	String type;
	int tiresCount;
	
	public void calculateToll() {
		if (tiresCount == 2) {
			System.out.println("Your toll amount is 0");
		} else if (tiresCount == 4) {
			System.out.println("Your toll amount is 10");
		} else if (tiresCount > 4) {
			System.out.println("Your toll amount is 20");
		} else {
			System.out.println("Incorrect tire count");
		}
	}
	
	public RoadToll () {
		System.out.println("Constructor is executed");
	}
	
	public RoadToll (String type, int tiresCount) {
		this.type = type;
		this.tiresCount = tiresCount;
	}
	
}

// Class 2

package oopsprogramming
public class RoadToll_Main {

	public static void main(String[] args) {
		
		Road_Toll rt1 = new RoadToll();
		
		rt1.type = "Sadan";
		rt1.tiresCount = 4;
		rt1.calculateToll();
		
		Road_Toll rt2 = new RoadToll("Truck", 6);
		rt2.calculateToll();
	}
}

» 4 Pillers of Object Oriented Programming

Data Encapsulation

Polymorphism

Inheritance

Abstraction

» Data Encapsulation or Data Hiding

Data Encapsulation also called as Data Hiding

Hiding the member variables of a class from other classes

So in Data Encapsulation we make member variables as "private" and we create getters/setters of those member variables so that an external class can use getters and setters instead of accessing direct member variable of the class

Example:

// Class 1
package oops_concepts;
public class Classroom {

	private String sub1;
	private int stdCount1;
	
	
	public String getSub() {
		return sub1;
	}


	public void setSub(String sub) {
		this.sub1 = sub;
	}


	public int getStdCount() {
		return stdCount1;
	}


	public void setStdCount(int stdCount) {
		this.stdCount1 = stdCount;
	}


	public void displayDetails() {
		System.out.println("This is a " + sub1 + " classroom and it has " + stdCount1 + " students");
	}
	
}

// Class 2
package oops_concepts;
public class Classroom_Main {

	public static void main(String[] args) {
		
		Classroom cs1 = new Classroom();
		
		cs1.setSub("Math");
		cs1.setStdCount(50);
		cs1.displayDetails();
	}

}

» Static keyword in Java

Static members (variables and methods) belong to a Class (type) and not to Object

The static keyword in Java is used for memory management mainly. We can apply static keyword with variables, methods, blocks and nested classes.

The static variable gets memory only once in the class area at the time of class loading which makes your program memory efficient (i.e. it saves memory)

More about static keyword: https://www.javatpoint.com/static-keyword-in-java

Example:

package oops_concepts;
public class Static_Keyword {
	
	static String name = "ABC";
	byte age = 6;
	String grade = "1st";
	
	public void displayDetails() {
		System.out.println("Student " + name + " is " + age + " years old and in " + grade + " grade.");
	}
	
	public static void doThis() {
		System.out.println("Do This Executed");
	}
		
}

package oops_concepts;
public class Static_Main {

	public static void main(String[] args) {
		
		Static_Keyword sk1 = new Static_Keyword();
		
		Static_Keyword sk2 = new Static_Keyword();
		
		sk1.age = 7;
		sk1.grade = "2nd";
		Static_Keyword.name = "Rob";
		Static_Keyword.doThis();
		
		sk2.age = 8;
		sk2.grade = "3rd";
		Static_Keyword.name = "Shyam";
		Static_Keyword.doThis();
		
		sk1.displayDetails();
		sk2.displayDetails();
	}
}

» What is JVM?

JVM is Java Virtual Machine

JVM is a baseline program which provide run-time environment to execute the Java code

JVM can be installed on any operating systems

» Main method in Java

public static void main(String[] args){
     // your_code
  }

Whenever we execute a Java application the JVM looks for the main() method and executes it

It is the starting point of Java program

First main() method gets executed then it executes other methods

main() method is void because it doesn't return any value

main() method is scopewise "public" so that JVM can identify it easily

main() method is static so that for JVM it is easy to access it without creating any object of it

What is String[] args?

This is an array of strings

args stands for arguments. Whenever you try to run Java application (ex: from command line) and you want to pass some arguments then you can pass those in form of array of strings which you can utilise in your application

What is NoSuchMethodError:main?

Whenever we run Java program JVM looks for public static void main(string[] args) method and if it doesn't find it in program it throws NoSuchMethodError:main error and terminates the program

» Math Class in Java

Example:

package special_classes;
public class MathClass {

	public static void main(String[] args) {
		
		/*
		 * Math Class is provided in java.lang package. java.lang package provides
		 * classes that are fundamental to the design of the Java programming language. 
		 * Math class contains methods for performing basic numeric
		 * operations such as the elementary exponential, logarithm,
		 * square root, and trigonometric functions. 
		 * 
		 * Math.min, Math.max, Math.E, Math.PI, 
		 * Math.pow, Math.sqrt, Math.cbrt
		 * Math.ceil, Math.floor, Math.round
		 * Math.sin, Math.cos, Math.tan, Math.log10
		 * Math.random
		 */
	
		int num1 = 100;
		int num2 = 200;
		
		System.out.println(Math.min(num1, num2));
		System.out.println(Math.max(num1, num2));
		System.out.println(Math.PI);
		System.out.println(Math.E);
		
		System.out.println(Math.pow(2, 10));
		System.out.println(Math.sqrt(200));
		System.out.println(Math.cbrt(300));
				
		System.out.println("-------------------------");
		
		double x = 12.98;
		double y = 10.24;
		
		System.out.println(Math.ceil(x));
		System.out.println(Math.ceil(y));
		
		System.out.println(Math.floor(x));
		System.out.println(Math.floor(y));
		
		System.out.println(Math.round(x));
		System.out.println(Math.round(y));
		System.out.println("-------------------------");
		
		System.out.println(Math.random());
	}
}

» StringBuilder Class in Java

Example:

package special_classes;
public class StringBuilderClass1 {

	public static void main(String[] args) {
		
		/*
		 * StringBuilder class is used to create mutable (modifiable) string
		 * Some useful methods:
		 * append, insert, replace, delete, reverse
		 */
		
		String str1 = "I";
		
		str1 = str1 + " Like";
		
		str1 = str1 + " Java";
		
		System.out.println(str1);
		
		//I / Like / I like / Java / I like Java
		
		StringBuilder sb1 = new StringBuilder("I");
		
		sb1.append(" Like");
		sb1.append(" Java");
		
		System.out.println(sb1);				
	}
}

public class StringBuilderClass2 {

	public static void main(String[] args) {
		
		/*
		 * Some useful methods from StringBuilder 
		 * insert, replace, delete, reverse
		 */
		StringBuilder sb1 = new StringBuilder("Learning is fun");
		
		sb1.insert(9, "Java ");
		
		System.out.println(sb1); //Output: Learning Java is fun
		
		sb1.replace(9, 13, "Everything");
		
		System.out.println(sb1); //Output: Learning Everything is fun
		
		sb1.deleteCharAt(0);
		
		System.out.println(sb1); //Output: earning Everything is fun
		
		sb1.delete(2, 10);
		
		System.out.println(sb1); //Output: eaerything is fun
		
		sb1.reverse();
		
		System.out.println(sb1);						
	}
}

» Scanner Class in Java

Scanner is a class used to accept the user input during execution of Java Program

Scanner class is from java.util.Scanner package so it requires to import java.util.Scanner to use it

Example:

import java.util.Scanner;

public class ScannerClass {

	public static void main(String[] args) {
		
		Scanner s1 = new Scanner(System.in);
		
		System.out.println("Please enter a string:");
		
		String str1 = s1.nextLine();
		
		String temp = "";
		
		for (int i = 0; i <= str1.length()-1; i++) {
			temp = str1.charAt(i) + temp;
		}		
		System.out.println("Reversed String is: " + temp);
	}
}

» Random Class in Java

To generate random numbers

From java.util.Random

Example:

import java.util.Random;
public class RandomClass {
	public static void main(String[] args) {		
		Random r1 = new Random();		
		for(int i = 1; i <= 100; i++) {
			System.out.println(r1.nextInt(100)); // output: 0 to 100 numbers
			System.out.println((int)(Math.random() * 40000) + 10000); //
		}				
	}
}

» UUID (Universal Unique Identifier) in Java

To generate UUID

Example:

import java.util.UUID;

public class UUIDClass {
	public static void main(String[] args) {				
		for(int i = 1; i <= 10; i++) {
			System.out.println(UUID.randomUUID());
		}
	}
}

» 'var' keyword in Java 10

You can use 'var' keyword in Java 10 to declare a variable

Based on the value assigned to variable Java will decide the type of it

Example:

Public class VarKeyword{
   public static void main(String[] args){
      var str = "abcd" // type String
      var num = 10 // type number
      var sc  = new Scanner(System.in) // object
   }
}

Limitations of 'var' in Java 10

You cannot use var keyword to create a variable at Class level

You cannot use var keyword to create a variable at Argument level

Example: public static int add(var a, var b) {} // => INCORRECT

You cannot use var keyword to declare array like this:

var myArr = {10,20,30} => Incorrect

var int [] myArr = {10,20,30} => Correct

» What is Garbage Collector in Java?

In Java Garbage means unreferenced objects

Garbage Collection is a way to destroy unused objects

Garbage collector is a program which run on JVM to get rid of the unused or unreferenced objects

Garbage collection is performed by a daemon thread called Garbage Collector(GC). This thread calls the finalize() method before object is garbage collected.

Java does it automatically unlike C & C++ which uses free() and delete() function respectively to do this task

It makes Java memory efficient

How can an object be unreferenced?

There are several ways like

By nulling the reference

Car c=new Car();=
c=null;

By assigning a reference to another

Employee e1=new Employee();  
Employee e2=new Employee();  
e1=e2;//now the first object referred by e1 is available for garbage collection

By anonymous object

1
new Department();  

» What is finalize method in Java

The finalize() method is invoked each time before the object is garbage collected. This method can be used to perform cleanup processing. This method is defined in Object class as:

protected void finalize(){}

» What is gc() method in Java

The gc() method is used to invoke the garbage collector to perform cleanup processing. The gc() is found in System and Runtime classes:

1
public static void gc(){}  

Example of Garbage Collection in Java

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
public class TestGarbage{  
 public void finalize(){System.out.println("object is garbage collected");}  
 public static void main(String args[]){  
  TestGarbage1 s1=new TestGarbage();  
  TestGarbage1 s2=new TestGarbage();  
  s1=null;  
  s2=null;  
  System.gc();  
 }  
}  

// output :  
// object is garbage collected
// object is garbage collected

» Inheritance in Java

Inheritance is an OOPS concept. In which one object acquires all the properties and behaviors of a parent object.

Ex. Class1 (parent) and Class2 (child)

When you inherit from an existing class, you can reuse methods and fields of the parent class. Moreover, you can add new methods and fields in your current class also

The extends keyword indicates that you are making a new class that derives from an existing class. The meaning of "extends" is to increase the functionality.

» Types of Inheritance in Java

1. Single

2. Multilevel

3. Hierarchical

In java programming, multiple and hybrid inheritance is supported through interface only.

» Single Inheritance

When a class inherits another class, it is known as a single inheritance.

Example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
class Animal{  
void eat(){System.out.println("eating...");}  
}  
class Dog extends Animal{  
void bark(){System.out.println("barking...");}  
}  
class TestInheritance{  
public static void main(String args[]){  
Dog d=new Dog();  
d.bark();  
d.eat();  
}}  

» Multilevel Inheritance

When there is a chain of inheritance, it is known as multilevel inheritance.

Example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
class Animal{  
void eat(){System.out.println("eating...");}  
}  
class Dog extends Animal{  
void bark(){System.out.println("barking...");}  
}  
class BabyDog extends Dog{  
void weep(){System.out.println("weeping...");}  
}  
class TestInheritance2{  
public static void main(String args[]){  
BabyDog d=new BabyDog();  
d.weep();  
d.bark();  
d.eat();  
}}  

» Method Overriding

If the parent class and child class has exact method with same name, same arguments the method from child class overrides the method from parent class. i.e. child overrides the parent

Example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// PARENT CLASS
package inheritance;
public class Animal {
	public void whoAmI() {
		System.out.println("I am an Animal");
	}
}

// CHILD CLASS 1
package inheritance;
public class Dog extends Animal{
	public void whoAmI() {
		System.out.println("I am Dog");
	}
}

// CHILD CLASS 2
package inheritance;
public class Cat extends Animal{
	public void whoAmI() {
		System.out.println("I am Cat");
	}
}

// MAIN CLASS
package inheritance;
public class Animal_Main {
	public static void main(String[] args) {		
		Dog d = new Dog();
		d.whoAmI();
		
		Cat c = new Cat();
		c.whoAmI();
	}
}

// OUTPUT: 

I am Dog
I am Cat

» Polymorphism in Java

Poly means Many

Morphs means Forms

So Polymorphism means Many Forms

So Polymorphism in Java means an ability of Object to get into multiple forms. It is a concept to performs single action in different ways.

There are two types of Polymorphism in Java 1) Compile-time and 2) Runtime

If you overrload a static method in Java, it is example of compile time Polymorphism.

Lets see Run Time polymorphism

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<p>Example:</p>

// PARENT CLASS
package inheritance;
public class Animal {
	public void whoAmI() {
		System.out.println("I am an Animal");
	}
}

// CHILD CLASS 1
package inheritance;
public class Dog extends Animal{
	public void whoAmI() {
		System.out.println("I am Dog");
	}
}

// CHILD CLASS 2
package inheritance;
public class Cat extends Animal{
	public void whoAmI() {
		System.out.println("I am Cat");
	}
}

// MAIN CLASS
package inheritance;
public class Animal_Main {
	public static void main(String[] args) {		
		Animal a;
		
		a = new Animal();
		a.whoAmI(); // output: I am an Animal
		
		a = new Dog();
		a.whoAmI(); // output: I am Dog
		
		a = new Cat();
		a.whoAmI() // output: I am Cat
	}
}

So here object a which we instantiated from Animal class (Parent class) is acting for Dog and Cat classes (Child classes) and calling their method.

Which simply means one object has many forms i.e. Polymorphism

More info on this: https://www.javatpoint.com/runtime-polymorphism-in-java

» Super keyword in Java

The keyword super denotes Super Class

Lets see this by example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
package super_keyword;
public class Parent {	
	int num1 = 100;	
	public void showInfo() {
		System.out.println("Show Info of Parent");
	}
}

package super_keyword;
public class Child extends Parent{
	int num1 = 200;	
	public void showInfo() {
		System.out.println("Show Info of Child");
	}
	
	public void getSomeMoreInfo() {
		System.out.println(num1); // the output will be 200
		showInfo();         	  // the output will be "Show Info of Child"
		super.showInfo();         // the output will be "Show Info of Parent"
		System.out.println(super.num1); // the output will be 100
	}	
}

Here we have same method i.e. showInfo() on Parent class & Child Class.

We have one more method in child class i.e. getSomeMoreInfo() and we want to call showInfo() method of Parent from getSomeMoreInfo()

If we directly call showInfo() then it will print "Show Info of Child" which we doesn't want.

So here come the super keyword, using super.showInfo() we can call the method of Parent Class.

» Super Class Constructor in Java

In Parent class if we have a constructor with argument(s) then it's subclass has to create a constructor with an argument which must call parent's constructor

Example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
package super_keyword;

public class Class1 {
	int num1;	
	public Class1(int a) {
		num1 = a;
	}
}

package super_keyword;

public class Class2 extends Class1{	
	int num2;	
	public Class2(int a, int b) {
		super(a);
		num2 = b;
	}
}

Now if Parent class still provide a no argument constructor then it's not mandatory for subclass to create a constructor

Example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
package super_keyword;

public class Class1 {
	int num1;	
	public Class1(int a) {
		num1 = a;
	}
	
	public Class1(){ 	// one more constructor
	 // ...
	}
}

package super_keyword;

public class Class2 extends Class1{	
	int num2;	 // now here subclass doesn't require any constructor	
}

» Protected Access in Java

When we create a variable or method as protected then it can be accessed in the same class, in the same package and in the classes of outside package as well when you inherit from it. If you do not inherit then you can't use it.

Example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package package1;
public class Car {
	
	private String model;
	
	int year;
	
	protected String make;
	
	public String color;	
}

package package1;

public class GermanCar extends Car {	
	public void setCarDetails() {
		model = "X6"; // ERROR: model is private so we cannot use it anywhere expect same class
		year = 2021; // default is accessible in child
		make = "BMW"; // protected is accessible in child
		color = "Red"; // public is accessible anywhere
	}	
}

package package2;

import package1.Car;

public class FrenchCar extends Car {	
	public void setCarDetails() {
		model = "X6"; // ERROR: model is private so we cannot use it anywhere expect same class
		year = 2021; // ERROR: year is default so we cannot access it outside of package
		make = "BMW"; // protected is accessible in child because we are inheriting Parent i.e. Car
		color = "Red"; // public is accessible anywhere
	}	
}

» Abstraction in Java

Abstraction is the process of hiding implementation details from user and provide only the functionalities. Let user know what method they are using and no need to provide the details of it as what code is getting executed as part of those methods.

Abstraction can be done in two ways:

1) By Abstract Classes and Abstract Methods

2) By creating Interfaces

» Abstraction in Java by Abstract Classes and Abstract Methods

Abstract class is a kind of guidline class which provide functional details of class and not the implementation details. The implementation details resides in subclass of it.

Abstract class is a class which cannot be instantiated. You cannot create object of it.

We use keyword 'abstract' to create abstract class.

Example: public abstract class Mobile

Use of abstract class is just to extend it by it's child class and implement an unimplemented methods in the child class.

We can just define methods in abstract class and provide the implementation in subclass.

We can create abstract method in abstract class but subclass must have to provide its implementation.

We can create non-abstract method in abstract class and subclass has no compultion to provide its implementation.

We use keyword 'abstract' to create abstract method.

Example: public abstract void doubleTap()

Example of Abstract class and method

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package abstraction;

public abstract class Mobile {

	public abstract void doubleTap(); // its abstract method so you must have to implement it in subclasses
	
	public void abc() {
		System.out.println("I am abc");
	}
}

package abstraction;

public class Android extends Mobile{

	@Override
	public void doubleTap() {						// implementing parent class method here o/w it will throw an error
		System.out.println("Android Double Tap");
	}
}

package abstraction;

public class IOS extends Mobile{

	@Override
	public void doubleTap() {						// implementing parent class method here o/w it will throw an error
		System.out.println("IOS Double Tap");
	}
}

» Abstraction in Java by creating Interfaces

Interface is collection of abstract methods. The method which does not have any implementation

We don't require any abstract keyword to declare class in interface.

Class can implement an Interface

Interface can extend from another Interface

Non abstract class extending from an abstract class needs to implement unimplemented methods

Non abstract class implementing an interface needs to implement unimplemented methods

Interface can not be instantiated

Interface does not have a constructor

All methods in interface are by default abstract (without implementation) except static and default methods. We don't require any abstract keyword for methods in interface.

Interface cannot have data members. All variables by default considered as Static and Final

Everything is public by default

Example:

- Creating Interface

1
2
3
public interface Interface1{
	void doThis();
}

- Class can implement an Interface

public class Class1 implements Interface1{ 		// implementing Interface1 in Class1
	@Override
	public void doThis(){
	  // to do...
	}
}

- Interface can extend from another Interface

public interface Interface2 extends Interface1{		// extending Interface1 in Interface2
	void doThat();
}

- Create Class2 which implements Interface2

public class Class2 implements Interface2{

	// Here both the methods of Interface1 and Interface2 has to implement in Class because Interface2 is child of Interface1 (or extending Interface1)

	@Override
	public void doThis(){
	  // to do...
	}
	
	@Override
	public void doThat(){
	  // to do...
	}
}

- Unlike class we can have Multiple Inheritance is possible in case of interfaces.

public class Class3 implements Int1, Int2 {

	@Override
	public void doThat() {
		// TODO Auto-generated method stub		
	}

	@Override
	public void doThis() {
		// TODO Auto-generated method stub		
	}
}

- Abstract class doesn't need to implement interface methods

public class Class2 implements Interface1{ // so here we are not implementing Interface1 methods because we made Class2 an Abstract class }

Non abstract class extending from an abstract class needs to implement unimplemented methods

Non abstract class implementing an interface needs to implement unimplemented methods

Example: Take above Class2 and add one abstract method to it

public class Class2 implements Interface2{
	public abstract void abc();
}

Lets create Class4

public class Class4 extends Class2{

	// because Class2 has method doThat() which has to implement
	@Override
	public void doThat() {						
		// TODO Auto-generated method stub		
	}

	// because Class2 has parent interface which Interface1 which has doThis() so has to implement
	@Override
	public void doThis() {						
		// TODO Auto-generated method stub		
	}

	// because Class2 is abstract class and abstract method so has to implement
	@Override
	public void abc() {							
		// TODO Auto-generated method stub		
	}	
}

- static and default methods in interface (in Java version 8+ only)

Child can override the default methods

Child cannot override the static methods

Lets go to Interface1 and add some static & default methods

public interface Interface1 {
	
	static final int a = 100;
	
	void doThis();
	
	static void xyz() {
		System.out.println("Static xyz from Int1");
	}
	
	default void uvw() {
		System.out.println("Default uvw from Int1");
	}
}

Interface cannot have data members (variables)

All the members must be static final

Example:

public interface Interface1{
	int num = 100; // NOT ALLOWED this will throw error
	static final int num = 100; // ALLOWED
}

» Final Keyword in Java

Final Field is used to create a Constant.

Final Method is used to avoid Method Overriding. Subclass cannot override it.

Final Class is used to prevent Inheritance. Final class cannot be inherited. You cannot create subclass of final class.

public class Final_Keyword {	
	final int A = 100;			// it becomes constant
	final void abc() {			// cannot override
		System.out.println("Final method abc");
	}	
}

» ArrayList vs LinkedList in Java

ArrayList:

In ArrayList we have index associated with every item so its internally implements dynamic array.

Accessing value is faster than LinkedList because we can use index of an element.

Inserting or deleting something inside the ArrayList is slower becauase when we do that then shift in the memory happens which makes it slower

LinkedList:

In LinkedList its internally implements the doubly linked list so elements are not adjecent to each other they are at random location but they connected to each other using pointers.

Accessing value is slower than ArrayList because always have to start from HEAD and then go to the next element till TAIL hence its time consuming.

Inserting or deleting something inside the LinkedList is faster as compared to ArrayList because of Pointers we can break the current link and add the new link in between of it.

More on this:

» Hash Set in Java

A Set is a collection (like List) that cannot contain duplicate elements.

HashSet doesn't maintain insertion order.

No positional access of elements.

Example:

import java.util.ArrayList;
import java.util.HashSet;

public class Hash_Set {

	public static void main(String[] args) {
		
		/*
		 * Set is a Collection that cannot contain duplicate elements.
		 * HashSet does not maintain insertion order
		 * No positional access of elements
		 * Basic Methods: add, remove, clear, contains, size, 
		 * Union and Intersection of Sets
		 * Convert set to list
		 */
		
		var set1 = new HashSet<Integer>();
		
		set1.add(10);
		set1.add(20);
		set1.add(30);
		set1.add(40);
		set1.add(50);
		set1.add(10);
		set1.add(20);
		
		var set2 = new HashSet<Integer>();
		
		set2.add(10);
		set2.add(40);
		set2.add(50);
		set2.add(70);
		set2.add(80);
		
		//set1.addAll(set2);	// UNION
		
		//set1.retainAll(set2);	// INTERSECTION
		
		//System.out.println(set1);
		
		//set1.remove(20);
		
		// Convert SET to LIST
		var list1 = new ArrayList<Integer>();		
		list1.addAll(set1);
		
		System.out.println(list1);
	}
}

» Linked Hash Set in Java

A LinkedHashSet is an ordered version of HashSet .

LinkedHashSet maintains a doubly-linked List across all elements.

No positional access of elements.

Example:

import java.util.LinkedHashSet;

public class Linked_Hash_Set {

	public static void main(String[] args) {
			
		LinkedHashSet<Character> set1 = new LinkedHashSet<Character>();
		
		set1.add('a');
		set1.add('e');
		set1.add('i');
		set1.add('o');
		set1.add('u');
		
		System.out.println(set1);			
	}
}

» TreeSet in Java

TreeSet is an important implementation of the SortedSet interface.

Elements are sorted in ascending order by default.

No positional access of elements.

Example:

import java.util.Set;
import java.util.TreeSet;

public class Tree_Set {

	public static void main(String[] args) {
		
		Set<String> set1 = new TreeSet<String>();
		
		set1.add("Rob");
		set1.add("Bob");
		set1.add("Andy");
		set1.add("Charls");
		
		System.out.println(set1);
		
		var set2 = new TreeSet<Integer>();
		
		set2.add(100);
		set2.add(10);
		set2.add(50);
		set2.add(2);
		set2.add(0);
		
		System.out.println(set2);
	}
}

» Iterating over Set in Java

We can use special for loop or an Iterator.

Example:

import java.util.HashSet;
import java.util.Iterator;
import java.util.TreeSet;

public class Iterating_Over_Set {

	public static void main(String[] args) {
		
		/*
		 * Special For Loop
		 * Iterator
		 */
		
		HashSet<Integer> set1 = new HashSet<Integer>();
				
		set1.add(100);
		set1.add(200);
		set1.add(300);
		set1.add(400);
		set1.add(500);
		
		for(int x : set1) {
			System.out.println(x);
		}
		
		var set2 = new TreeSet<String>();
		
		set2.add("Sun");
		set2.add("Mon");
		set2.add("Tue");
		set2.add("Wed");
		set2.add("Thu");
		
		System.out.println("---------------");
		
		Iterator it1 = set2.iterator();
		
		while(it1.hasNext()) {
			System.out.println(it1.next());
		}
	}
}

» HashMap in Java

HashMap provides the basic implementation of Map interface.

It stores data in Key and Value pairs

We can access a value using the corresponding key

Methods: put, get, containsKey, remove, clear, keySet, values, entrySet

Example:

import java.util.HashMap;

public class Hash_Map {

	public static void main(String[] args) {
		
		var map = new HashMap<Integer,String>();
		
		map.put(1, "Jan");
		map.put(0, "Feb");
		map.put(3, "Mar");
		map.put(4, "Apr");
		map.put(5, "May");
		
		System.out.println(map.get(2));
		
		System.out.println(map.containsKey(3));
		
		map.put(4, "Dec");
		
		//map.remove(4);
		
		//map.remove(5, "May1");
		
		//map.clear();
		
		// convert map to set
		
		var set1 = map.keySet(); // by key
		
		var set2 = map.values(); // by value
		
		var set3 = map.entrySet(); // by both key and value
		
		System.out.println(set1);
		System.out.println(set2);
		System.out.println(set3);
	
		System.out.println(map);
		
	}
}

» TreeMap in Java

TreeMap is implemented based on red-black tree structure.

It is sorted by keys.

Example:

import java.util.TreeMap;

public class Tree_Map {

	public static void main(String[] args) {
		
		/*		 
		 * Methods: put, get, containsKey, containsValue, replace, remove, clear, keySet, values, entrySet
		 * firstEntry,lastEntry,firstKey,lastKey,pollFirstEntry,pollLastEntry
		 */
		
		var map = new TreeMap<Character, Integer>();
			
		map.put('d', 1000);
		map.put('a', 2000);
		map.put('c', 3000);
		map.put('b', 4000);
		
		System.out.println(map); // output : {a=2000, b=4000, c=3000, d=1000}
		
		//System.out.println(map.containsValue(30000));
		//map.put('a', 6000);
		
		//map.replace('a', 6000);
		
		//System.out.println(map.firstEntry());
		//System.out.println(map.lastEntry());
		//System.out.println(map.firstKey());
		//System.out.println(map.lastKey());
		
		//System.out.println(map.pollFirstEntry());
		//System.out.println(map.pollLastEntry());
		
		System.out.println(map);
	}
}

» Iterating over Map

Example:

import java.util.Iterator;
import java.util.Map.Entry;
import java.util.TreeMap;

public class Map_Iterating {

	public static void main(String[] args) {
		
		var map = new TreeMap<Integer,Double>();
		
		map.put(10, Math.sqrt(10));
		map.put(30, Math.sqrt(30));
		map.put(50, Math.sqrt(50));
		map.put(40, Math.sqrt(40));
		map.put(20, Math.sqrt(20));
		/*
		for(Entry<Integer, Double> e : map.entrySet()) {
			System.out.println(e);
		}
		*/
		
		Iterator it = map.entrySet().iterator();
		
		while(it.hasNext()) {
			System.out.println(it.next());
		}
	}
}

» Exception Handling in Java

What is an Exception: Exceptions are events which occur during the execution of programs that disrupt the normal flow of the application. e.g. String Index Out Of Boundaries, Dividing by Zero, Null Pointer

String x = null;

System.out.println(x.length); // exception
		
System.out.println(100/0); // exception

What is Exception Object: An exception object is an instance of an exception class. It gets created and handed over to the Java runtime when an exceptional event occurs. Exception Object contains:

1) Information about the error

2) State of the program

Error vs Exception

Error : A serious problems that a reasonable application should not try to catch e.g. OutOfMemoryError, StackOverflowError, LinkageError

Exception : A conditions that a reasonable application might want to catch e.g. FileNotFoundException, ParseException, SQLException

Throwable : The Throwable class is the superclass of all errors and exceptions

Checked Exceptions vs Unchecked Exceptions

Lets see this by example

import java.io.FileInputStream;

public class CheckedVsUnchecked {

	public static void main(String[] args) {
		
		/*
		 * Checked Exceptions : Checked at Compile-Time
		 * e.g. IOException, SQLException, ClassNotFoundException etc.
		 * 
		 * Unchecked Exceptions (RunTime Exceptions): Checked at Run-Time
		 * e.g. ArithmeticException, ArrayIndexOutOfBoundsException etc.
		 */
		
		// checked exception
		FileInputStream x = new FileInputStream("Users⁩/md/⁨Downloads⁩/abc.txt");
		
		// unchecked exception
		System.out.println(100/0);		 		
	}
}

Try, Catch and Finally by Example:

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class Try_Catch {

	public static void main(String[] args) {
		
		// If there is an exception in test() function still the system.out.println 
		// will execute because we handling an exception there.
		test();		
		System.out.println("Hello World");
	}
	
	public static void test() {
		try {
			FileInputStream x = new FileInputStream("Users⁩/md/⁨Downloads⁩/abc.txt");
		} 
		catch (FileNotFoundException e) {
			System.out.println(e.getMessage());
			System.out.println(e.toString());
			e.printStackTrace();
		} 
		catch (IOException e2) {				// We can have multiple catch block
			System.out.println(e2.getMessage());
		}
		catch (Exception e1) {
			System.out.println(e1.getMessage());
		}
	}	
}
public class Finally_Block {

	public static void main(String[] args) {
		
		/*
		 * The finally block gets executed after successful run of the 
		 * try block or after one of the catch blocks handled an exception
		 */

		int num1 = 100;
		int num2 = 10;
		
		try {
			int num3 = num1 / num2;
		}  finally {
			System.out.println("Finally Block Code");
		}
	}
}

» Design Patterns in Java

Creational Design Pattern: Factory Pattern, Builder Pattern, Singleton Pattern etc..

Structural Design Pattern: Proxy Pattern, Adaptor Pattern etc..

Behavioral Design Pattern: Observer Pattern, State Pattern, Iterator Pattern etc..

» Singleton Design Patterns in Java

The Singleton design pattern ensures that a class has only one instance and provides a global point of access to that instance. In simpler terms, it's like having just one unique object of a particular class throughout the entire application

Imagine a company has a printer. Now, instead of having multiple printers wasting resources, they decide to implement the Singleton pattern. This means they'll have just one printer for the entire office.

Initialization: The first time anyone in the office tries to use the printer, the system initializes it, and from then on, everyone uses the same printer instance.

Access: Whenever an employee wants to print something, they don’t have to get a new printer; they just use the existing one because it’s a Singleton.

public class Printer {
    // Step 1: Create a private static instance of the class.
    private static Printer printerInstance;

    // Step 2: Make the constructor private so that it cannot be instantiated from outside.
    private Printer() {}

    // Step 3: Provide a method to access the single instance.
    public static Printer getInstance() {
        if (printerInstance == null) {
            printerInstance = new Printer();
        }
        return printerInstance;
    }

    // Other methods of the Printer class go here.
    public void printDocument(String document) {
        System.out.println("Printing: " + document);
    }
}

// Usage
public class Main {
    public static void main(String[] args) {
        // Get the singleton instance
        Printer myPrinter = Printer.getInstance();

        // Print using the singleton instance
        myPrinter.printDocument("Sample Document");

        // Try to get another instance, but it's the same one
        Printer anotherPrinter = Printer.getInstance();
        anotherPrinter.printDocument("Another Sample Document");
    }
}

In this example, no matter how many times you try to get an instance of the Printer class using the getInstance() method, you will always get the same instance. This ensures that there's only one printer object throughout the application.

In this example, the primary goal is to ensure that only one instance of the Printer class exists throughout the application's lifecycle. If you attempt to create another instance of the Printer class using its constructor directly, you'll encounter a compilation error because the constructor is marked as private.

// Step 2: Make the constructor private so that it cannot be instantiated from outside.
private Printer() {}

When a constructor is marked as private, it means that you cannot create an instance of that class from outside the class itself. This ensures that other parts of the code cannot instantiate the class using the new keyword.

If you try to do something like this like Attempting to Create Another Instance:

Printer anotherPrinterInstance = new Printer();  // This will give a compilation error.

You'll get a compilation error because the Printer constructor is not accessible from outside the class due to its private access modifier.

To get an instance of the Printer class, you have to use the getInstance() method, which is the only way to access the single instance of the Printer class:

Printer myPrinter = Printer.getInstance();  // This will give you the singleton instance.

In this way, the Singleton pattern ensures that there's only one instance of the Printer class throughout the application, and you cannot create another instance of it using its constructor directly.

The Singleton design pattern is useful in situations where you need to ensure that a class has only one instance and that instance is accessible globally within an application. Here are some common use cases and scenarios where you might use the Singleton pattern:

Logging, Database Management, Caching, Configuration Management

Key Considerations:

While the Singleton pattern provides a convenient way to manage global state and resources, it's essential to use it judiciously. Overuse of the Singleton pattern can lead to tightly coupled code, which can make unit testing difficult and reduce the flexibility of your application.

Additionally, when implementing the Singleton pattern, you should consider thread safety, especially in multi-threaded environments. In Java, you can use various techniques like lazy initialization with double-checked locking or static initialization to ensure thread safety when creating the Singleton instance.

How would you break singleton design pattern?

Reflection: Using Java's reflection API, you can access the private constructor of a Singleton class and create a new instance. Here's a simple code snippet demonstrating this:

public class Singleton {
    private static Singleton instance;

    private Singleton() {
        // Private constructor
    }

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

public class Main {
    public static void main(String[] args) {
        try {
            // Using reflection to create a new instance of Singleton
            Constructor<Singleton> constructor = Singleton.class.getDeclaredConstructor();
            constructor.setAccessible(true);
            Singleton newInstance = constructor.newInstance();
            
            // Now, you have broken the Singleton pattern
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

» Factory Design Pattern in Java

The Factory design pattern in Java is a creational pattern that provides an interface for creating objects, but allows subclasses to alter the type of objects that will be instantiated. In simpler terms, it's like a factory that produces different types of products based on the request it receives.

Let's take the example of a pizza restaurant. A pizza restaurant can produce different types of pizzas like Margherita, Pepperoni, and Veggie. Instead of having separate methods or classes for creating each type of pizza, the restaurant uses a Pizza Factory.

Factory Interface: Define an interface called Pizza with a method preparePizza.

interface Pizza {
    void preparePizza();
}

Concrete Implementations: Create concrete classes for different types of pizzas.

class Margherita implements Pizza {
    @Override
    public void preparePizza() {
        System.out.println("Preparing Margherita Pizza...");
    }
}

class Pepperoni implements Pizza {
    @Override
    public void preparePizza() {
        System.out.println("Preparing Pepperoni Pizza...");
    }
}

class Veggie implements Pizza {
    @Override
    public void preparePizza() {
        System.out.println("Preparing Veggie Pizza...");
    }
}

Pizza Factory: Implement a Pizza Factory that produces different types of pizzas based on the request.

class PizzaFactory {
    public Pizza createPizza(String type) {
        if ("Margherita".equalsIgnoreCase(type)) {
            return new Margherita();
        } else if ("Pepperoni".equalsIgnoreCase(type)) {
            return new Pepperoni();
        } else if ("Veggie".equalsIgnoreCase(type)) {
            return new Veggie();
        }
        return null;
    }
}

Usage: Use the Pizza Factory to create different types of pizzas.

public class Main {
    public static void main(String[] args) {
        PizzaFactory pizzaFactory = new PizzaFactory();

        Pizza margherita = pizzaFactory.createPizza("Margherita");
        margherita.preparePizza();

        Pizza pepperoni = pizzaFactory.createPizza("Pepperoni");
        pepperoni.preparePizza();

        Pizza veggie = pizzaFactory.createPizza("Veggie");
        veggie.preparePizza();
    }
}

In this example, the Pizza Factory acts as a centralized place to create different types of pizzas. Based on the type of pizza requested, the factory produces the corresponding pizza, demonstrating the Factory design pattern in action.

Key Benefits:

Flexibility: The Factory pattern provides flexibility by allowing you to create objects without specifying the exact class of object that will be created.

Encapsulation: It encapsulates the object creation logic, making it easier to manage and extend in the future.

Code Reusability: You can reuse the factory to create multiple instances of objects without duplicating the creation code.

» How do you create microservices in in Spring boot?

In today's digital era, microservices architecture offers scalability and flexibility. Let's explore how to create a simple e-commerce app using Spring Boot with three microservices: Product, Order, and User.

Setup Spring Boot Projects

Generate three Spring Boot projects using Spring Initializr: product-service, order-service, and user-service.

Define Dependencies

Add Spring Web, Spring Data JPA, and H2 Database dependencies to each project's pom.xml.

Create Microservice Components

Product Service

Create a Product entity, repository, and controller for CRUD operations.

@Entity
public class Product {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private String description;
    private BigDecimal price;
    
    // Getters and Setters
}

Repository: Create a ProductRepository interface extending JpaRepository.

@Repository
public interface ProductRepository extends JpaRepository<Product, Long> {
}

Controller: Implement a RESTful API to fetch products.

@RestController
@RequestMapping("/api/products")
public class ProductController {
    @Autowired
    private ProductRepository productRepository;

    @GetMapping
    public List<Product> getAllProducts() {
        return productRepository.findAll();
    }
}

Order Service: Similar to the Product Service, create entities (Order, OrderItem) and corresponding repositories and controllers.

User Service: Define a User entity and implement CRUD operations using repositories and controllers.

Configure Service Communication:

Use Spring Cloud Eureka for service registration and discovery. Each microservice registers itself with the Eureka server and looks up dependencies via service names.

Implement Service Interactions:

In the Order Service, when creating an order, call the Product Service to verify product availability and User Service to validate user details.

Dockerize Microservices

Create Dockerfile for each microservice to containerize them. Use docker-compose to manage multi-container Docker applications, defining services, networks, and volumes.

Implement Circuit Breakers

Use Spring Cloud Circuit Breaker (Hystrix) to handle failures gracefully between service interactions.

Build and Deploy

Build Docker images for each microservice and deploy them to a container orchestration platform like Kubernetes or cloud platforms (AWS, Azure, Google Cloud).

» Explain the components (entities, repositories, controllers) for each microservice. Explain how service communication is implemented using Spring Cloud Eureka and service interactions between microservices.

Components of Microservices:

Entities:

Think of entities as the blueprint for your data. In our e-commerce example, each microservice has its data structure:

Product Service: Defines what a product looks like (e.g., name, price).

Order Service: Defines what an order looks like (e.g., items, customer details).

User Service: Defines what a user looks like (e.g., username, email).

Repositories:

Repositories are like specialized libraries where you can save, retrieve, and manage your data.

Product Repository: This is where you'd save, fetch, or delete product information.

Order Repository: This is where you'd handle saving and fetching order details.

User Repository: This manages user-related tasks like saving user details.

Controllers:

Controllers act as traffic controllers for your application, deciding what to do when you receive a request.

Product Controller: When someone wants product info, this controller handles it.

Order Controller: This manages requests related to orders, like placing a new order.

User Controller: When someone needs user details or wants to create a new user, this controller takes care of it.

Service Communication using Spring Cloud Eureka:

Imagine you have three friends, and instead of calling their names whenever you want something, you use a directory or a phonebook to find them easily. Spring Cloud Eureka acts like that phonebook for your microservices.

Registering Services: Each microservice registers itself with Eureka when it starts up. It's like adding your friend's contact details to the phonebook.

Discovering Services: If one microservice needs to talk to another, instead of hardcoding the location, it asks Eureka where the other service is. This way, it can find and communicate with other services without guessing their locations.

Service Interactions Between Microservices:

Imagine you're buying a product online. Multiple things need to happen behind the scenes:

You browse products (Product Service).

You add products to the cart and place an order (Order Service).

You might need to log in or create an account (User Service).

These services don't work in isolation; they talk to each other:

Order Service might ask the Product Service if a product is available when you try to buy it.

When creating an order, the Order Service might check with the User Service to ensure you're a valid user.

This interaction is crucial because each microservice handles its specialized task, but they work together to provide a seamless experience for you, the user. And Spring Cloud Eureka ensures they find and communicate with each other easily.

No comments:

Post a Comment