Java Software Engineer Interview Questions And Answers
Download Java Software Engineer Interview Questions and Answers PDF
Optimize your Java Software Engineer interview preparation with our curated set of 45 questions. Each question is crafted to challenge your understanding and proficiency in Java Software Engineer. Suitable for all skill levels, these questions are essential for effective preparation. Access the free PDF to get all 45 questions and give yourself the best chance of acing your Java Software Engineer interview. This resource is perfect for thorough preparation and confidence building.
45 Java Software Engineer Questions and Answers:
Java Software Engineer Job Interview Questions Table of Contents:
1 :: Do you know how threadsafe is enum in Java?
Creation of an enum is guaranteed to be threadsafe. However, the methods on an enum type are not necessarily threadsafe
Read More2 :: Explain me what is a good usecase of calling System.gc()?
One may call System.gc() when profiling an application to search for possible memory leaks. All the profilers call this method just before taking a memory snapshot.
Read More3 :: Explain me why doesn’t the following code generate a NullPointerException even when the instance is null?
Test t = null;
t.someMethod();
public static void someMethod() {
...
}
There is no need for an instance while invoking a static member or method, since static members belongs to a class rather than an instance.
A null reference may be used to access a class (static) variable without causing an exception.
Read Moret.someMethod();
public static void someMethod() {
...
}
There is no need for an instance while invoking a static member or method, since static members belongs to a class rather than an instance.
A null reference may be used to access a class (static) variable without causing an exception.
4 :: Do you know what is the advantage of generic collection?
They enable stronger type checks at compile time.
A Java compiler applies strong type checking to generic code, and issues errors if the code violates type safety. Fixing compile-time errors is easier than fixing runtime errors, which can be difficult to find.
Read MoreA Java compiler applies strong type checking to generic code, and issues errors if the code violates type safety. Fixing compile-time errors is easier than fixing runtime errors, which can be difficult to find.
5 :: Tell us what do you mean by aggregation?
Aggregation is a specialized form of Association where all object have their own lifecycle but there is ownership and child object can not belongs to another parent object. Let’s take an example of Department and teacher. A single teacher can not belongs to multiple departments, but if we delete the department teacher object will not destroy.
Read More7 :: Explain me when do you need to override the equals and hashCode methods in Java?
By defining equals() and hashCode() consistently, the candidate can improve the usability of classes as keys in hash-based collections such as HashMap.
Read More8 :: Tell us what are checked and unchecked exceptions? When do you use them?
A checked exception is an exception that must be catch, they are checked by the compiler. An unchecked exception is mostly runtime exception, and is not required to be catch. In general, use checked exception when the situation is recoverable (retry, display reasonable error message).
Read More9 :: Tell us how can you swap the values of two numeric variables without using any other variables?
You can swap two values a and b without using any other variables as follows:
a = a + b;
b = a - b;
a = a - b;
Read Morea = a + b;
b = a - b;
a = a - b;
10 :: Tell us what are constructors in Java?
In Java, constructor refers to a block of code which is used to initialize an object. It must have the same name as that of the class. Also, it has no return type and it is automatically called when an object is created.
There are two types of constructors:
☛ Default constructor
☛ Parameterized constructor
Read MoreThere are two types of constructors:
☛ Default constructor
☛ Parameterized constructor
11 :: Can you explain me what is Polymorphism?
Polymorphism is briefly described as “one interface, many implementations”. Polymorphism is a characteristic of being able to assign a different meaning or usage to something in different contexts – specifically, to allow an entity such as a variable, a function, or an object to have more than one form. There are two types of polymorphism:
☛ Compile time polymorphism
☛ Run time polymorphism
Compile time polymorphism is method overloading whereas Runtime time polymorphism is done using inheritance and interface.
Read More☛ Compile time polymorphism
☛ Run time polymorphism
Compile time polymorphism is method overloading whereas Runtime time polymorphism is done using inheritance and interface.
12 :: Explain me what is method overloading and method overriding?
☛ Method Overloading:
In Method Overloading, Methods of the same class shares the same name but each method must have different number of parameters or parameters having different types and order.
Method Overloading is to “add” or “extend” more to method’s behavior.
It is a compile time polymorphism.
The methods must have different signature.
It may or may not need inheritance in Method Overloading.
Let’s take a look at the example below to understand it better.
class Adder {
Static int add(int a, int b)
{
return a+b;
}
Static double add( double a, double b)
{
return a+b;
}
public static void main(String args[])
{
System.out.println(Adder.add(11,11));
System.out.println(Adder.add(12.3,12.6));
}}
☛ Method Overriding:
In Method Overriding, sub class have the same method with same name and exactly the same number and type of parameters and same return type as a super class.
Method Overriding is to “Change” existing behavior of method.
It is a run time polymorphism.
The methods must have same signature.
It always requires inheritance in Method Overriding.
Let’s take a look at the example below to understand it better.
class Car {
void run(){
System.out.println(“car is running”);
}
Class Audi extends Car{
void run()
{
System.out.prinltn(“Audi is running safely with 100km”);
}
public static void main( String args[])
{
Car b=new Audi();
b.run();
}
}
Read MoreIn Method Overloading, Methods of the same class shares the same name but each method must have different number of parameters or parameters having different types and order.
Method Overloading is to “add” or “extend” more to method’s behavior.
It is a compile time polymorphism.
The methods must have different signature.
It may or may not need inheritance in Method Overloading.
Let’s take a look at the example below to understand it better.
class Adder {
Static int add(int a, int b)
{
return a+b;
}
Static double add( double a, double b)
{
return a+b;
}
public static void main(String args[])
{
System.out.println(Adder.add(11,11));
System.out.println(Adder.add(12.3,12.6));
}}
☛ Method Overriding:
In Method Overriding, sub class have the same method with same name and exactly the same number and type of parameters and same return type as a super class.
Method Overriding is to “Change” existing behavior of method.
It is a run time polymorphism.
The methods must have same signature.
It always requires inheritance in Method Overriding.
Let’s take a look at the example below to understand it better.
class Car {
void run(){
System.out.println(“car is running”);
}
Class Audi extends Car{
void run()
{
System.out.prinltn(“Audi is running safely with 100km”);
}
public static void main( String args[])
{
Car b=new Audi();
b.run();
}
}
13 :: Explain me what is association?
Association is a relationship where all object have their own lifecycle and there is no owner. Let’s take an example of Teacher and Student. Multiple students can associate with a single teacher and a single student can associate with multiple teachers but there is no ownership between the objects and both have their own lifecycle. These relationship can be one to one, One to many, many to one and many to many.
Read More14 :: int a = 1L;
won’t compile and int b = 0;
b += 1L;
compiles fine. Explain me why?
When += is used, that’s a compound statement and the compiler internally casts it. Whereas in the first case, the compiler straightaway shouts at you since it is a direct statement.
Compiler behavior and statement types can be confusing, so questions like this will test a candidate's grasp of these concepts.
Read MoreCompiler behavior and statement types can be confusing, so questions like this will test a candidate's grasp of these concepts.
15 :: Can you give real world examples of when to use an ArrayList and when to use LinkedList?
ArrayList is preferred when there are more get(int), or when search operations need to be performed as every search operation runtime is O(1).
If an application requires more insert(int) and delete(int) operations, then LinkedList is preferred, as LinkedList does not need to maintain back and forth to preserve continued indices as arraylist does. Overall this question tests the proper usage of collections.
Read MoreIf an application requires more insert(int) and delete(int) operations, then LinkedList is preferred, as LinkedList does not need to maintain back and forth to preserve continued indices as arraylist does. Overall this question tests the proper usage of collections.
16 :: Tell us why would it be more secure to store sensitive data (such as a password, social security number, etc.) in a character array rather than in a String?
In Java, Strings are immutable and are stored in the String pool. What this means is that, once a String is created, it stays in the pool in memory until being garbage collected. Therefore, even after you’re done processing the string value (e.g., the password), it remains available in memory for an indeterminate period of time thereafter (again, until being garbage collected) which you have no real control over. Therefore, anyone having access to a memory dump can potentially extract the sensitive data and exploit it.
In contrast, if you use a mutable object like a character array, for example, to store the value, you can set it to blank once you are done with it with confidence that it will no longer be retained in memory.
Read MoreIn contrast, if you use a mutable object like a character array, for example, to store the value, you can set it to blank once you are done with it with confidence that it will no longer be retained in memory.
17 :: Explain me what is the volatile keyword? How and why would you use it?
In Java, each thread has its own stack, including its own copy of variables it can access. When the thread is created, it copies the value of all accessible variables into its own stack. The volatile keyword basically says to the JVM “Warning, this variable may be modified in another Thread”.
In all versions of Java, the volatile keyword guarantees global ordering on reads and writes to a variable. This implies that every thread accessing a volatile field will read the variable’s current value instead of (potentially) using a cached value.
In Java 5 or later, volatile reads and writes establish a happens-before relationship, much like acquiring and releasing a mutex.
Using volatile may be faster than a lock, but it will not work in some situations. The range of situations in which volatile is effective was expanded in Java 5; in particular, double-checked locking now works correctly.
The volatile keyword is also useful for 64-bit types like long and double since they are written in two operations. Without the volatile keyword you risk stale or invalid values.
One common example for using volatile is for a flag to terminate a thread. If you’ve started a thread, and you want to be able to safely interrupt it from a different thread, you can have the thread periodically check a flag (i.e., to stop it, set the flag to true). By making the flag volatile, you can ensure that the thread that is checking its value will see that it has been set to true without even having to use a synchronized block. For example:
public class Foo extends Thread {
private volatile boolean close = false;
public void run() {
while(!close) {
// do work
}
}
public void close() {
close = true;
// interrupt here if needed
}
}
Read MoreIn all versions of Java, the volatile keyword guarantees global ordering on reads and writes to a variable. This implies that every thread accessing a volatile field will read the variable’s current value instead of (potentially) using a cached value.
In Java 5 or later, volatile reads and writes establish a happens-before relationship, much like acquiring and releasing a mutex.
Using volatile may be faster than a lock, but it will not work in some situations. The range of situations in which volatile is effective was expanded in Java 5; in particular, double-checked locking now works correctly.
The volatile keyword is also useful for 64-bit types like long and double since they are written in two operations. Without the volatile keyword you risk stale or invalid values.
One common example for using volatile is for a flag to terminate a thread. If you’ve started a thread, and you want to be able to safely interrupt it from a different thread, you can have the thread periodically check a flag (i.e., to stop it, set the flag to true). By making the flag volatile, you can ensure that the thread that is checking its value will see that it has been set to true without even having to use a synchronized block. For example:
public class Foo extends Thread {
private volatile boolean close = false;
public void run() {
while(!close) {
// do work
}
}
public void close() {
close = true;
// interrupt here if needed
}
}
18 :: Explain me what does it mean for a collection to be “backed by” another? Give an example of when this property is useful?
If a collection backs another, it means that changes in one are reflected in the other and vice-versa.
For example, suppose we wanted to create a whitelist function that removes invalid keys from a Map. This is made far easier with Map.keySet, which returns a set of keys that is backed by the original map. When we remove keys from the key set, they are also removed from the backing map:
public static <K, V> Map<K, V> whitelist(Map<K, V> map, K... allowedKeys) {
Map<K, V> copy = new HashMap<>(map);
copy.keySet().retainAll(asList(allowedKeys));
return copy;
}
retainAll writes through to the backing map, and allows us to easily implement something that would otherwise require iterating over the entries in the input map, comparing them against allowedKey, etcetera.
Note, it is important to consult the documentation of the backing collection to see which modifications will successfully write through. In the example above, map.keySet().add(value) would fail, because we cannot add a key to the backing map without a value.
Read MoreFor example, suppose we wanted to create a whitelist function that removes invalid keys from a Map. This is made far easier with Map.keySet, which returns a set of keys that is backed by the original map. When we remove keys from the key set, they are also removed from the backing map:
public static <K, V> Map<K, V> whitelist(Map<K, V> map, K... allowedKeys) {
Map<K, V> copy = new HashMap<>(map);
copy.keySet().retainAll(asList(allowedKeys));
return copy;
}
retainAll writes through to the backing map, and allows us to easily implement something that would otherwise require iterating over the entries in the input map, comparing them against allowedKey, etcetera.
Note, it is important to consult the documentation of the backing collection to see which modifications will successfully write through. In the example above, map.keySet().add(value) would fail, because we cannot add a key to the backing map without a value.
19 :: Explain me what is the difference between String s = "Test" and String s = new String("Test")? Which is better and why?
In general, String s = "Test" is more efficient to use than String s = new String("Test").
In the case of String s = "Test", a String with the value “Test” will be created in the String pool. If another String with the same value is then created (e.g., String s2 = "Test"), it will reference this same object in the String pool.
However, if you use String s = new String("Test"), in addition to creating a String with the value “Test” in the String pool, that String object will then be passed to the constructor of the String Object (i.e., new String("Test")) and will create another String object (not in the String pool) with that value. Each such call will therefore create an additional String object (e.g., String s2 = new String("Test") would create an addition String object, rather than just reusing the same String object from the String pool).
Read MoreIn the case of String s = "Test", a String with the value “Test” will be created in the String pool. If another String with the same value is then created (e.g., String s2 = "Test"), it will reference this same object in the String pool.
However, if you use String s = new String("Test"), in addition to creating a String with the value “Test” in the String pool, that String object will then be passed to the constructor of the String Object (i.e., new String("Test")) and will create another String object (not in the String pool) with that value. Each such call will therefore create an additional String object (e.g., String s2 = new String("Test") would create an addition String object, rather than just reusing the same String object from the String pool).
20 :: Explain me what is runtime polymorphism or dynamic method dispatch?
In Java, runtime polymorphism or dynamic method dispatch is a process in which a call to an overridden method is resolved at runtime rather than at compile-time. In this process, an overridden method is called through the reference variable of a superclass. Let’s take a look at the example below to understand it better.
class Car {
void run()
{
System.out.println(“car is running”);
}
}
class Audi extends Car {
void run()
{
System.out.prinltn(“Audi is running safely with 100km”);
}
public static void main(String args[])
{
Car b= new Audi(); //upcasting
b.run();
}
}
Read Moreclass Car {
void run()
{
System.out.println(“car is running”);
}
}
class Audi extends Car {
void run()
{
System.out.prinltn(“Audi is running safely with 100km”);
}
public static void main(String args[])
{
Car b= new Audi(); //upcasting
b.run();
}
}
21 :: Tell me public static void main(String args[])?
☛ public : Public is an access modifier, which is used to specify who can access this method. Public means that this Method will be accessible by any Class.
☛ static : It is a keyword in java which identifies it is class based i.e it can be accessed without creating the instance of a Class.
☛ void : It is the return type of the method. Void defines the method which will not return any value.
☛ main: It is the name of the method which is searched by JVM as a starting point for an application with a particular signature only. It is the method where the main execution occurs.
☛ String args[] : It is the parameter passed to the main method.
Read More☛ static : It is a keyword in java which identifies it is class based i.e it can be accessed without creating the instance of a Class.
☛ void : It is the return type of the method. Void defines the method which will not return any value.
☛ main: It is the name of the method which is searched by JVM as a starting point for an application with a particular signature only. It is the method where the main execution occurs.
☛ String args[] : It is the parameter passed to the main method.
22 :: Tell us what is the Java Classloader? List and explain the purpose of the three types of class loaders?
The Java Classloader is the part of the Java runtime environment that loads classes on demand (lazy loading) into the JVM (Java Virtual Machine). Classes may be loaded from the local file system, a remote file system, or even the web.
When the JVM is started, three class loaders are used:
1. Bootstrap Classloader: Loads core java API file rt.jar from folder.
2. Extension Classloader: Loads jar files from folder.
3. System/Application Classloader: Loads jar files from path specified in the CLASSPATH environment variable.
Read MoreWhen the JVM is started, three class loaders are used:
1. Bootstrap Classloader: Loads core java API file rt.jar from folder.
2. Extension Classloader: Loads jar files from folder.
3. System/Application Classloader: Loads jar files from path specified in the CLASSPATH environment variable.
23 :: Can you compare the sleep() and wait() methods in Java, including when and why you would use one vs. the other?
sleep() is a blocking operation that keeps a hold on the monitor / lock of the shared object for the specified number of milliseconds.
wait(), on the other hand, simply pauses the thread until either (a) the specified number of milliseconds have elapsed or (b) it receives a desired notification from another thread (whichever is first), without keeping a hold on the monitor/lock of the shared object.
sleep() is most commonly used for polling, or to check for certain results, at a regular interval. wait() is generally used in multithreaded applications, in conjunction with notify() / notifyAll(), to achieve synchronization and avoid race conditions.
Read Morewait(), on the other hand, simply pauses the thread until either (a) the specified number of milliseconds have elapsed or (b) it receives a desired notification from another thread (whichever is first), without keeping a hold on the monitor/lock of the shared object.
sleep() is most commonly used for polling, or to check for certain results, at a regular interval. wait() is generally used in multithreaded applications, in conjunction with notify() / notifyAll(), to achieve synchronization and avoid race conditions.
24 :: How to override a private or static method in Java?
You cannot override a private or static method in Java. If you create a similar method with same return type and same method arguments in child class then it will hide the super class method; this is known as method hiding. Similarly, you cannot override a private method in sub class because it’s not accessible there. What you can do is create another private method with the same name in the child class. Let’s take a look at the example below to understand it better.
class Base {
private static void display() {
System.out.println("Static or class method from Base");
}
public void print() {
System.out.println("Non-static or instance method from Base");
}
class Derived extends Base {
private static void display() {
System.out.println("Static or class method from Derived");
}
public void print() {
System.out.println("Non-static or instance method from Derived");
}
public class test {
public static void main(String args[])
{
Base obj= new Derived();
obj1.display();
obj1.print();
}
}
Read Moreclass Base {
private static void display() {
System.out.println("Static or class method from Base");
}
public void print() {
System.out.println("Non-static or instance method from Base");
}
class Derived extends Base {
private static void display() {
System.out.println("Static or class method from Derived");
}
public void print() {
System.out.println("Non-static or instance method from Derived");
}
public class test {
public static void main(String args[])
{
Base obj= new Derived();
obj1.display();
obj1.print();
}
}
25 :: Tell me what are static initializers and when would you use them?
A static initializer gives you the opportunity to run code during the initial loading of a class and it guarantees that this code will only run once and will finish running before your class can be accessed in any way.
They are useful for performing initialization of complex static objects or to register a type with a static registry, as JDBC drivers do.
Suppose you want to create a static, immutable Map containing some feature flags. Java doesn’t have a good one-liner for initializing maps, so you can use static initializers instead:
public static final Map<String, Boolean> FEATURE_FLAGS;
static {
Map<String, Boolean> flags = new HashMap<>();
flags.put("frustrate-users", false);
flags.put("reticulate-splines", true);
flags.put(...);
FEATURE_FLAGS = Collections.unmodifiableMap(flags);
}
Within the same class, you can repeat this pattern of declaring a static field and immediately initializing it, since multiple static initializers are allowed.
Read MoreThey are useful for performing initialization of complex static objects or to register a type with a static registry, as JDBC drivers do.
Suppose you want to create a static, immutable Map containing some feature flags. Java doesn’t have a good one-liner for initializing maps, so you can use static initializers instead:
public static final Map<String, Boolean> FEATURE_FLAGS;
static {
Map<String, Boolean> flags = new HashMap<>();
flags.put("frustrate-users", false);
flags.put("reticulate-splines", true);
flags.put(...);
FEATURE_FLAGS = Collections.unmodifiableMap(flags);
}
Within the same class, you can repeat this pattern of declaring a static field and immediately initializing it, since multiple static initializers are allowed.