Answers To Core Java Interview Questions
Answers To Core Java Interview Questions
1.
// Concrete Products
@Override
// Concrete Creators
@Override
@Override
// Client Code
productA.display();
productB.display();
}
Output
The above problem can be solved using Factory Method Design Pattern:
// Product Interface
interface Product {
void display();
// Concrete Products
@Override
@Override
// Factory Interface
interface Factory {
Product factoryMethod();
// Concrete Factories
@Override
@Override
}
// Client Code
productA.display();
productB.display();
Creational Frameworks:
GUI Toolkits:
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.
Plugin Systems:
Game Development:
Web Development:
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.
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.
Conclusion
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;
}
}
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;
}
// Corrected constructor
InterviewbitTest() {
counter = 20;
}
InterviewbitTest(int x){
counter = x;
}
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.
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
o So, num1 and num2 will reference two different Integer objects.
o So, num3 and num4 will reference the same Integer object.
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.
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 .
import java.io.Serializable;
// Constructor
public Person(String name, int age) {
this.name = name;
this.age = age;
}
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;
14.
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
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();
18.
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)
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");
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>();
S.
No
. ArrayList Vector
ArrayList is not
1. Vector is synchronized.
synchronized.
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
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);
}
}
import java.io.*;
import java.util.*;
class GFG
{
public static void main (String[] args)
{
// creating an ArrayList
ArrayList<String> al = new ArrayList<String>();
// creating Vector
Vector<String> v = new Vector<String>();
v.addElement("Practice");
v.addElement("quiz");
v.addElement("code");
Output
ArrayList elements are:
Practice.GeeksforGeeks.org
www.GeeksforGeeks.org
code.GeeksforGeeks.org
write.geeksforgeeks.org
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
Output
true
false
true
true
s2 =
“HELLO”
Java Heap
s3 =
“HELLO”
class Test {
public static void main(String[] args)
{
// integer-type
System.out.println(10 == 20);
// char-type
System.out.println('a' == 'b');
Output
false
false
true
true
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
Example:
String equals() method in Java
Java
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
22.
Four Main Object Oriented Programming Concepts of Java
Last Updated : 09 Jul, 2024
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");
}
}
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;
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;
// driver class
public class Main {
public static void main(String args[])
{
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{
class DeliveryBoy {
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
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
Shape(String name) {
this.objectName = name;
}
@Override
public void draw() {
System.out.println("Rectangle has been drawn ");
}
@Override
public double area() {
return (double)(length * width);
}
}
@Override
public void draw() {
System.out.println("Circle has been drawn ");
}
@Override
public double area() {
return (double)(pi * radius * radius);
}
}
System.out.println();
Output
Area of rectangle: 6.0
Rectangle has been moved to x = 1 and y = 2
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);
}
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);
}
}
Output
Circle has been drawn
Circle has been moved to x = 2 and y = 4
Abstract class vs Interface
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
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.
class MethodOverloadingEx {
// 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));
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.");
}
// 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
Output
Value of PI: 3.14159
Output:
Value of PI: 3.14159
// a final variable
// direct initialize
final int THRESHOLD = 5;
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 {
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 {
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)
{
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
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);
}
}
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
Eg:
• Animal
• Student
• Bird
• Vehicle
• Company
Java
class Student
{
int id;//data member (also instance variable)
String name; //data member (also instance variable)
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.*;
void Display()
{
System.out.print("Method for Base class.");
}
}
void Display()
{
System.out.print("Method of Extended class.");
}
}
class GFG {
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 {
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 {
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();
y.s = (y.s).toLowerCase();
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 {
class GFG {
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);
}
}
class Outer {
void outerMethod()
{
System.out.println("Outer Method");
class Inner {
void innerMethod()
{
System.out.println("Inner Method");
}
}
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
// Main class
class GFG {
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
// Main class
class GFG {
// Main class
class GFG {
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.
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();
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
class Employee {
{
// 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");
}
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
class Test
{
// static variable
static int a = 10;
static int b;
// static block
static {
System.out.println("Static block initialized.");
b = a * 4;
}
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
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;
}
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
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");
// instance method
void m2()
{
System.out.println("from m2");
}
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
// Student class
class Student {
String name;
int rollNo;
// static variable
static String cllgName;
this.rollNo = setRollNo();
}
// 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);
// Driver class
public class StaticDemo {
public static void main(String[] args)
{
// calling static method
// without instantiating Student class
Student.setCllg("XYZ");
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
import java.io.*;
// Static class
static class MyNestedClass {
// non-static method
public void disp(){
System.out.println(str);
}
}
Output
GeeksforGeeks
Here’s an example Java program that demonstrates the use of the
static keyword:
public ExampleClass() {
count++;
id = count;
}
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
// 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
// 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
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");
}
}
// 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);
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
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();
a.start();
b.start();
}
}
Output
16
17
18
31
32
33