0% found this document useful (0 votes)
37 views

Answers To Core Java Interview Questions

Answers
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
37 views

Answers To Core Java Interview Questions

Answers
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 142

Answers To Core java interview Questions

1.

 It is a creational design pattern that talks about the creation of an


object. The factory design pattern says to define an interface (A java
interface or an abstract class) for creating the object and let the
subclasses decide which class to instantiate.
 The factory method in the interface lets a class defer the
instantiation to one or more concrete subclasses.
 Since these design patterns talk about the instantiation of an object
they come under the category of creational design pattern.
 If we notice the name Factory method, that means there is a
method which is a factory, and in general, factories are involved
with creational stuff and here with this, an object is being created.
 It is one of the best ways to create an object where object creation
logic is hidden from the client. Now Let’s look at the
implementation.

Factory method design pattern can be used in java in following


cases:

 A class cannot predict the type of objects it needs to create.


 A class wants its subclasses to specify the objects it creates.
 Classes delegate responsibility to one of multiple helper subclasses,
and you aim to keep the information about which helper subclass is
the delegate within a specific scope or location.
 Key Components of Factory Method Design Pattern

Product
 It’s an abstract class or interface that defines the common operations for
the objects that the factory will create.
 Concrete Products are the actual classes that implement the Product
interface, each representing a specific type of object to be created.
Creator
 It’s an abstract class or interface that declares the factory method.
 This method is responsible for creating Product objects, but it delegates
the actual creation to subclasses.
Concrete Creators
 These are subclasses of the Creator that implement the factory method.
 They decide which specific Concrete Product to create, often based on
input parameters or configuration.
Factory Method
 It’s a method defined in the Creator class that is responsible for creating
Product objects.
 It’s typically declared as abstract in the Creator and implemented in the
Concrete Creators.
Problem Statement
 You are developing a software system for an e-commerce platform that
deals with various types of products. Each product category (e.g.,
electronics, clothing, books) requires specific handling during creation.
However, you want to decouple the client code from the concrete
product creation logic to enhance flexibility and maintainability.
Additionally, you want to allow for easy extension by adding new product
types in the future without modifying existing code.

Solution using Abstract Class


 The above problem can be solved using Factory Method Design Pattern:

// Abstract Product Class

