Java
Java
Can you tell the difference between equals() method and equality
operator (==) in Java?
We are already aware of the (==) equals operator. That we have used this to
compare the equality of the values. But when we talk about the terms of
object-oriented programming, we deal with the values in the form of objects.
And this object may contain multiple types of data. So using the (==)
operator does not work in this case. So we need to go with the .equals()
method.
Both [(==) and .equals()] primary functionalities are to compare the values,
but the secondary functionality is different.
(==) Operators compares the memory location. equals() method compares
the values and returns the result accordingly.
In the cases where the equals method is not overridden in a class, then the
class uses the default implementation of the equals method that is closest to
the parent class.
Object class is considered as the parent class of all the java classes. The
implementation of the equals method in the Object class uses the == operator
to compare two objects. This default implementation can be overridden as per
the business logic.
Briefly explain the concept of constructor overloading
Constructor overloading is the process of creating multiple constructors in the
class consisting of the same name with a difference in the constructor
parameters. Depending upon the number of parameters and their
corresponding types, distinguishing of the different types of constructors is
done by the compiler.
Method overriding is the concept in which two methods having the same
method signature are present in two different classes in which an inheritance
relationship is present. A particular method implementation (already present in
the base class) is possible for the derived class by using method overriding.
A single try block and multiple catch blocks can co-exist in a Java
Program. Explain.
Yes, multiple catch blocks can exist, but specific approaches should come
prior to the general approach because only the first catch block satisfying the
catch condition is executed.
The clone() will do this deep copy internally and return a new object. And to do this
we need to write only 1 line of code. That is - Rectangle obj2 = obj1.clone().
Apart from the security aspect, what are the reasons behind making
strings immutable in Java?
A String is made immutable due to the following reasons:
String Pool: Designers of Java knew String data type is going to be majorly
used by the programmers and developers. Thus, they wanted optimization
from the beginning. They came up with the notion of using the String pool (a
storage area in Java heap) to store the String literals. They intended to
decrease the temporary String object with the help of sharing. An immutable
class is needed to facilitate sharing. The sharing of the mutable structures
between two unknown parties is not possible. Thus, immutable Java String
helps in executing the concept of String Pool.
Multithreading: The safety of threads regarding the String objects is an
important aspect in Java. No external synchronization is required if the String
objects are immutable. Thus, a cleaner code can be written for sharing the
String objects across different threads. The complex process of concurrency
is facilitated by this method.
Collections: In the case of Hash tables and HashMap, keys are String
objects. If the String objects are not immutable, then it can get modified during
the period when it resides in the HashMap. Consequently, the retrieval of the
desired data is not possible. Such changing states pose a lot of risks.
Therefore, it is quite safe to make the string immutable.
What is a singleton class in Java? And how to implement a singleton
class?
Singleton classes are those classes, whose objects are created only once.
And with only that object the class members can be accessed.
the Constructor is private so we cannot create the object of the class. But we can get
the object by calling the method getInstance(). And the getInstance is static so it can
be called without creating the object. And it returns the object. Now with that object,
we can call instance methods of the class.
We can get the single object using this getInstance(). And it is static, so it is a
thread-safe singleton class. Although there are many ways to create a thread-
safe singleton class. So, thread-safe classes can also be:
When singletons are written with double-checked locking, they can be
thread safe.
We can use static singletons that are initialized during class loading.
But the most straightforward way to create a thread-safe singleton is to
use Java Enums.
How would you differentiate between a String, StringBuffer, and a
StringBuilder?
Storage area: In string, the String pool serves as the storage area. For
StringBuilder and StringBuffer, heap memory is the storage area.
Mutability: A String is immutable, whereas both the StringBuilder and
StringBuffer are mutable.
Efficiency: It is quite slow to work with a String. However, StringBuilder is the
fastest in performing operations. The speed of a StringBuffer is more than a
String and less than a StringBuilder. (For example, appending a character is
fastest in StringBuilder and very slow in String because a new memory is
required for the new String with appended character.)
Thread-safe: In the case of a threaded environment, StringBuilder and
StringBuffer are used whereas a String is not used. However, StringBuilder is
suitable for an environment with a single thread, and a StringBuffer is suitable
for multiple threads.
Using relevant properties highlight the differences between interfaces
and abstract classes.
Availability of methods: Only abstract methods are available in interfaces,
whereas non-abstract methods can be present along with abstract methods in
abstract classes.
Variable types: Static and final variables can only be declared in the case of
interfaces, whereas abstract classes can also have non-static and non-final
variables.
Inheritance: Multiple inheritances are facilitated by interfaces, whereas
abstract classes do not promote multiple inheritances.
Data member accessibility: By default, the class data members of
interfaces are of the public- type. Conversely, the class members for an
abstract class can be protected or private also.
Implementation: With the help of an abstract class, the implementation of an
interface is easily possible. However, the converse is not true;
What is a Comparator in java?
Consider the example where we have an ArrayList of employees like(Eid,
Ename, Salary), etc. Now if we want to sort this list of employees based on
the names of employees. Then that is not possible to sort using the
Collections.sort() method. We need to provide something to the sort() function
depending on what values we have to perform sorting. Then in that case a
comparator is used.
Comparator is the interface in java that contains the compare method. And by
overloading the compare method, we can define that on what basis we need
to compare the values.
Example:
Collections.sort(employees, new Comparator<Employee>() {
@Override
public int compare(Employee o1, Employee o2) {
return o1.getEname().compareToIgnoreCase(o2.getEname());
}
});
What is the difference between the ‘throw’ and ‘throws’ keyword in java?
The ‘throw’ keyword is used to manually throw the exception to the calling
method. And the ‘throws’ keyword is used in the function definition to inform
the calling method that this method throws the exception. So, if you are
calling, then you have to handle the exception.
What are the differences between constructor and method of a class in
Java?
Constructor
Constructor is used for initializing the object state.
Constructor has no return type.
Constructor gets invoked implicitly.
If the constructor is not defined, then a default constructor is provided
by the java compiler.
The constructor’s name should be equal to the class name.
A constructor cannot be marked as final because whenever a class is
inherited, the constructors are not inherited. Hence, making it final
doesn’t make sense. Java throws compilation error saying – modifier
final not allowed here.
Final variable instantiations are possible inside a constructor and the
scope of this applies to the whole class and its objects.
Method
Method is used for exposing the object’s behaviour.
Method should have a return type. Even if it does not return anything,
return type is void.
Method must be invoked on the object explicitly.
If a method is not defined, then the compiler does not provide it.
The name of the method can have any name or have a class name
too.
A method can be defined as final, but it cannot be overridden in its
subclass.
A final variable if initialised inside a method ensures that the variable
cant be changed only within the scope of the method.
Java works as “pass by value” or “pass by reference” phenomenon?
Java always works as a “pass by value”. There is nothing called a “pass by
reference” in Java. However, when the object is passed in any method, the
address of the value is passed due to the nature of object handling in Java.
When an object is passed, a copy of the reference is created by Java and that
is passed to the method. The objects point to the same memory location.
What is the ‘IS-A’ relationship in OOPs Java?
‘IS-A’ relationship is another name for inheritance. When we inherit the base
class from the derived class, then it forms a relationship between the classes.
So that relationship is termed as ‘IS-A’ relationship.
Which among String or String Buffer should be preferred when there are
lot of updates required to be done in the data?
StringBuffer is mutable and dynamic in nature whereas String is immutable.
Every updation / modification of String creates a new String thereby
overloading the string pool with unnecessary objects. Hence, in the cases of a
lot of updates, it is always preferred to use StringBuffer as it will reduce the
overhead of the creation of multiple String objects in the string pool.
How to not allow serialization of attributes of a class in Java?
To achieve this, the attribute can be declared along with the usage of
transient. There are several reasons why you might want to mark a field as
transient:
Security: If a field contains sensitive information, you should mark it as
transient to prevent it from being stored in a file or transmitted over a
network.
Performance: Serializing and deserializing large objects can be time-
consuming. By marking fields as transient, you can reduce the amount
of data that needs to be serialized and improve the performance of
your program.
State management: Sometimes, the state of an object can be
reconstructed based on other information. In these cases, you can
mark the fields that represent this state as transient and avoid the
overhead of serializing and deserializing them.
What do you understand by Object Cloning and how do you achieve it in
Java?
It is the process of creating an exact copy of any object. In order to support
this, a java class has to implement the Cloneable interface of java.lang
package and override the clone() method provided by the Object class.
In case the Cloneable interface is not implemented and just the method is
overridden, it results in CloneNotSuppoertedException in Java.
Is it mandatory for a catch block to be followed by a try block?
No, it is not necessary for a catch block to be present after a try block. - A try
block should be followed either by a catch block or by a finally block. If the
exceptions likelihood is more, then they should be declared using the throws
clause of the method.
Can we call a constructor of a class inside another constructor?
Yes, the concept of calling a constructor of class inside another constructor is
called constructor chaining and can be achieved by using this().
Contiguous memory locations are usually used for storing actual values
in an array but not in ArrayList. Explain.
In the case of ArrayList, data storing in the form of primitive data types (like
int, float, etc.) is not possible. The data members/objects present in the
ArrayList have references to the objects which are located at various sites in
the memory. Thus, storing of actual objects or non-primitive data types (like
Integer, Double, etc.) takes place in various memory locations.
However, the same does not apply to arrays. Object or primitive type values
can be stored in arrays in contiguous memory locations; hence every element
does not require any reference to the next element.
How does the size of ArrayList grow dynamically? And state how it is
implemented internally.
ArrayList is implemented in such a way that it can grow dynamically. We don't
need to specify the size of ArrayList. If we need to add element into it, then
internally ArrayList will allocate the new ArrayList of size (current size + half of
the current size). And add the old elements into the new. Then the new value
will be inserted into it. And for the next time, the extra space will be available
inserting new value.
Although inheritance is a popular OOPs concept, it is less advantageous
than composition. Explain.
While inheritance is a fundamental concept in object-oriented programming, it
has certain drawbacks that make composition a more advantageous
approach in many situations.
Here's a breakdown of the key reasons why composition is often preferred
over inheritance:
1. Tight Coupling:
Inheritance: Creates a tight coupling between parent and child classes.
Changes to the parent class can unintentionally affect all its children,
potentially leading to cascading issues and maintenance challenges.
Composition: Composes objects loosely, allowing you to change one object's
implementation without affecting others. This promotes better code modularity
and maintainability.
2. Inheritance Hierarchies can become Complex:
Inheritance: Deep inheritance hierarchies can become difficult to manage and
understand, as changes in one class can ripple through multiple levels.
Composition: Enables you to create flexible and adaptable relationships
between classes without the rigid structure of inheritance hierarchies.
3. Enforces a Strict "Is-A" Relationship:
Inheritance: Models a strict "is-a" relationship, which may not always
accurately represent the real-world relationships between objects.
Composition: Offers more flexibility to model "has-a" relationships, which are
often more appropriate for modelling real-world scenarios.
4. Inheritance can Lead to Overuse of Subclasses:
Inheritance: Developers might overuse subclasses to add functionality,
leading to overly complex hierarchies and potential design issues.
Composition: Encourages thinking about objects as independent entities that
collaborate, leading to cleaner designs and better code organization.
5. Inheritance can Limit Code Reusability:
Inheritance: Code reuse is limited to members inherited from parent classes.
Composition: Allows you to reuse code from any object, promoting better
code flexibility and modularity.
6. Encapsulation and Testing:
Inheritance: Can sometimes break encapsulation, as child classes can access
and modify private members of parent classes. This can also make testing
more challenging.
Composition: Preserves encapsulation, making classes more independent
and testable.
What are Composition and Aggregation? State the difference.
Composition represents a “HAS-A” relationship. The containing object owns
the contained object and is responsible for its lifecycle. The contained object
cannot exist independently of the containing object. Example – A car has an
engine. The car cannot exist without an engine, and the engine is tightly
coupled to the car.
Aggregation represents a “USES-A” relationship. The containing object has a
reference to the contained object but does not own it. The contained object
can exist independently of the containing object. Example – A car uses a GPS
device. The car can exist without a GPS device, and the GPS device can be
used by other objects as well. GPS device is loosely coupled to the car.
Why is synchronization necessary?
Concurrent execution of different processes is made possible by
synchronization. When a particular resource is shared between many threads,
situations may arise in which multiple threads require the same shared
resource.
Synchronization assists in resolving the issue and the resource is shared by a
single thread at a time. Let’s take an example to understand it more clearly.
For example, you have a URL and you have to find out the number of
requests made to it. Two simultaneous requests can make the count erratic.
If a thread Thread1 views the count as 10, it will be increased by 1 to 11.
Simultaneously, if another thread Thread2 views the count as 10, it will be
increased by 1 to 11. Thus, inconsistency in count values takes place
between the expected final value is 12 but the actual final value we get will be
11.
With synchronized, if thread Thread1 views the count as 10, it will be
increased by 1 to 11, then thread Thread2 will view the count as 11, it will be
increased by 1 to 12. Thus, consistency in count values takes place.
Can you explain the Java thread lifecycle?
Java thread lifecycle is as follows
New – When the instance of the thread is created and the start()
method has not been invoked, the thread is considered to be alive and
hence in the NEW state.
Runnable – Once the start() method is invoked, before the run()
method is called by JVM, the thread is said to be in RUNNABLE (ready
to run) state. This state can also be entered from the Waiting or
Sleeping state of the thread.
Running – When the run() method has been invoked and the thread
starts its execution, the thread is said to be in a RUNNING state.
Non-Runnable (Blocked/Waiting) – When the thread is not able to
run despite the fact of its aliveness, the thread is said to be in a NON-
RUNNABLE state. Ideally, after some time of its aliveness, the thread
should go to a runnable state.
A thread is said to be in a Blocked state if it wants to enter
synchronized code but it is unable to as another thread is
operating in that synchronized block on the same object. The
first thread must wait until the other thread exits the
synchronized block.
A thread is said to be in a Waiting state if it is waiting for the
signal to execute from another thread, i.e., it waits for work until
the signal is received.
Terminated – Once the run() method execution is completed, the
thread is said to enter the TERMINATED step and is considered to not
be alive
What are the various access specifiers in Java?
In Java, access specifiers are the keywords which are used to define the
access scope of the method, class, or a variable. In Java, there are four
access specifiers given below.
Public: The classes, methods, or variables which are defined as public, can
be accessed by any class or method.
Protected: Protected can be accessed by the class of the same package, or
by the sub-class of this class, or within the same class.
Default: Default are accessible within the package only. By default, all the
classes, methods, and variables are of default scope.
Private: The private class, methods, or variables defined as private can be
accessed within the class only.
What are the types and common ways to use lambda expression?
A lambda expression does not have any specific type by itself. A lambda
expression receives type once it is assigned to a functional interface. That
same lambda expression can be assigned to different functional interface
types and can have a different type.
For example consider expression s -> s.isEmpty() :
Predicate<String> stringPredicate = s -> s.isEmpty();
Predicate<List> listPredicate = s -> s.isEmpty();
Function<String, Boolean> func = s -> s.isEmpty();
Consumer<String> stringConsumer = s -> s.isEmpty();
Common ways to use the expression.
Assignment to a functional Interface —> Predicate<String> stringPredicate = s ->
s.isEmpty();
Can be passed as a parameter that has a functional type —> stream.filter(s ->
s.isEmpty())
Returning it from a function —> return s -> s.isEmpty()
Casting it to a functional type —> (Predicate<String>) s -> s.isEmpty()