abstract class Product {

public abstract void display();

// Concrete Products

class ConcreteProductA extends Product {


@Override

public void display() {

System.out.println("This is Concrete Product A.");

class ConcreteProductB extends Product {

@Override

public void display() {

System.out.println("This is Concrete Product B.");

// Creator Abstract Class

abstract class Creator {

public abstract Product factoryMethod();

// Concrete Creators

class ConcreteCreatorA extends Creator {

@Override

public Product factoryMethod() {

return new ConcreteProductA();


}

class ConcreteCreatorB extends Creator {

@Override

public Product factoryMethod() {

return new ConcreteProductB();

// Client Code

public class FactoryMethodExample {

public static void main(String[] args) {

Creator creatorA = new ConcreteCreatorA();

Product productA = creatorA.factoryMethod();

productA.display();

Creator creatorB = new ConcreteCreatorB();

Product productB = creatorB.factoryMethod();

productB.display();

}
Output

This is Concrete Product A.

This is Concrete Product B.

Solution using Interface

The above problem can be solved using Factory Method Design Pattern:

// Product Interface

interface Product {

void display();

// Concrete Products

class ConcreteProductA implements Product {

@Override

public void display() {

System.out.println("This is Concrete Product A.");

class ConcreteProductB implements Product {

@Override

public void display() {

System.out.println("This is Concrete Product B.");


}

// Factory Interface

interface Factory {

Product factoryMethod();

// Concrete Factories

class ConcreteFactoryA implements Factory {

@Override

public Product factoryMethod() {

return new ConcreteProductA();

class ConcreteFactoryB implements Factory {

@Override

public Product factoryMethod() {

return new ConcreteProductB();

}
// Client Code

public class FactoryMethodExample {

public static void main(String[] args) {

Factory factoryA = new ConcreteFactoryA();

Product productA = factoryA.factoryMethod();

productA.display();

Factory factoryB = new ConcreteFactoryB();

Product productB = factoryB.factoryMethod();

productB.display();

Use Cases of the Factory Method Design Pattern in Java

Here are some common applications of the Factory Method Design


pattern in Java:

 Creational Frameworks:

o JDBC (Java Database Connectivity) uses factories extensively for


creating connections, statements, and result sets. Dependency
injection frameworks like Spring and Guice rely heavily on factories
to create and manage beans.

 GUI Toolkits:

o Swing and JavaFX use factories to create UI components like


buttons, text fields, and labels, allowing for customization and
flexibility in UI design.

 Logging Frameworks:
o Logging frameworks like Log4j and Logback use factories to create
loggers with different configurations, enabling control over logging
levels and output destinations.

 Serialization and Deserialization:

o Object serialization frameworks often use factories to create


objects from serialized data, supporting different serialization
formats and versioning.

 Plugin Systems:

o Plugin-based systems often use factories to load and create plugin


instances dynamically, allowing for extensibility and customization.

 Game Development:

o Game engines often use factories to create different types of game


objects, characters, and levels, promoting code organization and
flexibility.

 Web Development:

o Web frameworks sometimes use factories to create view


components, controllers, and services, enabling modularity and
testability in web applications.

Advantages of Factory Method Design Pattern in Java

The advantages of Factory Method Design Pattern in Java are:

 Decoupling: It separates object creation logic from the client code that
uses those objects. This makes the code more flexible and maintainable
because changes to the creation process don’t require modifications to
client code.

 Extensibility: It’s easy to introduce new product types without changing


the client code. You simply need to create a new Concrete Creator
subclass and implement the factory method to produce the new product.

 Testability: It simplifies unit testing by allowing you to mock or stub out


product creation during tests. You can test different product
implementations in isolation without relying on actual object creation.

 Code Reusability: The factory method can be reused in different parts


of the application where object creation is needed. This promotes
centralizing and reusing object creation logic.
 Encapsulation: It hides the concrete product classes from the client
code, making the code less dependent on specific implementations. This
improves maintainability and reduces coupling.

Disadvantages of Factory Method Design Pattern in Java

The disavantages of Factory Method Design Pattern in Java are:

 Increased Complexity: It introduces additional classes and


interfaces, adding a layer of abstraction that can make the code more
complex to understand and maintain, especially for those unfamiliar with
the pattern.

 Overhead: The use of polymorphism and dynamic binding can slightly


impact performance, although this is often negligible in most
applications.

 Tight Coupling Within Product Hierarchies: Concrete Creators are


still tightly coupled to their corresponding Concrete Products. Changes to
one often necessitate changes to the other.

 Dependency on Concrete Subclasses: The client code still depends


on the abstract Creator class, requiring knowledge of its concrete
subclasses to make correct factory method calls.

 Potential for Overuse: It’s important to use the Factory Method pattern
judiciously to avoid over-engineering the application. Simple object
creation can often be handled directly without the need for a factory.

 Testing Challenges: Testing the factory logic itself can be more


complex.

Conclusion

So far we learned what is Factory method design pattern and how to


implement it. I believe now we have a fair understanding of the
advantage of this design mechanism. Factory methods pervade toolkits
and frameworks.The preceding document example is a typical use in
MacApp and ET++.
2. Immutable class/object is the one whose value cannot be modified. For
example, Strings are immutable in Java i.e. once you create a String value in
Java you cannot modify it. Even if you try to modify, an intermediate String is
created with the modified value and is assigned to the original literal.
Defining immutable objects
Whenever you need to create an object which cannot be changed after
initialization you can define an immutable object. There are no specific rules to
create immutable objects, the idea is to restrict the access of the fields of a
class after initialization.
Example
Following Java program demonstrates the creation of a final class. Here, we
have two instance variables name and age, except the constructor you cannot
assign values to them.
final public class Student {
private final String name;
private final int age;
public Student(String name, int age){
this.name = name;
this.age = age;
}
public String getName() {
return this.name;
}
public int getAge() {
return this.age;
}
public static void main(String[] args){
Student std = new Student("Krishna", 29);
System.out.println(std.getName());
System.out.println(std.getAge());
}
}

Output
Krishna
29
Is it a must to declare all variables final
No, it is not mandatory to have all properties final to create an immutable
object. In immutable objects you should not allow users to modify the variables
of the class.
You can do this just by making variables private and not providing setter
methods to modify them.
Example
public class Sample{
String name;
int age;
public Sample(){
this.name = name;
this.age = age;
}
public String getName(){
return this.name;
}
public int getAge(){
return this.age;
}
}

An immutable object is an object whose internal state remains constant


after it has been entirely created.
This means that the public API of an immutable object guarantees us that it will
behave in the same way during its whole lifetime.
If we take a look at the class String, we can see that even when its API seems
to provide us a mutable behavior with its replace method, the
original String doesn’t change:

String name = "baeldung";


String newName = name.replace("dung", "----");
assertEquals("baeldung", name);
assertEquals("bael----", newName);
The API gives us read-only methods, it should never include methods that
change the internal state of the object.
Before trying to achieve immutability in Java, we should talk about
the final keyword.
In Java, variables are mutable by default, meaning we can change the
value they hold.
By using the final keyword when declaring a variable, the Java compiler won’t
let us change the value of that variable. Instead, it will report a compile-time
error:
final String name = "baeldung";
name = "bael...";
that final only forbids us from changing the reference the variable holds, it
doesn’t protect us from changing the internal state of the object it refers to by
using its public API:
final List<String> strings = new ArrayList<>();
assertEquals(0, strings.size());
strings.add("baeldung");
assertEquals(0, strings.size());

The second assertEquals will fail because adding an element to the list changes
its size, therefore, it isn’t an immutable object.
4. Immutability in Java
Now that we know how to avoid changes to the content of a variable, we can
use it to build the API of immutable objects.
Building the API of an immutable object requires us to guarantee that its
internal state won’t change no matter how we use its API.
A step forward in the right direction is to use final when declaring its attributes:
class Money {
private final double amount;
private final Currency currency;
// ...
}
Note that Java guarantees us that the value of amount won’t change, that’s the
case with all primitive type variables.
However, in our example we are only guaranteed that the currency won’t
change, so we must rely on the Currency API to protect itself from
changes.
Most of the time, we need the attributes of an object to hold custom values,
and the place to initialize the internal state of an immutable object is its
constructor:
class Money {
// ...
public Money(double amount, Currency currency) {
this.amount = amount;
this.currency = currency;
}

public Currency getCurrency() {


return currency;
}

public double getAmount() {


return amount;
}
}
As we’ve said before, to meet the requirements of an immutable API,
our Money class only has read-only methods.
Using the reflection API, we can break immutability and change immutable
objects. However, reflection violates immutable object’s public API, and usually,
we should avoid doing this.
5. Benefits
Since the internal state of an immutable object remains constant in time, we can
share it safely among multiple threads.
We can also use it freely, and none of the objects referencing it will notice any
difference, we can say that immutable objects are side-effects free.
6. Conclusion
Immutable objects don’t change their internal state in time, they are thread-safe
and side-effects free. Because of those properties, immutable objects are also
especially useful when dealing with multi-thread environments.
You can find the examples used in this article over on GitHub.
3. The code provided will not compile because of an error related to the
constructor.
Code Explanation:
1. Constructor Definition:
o In Java, a constructor does not have a return type. However, in your
code, the method void InterviewbitTest() appears to be intended as
a constructor, but it has a return type of void. This makes it a
regular method, not a constructor.
o The constructor that should be executed when you create an object
using new InterviewbitTest() is the default no-argument constructor.
However, since you've defined a constructor with an argument
(InterviewbitTest(int x)), the default no-argument constructor is not
provided by Java automatically, and you haven't explicitly defined
one.
2. Main Method:
o The main method tries to create an instance of InterviewbitTest
using new InterviewbitTest(). Since there is no valid no-argument
constructor defined, this will result in a compilation error.
Corrected Code:
If you remove the void keyword from InterviewbitTest() to make it a valid
constructor, the code would look like this:
java
Copy code
public class InterviewbitTest {
private static int counter = 0;

// Corrected constructor
InterviewbitTest() {
counter = 20;
}

InterviewbitTest(int x){
counter = x;
}

public static void main(String[] args) {


InterviewbitTest interviewbitTest = new InterviewbitTest();
System.out.println(counter);
}
}
Output of Corrected Code:
 When you run this corrected code, the constructor InterviewbitTest() will
be called, which sets counter to 20.
 The System.out.println(counter); statement will then print 20.
So, the output would be:
20
4o

4. Let's break down the code step by step to understand what happens:
Initial Setup
 Class X:
o static int i = 1111; initializes i to 1111.

o The static block in class X (L1) modifies i using the expression i = i--
- --i;.
 Class Y:
o Class Y extends X.

o The static block in class Y (L3) further modifies i using the


expression i = --i - i--;.
 Instance Initialization:
o When an instance of Y is created (Y y = new Y();), the instance
initialization blocks in both X (L2) and Y (L4) are executed.
Execution Flow and Calculations
1. Static Initialization of Class X:
o i = 1111; (initialization)

o i = i-- - --i; (L1)

 Breakdown:
 First, i-- evaluates to 1111 (but i is decremented to
1110 after evaluation).
 Then, --i decrements i to 1109 and evaluates to 1109.
 The expression becomes 1111 - 1109 = 2.
 i is now 2.
2. Static Initialization of Class Y:
o i = --i - i--; (L3)

 Breakdown:
 --i decrements i from 2 to 1 and evaluates to 1.
 i-- evaluates to 1 (but i is decremented to 0 after
evaluation).
 The expression becomes 1 - 1 = 0.
 i is now 0.
3. Instance Initialization of Class X:
o When new Y() is called, the instance initialization block in X is
executed.
o i = i++ + ++i; (L2)

 Breakdown:
 i++ evaluates to 0 (but i is incremented to 1 after
evaluation).
 ++i increments i to 2 and evaluates to 2.
 The expression becomes 0 + 2 = 2.
 i is now 2.
4. Instance Initialization of Class Y:
o i = ++i + i++; (L4)

 Breakdown:
 ++i increments i from 2 to 3 and evaluates to 3.
 i++ evaluates to 3 (but i is incremented to 4 after
evaluation).
 The expression becomes 3 + 3 = 6.
 i is now 6.
5. Output:
o Finally, System.out.println(y.i); (L5) prints the value of i, which is 6.

Final Output:
6

5. Let's analyze the code step by step to understand the output:


Key Concepts:
 In Java, Integer is a wrapper class for the primitive type int.
 Java caches Integer objects for values in the range of -128 to 127 for
memory optimization. This means that Integer objects within this range
are reused, so when you compare two Integer objects using ==, they may
reference the same object if they are within this range.
 For values outside this range, new objects are created, so == will return
false even if the values are the same because they reference different
objects.
Code Breakdown:
1. Integer num1 = 1000, num2 = 1000;
o Here, 1000 is outside the cached range (-128 to 127).

o So, num1 and num2 will reference two different Integer objects.

o System.out.println(num1 == num2); (Line 1):

 Since num1 and num2 refer to different objects, num1 ==


num2 will return false.
2. Integer num3 = 20, num4 = 20;
o Here, 20 is within the cached range.

o So, num3 and num4 will reference the same Integer object.

o System.out.println(num3 == num4); (Line 2):

 Since num3 and num4 refer to the same object, num3 ==


num4 will return true.
Final Output:
arduino
false
true
6. Yes, there is a difference between defining a String using a string literal and
creating a String using the new operator in Java. The differences lie in how
memory is managed and how string objects are stored and reused.
1. String Literal
Example:
String str1 = "Hello";
String str2 = "Hello";
 String Pool:
o When you create a string using a string literal, Java checks the
string pool (a special area in the heap memory) to see if an
identical string already exists.
o If the string already exists in the pool, the new reference (str1 or
str2) will point to the existing string object in the pool.
o If the string does not exist in the pool, Java creates a new string
object in the pool and points the reference to it.
 Memory Efficiency:
o Since strings created using literals are stored in the pool and
shared, this method is more memory-efficient.
o In the example above, str1 and str2 will reference the same object
in the string pool, so str1 == str2 will return true.
2. String Using new Operator
Example:
String str1 = new String("Hello");
String str2 = new String("Hello");
 Heap Memory:
o When you create a string using the new operator, Java creates a
new String object in the heap memory, outside of the string pool.
o Even if an identical string already exists in the string pool, new will
create a separate object in the heap memory.
 Memory Usage:
o This approach uses more memory because every new operation
creates a distinct String object.
o In the example above, str1 and str2 will reference different objects
in the heap memory, so str1 == str2 will return false.
Summary
 String Literals: Efficient, uses the string pool, and reuses objects if they
already exist. == will return true for identical string literals.
 new Operator: Creates a new String object in heap memory every time,
regardless of whether an identical string exists. == will return false for
different objects created with new, even if they contain the same text.
Example Code:
java
Copy code
public class StringTest {
public static void main(String[] args) {
String str1 = "Hello";
String str2 = "Hello";
String str3 = new String("Hello");
String str4 = new String("Hello");

System.out.println(str1 == str2); // true (same object in the pool)


System.out.println(str1 == str3); // false (different objects: one in pool, one
in heap)
System.out.println(str3 == str4); // false (different objects in heap)
}
}
Output:
arduino
Copy code
true
false
false
7. Yes, it is possible to override a method in a subclass to throw a
RuntimeException (or any other subclass of RuntimeException) when the parent
class method throws a NullPointerException.
Key Points to Consider:
 RuntimeException and Subtypes: In Java, RuntimeException and its
subclasses (like NullPointerException, IllegalArgumentException, etc.) are
unchecked exceptions. This means they are not subject to the same rules
as checked exceptions (like IOException or SQLException), which must be
declared in the method signature using the throws keyword.
 Method Overriding: When you override a method in a subclass, the
overriding method can:
o Throw no exceptions at all.

o Throw the same exception(s) as the parent method.

o Throw a subclass of the exception(s) thrown by the parent method.

Example:
Consider the following parent class with a method that throws
NullPointerException:
java
class Parent {
public void doSomething() throws NullPointerException {
// Method implementation
throw new NullPointerException("Parent method");
}
}
You can override this method in a subclass to throw a RuntimeException:
java
class Child extends Parent {
@Override
public void doSomething() throws RuntimeException {
// Method implementation
throw new RuntimeException("Child method");
}
}
Explanation:
 Compatibility: The Child class method is compatible with the Parent class
method because RuntimeException is a superclass of NullPointerException.
Java allows a method to throw a broader range of unchecked exceptions or
even different unchecked exceptions, as they do not need to be declared.
 Flexibility: This flexibility exists because the Java language assumes that
unchecked exceptions represent programming errors (like
NullPointerException or ArrayIndexOutOfBoundsException), and it does not
enforce compile-time checks on them.
Summary:
 You can override a method that throws NullPointerException in a parent
class to throw RuntimeException (or any other unchecked exception) in
the subclass.
 This is allowed because both NullPointerException and RuntimeException
are unchecked exceptions, and Java does not enforce restrictions on
unchecked exceptions in overridden methods.
8. In Java, if you run the expression 1.0 / 0.0, it will result in positive infinity
(Infinity), and no exception will be thrown.
Explanation:
1. Floating-Point Arithmetic:
o Java follows the IEEE 754 standard for floating-point arithmetic.
o According to this standard, dividing a positive floating-point number
by zero results in positive infinity (Infinity).
o Similarly, dividing a negative floating-point number by zero would
result in negative infinity (-Infinity).
2. No Exception:
o Unlike integer division by zero, which throws an
ArithmeticException, dividing by zero in floating-point arithmetic
does not throw an exception.
o Instead, the result is a special floating-point value representing
infinity.
Example Code:
java
public class DivisionByZero {
public static void main(String[] args) {
double result = 1.0 / 0.0;
System.out.println(result); // This will print "Infinity"
}
}
Output:
Infinity
Other Scenarios:
 Negative Division: If you run -1.0 / 0.0, the result will be -Infinity.
 Zero Division: If you run 0.0 / 0.0, the result will be NaN (Not a Number),
which represents an undefined or unrepresentable value in floating-point
arithmetic.
Summary:
 1.0 / 0.0 results in Infinity.
 No exception is thrown in this case.
9. The code provided prints the result of Math.min(Double.MIN_VALUE, 0.0d) in
Java.
Key Concepts:
1. Double.MIN_VALUE:
o Double.MIN_VALUE is not the smallest negative value. Instead, it
represents the smallest positive non-zero value that can be
represented by a double in Java.
o The value of Double.MIN_VALUE is 4.9e-324, which is a very small
positive number.
2. Math.min(double a, double b):
o This method returns the smaller of the two double values.

Evaluation:
 Math.min(Double.MIN_VALUE, 0.0d) compares 4.9e-324 (a tiny positive
number) with 0.0d (exactly zero).
 Since 0.0 is smaller than 4.9e-324, the method will return 0.0.
Output:
0.0
So, when you run the code, it will print 0.0.
10.
The provided code checks the equality of two floating-point expressions. Let's
analyze what happens when you run the code:
Key Concepts:
1. Floating-Point Arithmetic:
o Floating-point numbers in Java (and most programming languages)
are represented using a finite precision according to the IEEE 754
standard.
o Some decimal fractions (like 0.1) cannot be represented exactly as
binary fractions, leading to small rounding errors in calculations.
Code Analysis:
1. First Expression: 0.1 * 3 == 0.3:
o 0.1 * 3 evaluates to a value very close to 0.3, but due to the
inability to represent 0.1 exactly, the result is slightly off from 0.3.
o Therefore, 0.1 * 3 == 0.3 will return false because the two values
are not exactly equal in the binary representation.
2. Second Expression: 0.1 * 2 == 0.2:
o 0.1 * 2 similarly results in a value very close to 0.2, but in this case,
due to how floating-point arithmetic works, the result might still
match 0.2 exactly.
o However, depending on the specific implementation and precision,
this comparison could return true.
Expected Output:
The actual result depends on the internal representation and rounding, but
typically:
 System.out.println(0.1 * 3 == 0.3); will print false.
 System.out.println(0.1 * 2 == 0.2); will print true.
Final Output:
false
true
This demonstrates the precision issues that can arise with floating-point
arithmetic in Java.

11.
Using a HashMap in a multi-threaded environment is generally not safe.
HashMap is not synchronized, meaning it does not provide thread safety when
accessed by multiple threads concurrently. This can lead to several issues, such
as:
1. Data Corruption: If multiple threads modify the HashMap concurrently, it
can lead to data corruption. For example, two threads might try to put
entries into the HashMap simultaneously, leading to incorrect data or even
infinite loops during iteration.
2. Non-Deterministic Behavior: Since HashMap is not thread-safe,
operations that appear to be atomic (like put and get) can behave
unpredictably when performed by multiple threads.
Alternatives for Thread Safety
If you need to use a map in a multi-threaded environment, consider the following
alternatives:
1. ConcurrentHashMap: This is a thread-safe variant of HashMap designed
specifically for concurrent use. It allows for better performance under high
contention compared to synchronizing a HashMap.
2. Synchronized Map: You can create a synchronized version of a HashMap
using Collections.synchronizedMap(new HashMap<>()). However, this
approach generally offers lower performance than ConcurrentHashMap
because it locks the entire map for each operation.
3. ReadWriteLock: If the majority of operations are reads, and writes are
infrequent, using a ReadWriteLock can be a good solution. It allows
multiple threads to read concurrently but ensures that only one thread can
write at a time.
Conclusion
For a multi-threaded environment, using ConcurrentHashMap is usually the best
choice for balancing thread safety and performance.
12.
The best approach to calling the wait() method, whether to use an if construct or
a loop, depends on the context and specific requirements of your code. Here’s a
breakdown:
1. Using if Construct
 When to Use:
o You need to wait under a specific condition and that condition is
expected to become true only once or does not change often.
o You want to wait only once, and if the condition is already met, you
proceed without waiting.
synchronized (object) {
if (!condition) {
object.wait();
}
// Proceed when condition is met
}
Pros: Simple and straightforward when the wait condition is not dynamic.
Cons: Not suitable if the condition may change frequently, or if you need to re-
check the condition after being notified.

2. Using Loop Construct


 When to Use:
o The condition you're waiting for might be changed by other threads
multiple times.
o You need to repeatedly check the condition after being notified
(e.g., if multiple threads are involved and notify() or notifyAll() might
have been called without actually fulfilling the condition).
synchronized (object) {
while (!condition) {
object.wait();
}
// Proceed when condition is met
}
 Pros: Ensures that the thread only proceeds when the condition is truly
met, even if it wakes up prematurely (due to spurious wakeups).
 Cons: Slightly more complex than an if construct, but much safer in multi-
threaded scenarios.
Best Practice
In most cases, particularly in multi-threaded programming, the loop construct is
preferred:
 Why? It accounts for the possibility of spurious wakeups, where the thread
might wake up without the condition actually being met. The loop
construct ensures the condition is rechecked after the wait() method
returns, guaranteeing that the thread only proceeds when the condition is
truly satisfied.

 Conclusion
 Use the loop construct (while) when calling wait() in most multi-threaded
applications to ensure reliability. The if construct can be used in simpler scenarios
where the condition is stable and the wakeup behavior is straightforward, but it is
generally less safe.

13 .

Explain the Concept of Serialization


 What is Serialization?
o Serialization is the process of converting an object into a byte
stream, which can then be stored in a file, sent over a network, or
saved to a database. Deserialization is the reverse process, where
the byte stream is converted back into a copy of the object.
 Why is Serialization Used?
o It is useful for persisting object state, deep copying objects, and for
sending objects over a network or between Java Virtual Machines
(JVMs).

import java.io.Serializable;

public class Person implements Serializable {


private static final long serialVersionUID = 1L;
private String name;
private int age;

// Constructor
public Person(String name, int age) {
this.name = name;
this.age = age;
}

// Getters and Setters


public String getName() {
return name;
}

public void setName(String name) {


this.name = name;
}

public int getAge() {


return age;
}

public void setAge(int age) {


this.age = age;
}
}

 Explain how the class implements Serializable and how serialVersionUID is


used for version control of the class during deserialization.
3. Discuss Common Pitfalls
 Not Implementing Serializable:
o Ensure that the class implements the Serializable interface.

 Transient Fields:
o Explain that fields marked as transient are not serialized. For
example, if certain sensitive data should not be serialized, it should
be marked as transient.
 SerialVersionUID:
o Mention the importance of declaring a serialVersionUID to maintain
version consistency between serialized and deserialized objects.
4. Demonstrate Serialization and Deserialization
 Serialization Example:
java
Copy code
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

public class SerializeExample {


public static void main(String[] args) {
Person person = new Person("John Doe", 30);
try (FileOutputStream fileOut = new FileOutputStream("person.ser");
ObjectOutputStream out = new ObjectOutputStream(fileOut)) {
out.writeObject(person);
System.out.println("Serialized data is saved in person.ser");
} catch (IOException i) {
i.printStackTrace();
}
}
}
 Deserialization Example:
java
Copy code
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;

public class DeserializeExample {


public static void main(String[] args) {
Person person = null;
try (FileInputStream fileIn = new FileInputStream("person.ser");
ObjectInputStream in = new ObjectInputStream(fileIn)) {
person = (Person) in.readObject();
System.out.println("Deserialized Person:");
System.out.println("Name: " + person.getName());
System.out.println("Age: " + person.getAge());
} catch (IOException | ClassNotFoundException i) {
i.printStackTrace();
}
}
}
5. Encourage Hands-On Practice
 Task Assignment: Give your colleague a small task to serialize and
deserialize another class, or modify the existing example with additional
fields or nested objects.
 Error Handling: Discuss potential exceptions like
NotSerializableException and how to handle them.
6. Review and Provide Feedback
 Code Review: Offer to review their code and provide constructive
feedback. Point out areas where they might improve, such as handling
edge cases or optimizing the serialization process.
 Answer Questions: Encourage them to ask questions if they’re stuck or
unsure about certain aspects of serialization.

14.

String method Invoked


Explanation
This happens due to Java's method overloading and how it resolves which
method to invoke when there are multiple overloaded methods.
1. Method Overloading:
o Java allows multiple methods in the same class to have the same
name as long as their parameter lists (types or number of
parameters) are different. This is known as method overloading.
2. Null Argument and Overloading:
o When you pass null as an argument to an overloaded method, Java
tries to determine which method to call by examining the most
specific method available that can accept null.
o In this case, there are two overloaded versions of someMethod:

 someMethod(Object o) which accepts an Object.


 someMethod(String s) which accepts a String.
3. Resolution Process:
o Since null can be assigned to any reference type, both
someMethod(Object o) and someMethod(String s) are potential
matches.
o However, String is a subclass of Object, so the String version is
more specific.
o Java will choose the most specific method that can handle the null
argument, which is someMethod(String s).
Therefore, the output is "String method Invoked".

15.
1. PATH Variable
 Purpose:
o The PATH environment variable tells the operating system where to
find executable files (programs or scripts). It is used by the
command line to locate programs that you can run without needing
to specify their full path.
 How It Works:
o When you type a command in the terminal or command prompt
(like java, javac, or any other executable), the operating system
searches through the directories listed in the PATH variable to find
the corresponding executable.
 Example:
o If PATH includes /usr/bin and /usr/local/bin, when you type java, the
system looks for the java executable in those directories.
Example value on Unix/Linux/Mac:
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin

Example value on Windows:


C:\Program Files\Java\jdk1.8.0_221\bin;C:\Windows\System32


o Primarily used to run executables from the command line without
needing to specify their full paths.
2. CLASSPATH Variable
 Purpose:
o The CLASSPATH environment variable tells the Java Virtual Machine
(JVM) and Java tools (like javac and java) where to find class files
and libraries (JAR files) that your Java program needs to run.
 How It Works:
o When you run a Java program, the JVM uses the CLASSPATH to
locate the .class files or JAR files that contain the bytecode your
program depends on. If your program depends on external libraries,
you need to include them in the CLASSPATH.
 Example:
o If your program depends on mylib.jar and otherlib.jar located in
/usr/local/lib, you would include these paths in the CLASSPATH
variable.
Example value on Unix/Linux/Mac:
/usr/local/lib/mylib.jar:/usr/local/lib/otherlib.jar:.
Example value on Windows
C:\libs\mylib.jar;C:\libs\otherlib.jar;.
Used by Java applications to locate required classes and libraries at runtime and
compile time.
Scope:
PATH is used by the operating system to find executable files.
CLASSPATH is used by the JVM to find Java class files and libraries.
Content:
PATH contains directories where executables are stored.
CLASSPATH contains directories, JAR files, or both, where Java classes and
packages are stored.
Default Behavior:
If PATH is not set correctly, you may not be able to run programs from the
command line without specifying their full path.
If CLASSPATH is not set or incomplete, Java may not find the classes it needs,
leading to ClassNotFoundException or NoClassDefFoundError.
Conclusion:
Use PATH when you want to ensure the system can find executables.
Use CLASSPATH when you want to ensure the JVM can find the necessary Java
classes and libraries for your application.

16.
The hashCode() and equals() contract in Java is crucial for maintaining
consistency and correctness when working with collections that rely on hashing,
such as HashMap, HashSet, and Hashtable. Here's why these methods are
important and how they work together:
1. The equals() Method
 Purpose:
o The equals() method is used to compare two objects for equality. It
determines whether two objects are "meaningfully equivalent"
according to the logic defined in the method.
 Default Behavior:
o The default implementation in the Object class checks for reference
equality, meaning two objects are considered equal if they are the
same instance (i.e., this == obj).
 Custom Implementation:
o When overriding equals(), you define what it means for two objects
of your class to be equal (e.g., two Person objects might be
considered equal if they have the same social security number).
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Person person = (Person) obj;
return ssn.equals(person.ssn);
}
2. The hashCode() Method
 Purpose:
o The hashCode() method returns an integer representation (hash
code) of the object. This hash code is used by hash-based
collections to efficiently store and retrieve objects.
 Default Behavior:
o The default implementation in the Object class generates a hash
code based on the memory address of the object.
 Custom Implementation:
o When you override equals(), you must also override hashCode() to
ensure that equal objects have the same hash code.
 Example:
@Override
public int hashCode() {
return ssn.hashCode();
}
3. The hashCode() and equals() Contract
 Contract Overview:
o If two objects are equal according to the equals(Object)
method, then they must have the same hash code.
o If two objects have the same hash code, they are not
necessarily equal according to the equals(Object) method.
 Why This Matters:
o Hash-Based Collections: Collections like HashMap and HashSet
use hashCode() to quickly locate the bucket where an object might
be stored. Once the bucket is identified, equals() is used to find the
exact object.
o Consistency: If equals() indicates two objects are equal but
hashCode() gives them different values, they might be placed in
different buckets. This inconsistency can cause issues like duplicate
entries in a HashSet or failed lookups in a HashMap.
o Performance: If hashCode() always returns the same value (e.g.,
0), it forces the collection to rely entirely on equals() to compare
objects, leading to poor performance because all objects will be
stored in a single bucket.
4. Examples of Contract Violations
 Violation Scenario:
o Suppose two Person objects are considered equal by equals() (e.g.,
same ssn), but they have different hashCode() values. If these
objects are added to a HashSet, both could be stored separately,
violating the set’s contract to store only unique elements.
 Consequences:
o Incorrect behavior in collections like HashMap, HashSet, or
Hashtable.
o Potentially severe bugs that are difficult to trace, as they might only
manifest under certain conditions.
5. Best Practices
 Always Override Both: When you override equals(), you should always
override hashCode() to ensure they are consistent.
 Use Same Fields for Both: The fields used to determine equality in
equals() should also be used to compute the hash code in hashCode().
 Use Objects.hash(): Java provides utility methods like Objects.hash() to
easily create a consistent hashCode() implementation based on multiple
fields.
 Example:
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return ssn.equals(person.ssn);
}

@Override
public int hashCode() {
return Objects.hash(ssn);
}
Conclusion
The hashCode() and equals() contract is fundamental to the correct
functioning of hash-based collections in Java. Ensuring that objects that
are equal have the same hash code is key to maintaining consistency,
avoiding bugs, and ensuring efficient performance in collections like
HashMap and HashSet.

17.
Certainly! A thread-safe singleton pattern ensures that only one instance of a
class is created, even when multiple threads attempt to access the class
simultaneously. Below are some common ways to implement a thread-safe
singleton pattern in Java:
1. Eager Initialization
This approach initializes the singleton instance at the time of class loading,
making it inherently thread-safe.
java
Copy code
public class EagerSingleton {
// Instance is created at the time of class loading
private static final EagerSingleton instance = new EagerSingleton();

// Private constructor prevents instantiation from other classes


private EagerSingleton() {}

// Method to return the singleton instance


public static EagerSingleton getInstance() {
return instance;
}
}
2. Synchronized Method
This method involves synchronizing the getInstance() method to make it thread-
safe.
java
Copy code
public class SynchronizedSingleton {
private static SynchronizedSingleton instance;

// Private constructor prevents instantiation from other classes


private SynchronizedSingleton() {}

// Method to return the singleton instance, synchronized to make it thread-safe


public static synchronized SynchronizedSingleton getInstance() {
if (instance == null) {
instance = new SynchronizedSingleton();
}
return instance;
}
}
3. Double-Checked Locking
This method reduces the overhead of calling a synchronized method by
synchronizing only the block of code that creates the instance.
java
Copy code
public class DoubleCheckedLockingSingleton {
private static volatile DoubleCheckedLockingSingleton instance;

// Private constructor prevents instantiation from other classes


private DoubleCheckedLockingSingleton() {}

// Method to return the singleton instance, using double-checked locking


public static DoubleCheckedLockingSingleton getInstance() {
if (instance == null) {
synchronized (DoubleCheckedLockingSingleton.class) {
if (instance == null) {
instance = new DoubleCheckedLockingSingleton();
}
}
}
return instance;
}
}
4. Bill Pugh Singleton (Static Inner Class)
This method uses a static inner class to hold the singleton instance, ensuring
thread safety and lazy initialization.
java
Copy code
public class BillPughSingleton {
// Private constructor prevents instantiation from other classes
private BillPughSingleton() {}

// Static inner class responsible for holding the Singleton instance


private static class SingletonHelper {
// Instance is created when the class is loaded
private static final BillPughSingleton INSTANCE = new BillPughSingleton();
}

// Method to return the singleton instance


public static BillPughSingleton getInstance() {
return SingletonHelper.INSTANCE;
}
}
5. Enum Singleton
The Enum Singleton pattern is considered the most effective way to implement a
singleton in Java. It is thread-safe, provides serialization guarantees, and
prevents multiple instances even in complex scenarios such as serialization or
reflection attacks.
java
Copy code
public enum EnumSingleton {
INSTANCE;

// Any methods you want to add to the singleton


public void someMethod() {
// Perform operations
}
}
Explanation of Each Approach:
 Eager Initialization: The instance is created at class loading time,
making it thread-safe. However, the instance is created even if it's never
used, potentially wasting resources.
 Synchronized Method: Simple but may lead to performance issues
because every call to getInstance() is synchronized.
 Double-Checked Locking: Offers a balance between thread safety and
performance. The volatile keyword ensures that changes to the instance
variable are visible to all threads.
 Bill Pugh Singleton: Combines lazy initialization with thread safety
without synchronization overhead. The singleton instance is created only
when it's accessed for the first time.
 Enum Singleton: Recommended for most cases as it handles
serialization automatically and protects against multiple instances via
reflection.
Each of these implementations ensures that only one instance of the singleton
class is created, even in a multi-threaded environment. The choice of method
depends on your specific requirements regarding lazy initialization, performance,
and simplicity.

18.

The ... in the method parameters in Java represents a varargs (variable


arguments) parameter. This allows you to pass a variable number of arguments
(zero or more) of a specified type to a method.
How Varargs Work
 Syntax: The varargs parameter is defined by placing three dots (...) after
the type, followed by the parameter name.
 Usage: Varargs allows you to call a method with different numbers of
arguments without having to overload the method for each possible
number of parameters.
Example
public class VarargsExample {

// Method with varargs parameter


public static void printNumbers(int... numbers) {
for (int number : numbers) {
System.out.println(number);
}
}

public static void main(String[] args) {


// Calling method with different numbers of arguments
printNumbers(1); // Single argument
printNumbers(1, 2, 3); // Multiple arguments
printNumbers(); // No argument
}
}
Output
1
1
2
3
Key Points about Varargs
1. Type: The type of the varargs parameter must be specified. In the
example above, int... numbers means the method accepts any number of
int values.
2. Array Representation: Internally, the varargs parameter is treated as an
array. For instance, in the printNumbers(int... numbers) method, numbers
is an int[] array.
3. Single Varargs Parameter: A method can have only one varargs
parameter, and it must be the last parameter in the method signature.
This ensures that the compiler can correctly interpret how many
arguments belong to the varargs parameter.
public static void exampleMethod(String name, int... numbers) {
// Valid: Varargs is the last parameter
}

public static void invalidMethod(int... numbers, String name) {


// Invalid: Varargs is not the last parameter
}
4. Optional: The varargs parameter is optional, meaning you can call the
method without passing any arguments for it. The method will then
receive an empty array.
Benefits of Varargs
 Simplicity: It simplifies method calls by allowing you to pass multiple
arguments without needing to create an array manually or define multiple
overloaded methods.
 Flexibility: It offers flexibility in API design, making methods more
adaptable to different input sizes.
Conclusion
The ... in method parameters is a powerful feature in Java that simplifies the
handling of methods with a variable number of arguments, enhancing both
readability and usability in code design.

19.

In Java, Collection and Collections are distinct concepts that serve different
purposes, even though their names are similar. Here's a breakdown of their
differences:
1. Collection (Interface)
 Type: It is a root interface in the Java Collections Framework (JCF).
 Purpose:
o The Collection interface provides a general contract for managing
groups of objects, known as elements.
o It is the superinterface for various other interfaces, like List, Set,
and Queue.
o It defines basic operations that can be performed on collections,
such as adding, removing, and querying elements.
 Key Methods:
o boolean add(E e)

o boolean remove(Object o)

o int size()

o boolean isEmpty()

o boolean contains(Object o)

o Iterator<E> iterator()

o Object[] toArray()

 Implementing Classes:
o Since Collection is an interface, it cannot be instantiated directly.
Instead, various classes that implement Collection can be
instantiated, such as:
 ArrayList (which implements List)
 HashSet (which implements Set)
 LinkedList (which implements List and Queue)
 Example:
java
Copy code
Collection<String> myCollection = new ArrayList<>();
myCollection.add("Hello");
myCollection.add("World");
2. Collections (Utility Class)
 Type: It is a utility class in the java.util package.
 Purpose:
o The Collections class provides static methods that operate on or
return collections. These methods are meant to assist in managing
and manipulating collections.
o It includes methods for sorting, searching, reversing, and more.

 Key Methods:
o static <T> void sort(List<T> list)

o static <T> int binarySearch(List<? extends Comparable<? super


T>> list, T key)
o static <T> T max(Collection<? extends T> coll)

o static void reverse(List<?> list)

o static <T> void shuffle(List<T> list)

o static <T> List<T> unmodifiableList(List<? extends T> list)

 Usage:
o Collections methods are all static, meaning you do not need to
instantiate Collections to use them.
 Example:
java
Copy code
List<String> myList = new ArrayList<>();
myList.add("Apple");
myList.add("Banana");
myList.add("Orange");

// Sorting the list using Collections utility method


Collections.sort(myList);
// Reversing the list
Collections.reverse(myList);

// Creating an unmodifiable list


List<String> unmodifiableList = Collections.unmodifiableList(myList);
Key Differences:
 Nature:
o Collection is an interface that defines a group of methods for
working with collections of objects.
o Collections is a utility class that provides static methods to perform
operations on or return collections.
 Usage:
o You implement or use classes that implement Collection when you
want to create a data structure to hold and manage elements (e.g.,
ArrayList, HashSet).
o You use Collections when you need to perform operations like
sorting, searching, or creating synchronized or immutable
collections.
Conclusion:
 Collection is a fundamental interface in the Java Collections Framework,
defining the basic behaviors that all collections should have.
 Collections is a helper class that provides utility methods to manipulate
and manage collections more efficiently.
20.
In Java, both Vector and ArrayList are part of the Java Collections Framework and
implement the List interface, providing similar functionalities. However, there are
important differences between the two that affect their performance,
synchronization, and usage. Here's a detailed comparison:
1. Synchronization
 Vector:
o Thread-Safe: Vector is synchronized by default, meaning that it is
thread-safe and can be safely used in a multi-threaded
environment. However, this synchronization incurs a performance
cost.
o Example:

java
Copy code
Vector<Integer> vector = new Vector<>();
vector.add(1); // Synchronized add
 ArrayList:
o Not Thread-Safe: ArrayList is not synchronized, making it faster in
single-threaded scenarios but unsafe in multi-threaded
environments unless externally synchronized.
o Example:

java
Copy code
ArrayList<Integer> arrayList = new ArrayList<>();
arrayList.add(1); // Non-synchronized add
2. Performance
 Vector:
o Slower: Due to its synchronized nature, Vector is generally slower
than ArrayList when used in single-threaded contexts because of
the overhead of synchronization.
o Growth Factor: When a Vector needs to grow (i.e., when it runs out
of space), it doubles its size by default (i.e., grows by 100%).
 ArrayList:
o Faster: Since ArrayList is not synchronized, it performs faster in
most scenarios where thread safety is not a concern.
o Growth Factor: When an ArrayList needs to grow, it increases its size
by 50% by default, which is more memory efficient than Vector.
3. Legacy Status
 Vector:
o Legacy Class: Vector is considered a legacy class, introduced in the
initial versions of Java. While still available, its usage has declined in
favor of more modern alternatives like ArrayList.
o Preferred Alternative: In modern Java development, ArrayList is
generally preferred unless thread safety is explicitly required.
 ArrayList:
o Modern Class: ArrayList was introduced later as part of the Java
Collections Framework in Java 2 (JDK 1.2). It is the preferred choice
for implementing a resizable array in most cases.
4. Iteration
 Vector:
o Enumeration and Iterator: Vector supports both the legacy
Enumeration and the more modern Iterator and ListIterator for
traversing elements.
o Fail-Safe Behavior: Iterators in Vector are fail-safe when used in a
single-threaded context, but not in a multi-threaded context without
external synchronization.
 ArrayList:
o Iterator and ListIterator: ArrayList supports Iterator and ListIterator
for element traversal. It does not support the legacy Enumeration
interface.
o Fail-Fast Behavior: The iterators in ArrayList are fail-fast, meaning
they will throw a ConcurrentModificationException if the list is
structurally modified while iterating.
5. Usage Context
 Vector:
o Use Case: Vector might be used when you need a thread-safe,
resizable array, though it's typically recommended to use ArrayList
with manual synchronization (e.g., using
Collections.synchronizedList) instead.
o Example:

java
Copy code
List<Integer> vector = new Vector<>();
 ArrayList:
o Use Case: ArrayList is the go-to choice for most scenarios where a
resizable array is needed, and thread safety is not a primary
concern.
o Example:

java
List<Integer> arrayList = new ArrayList<>();
6. Memory Consumption
 Vector:
o Higher Memory Consumption: Because Vector doubles its size when
it grows, it can potentially consume more memory if growth is
frequent.
 ArrayList:
o More Memory Efficient: With a 50% growth rate, ArrayList tends to
be more memory efficient than Vector.
Conclusion
 When to Use Vector:
o Use Vector if you need a thread-safe collection without external
synchronization and if you are working in a legacy codebase where
Vector is already in use.
 When to Use ArrayList:
o Use ArrayList in most cases where you need a resizable array. It's
faster and more modern, and if thread safety is required, you can
use Collections.synchronizedList() to wrap the ArrayList.
In summary, ArrayList is generally preferred over Vector due to its better
performance in most scenarios, with Vector being reserved for cases where
synchronization is necessary without external synchronization mechanisms.

However, there are many differences between ArrayList and Vector classes that
are given below.
ArrayList and Vectors both implement the List interface, and both
use (dynamically resizable) arrays for their internal data structure, much like
using an ordinary array.
Syntax:
ArrayList: ArrayList<T> al = new ArrayList<T>();

Vector: Vector<T> v = new Vector<T>();


ArrayList Vs vector

S.
No
. ArrayList Vector

ArrayList is not
1. Vector is synchronized.
synchronized.

2. ArrayList increments 50% Vector increments 100% means doubles the


of the current array size if array size if the total number of elements
the number of elements
S.
No
. ArrayList Vector

exceeds ts capacity. exceeds its capacity.

ArrayList is not a legacy


3. class. It is introduced in Vector is a legacy class.
JDK 1.2.

Vector is slow because it is synchronized,


i.e., in a multithreading environment, it
ArrayList is fast because it
4. holds the other threads in a runnable or
is non-synchronized.
non-runnable state until the current thread
releases the lock of the object.

ArrayList uses the Iterator A Vector can use the Iterator interface or
5. interface to traverse the Enumeration interface to traverse the
elements. elements.

ArrayList performance is
6 Vector performance is low
high

Multiple threads is
7 only one threads are allowed .
allowed

Significant Differences between ArrayList and Vector:


 Synchronization: Vector is synchronized, which means only one thread
at a time can access the code, while ArrayList is not synchronized, which
means multiple threads can work on ArrayList at the same time. For
example, if one thread is performing an add operation, then there can be
another thread performing a remove operation in a multithreading
environment. If multiple threads access ArrayList concurrently, then we
must synchronize the block of the code which modifies the list structurally
or allow simple element modifications. Structural modification means the
addition or deletion of element(s) from the list. Setting the value of an
existing element is not a structural modification.
 Performance: ArrayList is faster. Since it is non-synchronized, while
vector operations give slower performance since they are synchronized
(thread-safe), if one thread works on a vector, it has acquired a lock on it,
which forces any other thread wanting to work on it to have to wait until
the lock is released.
 Data Growth: ArrayList and Vector both grow and shrink
dynamically to maintain optimal use of storage – but the way they resize
is different. ArrayList increments 50% of the current array size if the
number of elements exceeds its capacity, while vector increments 100% –
essentially doubling the current array size.
 Traversal: Vector can use both Enumeration and Iterator for traversing
over vector elements, while ArrayList can only use Iterator for traversing.
 Applications: Most of the time, programmers prefer ArrayList over Vector
because ArrayList can be synchronized explicitly
using Collections.synchronizedList.
How to get Synchronized version of arraylist object:
by default arraylist is object is non-synchronized but we can get synchronized
version of arraylist by using collection class Synchronized List() method.
 Java

/*package whatever //do not write package name here */

import java.io.*;

class GFG {
public static void main (String[] args) {
public static List SynchronizedList(list1)
// non synchronized
ArrayList l1 = new ArrayList();
// Synchronized
List l= Collections.SynchronizedList(l1);
}
}

Note: ArrayList is preferable when there is no specific requirement to use


vector.
 Java

// Java Program to illustrate use


// of ArrayList and Vector in Java

import java.io.*;
import java.util.*;

class GFG
{
public static void main (String[] args)
{
// creating an ArrayList
ArrayList<String> al = new ArrayList<String>();

// adding object to arraylist


al.add("Practice.GeeksforGeeks.org");
al.add("www.GeeksforGeeks.org");
al.add("code.GeeksforGeeks.org");
al.add("write.geeksforgeeks.org");
// traversing elements using Iterator'
System.out.println("ArrayList elements are:");
Iterator it = al.iterator();
while (it.hasNext())
System.out.println(it.next());

// creating Vector
Vector<String> v = new Vector<String>();
v.addElement("Practice");
v.addElement("quiz");
v.addElement("code");

// traversing elements using Enumeration


System.out.println("\nVector elements are:");
Enumeration e = v.elements();
while (e.hasMoreElements())
System.out.println(e.nextElement());
}
}

Output
ArrayList elements are:
Practice.GeeksforGeeks.org
www.GeeksforGeeks.org
code.GeeksforGeeks.org
write.geeksforgeeks.org

Vector elements are:


Practice
quiz
code
How to choose between ArrayList and Vector?
 ArrayList is unsynchronized and not thread-safe, whereas Vectors are. Only
one thread can call methods on a Vector, which is slightly overhead but
helpful when safety is a concern. Therefore, in a single-threaded case,
ArrayList is the obvious choice, but where multithreading is concerned,
vectors are often preferable.
 If we don’t know how much data we will have but know the rate at which it
grows, Vector has an advantage since we can set the increment value in
vectors.
 ArrayList is newer and faster. If we don’t have any explicit requirements
for using either of them, we use ArrayList over vector.
21.
Difference between comparing String using == and .equals() method in Java
Last Updated : 16 Feb, 2024

Both the equals() method and the == operator are used to compare two objects
in Java.
The Java string equals() method, compares two strings and returns true if all
characters match in both strings, else returns false.
The == operator compares the reference or memory location of objects in a
heap, whether they point to the same location or not.
Whenever we create an object using the operator new, it will create a new
memory location for that object. So we use the == operator to check memory
location or address of two objects are the same or not.
In general, both equals() and “==” operators in Java are used to compare objects
to check equality, but here are some of the differences between the two:
1. The main difference between the .equals() method and the == operator is
that one is a method, and the other is the operator.
2. We can use == operators for reference comparison (address comparison)
and .equals() method for content comparison. In simple words, == checks
if both objects point to the same memory location whereas .equals()
evaluates to the comparison of values in the objects.
3. If a class does not override the equals method, then by default, it uses the
equals(Object o) method of the closest parent class that has overridden
this method. **See Why to Override equals(Object) and hashCode()
method? in detail.
Example:
String equals() method and == operator in Java.
 Java
// Java program to understand
// the concept of == operator

public class Test {


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

System.out.println(s1 == s2); // true


System.out.println(s1 == s3); // false
System.out.println(s1.equals(s2)); // true
System.out.println(s1.equals(s3)); // true
}
}

Output
true
false
true
true

Explanation: Here, we create two objects, namely s1 and s2.


 Both s1 and s2 refer to the same objects.
 When we use the == operator for s1 and s2 comparison, the result is true
as both have the same addresses in the string constant pool.
 Using equals, the result is true because it’s only comparing the values
given in s1 and s2.
Java String Pool
s1 =
“HELLO”

s2 =
“HELLO”

Java Heap

s3 =
“HELLO”

Let us understand both the operators in detail:


Equality operator(==)
We can apply equality operators for every primitive type, including the boolean
type. We can also apply equality operators for object types.
Example:
== operator in Java.
 Java

// Java program to illustrate


// == operator for compatible data
// types

class Test {
public static void main(String[] args)
{
// integer-type
System.out.println(10 == 20);

// char-type
System.out.println('a' == 'b');

// char and double type


System.out.println('a' == 97.0);
// boolean type
System.out.println(true == true);
}
}

Output
false
false
true
true

If we apply == for object types then, there should be compatibility between


argument types (either child to parent or parent to child or same type).
Otherwise, we will get a compile-time error.
Example:
 Java

// Java program to illustrate


// == operator for incompatible data types

class Test {
public static void main(String[] args)
{
Thread t = new Thread();
Object o = new Object();
String s = new String("GEEKS");

System.out.println(t == o);
System.out.println(o == s);
// Uncomment to see error
System.out.println(t==s);
}
}

Output:
false
false
// error: incomparable types: Thread and String
Java String equals() Method
In Java, the String equals() method compares the two given strings based on the
data/content of the string. If all the contents of both strings are the same,
it returns true. If all characters are not matched, then it returns false.
Syntax:
Syntax: public boolean equals(Object anotherObject)
Parameter:
 anotherObject- String to be compared
Returns:
 Boolean value:
o true- If strings are equal

o false- if strings are not equal

Example:
String equals() method in Java
 Java

public class Test {


public static void main(String[] args)
{
Thread t1 = new Thread();
Thread t2 = new Thread();
Thread t3 = t1;

String s1 = new String("GEEKS");


String s2 = new String("GEEKS");

System.out.println(t1 == t3);
System.out.println(t1 == t2);
System.out.println(s1 == s2);

System.out.println(t1.equals(t2));
System.out.println(s1.equals(s2));
}
}

Output:
true
false
false
false
true
Explanation: Here, we are using the .equals method to check whether two
objects contain the same data or not.
 In the above example, we create 3 Thread objects and 2 String objects.
 In the first comparison, we check whether t1 == t3 or not. As we know
both t1 and t3 point to the same object. That’s why it returns true.
 In the second comparison, we are using the operator “==” for comparing
the String Objects and not the contents of the objects. Here, both the
objects are different, and hence the outcome of this comparison is “False.”
 When we are comparing 2 String objects by the equals() operator, then we
are checking that is both objects contain the same data or not.
 Both the objects contain the same String, i.e., GEEKS. That’s why it returns
true.
Also Read:
 Character.equals() method in Java with examples
 ==, equals(), compareTo(), equalsIgnoreCase() and compare()
Conclusion
Java string equals() method and == operator are both used to compare strings in
Java. In this tutorial we have covered the ==operator and String equals() method
in Java with examples.
Read More String Methods in Java

Difference between == and .equals() method- FAQs


1. What is the difference between str1 == str2 and str1 equals str2?
In Java, str1==str2 will return true if str1 and str2 are strings with the same
content. This is because strings with the same content are stored at the same
location.
str1.equals(str2) will return true if str1 and str 2 are different string objects, but
have same content.
2. What is the difference between == and equals in string comparison?
The string equals() method compares two strings and returns true if all
characters match in both strings, else returns false.
The == operator compares the reference or memory location of objects in a
heap, whether they point to the same location or not.
3. What are the rules of equals() method?
1. Reflexivity: For any object x, x.equals(x) should always return true.
2. Symmetry: If x.equals(y) returns true, then y.equals(x) must also return
true.
3. Transitivity: If x.equals(y) and y.equals(z) are both true, then x.equals(z)
must also be true.
4. Consistency: Multiple invocations of x.equals(y) should return the same
result.
5. Non-nullity: The equals() method should never return true when compared
to null.

22.
Four Main Object Oriented Programming Concepts of Java
Last Updated : 09 Jul, 2024

Object-oriented programming generally referred to as OOPS is the backbone of


java as java is not a purely object oriented language but it is object oriented
language. Java organizes a program around the various objects and well-defined
interfaces. There are four pillars been here in OOPS which are listed below.
These concepts aim to implement real-world entities in programs.
 Abstraction
 Encapsulation
 Inheritance
 Polymorphism
Abstraction
Abstraction is a process of hiding implementation details and exposing only the
functionality to the user. In abstraction, we deal with ideas and not events. This
means the user will only know “what it does” rather than “how it does”.
There are two ways to achieve abstraction in Java:
 Abstract class (0 to 100%)
 Interface (100%)
Real-Life Example: A driver will focus on the car functionality (Start/Stop ->
Accelerate/ Break), he/she does not bother about how the Accelerate/ brake
mechanism works internally. And this is how the abstraction works.
Certain key points should be remembered regarding this pillar of OOPS as
follows:
 The class should be abstract if a class has one or many abstract methods
 An abstract class can have constructors, concrete methods, static method,
and final method
 Abstract class can’t be instantiated directly with the new operator. It can
be possible as shown in pre tag below:
A b = new B();
 The child class should override all the abstract methods of parent else the
child class should be declared with abstract keyword.

Example:
Java
// Abstract class
public abstract class Car {
public abstract void stop();
}

// Concrete class
public class Honda extends Car {
// Hiding implementation details
@Override public void stop()
{
System.out.println("Honda::Stop");
System.out.println(
"Mechanism to stop the car using break");
}
}

public class Main {


public static void main(String args[])
{
Car obj
= new Honda(); // Car object =>contents of Honda
obj.stop(); // call the method
}
}

Encapsulation
Encapsulation is the process of wrapping code and data together into a single
unit.
Real-Life Example:
A capsule which is mixed of several medicines. The medicines are hidden data to
the end user.
In order to achieve encapsulation in java follow certain steps as proposed below:
 Declare the variables as private
 Declare the setters and getters to set and get the variable values
Note: There are few advantages of encapsulation in java as follows:
 Control Over Data: We can write the logic in the setter method to not
store the negative values for an Integer. So by this way we can control the
data.
 Data Hiding: The data members are private so other class can’t access
the data members.
 Easy to test: Unit testing is easy for encapsulated classes
Example:
Java
// A Java class which is a fully encapsulated class.
public class Car {

// private variable
private String name;

// getter method for name


public String getName(){
return name;
}

// setter method for name


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

// Java class to test the encapsulated class.


public class Test {
public static void main(String[] args)
{
// creating instance of the encapsulated class
Car car
= new Car();

// setting value in the name member


car.setName("Honda");

// getting value of the name member


System.out.println(car.getName());

Inheritance
Inheritance is the process of one class inheriting properties and methods from
another class in Java. Inheritance is used when we have is-a relationship
between objects. Inheritance in Java is implemented using extends keyword.
Real-life Example:
The planet Earth and Mars inherits the super class Solar System and Solar
system inherits the Milky Way Galaxy. So Milky Way Galaxy is the top super class
for Class Solar System, Earth and Mars.
Let us do discuss the usage of inheritance in java applications with a generic
example before proposing the code. So consider an example extending
the Exception class to create an application-specific Exception class that contains
more information like error codes. For example NullPointerException.
There are 5 different types of inheritance in java as follows:
 Single Inheritance: Class B inherits Class A using extends keyword
 Multilevel Inheritance: Class C inherits class B and B inherits class A
using extends keyword
 Hierarchy Inheritance: Class B and C inherits class A in hierarchy order
using extends keyword
 Multiple Inheritance: Class C inherits Class A and B. Here A and B both
are superclass and C is only one child class. Java is not supporting Multiple
Inheritance, but we can implement using Interfaces.
 Hybrid Inheritance: Class D inherits class B and class C. Class B and C
inherits A. Here same again Class D inherits two superclass, so Java is not
supporting Hybrid Inheritance as well.
Example:
Java
// super class
class Car {
// the Car class have one field
public String wheelStatus;
public int noOfWheels;

// the Car class has one constructor


public Car(String wheelStatus, int noOfWheels)
{
this.wheelStatus = wheelStatus;
this.noOfWheels = noOfWheels;
}

// the Car class has three methods


public void applyBrake()
{
wheelStatus = "Stop";
System.out.println("Stop the car using break");
}

// toString() method to print info of Car


public String toString()
{
return ("No of wheels in car " + noOfWheels + "\n"
+ "status of the wheels " + wheelStatus);
}
}
// sub class
class Honda extends Car {

// the Honda subclass adds one more field


public Boolean alloyWheel;

// the Honda subclass has one constructor


public Honda(String wheelStatus, int noOfWheels,
Boolean alloyWheel)
{
// invoking super-class(Car) constructor
super(wheelStatus, noOfWheels);
this.alloyWheel = alloyWheel;
}

// the Honda subclass adds one more method


public void setAlloyWheel(Boolean alloyWheel)
{
this.alloyWheel = alloyWheel;
}

// overriding toString() method of Car to print more


// info
@Override public String toString()
{
return (super.toString() + "\nCar alloy wheel "
+ alloyWheel);
}
}

// driver class
public class Main {
public static void main(String args[])
{

Honda honda = new Honda("stop", 4, true);


System.out.println(honda.toString());
}
}

Polymorphism
Polymorphism is the ability to perform many things in many ways. The word
Polymorphism is from two different Greek words- poly and morphs. “Poly” means
many, and “Morphs” means forms. So polymorphism means many forms. The
polymorphism can be present in the case of inheritance also. The functions
behave differently based on the actual implementation.
Real-life Example:
A delivery person delivers items to the user. If it’s a postman he will deliver the
letters. If it’s a food delivery boy he will deliver the foods to the user. Like this
polymorphism implemented different ways for the delivery function.
There are two types of polymorphism as listed below:
1. Static or Compile-time Polymorphism
2. Dynamic or Run-time Polymorphism
Static or Compile-time Polymorphism when the compiler is able to determine the
actual function, it’s called compile-time polymorphism. Compile-time
polymorphism can be achieved by method overloading in java. When different
functions in a class have the same name but different signatures, it’s
called method overloading. A method signature contains the name and method
arguments. So, overloaded methods have different arguments. The arguments
might differ in the numbers or the type of arguments.
Example 1: Static Polymorphism
Java
public class Car{

public void speed() {


}

public void speed(String accelerator) {


}

public int speed(String accelerator, int speedUp) {


return carSpeed;
}
}

Dynamic or Run-time Polymorphism Dynamic (or run-time) polymorphism


occurs when the compiler is not able to determine at compile-time which method
(superclass or subclass) will be called. This decision is made at run-time. Run-
time polymorphism is achieved through method overriding, which happens when
a method in a subclass has the same name, return type, and parameters as a
method in its superclass. When the superclass method is overridden in the
subclass, it is called method overriding.
Example 2: Dynamic Polymorphism
import java.util.Random;

class DeliveryBoy {

public void deliver() {


System.out.println("Delivering Item");
}

public static void main(String[] args) {


DeliveryBoy deliveryBoy = getDeliveryBoy();
deliveryBoy.deliver();
}

private static DeliveryBoy getDeliveryBoy() {


Random random = new Random();
int number = random.nextInt(5);
return number % 2 == 0 ? new Postman() : new FoodDeliveryBoy();
}
}
class Postman extends DeliveryBoy {
@Override
public void deliver() {
System.out.println("Delivering Letters");
}
}

class FoodDeliveryBoy extends DeliveryBoy {


@Override
public void deliver() {
System.out.println("Delivering Food");
}
}

Output
Delivering Food

23.
Difference between Abstract Class and Interface in Java
In object-oriented programming (OOP), both abstract classes and interfaces
serve as fundamental constructs for defining contracts. They establish a
blueprint for other classes, ensuring consistent implementation of methods and
behaviors. However, they each come with distinct characteristics and use cases.
In this article, we will learn abstract class vs interface in Java.
Difference Between Abstract Class and Interface

Points Abstract Class Interface

Cannot be instantiated;
Specifies a set of
contains both abstract
methods a class must
(without implementation)
implement; methods are
and concrete methods
abstract by default.
Definition (with implementation)
Points Abstract Class Interface

Methods are abstract by


Can have both
default; Java 8, can have
implemented and abstract
Implementation default and static
methods.
Method methods.

class can inherit from only A class can implement


Inheritance one abstract class. multiple interfaces.

Methods and properties


can have any access Methods and properties
modifier (public, protected, are implicitly public.
Access Modifiers private).

Can have member Variables are implicitly


variables (final, non-final, public, static, and final
Variables static, non-static). (constants).

As we know that abstraction refers to hiding the internal implementation of the


feature and only showing the functionality to the users. i.e. showing only the
required features, and hiding how those features are implemented behind the
scene. Whereas, an Interface is another way to achieve abstraction in java.
Both abstract class and interface are used for abstraction, henceforth Interface
and Abstract Class are required prerequisites.

Abstract Class in Java


1. Definition:
An abstract class is a class that cannot be instantiated directly. It serves as a
blueprint for other classes to derive from.
2. Method Implementation:
An abstract class can contain both abstract methods (methods without an
implementation) and concrete methods (methods with an implementation).
3. Variables:
Abstract classes can have member variables, including final, non-final, static,
and non-static variables.
4. Constructors:
Abstract classes can have constructors, which can be used to initialize variables
in the abstract class when it is instantiated by a subclass.
Example 1:
Java
abstract class Shape {
String objectName = " ";

Shape(String name) {
this.objectName = name;
}

public void moveTo(int x, int y) {


System.out.println(this.objectName + " has been moved to x = " + x + "
and y = " + y);
}

abstract public double area();


abstract public void draw();
}

class Rectangle extends Shape {


int length, width;

Rectangle(int length, int width, String name) {


super(name);
this.length = length;
this.width = width;
}

@Override
public void draw() {
System.out.println("Rectangle has been drawn ");
}

@Override
public double area() {
return (double)(length * width);
}
}

class Circle extends Shape {


double pi = 3.14;
int radius;

Circle(int radius, String name) {


super(name);
this.radius = radius;
}

@Override
public void draw() {
System.out.println("Circle has been drawn ");
}

@Override
public double area() {
return (double)(pi * radius * radius);
}
}

public class Main {


public static void main(String[] args) {
Shape rect = new Rectangle(2, 3, "Rectangle");
System.out.println("Area of rectangle: " + rect.area());
rect.moveTo(1, 2);

System.out.println();

Shape circle = new Circle(2, "Circle");


System.out.println("Area of circle: " + circle.area());
circle.moveTo(2, 4);
}
}

Output
Area of rectangle: 6.0
Rectangle has been moved to x = 1 and y = 2

Area of circle: 12.56


Circle has been moved to x = 2 and y = 4
Example 2:
Java
// Abstract class Sunstar
abstract class Sunstar {
// Abstract method printInfo
abstract void printInfo();
}

// Employee class that extends the abstract class Sunstar


class Employee extends Sunstar {
// Implementation of the abstract method printInfo
void printInfo() {
String name = "Avinash"; // Employee name
int age = 21; // Employee age
float salary = 222.2F; // Employee salary

System.out.println(name); // Print name


System.out.println(age); // Print age
System.out.println(salary); // Print salary
}
}

// Base class to test the implementation


class Base {
public static void main(String args[]) {
Sunstar s = new Employee(); // Create an Employee object
s.printInfo(); // Call the printInfo method
}
}

Output
Avinash
21
222.2
Interface in Java
1. Definition:
An interface is a reference type in Java, it is similar to a class, and it is a
collection of abstract methods and static constants.
2. Method Implementation:
All methods in an interface are by default abstract and must be implemented by
any class that implements the interface.From Java 8, interfaces can have default
and static methods with concrete implementations.From Java 9, interfaces can
also have private methods.
3. Variables:
Variables declared in an interface are by default public, static, and final
(constants).
Example:
Java
interface Drawable {
void draw();
}

interface Movable {
void moveTo(int x, int y);
}

class Circle implements Drawable, Movable {


double pi = 3.14;
int radius;

Circle(int radius) {
this.radius = radius;
}

@Override
public void draw() {
System.out.println("Circle has been drawn ");
}

@Override
public void moveTo(int x, int y) {
System.out.println("Circle has been moved to x = " + x + " and y = " + y);
}
}

public class Main {


public static void main(String[] args) {
Circle circle = new Circle(2);
circle.draw();
circle.moveTo(2, 4);
}
}

Output
Circle has been drawn
Circle has been moved to x = 2 and y = 4
Abstract class vs Interface

Points Abstract Class Interface

Can have only abstract


methods (until Java 7),
and from Java 8, can have
Can have both abstract
default and static
and concrete methods
methods, and from Java 9,
can have private
Type of Methods methods.

Can have final, non-final,


Only static and final
static, and non-static
variables
Variables variables.

Can extend only one class A class can implement


Inheritance (abstract or not) multiple interfaces

Constructors Can have constructors Cannot have constructors

Can provide the Cannot provide the


implementation of implementation of
Implementation interface methods abstract class methods

By understanding these distinctions, you can make informed decisions about


when to use abstract classes and interfaces in Java programming.
Features of an Abstract Class in Java
An abstract class in Java is a special type of class that cannot be instantiated
directly and serves as a blueprint for other classes. It provides a way to define a
common interface or behavior that can be shared by multiple related classes, but
with specific implementations in each derived class.
Key features:
 Cannot be instantiated: Abstract classes cannot be directly
instantiated, meaning you cannot create objects of an abstract class.
 Combining Partial Implementation and Subclass Contract: Abstract
classes can contain abstract methods (methods without implementations)
that must be overridden by subclasses. Additionally, they can have
concrete methods with implementations, allowing abstract classes to
provide both a partial implementation and a contract for subclasses to
follow.
 Can contain both abstract and non-abstract methods: Abstract
classes can have both abstract and non-abstract methods. Non-abstract
methods have complete implementations and can be called directly.
 Can have constructors: Abstract classes can have constructors that can
be called when a subclass is instantiated, allowing for initialization of the
class’s fields.
 Can have member variables: Abstract classes can have member
variables, which are variables that belong to an instance of the class.
These variables can be final, non-final, static, or non-static.
 Can be used as a base class: Abstract classes can be used as a base
class for other classes, meaning they can be inherited by other classes.
This allows for code reuse and the creation of a common interface or
behavior for related classes.
Overall, abstract classes in Java are used to define a common interface or
behavior that can be shared by multiple related classes, with specific
implementations provided by each derived class.
Features of an Interface in Java
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. The methods in interfaces are
abstract by default (except for default and static methods introduced in Java 8
and private methods in Java 9). Here are the
Key features:
 Defines a set of methods and properties: An interface defines a set of
abstract methods that any class implementing the interface must provide
implementations for. It acts as a contract that ensures certain methods are
present in the implementing class. Interfaces can also declare constants
(public static final variables).
 Provides a common protocol: Interfaces establish a common protocol
for different software components, allowing them to communicate with
each other. This ensures consistency and interoperability across different
parts of a software system.
 Supports polymorphism: Interfaces support polymorphism, enabling
objects of different classes to be treated as instances of the interface type.
As long as the objects implement the same interface, they can be used
interchangeably, promoting flexibility and extensibility.
 Enables separation of concerns: By defining method signatures
without implementations, interfaces promote separation of concerns. This
allows different parts of a software system to be developed independently,
as long as they adhere to the interface specifications. This decouples the
implementation details from the interface.
 Improves code reusability: Interfaces improve code reusability by
allowing different classes to implement the same interface. This means
that common functionality defined by the interface can be reused across
multiple classes, reducing code duplication and enhancing maintainability.
 Enforces design patterns: Interfaces can enforce design patterns, such
as the Adapter pattern or Strategy pattern, by requiring certain methods
or properties to be implemented by the implementing classes. This
promotes consistent design and adherence to established best practices.
 Facilitates testing: Interfaces facilitate testing by enabling the use of
mock objects that implement the interface. This allows software
components to be tested independently of each other, ensuring that each
component behaves correctly in isolation before integrating them into the
larger system.
 Static and Default Methods: Since Java 8, interfaces can include
default methods with implementations, which provide a way to add new
methods to interfaces without breaking existing implementations.
Interfaces can also include static methods, which belong to the interface
itself rather than any instance.
 Private Methods: Since Java 9, interfaces can also include private
methods to encapsulate shared code between default methods, helping to
avoid code duplication within the interface.
Overall, interfaces in Java are powerful tools for defining contracts and promoting
flexibility, interoperability, and maintainability in software design.
When to use what?
Consider using abstract classes if any of these statements apply to your
situation:
 In the Java application, there are some related classes that need to share
some lines of code then you can put these lines of code within the abstract
class and this abstract class should be extended by all these related
classes.
 You can define the non-static or non-final field(s) in the abstract class so
that via a method you can access and modify the state of the object to
which they belong.
 You can expect that the classes that extend an abstract class have many
common methods or fields, or require access modifiers other than public
(such as protected and private).
Consider using interfaces if any of these statements apply to your situation:
 It is a total abstraction, all methods declared within an interface must be
implemented by the class(es) that implements this interface.
 A class can implement more than one interface. It is called multiple
inheritances.
 You want to specify the behavior of a data type without worrying about its
implementation.
Summary
Abstract classes in Java serve as blueprints that cannot be instantiated directly
and can include both abstract and concrete methods. They allow for partial
implementation and can contain various types of member variables with any
access modifier. A class can inherit only one abstract class. Interfaces, on the
other hand, are contracts that specify a set of abstract methods that a class
must implement, though they can include default and static methods from Java 8
onwards. Interfaces enable multiple inheritance of type, support polymorphism,
and enforce a common protocol for different software components. Unlike
abstract classes, all interface methods are implicitly public, and variables are
public, static, and final.

24.
Difference Between Method Overloading and Method Overriding in Java
Last Updated : 12 Jul, 2024

The differences between Method Overloading and Method Overriding in Java are
as follows:
Method Overloading Method Overriding

Method overloading is a compile- Method overriding is a run-time


time polymorphism. polymorphism.

Method overriding is used to grant the


Method overloading helps to
specific implementation of the method
increase the readability of the
which is already provided by its parent
program.
class or superclass.

It is performed in two classes with


It occurs within the class.
inheritance relationships.

Method overloading may or may Method overriding always needs


not require inheritance. inheritance.

In method overloading, methods In method overriding, methods must


must have the same name and have the same name and same
different signatures. signature.

In method overloading, the return


type can or can not be the same, In method overriding, the return type
but we just have to change the must be the same or co-variant.
parameter.

Static binding is being used for Dynamic binding is being used for
overloaded methods. overriding methods.

Private and final methods can be Private and final methods can’t be
overloaded. overridden.

The argument list should be


The argument list should be the same in
different while doing method
method overriding.
overloading.

Method Overloading in Java


Method Overloading is a Compile time polymorphism. In method overloading,
more than one method shares the same method name with a different signature
in the class. In method overloading, the return type can or can not be the same,
but we have to change the parameter because, in java, we can not achieve
method overloading by changing only the return type of the method.
Example of Method Overloading:
Java
// Java Program to Implement
// Method Overloading
import java.io.*;

class MethodOverloadingEx {

static int add(int a, int b) { return a + b; }

static int add(int a, int b, int c)


{
return a + b + c;
}

// Main Function
public static void main(String args[])
{
System.out.println("add() with 2 parameters");
// Calling function with 2 parameters
System.out.println(add(4, 6));

System.out.println("add() with 3 parameters");


// Calling function with 3 Parameters
System.out.println(add(4, 6, 7));
}
}

Output
add() with 2 parameters
10
add() with 3 parameters
17
Method Overriding in Java
Method Overriding is a type of runtime polymorphism. In method overriding, a
method in a derived class has the same name, return type, and parameters as a
method in its parent class. The derived class provides a specific implementation
for the method that is already defined in the parent class.
Example of Method Overriding:
Java
import java.io.*;

// Base Class
class Animal {
void eat() {
System.out.println("eat() method of base class");
System.out.println("Animal is eating.");
}
}

// Derived Class
class Dog extends Animal {
@Override
void eat() {
System.out.println("eat() method of derived class");
System.out.println("Dog is eating.");
}

// Method to call the base class method


void eatAsAnimal() {
super.eat();
}
}
// Driver Class
class MethodOverridingEx {
// Main Function
public static void main(String args[]) {
Dog d1 = new Dog();
Animal a1 = new Animal();

// Calls the eat() method of Dog class


d1.eat();
// Calls the eat() method of Animal class
a1.eat();

// Polymorphism: Animal reference pointing to Dog object


Animal animal = new Dog();

// Calls the eat() method of Dog class


animal.eat();

// To call the base class method, you need to use a Dog reference
((Dog) animal).eatAsAnimal();
}
}

Output
eat() method of derived class
Dog is eating.
eat() method of base class
Animal is eating.
eat() method of derived class
Dog is eating.
eat() method of base class
Animal is eating.
Explanation of the above Program:
Here, we can see that a method eat() has overridden in the derived class
name Dog that is already provided by the base class name Animal. When we
create the instance of class Dog and call the eat() method, we see that only
derived class eat() method run instead of base class method eat(), and When we
create the instance of class Animal and call the eat() method, we see that only
base class eat() method run instead of derived class method eat().

25.
final Keyword in Java
Last Updated : 31 Jul, 2024

The final method in Java is used as a non-access modifier applicable only to


a variable, a method, or a class. It is used to restrict a user in Java.
The following are different contexts where the final is used:
1. Variable
2. Method
3. Class
Characteristics of final keyword in Java:
In Java, the final keyword is used to indicate that a variable, method, or class
cannot be modified or extended. Here are some of its characteristics:
 Final variables: When a variable is declared as final, its value cannot be
changed once it has been initialized. This is useful for declaring constants
or other values that should not be modified.
 Final methods: When a method is declared as final, it cannot be
overridden by a subclass. This is useful for methods that are part of a
class’s public API and should not be modified by subclasses.
 Final classes: When a class is declared as final, it cannot be extended by
a subclass. This is useful for classes that are intended to be used as is and
should not be modified or extended.
 Initialization: Final variables must be initialized either at the time of
declaration or in the constructor of the class. This ensures that the value
of the variable is set and cannot be changed.
 Performance: The use of a final can sometimes improve performance, as
the compiler can optimize the code more effectively when it knows that a
variable or method cannot be changed.
 Security: The final can help improve security by preventing malicious
code from modifying sensitive data or behavior.
Overall, the final keyword is a useful tool for improving code quality and ensuring
that certain aspects of a program cannot be modified or extended. By declaring
variables, methods, and classes as final, developers can write more secure,
robust, and maintainable code.
Java Final Variable
When a variable is declared with the final keyword, its value can’t be
changed, essentially, a constant. This also means that you must initialize a
final variable.
If the final variable is a reference, this means that the variable cannot be re-
bound to reference another object, but the internal state of the object pointed
by that reference variable can be changed i.e. you can add or remove elements
from the final array or final collection.
It is good practice to represent final variables in all uppercase, using underscore
to separate words.
Example:
Java
public class ConstantExample {
public static void main(String[] args) {
// Define a constant variable PI
final double PI = 3.14159;

// Print the value of PI


System.out.println("Value of PI: " + PI);
}
}

Output
Value of PI: 3.14159
Output:
Value of PI: 3.14159

Different Methods of Using Final Variable


Let’s see different methods that we can use final variable in Java.
1. final Variable
Example:
// Final variable
final int THRESHOLD = 5;

2. Blank final Variable


Example:
// Blank final variable
final int THRESHOLD;

3. Static final Variable


Example:
// Final static variable PI
static final double PI = 3.141592653589793;

4. Static Blank final Variable


Example:
// Blank final static variable
static final double PI;

Initializing a final Variable


We must initialize a final variable, otherwise, the compiler will throw a compile-
time error. A final variable can only be initialized once, either via an initializer or
an assignment statement. There are three ways to initialize a final variable:
1. You can initialize a final variable when it is declared. This approach is the
most common. A final variable is called a blank final variable if it
is not initialized while declaration. Below are the two ways to initialize a
blank final variable.
2. A blank final variable can be initialized inside an instance-initializer
block or the constructor. If you have more than one constructor in your
class then it must be initialized in all of them, otherwise, a compile-time
error will be thrown.
3. A blank final static variable can be initialized inside a static block.
Let us see these two different ways of initializing a final variable
Example:
Java
// Java Program to demonstrate Different
// Ways of Initializing a final Variable
// Main class
class GFG {

// a final variable
// direct initialize
final int THRESHOLD = 5;

// a blank final variable


final int CAPACITY;

// another blank final variable


final int MINIMUM;

// a final static variable PI


// direct initialize
static final double PI = 3.141592653589793;

// a blank final static variable


static final double EULERCONSTANT;

// instance initializer block for


// initializing CAPACITY
{
CAPACITY = 25;
}

// static initializer block for


// initializing EULERCONSTANT
static{
EULERCONSTANT = 2.3;
}
// constructor for initializing MINIMUM
// Note that if there are more than one
// constructor, you must initialize MINIMUM
// in them also
public GFG()
{
MINIMUM = -1;
}

There was no main method in the above code as it was simply for illustration
purposes to get a better understanding to draw conclusions:
Observation 1: When to use a final variable?
The only difference between a normal variable and a final variable is that we can
re-assign the value to a normal variable but we cannot change the value of a
final variable once assigned. Hence final variables must be used only for the
values that we want to remain constant throughout the execution of the
program.
Observation 2: Reference final variable.
When a final variable is a reference to an object, then this final variable is called
the reference final variable. For example, a final StringBuffer variable looks
defined below as follows:
final StringBuffer sb;
As we all know a final variable cannot be re-assign. But in the case of a reference
final variable, the internal state of the object pointed by that reference variable
can be changed. Note that this is not re-assigning.
This property of the final is called non-transitivity. To understand what is
meant by the internal state of the object as shown in the below example as
follows:
Example 1:
Java
// Java Program to demonstrate
// Reference of Final Variable

// Main class
class GFG {

// Main driver method


public static void main(String[] args)
{
// Creating an object of StringBuilder class
// Final reference variable
final StringBuilder sb = new StringBuilder("Geeks");

// Printing the element in StringBuilder object


System.out.println(sb);

// changing internal state of object reference by


// final reference variable sb
sb.append("ForGeeks");

// Again printing the element in StringBuilder


// object after appending above element in it
System.out.println(sb);
}
}

Output
Geeks
GeeksForGeeks
The non-transitivity property also applies to arrays, because arrays are objects in
Java. Arrays with the final keyword are also called final arrays.
Note: As discussed above, a final variable cannot be reassign, doing it will throw
compile-time error.
Example 2:
Java
// Java Program to Demonstrate Re-assigning
// Final Variable will throw Compile-time Error
// Main class
class GFG {

// Declaring and customly initializing


// static final variable
static final int CAPACITY = 4;

// Main driver method


public static void main(String args[])
{

// Re-assigning final variable


// will throw compile-time error
CAPACITY = 5;
}
}
Output:

Remember: When a final variable is created inside a method/constructor/block,


it is called local final variable, and it must initialize once where it is created. See
below program for local final variable.
Example:
Java
// Java program to demonstrate
// local final variable
// Main class
class GFG {

// Main driver method


public static void main(String args[])
{
// Declaring local final variable
final int i;

// Now initializing it with integer value


i = 20;

// Printing the value on console


System.out.println(i);
}
}

Output
20
Remember these key points as perceived before moving forward as
listed below as follows:
1. Note the difference between C++ const variables and Java final variables.
const variables in C++ must be assigned a value when declared. For
final variables in Java, it is not necessary as we see in the above
examples. A final variable can be assigned value later, but only once.
2. final with foreach loop: final with for-each statement is a legal statement.
Example:
Java
// Java Program to demonstrate Final
// with for-each Statement

// Main class
class GFG {
// Main driver method
public static void main(String[] args)
{

// Declaring and initializing


// custom integer array
int arr[] = { 1, 2, 3 };

// final with for-each statement


// legal statement
for (final int i : arr)
System.out.print(i + " ");
}
}

Output
123
Output explanation: Since the “i” variable goes out of scope with each
iteration of the loop, it is re-declared each iteration, allowing the same token (i)
to be used to represent multiple variables.
Example:
Java
public class Example {
public static void main(String[] args) {
final int VALUE = 10; // declaring a final variable

System.out.println("The value is: " + VALUE);


// VALUE = 20; // uncommenting this line will cause a compiler error
// System.out.println("The new value is: " + VALUE);

final String MESSAGE = "Hello, world!"; // declaring a final variable


System.out.println(MESSAGE);
MyClass myObj = new MyClass();
myObj.printMessage();
myObj.printFinalMessage();

// MyOtherClass extends MyClass {} // uncommenting this line will cause a


compiler error
}
}

class MyClass {
final String message = "Hello!"; // declaring a final instance variable

void printMessage() {
System.out.println(message);
}

void printFinalMessage() {
final String finalMessage = "Hello, final!";
System.out.println(finalMessage);
}
}

final class MyOtherClass { // declaring a final class


// ...
}

Output
The value is: 10
Hello, world!
Hello!
Hello, final!
Java Final classes
When a class is declared with the final keyword in Java, it is called a final class.
A final class cannot be extended(inherited).
There are two uses of a final class:
Usage 1: One is definitely to prevent inheritance, as final classes cannot be
extended. For example, all Wrapper Classes like Integer, Float, etc. are final
classes. We can not extend them.
final class A
{
// methods and fields
}
// The following class is illegal
class B extends A
{
// COMPILE-ERROR! Can't subclass A
}
Usage 2: The other use of final with classes is to create an immutable class like
the predefined String class. One can not make a class immutable without making
it final.
Java Final Method
When a method is declared with final keyword, it is called a final method in
Java. A final method cannot be overridden.
The Object class does this—a number of its methods are final. We must declare
methods with the final keyword for which we are required to follow the same
implementation throughout all the derived classes.
Illustration: Final keyword with a method
class A
{
final void m1()
{
System.out.println("This is a final method.");
}
}
class B extends A
{
void m1()
{
// Compile-error! We can not override
System.out.println("Illegal!");
}
}
Advantages of final Keyword in Java:
The final keyword in Java provides several advantages, including:
 Ensuring immutability: When a variable or reference is marked as final,
its value cannot be changed once it is assigned. This helps ensure that
data is immutable and cannot be accidentally or maliciously modified.
 Improving performance: The use of the final can sometimes help
improve performance, as the Java Virtual Machine (JVM) can optimize code
more effectively when it knows that certain values or references cannot be
changed.
 Making code easier to understand: By declaring variables, methods,
or classes as final, developers can make their code easier to understand
and reason about. When a value or reference is marked as final, it is clear
that it will not change, which can simplify code analysis and debugging.
 Promoting code reuse: By declaring methods as final, developers can
prevent subclasses from overriding them. This can help promote code
reuse and reduce duplication, as subclasses must use the parent class’s
implementation of the method.
 Enhancing security: The use of final can help enhance security by
preventing malicious code from modifying sensitive data or behavior.
Overall, the final keyword is a useful tool for improving code quality and ensuring
that certain aspects of a program cannot be modified. By declaring variables,
methods, and classes as final, developers can write more secure, robust, and
maintainable code.
For more examples and behavior of final methods and final classes,
please see Using final with inheritance. Please see the abstract in java article for
differences between the final and the abstract.
Related Interview Question(Important): Difference between final, finally,
and finalize in Java
Conclusion
The final Keyword in Java is a method to make user-restricted variables, methods,
or classes. In this tutorial, we cover Java’s final keyword in detail and understand
all its contexts.
The contexts are explained with Java programs in examples, providing a
complete understanding of the subject.

26.
Types of Classes in Java
A class is a blueprint in the Java programming language from which an individual
object can be built. In Java, we may declare a class by using the class keyword.
Class members and functions are declared simply within the class. Classes are
required for the creation of Java programs. The object-oriented paradigm (OOP)
allows users to describe real-world objects. Also, a class is sometimes known as a
user-defined data type. The following components make up a class declaration:
 Modifiers
 Class name
 Keywords
 The class body within curly brackets {}.
Class in Java
1. Class is a set of object which shares common characteristics/ behavior and
common properties/ attributes.
2. Class is not a real world entity. It is just a template or blueprint or prototype
from which objects are created.
3. Class does not occupy memory.
4. Class is a group of variables of different data types and group of methods.
A class in java can contain:
• data member
• method
• constructor
• nested class and
• interface

Syntax to declare a class:


access_modifier class<class_name>
{
data member;
method;
constructor;
nested class;
interface;
}

Eg:
• Animal
• Student
• Bird
• Vehicle
• Company
Java
class Student
{
int id;//data member (also instance variable)
String name; //data member (also instance variable)

public static void main(String args[])


{
Student s1=new Student();//creating an object of Student
System.out.println(s1.id);
System.out.println(s1.name);
}
}

Output
0
null
Types of Classes
1. Final Class
2. Static Class
3. Abstract Class
4. Concrete Class
5. POJO Class
6. Singleton Class
7. Inner Class
1. Final Class
When a variable, function, or class is declared final, its value persists throughout
the program. Declaring a method with the final keyword indicates that the
method cannot be overridden by subclasses. That is a class that is marked final
cannot be subclasses. This is very useful when creating immutable classes such
as String classes. A class cannot be mutated unless it is declared final. If only all
the members of the class is final then it can’t be mutated otherwise it can be
mutated
Java
import java.io.*;
import java.lang.*;
import java.util.*;

final class Base {

void Display()
{
System.out.print("Method for Base class.");
}
}

class Extended extends Base {

void Display()
{
System.out.print("Method of Extended class.");
}
}

class GFG {

public static void main(String[] arg)


{
Extended d = new Extended();
d.Display();
}
}
2. Static Class
Static is a Java word that explains how objects are kept in memory. A static
object belongs to that class rather than instances of that class. The primary
function of the class is to provide blueprints for the inherited classes. A static
class has only static members. An object cannot be created for a static class.
Java
import java.io.*;
import java.lang.*;
import java.util.*;

class staticclasses {
static int s;
static void met(int x, int y)
{
System.out.println(
"static method to calculate sum");
s = x + y;
System.out.println(x + "+" + y);
}
static class MyNestedClass {
static
{
System.out.println(
"static block inside a static class");
}
public void disp()
{
int x1;
int y1;
Scanner sc = new Scanner(System.in);
System.out.println("Enter two numbers");
x1 = sc.nextInt();
y1 = sc.nextInt();
met(x1, y1);
System.out.println("Sum of the 2 numbers-" + s);
}
}
}
public class GFG {
public static void main(String args[])
{
staticclasses.MyNestedClass nestedclass
= new staticclasses.MyNestedClass();
nestedclass.disp();
}
}
3. Abstract Class
A class that has zero or more abstract methods and is specified with the abstract
keyword is called an abstract class. We must rigorously extend the abstract
classes to a concrete class in order to use them because they are incomplete
classes. Constructors and static methods can also be included. It can have final
methods, which force the subclass to keep the body of the method unhung.
Java
import java.io.*;
import java.lang.*;
import java.util.*;

interface X {
int product(int x, int y);
}
abstract class Product implements X {

public int product(int x, int y) { return x * y; }


}
class GFG extends Product {
public static void main(String args[])
{
Main ob = new Main();
int p = ob.product(20, 10);
System.out.println("Product: " + p);
}
}
4. Concrete Class
A normal class with an implementation for all of its methods and no abstract
methods is called a concrete class. They are not permitted to have any processes
that are not in use at the time. If it implements all of its methods, a concrete
class can extend its parent, an abstract class, or an interface. It’s a fully working,
instantiable class.
Java
import java.io.*;
import java.lang.*;
import java.util.*;

public class GFG {


static int sum(int x, int y) { return x + y; }

public static void main(String args[])


{
int p = sum(10, 8);
System.out.println("Sum: " + p);
}
}
5. POJO Class
“Plain Old Java Object” is an abbreviation for “Plain Old Java Object.” A POJO
class has only private variables with setter and getter methods to access them.
It’s a pure data structure with fields that can override some Object methods (e.g.
equals) or other interfaces (e.g. serializable), but it has no behavior of its own.
POJO class properties:
 When writing a POJO class, public setter and getter methods are required.
 Private variables should be used for all instance variables.
 It should not extend classes that have already been defined.
 It should not implement interfaces that have been pre-defined.
 There should be no pre-defined annotations.
 It might not have a function Object() { [native code] } that takes no
arguments.
Java
import java.io.*;
import java.lang.*;
import java.util.*;

class POJO {
private int value = 365;
public int getValue() { return value; }
public void setValue(int value) { this.value = value; }
}
public class GFG {
public static void main(String args[])
{
POJO p = new POJO();
System.out.println(p.getValue());
}
}
6. Singleton Class
A singleton class is one that has just one object at any one moment. Even yet, if
we try to create an instance again, the newly created instance refers to the
previous one. Any modification we make to the class through any instance
impacts the variables in that specific instance as well. It’s commonly used to
manage access while working with database connections and socket
programming.
The following is used to make Singleton Class:
 Make a function Object() { [native code] } that is only available to you.
 Create a static function that returns the singleton class’s object (using lazy
initialization).
Java
import java.io.*;
import java.lang.*;
import java.util.*;

class Singleton {

private static Singleton single_instance = null;

public String s;

private Singleton()
{
s = "This is a string part of Singleton class";
}
// here a private constructor is used

// Method
public static Singleton Singleton()
{
if (single_instance == null) {
single_instance = new Singleton();
}
return single_instance;
}
}

// Main class
class GFG {
public static void main(String args[])
{
Singleton x = Singleton.Singleton();
Singleton y = Singleton.Singleton();

// change var of x
x.s = (x.s).toUpperCase();

System.out.println("String from x is -->" + x.s);


System.out.println("String from y is -->" + y.s);
System.out.println("\n");

y.s = (y.s).toLowerCase();

System.out.println("String from x is -->" + x.s);


System.out.println("String from y is -->" + y.s);
}
}
7. Inner Class
We can define a class within a class in Java, and these classes are referred to as
nested classes. It’s used to logically arrange classes and achieve encapsulation.
The outer class members (including private) can be accessed by the inner class.
Syntax:
Java
import java.io.*;

class OuterClass {
// Write the code
class NestedClass {
// Write the code
}
}
There are 4 types of inner classes:
 Nested Inner class
 Anonymous inner classes
 Static nested classes
 Method Local inner classes
A. Nested Inner Class:
It has access to an outer class’s private instance variables. The access modifiers
private, protected, public, and default can be applied to any instance variable.
Java
import java.io.*;
import java.lang.*;
import java.util.*;

class Outer {
class Inner {
public void show()
{
System.out.println("Inside a nested class");
}
}
}

class GFG {
public static void main(String[] args)
{
Outer.Inner in = new Outer().new Inner();
in.show();
}
}
B. Anonymous Inner Class:
Basically, these classes are declared without any name.
Example 1: Using Subclass
Java
import java.io.*;
import java.lang.*;
import java.util.*;

class Outer {
void show()
{
System.out.println("Show method of super class");
}
}

class GFG {

static Outer o = new Outer() {


void show()
{
super.show();
System.out.println("Demo class");
}
};

public static void main(String[] args) { o.show(); }


}
Example 2: Using Interface
import java.io.*;
import java.lang.*;
import java.util.*;

class GFG {

static Hello h = new Hello() {


public void show()
{
System.out.println(
"This is an anonymous class");
}
};

public static void main(String[] args) { h.show(); }


}

interface Hello {
void show();
}
C. Static Nested Class:
These classes are like static members of the outer class.
Java
import java.io.*;
import java.lang.*;
import java.util.*;

class GFG {
static int data = 100;
static class Inner {

void msg()
{
System.out.println("data is " + data);
}
}

public static void main(String args[])


{
GFG.Inner obj = new GFG.Inner();
obj.msg();
}
}
D. Method Local inner Class:
An inner class can be declared within a method of an outer class.
import java.io.*;
import java.lang.*;
import java.util.*;

class Outer {
void outerMethod()
{
System.out.println("Outer Method");
class Inner {
void innerMethod()
{
System.out.println("Inner Method");
}
}

Inner y = new Inner();


y.innerMethod();
}
}
class GFG {
public static void main(String[] args)
{
Outer x = new Outer();
x.outerMethod();
}
}

27.
Checked vs Unchecked Exceptions in Java
In Java, Exception is an unwanted or unexpected event, which occurs during
the execution of a program, i.e. at run time, that disrupts the normal flow of the
program’s instructions.
In Java, there are two types of exceptions:
1. Checked exceptions
2. Unchecked exceptions
Checked Exceptions in Java
These are the exceptions that are checked at compile time. If some code within a
method throws a checked exception, then the method must either handle the
exception or it must specify the exception using the throws keyword. Checked
exceptions can be fully checked or partially checked.
 Fully Checked Exception: A checked exception where all its child classes
are also checked (e.g., IOException, InterruptedException).
 Partially Checked Exception: A checked exception where some of its
child classes are unchecked (e.g., Exception).
Checked exceptions represent invalid conditions in areas outside the immediate
control of the program (like memory, network, file system, etc.). Any checked
exception is a subclass of Exception. Unlike unchecked exceptions, checked
exceptions must be either caught by the caller or listed as part of the method
signature using the throws keyword.
Example:
Java
// Java Program to Illustrate Checked Exceptions
// Where FileNotFoundException occurred

// Importing I/O classes


import java.io.*;

// Main class
class GFG {

// Main driver method


public static void main(String[] args)
{

// Reading file from path in local directory


FileReader file = new FileReader("C:\\test\\a.txt");

// Creating object as one of ways of taking input


BufferedReader fileInput = new BufferedReader(file);

// Printing first 3 lines of file "C:\test\a.txt"


for (int counter = 0; counter < 3; counter++)
System.out.println(fileInput.readLine());

// Closing file connections


// using close() method
fileInput.close();
}
}

Output:
To fix the above program, we either need to specify a list of exceptions using
throws, or we need to use a try-catch block. We have used throws in the below
program. Since FileNotFoundException is a subclass of IOException, we can just
specify IOException in the throws list and make the above program compiler-
error-free.
Example:
Java
// Java Program to Illustrate Checked Exceptions
// Where FileNotFoundException does not occur

// Importing I/O classes


import java.io.*;

// Main class
class GFG {

// Main driver method


public static void main(String[] args)
throws IOException
{

// Creating a file and reading from local repository


FileReader file = new FileReader("C:\\test\\a.txt");
// Reading content inside a file
BufferedReader fileInput = new BufferedReader(file);

// Printing first 3 lines of file "C:\test\a.txt"


for (int counter = 0; counter < 3; counter++)
System.out.println(fileInput.readLine());

// Closing all file connections


// using close() method
// Good practice to avoid any memory leakage
fileInput.close();
}
}
Output:
First three lines of file "C:\test\a.txt"
Unchecked Exceptions in Java
These are the exceptions that are not checked at compile time. In C++, all
exceptions are unchecked, so it is not forced by the compiler’s to either handle
or specify the exception. It is up to the programmers to be civilized and specify
or catch the exceptions. In Java, exceptions
under Error and RuntimeException classes are unchecked exceptions, everything
else under throwable is checked.
Consider the following Java program. It compiles fine, but it
throws ArithmeticException when run. The compiler allows it to compile
because ArithmeticException is an unchecked exception.
Example:
Java
// Java Program to Illustrate Un-checked Exceptions

// Main class
class GFG {

// Main driver method


public static void main(String args[])
{
// Here we are dividing by 0
// which will not be caught at compile time
// as there is no mistake but caught at runtime
// because it is mathematically incorrect
int x = 0;
int y = 10;
int z = y / x;
}
}
Output
Exception in thread "main" java.lang.ArithmeticException: / by zero
at Main.main(Main.java:5)
Java Result: 1
In short unchecked exceptions are runtime exceptions that are not required to be
caught or declared in a throws clause. These exceptions are usually caused by
programming errors, such as attempting to access an index out of bounds in an
array or attempting to divide by zero.
Unchecked exceptions include all subclasses of the RuntimeException class, as
well as the Error class and its subclasses.
The separation into checked and unchecked exceptions sounded like a good idea
at the time. However, over the years, it has introduced more boilerplate and less
aesthetically pleasing code patterns than it solved real problems. The typical
(and unfortunately quite cumbersome) pattern within the Java ecosystem is to
hide (or wrap) the checked exception within an unchecked one.
Example:
Java
try {
// Some I/O operation here
} catch( final IOException ex ) {
throw new RuntimeException( "I/O operation failed", ex );
}

Here are some examples of unchecked exceptions in Java:


1. ArrayIndexOutOfBoundsException: This exception is thrown when you
attempt to access an array index that is out of bounds.
2. NullPointerException: This exception is thrown when you attempt to access
a null object reference.
3. ArithmeticException: This exception is thrown when you attempt to divide
by zero or perform an invalid arithmetic operation.
Conclusion
Checked exceptions in Java must be either caught or declared in the method
signature, representing conditions outside the program’s control. Unchecked
exceptions, typically caused by programming errors, are not required to be
caught or declared. Understanding the difference between these exceptions
helps write more robust and error-free code.

28.
Garbage Collection in Java
Garbage collection in Java is the process by which Java programs perform
automatic memory management. Java programs compile to bytecode that can be
run on a Java Virtual Machine, or JVM for short. When Java programs run on the
JVM, objects are created on the heap, which is a portion of memory dedicated to
the program. Eventually, some objects will no longer be needed. The garbage
collector finds these unused objects and deletes them to free up memory.
What is Garbage Collection?
In C/C++, a programmer is responsible for both the creation and destruction of
objects. Usually, programmer neglects the destruction of useless objects. Due to
this negligence, at a certain point, sufficient memory may not be available to
create new objects, and the entire program will terminate abnormally,
causing OutOfMemoryErrors.
But in Java, the programmer need not care for all those objects which are no
longer in use. Garbage collector destroys these objects. The main objective of
Garbage Collector is to free heap memory by destroying unreachable objects.
The garbage collector is the best example of the Daemon thread as it is always
running in the background.
How Does Garbage Collection in Java works?
Java garbage collection is an automatic process. Automatic garbage collection is
the process of looking at heap memory, identifying which objects are in use and
which are not, and deleting the unused objects. An in-use object, or a referenced
object, means that some part of your program still maintains a pointer to that
object. An unused or unreferenced object is no longer referenced by any part of
your program. So the memory used by an unreferenced object can be reclaimed.
The programmer does not need to mark objects to be deleted explicitly. The
garbage collection implementation lives in the JVM.
Types of Activities in Java Garbage Collection
Two types of garbage collection activity usually happen in Java. These are:
1. Minor or incremental Garbage Collection: It is said to have occurred when
unreachable objects in the young generation heap memory are removed.
2. Major or Full Garbage Collection: It is said to have occurred when the
objects that survived the minor garbage collection are copied into the old
generation or permanent generation heap memory are removed. When
compared to the young generation, garbage collection happens less
frequently in the old generation.
Important Concepts Related to Garbage Collection in Java
1. Unreachable objects: An object is said to be unreachable if it doesn’t contain
any reference to it. Also, note that objects which are part of the island of isolation
are also unreachable.
Integer i = new Integer(4);
// the new Integer object is reachable via the reference in 'i'
i = null;
// the Integer object is no longer reachable.

2. Eligibility for garbage collection: An object is said to be eligible for GC(garbage


collection) if it is unreachable. After i = null, integer object 4 in the heap area is
suitable for garbage collection in the above image.
Ways to make an object eligible for Garbage Collector
 Even though the programmer is not responsible for destroying useless
objects but it is highly recommended to make an object unreachable(thus
eligible for GC) if it is no longer required.
 There are generally four ways to make an object eligible for garbage
collection.
1. Nullifying the reference variable
2. Re-assigning the reference variable
3. An object created inside the method
4. Island of Isolation
Ways for requesting JVM to run Garbage Collector
 Once we make an object eligible for garbage collection, it may not destroy
immediately by the garbage collector. Whenever JVM runs the Garbage
Collector program, then only the object will be destroyed. But when JVM
runs Garbage Collector, we can not expect.
 We can also request JVM to run Garbage Collector. There are two ways to
do it :
1. Using System.gc() method: System class contain static
method gc() for requesting JVM to run Garbage Collector.
2. Using Runtime.getRuntime().gc() method: Runtime class allows the
application to interface with the JVM in which the application is
running. Hence by using its gc() method, we can request JVM to run
Garbage Collector.
3. There is no guarantee that any of the above two methods will run
Garbage Collector.
4. The call System.gc() is effectively equivalent to the
call : Runtime.getRuntime().gc()
Finalization
 Just before destroying an object, Garbage Collector calls finalize() method
on the object to perform cleanup activities. Once finalize() method
completes, Garbage Collector destroys that object.
 finalize() method is present in Object class with the following prototype.
protected void finalize() throws Throwable
Based on our requirement, we can override finalize() method for performing our
cleanup activities like closing connection from the database.
1. The finalize() method is called by Garbage Collector, not JVM. However,
Garbage Collector is one of the modules of JVM.
2. Object class finalize() method has an empty implementation. Thus, it is
recommended to override the finalize() method to dispose of system
resources or perform other cleanups.
3. The finalize() method is never invoked more than once for any object.
4. If an uncaught exception is thrown by the finalize() method, the exception
is ignored, and the finalization of that object terminates.
Advantages of Garbage Collection in Java
The advantages of Garbage Collection in Java are:
 It makes java memory-efficient because the garbage collector removes the
unreferenced objects from heap memory.
 It is automatically done by the garbage collector(a part of JVM), so we
don’t need extra effort.
Real-World Example
Let’s take a real-life example, where we use the concept of the garbage collector.
Question: Suppose you go for the internship at GeeksForGeeks, and you were
told to write a program to count the number of employees working in the
company(excluding interns). To make this program, you have to use the concept
of a garbage collector.
This is the actual task you were given at the company:
Write a program to create a class called Employee having the following data
members.
1. An ID for storing unique id allocated to every employee.
2. Name of employee.
3. age of an employee.
Also, provide the following methods:
1. A parameterized constructor to initialize name and age. The ID should be
initialized in this constructor.
2. A method show() to display ID, name, and age.
3. A method showNextId() to display the ID of the next employee.
Now any beginner, who doesn’t know Garbage Collector in Java will code like
this:
 Java

// Java Program to count number


// of employees working
// in a company
class Employee {

private int ID;


private String name;
private int age;
private static int nextId = 1;
// it is made static because it
// is keep common among all and
// shared by all objects

public Employee(String name, int age)


{
this.name = name;
this.age = age;
this.ID = nextId++;
}
public void show()
{
System.out.println("Id=" + ID + "\nName=" + name
+ "\nAge=" + age);
}
public void showNextId()
{
System.out.println("Next employee id will be="
+ nextId);
}
}

class UseEmployee {
public static void main(String[] args)
{
Employee E = new Employee("GFG1", 56);
Employee F = new Employee("GFG2", 45);
Employee G = new Employee("GFG3", 25);
E.show();
F.show();
G.show();
E.showNextId();
F.showNextId();
G.showNextId();

{ // It is sub block to keep


// all those interns.
Employee X = new Employee("GFG4", 23);
Employee Y = new Employee("GFG5", 21);
X.show();
Y.show();
X.showNextId();
Y.showNextId();
}
// After countering this brace, X and Y
// will be removed.Therefore,
// now it should show nextId as 4.

// Output of this line


E.showNextId();
// should be 4 but it will give 6 as output.
}
}

Output
Id=1
Name=GFG1
Age=56
Id=2
Name=GFG2
Age=45
Id=3
Name=GFG3
Age=25
Next employee id will be=4
Next employee id will be=4
Next employee id will be=4
Id=4
Name=GFG4
Age=23
Id=5
Name=GFG5
Age=21
Next employee id will be=6
Next employee id will be=6
Next employee id will be=6
Now to get the correct output:
Now garbage collector(gc) will see 2 objects free. Now to decrement
nextId,gc(garbage collector) will call method to finalize() only when we
programmers have overridden it in our class. And as mentioned previously, we
have to request gc(garbage collector), and for this, we have to write the
following 3 steps before closing brace of sub-block.
1. Set references to null(i.e X = Y = null;)
2. Call, System.gc();
3. Call, System.runFinalization();
Now the correct code for counting the number of employees(excluding interns)
 Java

// Correct code to count number


// of employees excluding interns.

class Employee {

private int ID;


private String name;
private int age;
private static int nextId = 1;

// it is made static because it


// is keep common among all and
// shared by all objects
public Employee(String name, int age)
{
this.name = name;
this.age = age;
this.ID = nextId++;
}
public void show()
{
System.out.println("Id=" + ID + "\nName=" + name
+ "\nAge=" + age);
}
public void showNextId()
{
System.out.println("Next employee id will be="
+ nextId);
}
protected void finalize()
{
--nextId;
// In this case,
// gc will call finalize()
// for 2 times for 2 objects.
}
}

public class UseEmployee {


public static void main(String[] args)
{
Employee E = new Employee("GFG1", 56);
Employee F = new Employee("GFG2", 45);
Employee G = new Employee("GFG3", 25);
E.show();
F.show();
G.show();
E.showNextId();
F.showNextId();
G.showNextId();

{
// It is sub block to keep
// all those interns.
Employee X = new Employee("GFG4", 23);
Employee Y = new Employee("GFG5", 21);
X.show();
Y.show();
X.showNextId();
Y.showNextId();
X = Y = null;
System.gc();
System.runFinalization();
}
E.showNextId();
}
}

Output
Id=1
Name=GFG1
Age=56
Id=2
Name=GFG2
Age=45
Id=3
Name=GFG3
Age=25
Next employee id will be=4
Next employee id will be=4
Next employee id will be=4
Id=4
Name=GFG4
Age=23
Id=5
Name=GFG5
Age=21
Next employee id will be=6
Next employee id will be=6
Next employee id will be=4

29.
static Keyword in Java
The static keyword in Java is mainly used for memory management. The static
keyword in Java is used to share the same variable or method of a given class.
The users can apply static keywords with variables, methods, blocks, and nested
classes. The static keyword belongs to the class than an instance of the class.
The static keyword is used for a constant variable or a method that is the same
for every instance of a class.
The static keyword is a non-access modifier in Java that is applicable for
the following:
1. Blocks
2. Variables
3. Methods
4. Classes
Note: To create a static member(block, variable, method, nested class), precede
its declaration with the keyword static.
Characteristics of static keyword:
Here are some characteristics of the static keyword in Java:
 Shared memory allocation: Static variables and methods are allocated
memory space only once during the execution of the program. This
memory space is shared among all instances of the class, which makes
static members useful for maintaining global state or shared functionality.
 Accessible without object instantiation: Static members can be
accessed without the need to create an instance of the class. This makes
them useful for providing utility functions and constants that can be used
across the entire program.
 Associated with class, not objects: Static members are associated
with the class, not with individual objects. This means that changes to a
static member are reflected in all instances of the class, and that you can
access static members using the class name rather than an object
reference.
 Cannot access non-static members: Static methods and variables
cannot access non-static members of a class, as they are not associated
with any particular instance of the class.
 Can be overloaded, but not overridden: Static methods can be
overloaded, which means that you can define multiple methods with the
same name but different parameters. However, they cannot be
overridden, as they are associated with the class rather than with a
particular instance of the class.
When a member is declared static, it can be accessed before any objects of its
class are created, and without reference to any object. For example, in the below
java program, we are accessing static method m1() without creating any object
of the Test class.
 Java
// Java program to demonstrate that a static member
// can be accessed before instantiating a class

class Test
{
// static method
static void m1()
{
System.out.println("from m1");
}

public static void main(String[] args)


{
// calling m1 without creating
// any object of class Test
m1();
}
}

Output
from m1
Static blocks
If you need to do the computation in order to initialize your static variables,
you can declare a static block that gets executed exactly once, when the class is
first loaded.
Consider the following java program demonstrating the use of static blocks.
 Java

// Java program to demonstrate use of static blocks

class Test
{
// static variable
static int a = 10;
static int b;

// static block
static {
System.out.println("Static block initialized.");
b = a * 4;
}

public static void main(String[] args)


{
System.out.println("from main");
System.out.println("Value of a : "+a);
System.out.println("Value of b : "+b);
}
}

Output
Static block initialized.
from main
Value of a : 10
Value of b : 40
For a detailed article on static blocks, see static blocks
Static variables
When a variable is declared as static, then a single copy of the variable is
created and shared among all objects at the class level. Static variables are,
essentially, global variables. All instances of the class share the same static
variable.
Important points for static variables:
 We can create static variables at the class level only. See here
 static block and static variables are executed in the order they are present
in a program.
Below is the Java program to demonstrate that static block and static variables
are executed in the order they are present in a program.
 Java

// Java program to demonstrate execution


// of static blocks and variables

class Test
{
// static variable
static int a = m1();

// static block
static {
System.out.println("Inside static block");
}

// static method
static int m1() {
System.out.println("from m1");
return 20;
}

// static method(main !!)


public static void main(String[] args)
{
System.out.println("Value of a : "+a);
System.out.println("from main");
}
}

Output
from m1
Inside static block
Value of a : 20
from main
Static methods
When a method is declared with the static keyword, it is known as the static
method. The most common example of a static method is the main( ) method. As
discussed above, Any static member can be accessed before any objects of its
class are created, and without reference to any object. Methods declared as
static have several restrictions:
 They can only directly call other static methods.
 They can only directly access static data.
 They cannot refer to this or super in any way.
Below is the java program to demonstrate restrictions on static methods.
 Java

// Java program to demonstrate restriction on static methods

class Test
{
// static variable
static int a = 10;

// instance variable
int b = 20;

// static method
static void m1()
{
a = 20;
System.out.println("from m1");

// Cannot make a static reference to the non-static field b


b = 10; // compilation error
// Cannot make a static reference to the
// non-static method m2() from the type Test
m2(); // compilation error

// Cannot use super in a static context


System.out.println(super.a); // compiler error
}

// instance method
void m2()
{
System.out.println("from m2");
}

public static void main(String[] args)


{
// main method
}
}

Output:
prog.java:18: error: non-static variable b cannot be referenced from a static
context
b = 10; // compilation error
^
prog.java:22: error: non-static method m2() cannot be referenced from a static
context
m2(); // compilation error
^
prog.java:25: error: non-static variable super cannot be referenced from a static
context
System.out.println(super.a); // compiler error
^
prog.java:25: error: cannot find symbol
System.out.println(super.a); // compiler error
^
symbol: variable a
4 errors
When to use static variables and methods?
Use the static variable for the property that is common to all objects. For
example, in class Student, all students share the same college name. Use static
methods for changing static variables.
Consider the following java program, that illustrates the use of static keywords
with variables and methods.
 Java

// A java program to demonstrate use of


// static keyword with methods and variables

// Student class
class Student {
String name;
int rollNo;

// static variable
static String cllgName;

// static counter to set unique roll no


static int counter = 0;

public Student(String name)


{
this.name = name;

this.rollNo = setRollNo();
}

// getting unique rollNo


// through static variable(counter)
static int setRollNo()
{
counter++;
return counter;
}

// static method
static void setCllg(String name) { cllgName = name; }

// instance method
void getStudentInfo()
{
System.out.println("name : " + this.name);
System.out.println("rollNo : " + this.rollNo);

// accessing static variable


System.out.println("cllgName : " + cllgName);
}
}

// Driver class
public class StaticDemo {
public static void main(String[] args)
{
// calling static method
// without instantiating Student class
Student.setCllg("XYZ");

Student s1 = new Student("Alice");


Student s2 = new Student("Bob");

s1.getStudentInfo();
s2.getStudentInfo();
}
}

Output
name : Alice
rollNo : 1
cllgName : XYZ
name : Bob
rollNo : 2
cllgName : XYZ

Static Classes
A class can be made static only if it is a nested class. We cannot declare a top-
level class with a static modifier but can declare nested classes as static. Such
types of classes are called Nested static classes. Nested static class doesn’t need
a reference of Outer class. In this case, a static class cannot access non-static
members of the Outer class.
Note: For static nested class, see a static nested class in java
Implementation:
 Java

// A java program to demonstrate use


// of static keyword with Classes

import java.io.*;

public class GFG {

private static String str = "GeeksforGeeks";

// Static class
static class MyNestedClass {

// non-static method
public void disp(){
System.out.println(str);
}
}

public static void main(String args[])


{
GFG.MyNestedClass obj
= new GFG.MyNestedClass();
obj.disp();
}
}

Output
GeeksforGeeks
Here’s an example Java program that demonstrates the use of the
static keyword:

public class ExampleClass {


public static int count = 0;
public int id;

public ExampleClass() {
count++;
id = count;
}

public static void printCount() {


System.out.println("Number of instances: " + count);
}

public void printId() {


System.out.println("Instance ID: " + id);
}

public static void main(String[] args) {


ExampleClass e1 = new ExampleClass();
ExampleClass e2 = new ExampleClass();
ExampleClass e3 = new ExampleClass();

e1.printId();
e2.printId();
e3.printId();

ExampleClass.printCount();
}
}

Output
Instance ID: 1
Instance ID: 2
Instance ID: 3
Number of instances: 3
Advantages:
 Memory efficiency: Static members are allocated memory only once
during the execution of the program, which can result in significant
memory savings for large programs.
 Improved performance: Because static members are associated with
the class rather than with individual instances, they can be accessed more
quickly and efficiently than non-static members.
 Global accessibility: Static members can be accessed from anywhere in
the program, regardless of whether an instance of the class has been
created.
 Encapsulation of utility methods: Static methods can be used to
encapsulate utility functions that don’t require any state information from
an object. This can improve code organization and make it easier to reuse
utility functions across multiple classes.
 Constants: Static final variables can be used to define constants that are
shared across the entire program.
 Class-level functionality: Static methods can be used to define class-
level functionality that doesn’t require any state information from an
object, such as factory methods or helper functions.
Overall, the static keyword is a powerful tool that can help to improve the
efficiency and organization of your Java programs.

30.
Multithreading in Java
Multithreading is a Java feature that allows concurrent execution of two or more
parts of a program for maximum utilization of CPU. Each part of such program is
called a thread. So, threads are light-weight processes within a process.
Threads can be created by using two mechanisms:
1. Extending the Thread class
2. Implementing the Runnable Interface
Thread creation by extending the Thread class
We create a class that extends the java.lang.Thread class. This class overrides
the run() method available in the Thread class. A thread begins its life inside
run() method. We create an object of our new class and call start() method to
start the execution of a thread. Start() invokes the run() method on the Thread
object.
 Java

// Java code for thread creation by extending


// the Thread class
class MultithreadingDemo extends Thread {
public void run()
{
try {
// Displaying the thread that is running
System.out.println(
"Thread " + Thread.currentThread().getId()
+ " is running");
}
catch (Exception e) {
// Throwing an exception
System.out.println("Exception is caught");
}
}
}

// Main Class
public class Multithread {
public static void main(String[] args)
{
int n = 8; // Number of threads
for (int i = 0; i < n; i++) {
MultithreadingDemo object
= new MultithreadingDemo();
object.start();
}
}
}

Output
Thread 15 is running
Thread 14 is running
Thread 16 is running
Thread 12 is running
Thread 11 is running
Thread 13 is running
Thread 18 is running
Thread 17 is running
Thread creation by implementing the Runnable Interface
We create a new class which implements java.lang.Runnable interface and
override run() method. Then we instantiate a Thread object and call start()
method on this object.

 Java

// Java code for thread creation by implementing


// the Runnable Interface
class MultithreadingDemo implements Runnable {
public void run()
{
try {
// Displaying the thread that is running
System.out.println(
"Thread " + Thread.currentThread().getId()
+ " is running");
}
catch (Exception e) {
// Throwing an exception
System.out.println("Exception is caught");
}
}
}

// Main Class
class Multithread {
public static void main(String[] args)
{
int n = 8; // Number of threads
for (int i = 0; i < n; i++) {
Thread object
= new Thread(new MultithreadingDemo());
object.start();
}
}
}

Output
Thread 13 is running
Thread 11 is running
Thread 12 is running
Thread 15 is running
Thread 14 is running
Thread 18 is running
Thread 17 is running
Thread 16 is running
Thread Class vs Runnable Interface
1. If we extend the Thread class, our class cannot extend any other class
because Java doesn’t support multiple inheritance. But, if we implement
the Runnable interface, our class can still extend other base classes.
2. We can achieve basic functionality of a thread by extending Thread class
because it provides some inbuilt methods like yield(), interrupt() etc. that
are not available in Runnable interface.
3. Using runnable will give you an object that can be shared amongst
multiple threads.

Synchronization in Java
Multi-threaded programs may often come to a situation where multiple threads
try to access the same resources and finally produce erroneous and unforeseen
results.
Why use Java Synchronization?
Java Synchronization is used to make sure by some synchronization method that
only one thread can access the resource at a given point in time.
Java Synchronized Blocks
Java provides a way of creating threads and synchronizing their tasks using
synchronized blocks.
A synchronized block in Java is synchronized on some object. All synchronized
blocks synchronize on the same object and can only have one thread executed
inside them at a time. All other threads attempting to enter the synchronized
block are blocked until the thread inside the synchronized block exits the block.
Note: Synchronized blocks in Java are marked with the synchronized keyword.
General Form of Synchronized Block
// Only one thread can execute at a time.
// sync_object is a reference to an object
// whose lock associates with the monitor.
// The code is said to be synchronized on
// the monitor object
synchronized(sync_object)
{
// Access shared variables and other
// shared resources
}
This synchronization is implemented in Java with a concept called monitors or
locks. Only one thread can own a monitor at a given time. When a thread
acquires a lock, it is said to have entered the monitor. All other threads
attempting to enter the locked monitor will be suspended until the first thread
exits the monitor.
Types of Synchronization
There are two synchronizations in Java mentioned below:
1. Process Synchronization
2. Thread Synchronization
1. Process Synchronization in Java
Process Synchronization is a technique used to coordinate the execution of
multiple processes. It ensures that the shared resources are safe and in order.
2. Thread Synchronization in Java
Thread Synchronization is used to coordinate and ordering of the execution of
the threads in a multi-threaded program. There are two types of thread
synchronization are mentioned below:
 Mutual Exclusive
 Cooperation (Inter-thread communication in Java)
Mutual Exclusive
Mutual Exclusive helps keep threads from interfering with one another while
sharing data. There are three types of Mutual Exclusive mentioned below:
 Synchronized method.
 Synchronized block.
 Static synchronization.
Example of Synchronization
Below is the implementation of the Java Synchronization:
 Java

// A Java program to demonstrate working of


// synchronized.

import java.io.*;
import java.util.*;
// A Class used to send a message
class Sender {
public void send(String msg)
{
System.out.println("Sending\t" + msg);
try {
Thread.sleep(1000);
}
catch (Exception e) {
System.out.println("Thread interrupted.");
}
System.out.println("\n" + msg + "Sent");
}
}

// Class for send a message using Threads


class ThreadedSend extends Thread {
private String msg;
Sender sender;

// Receives a message object and a string


// message to be sent
ThreadedSend(String m, Sender obj)
{
msg = m;
sender = obj;
}

public void run()


{
// Only one thread can send a message
// at a time.
synchronized (sender)
{
// synchronizing the send object
sender.send(msg);
}
}
}

// Driver class
class SyncDemo {
public static void main(String args[])
{
Sender send = new Sender();
ThreadedSend S1 = new ThreadedSend(" Hi ", send);
ThreadedSend S2 = new ThreadedSend(" Bye ", send);

// Start two threads of ThreadedSend type


S1.start();
S2.start();

// wait for threads to end


try {
S1.join();
S2.join();
}
catch (Exception e) {
System.out.println("Interrupted");
}
}
}
Output
Sending Hi

Hi Sent
Sending Bye

Bye Sent
The output is the same every time we run the program.
Explanation
In the above example, we choose to synchronize the Sender object inside the
run() method of the ThreadedSend class. Alternately, we could define the whole
send() block as synchronized, producing the same result. Then we don’t have
to synchronize the Message object inside the run() method in ThreadedSend
class.
// An alternate implementation to demonstrate
// that we can use synchronized with method also.

class Sender {
public synchronized void send(String msg)
{
System.out.println("Sending\t" + msg);
try {
Thread.sleep(1000);
}
catch (Exception e) {
System.out.println("Thread interrupted.");
}
System.out.println("\n" + msg + "Sent");
}
}
We do not always have to synchronize a whole method. Sometimes it is
preferable to synchronize only part of a method. Java synchronized blocks
inside methods make this possible.
// One more alternate implementation to demonstrate
// that synchronized can be used with only a part of
// method

class Sender
{
public void send(String msg)
{
synchronized(this)
{
System.out.println("Sending\t" + msg );
try
{
Thread.sleep(1000);
}
catch (Exception e)
{
System.out.println("Thread interrupted.");
}
System.out.println("\n" + msg + "Sent");
}
}
}
Example of the synchronized method by using an anonymous class
 Java

// Java Pogram to synchronized method by


// using an anonymous class
import java.io.*;

class Test {
synchronized void test_function(int n)
{
// synchronized method
for (int i = 1; i <= 3; i++) {
System.out.println(n + i);
try {
Thread.sleep(500);
}
catch (Exception e) {
System.out.println(e);
}
}
}
}

// Driver Class
public class GFG {
// Main function
public static void main(String args[])
{
// only one object
final Test obj = new Test();

Thread a = new Thread() {


public void run() { obj.test_function(15); }
};

Thread b = new Thread() {


public void run() { obj.test_function(30); }
};

a.start();
b.start();
}
}

Output
16
17
18
31
32
33

You might also like