Grokking The Java Developer Interview - More Than 200 Questions To Crack The Java, Spring
Grokking The Java Developer Interview - More Than 200 Questions To Crack The Java, Spring
JATIN ARORA
GROKKING THE JAVA DEVELOPER INTERVIEW
COPYRIGHT © 2020 BY JATIN ARORA.
All rights reserved. No part of this book may be reproduced, distributed, or transmitted in any
form or by any means, including photocopying, recording or other electronic or mechanical
methods, without the prior written permission of the author, except in the case of brief
quotations embodied in critical reviews and certain other non-commercial uses permitted by
copyright law.
For permission or any other information, contact me at:
jatinarora208@gmail.com
Preface
Grokking The Java Developer Interview helps you to crack a Java, Spring & Hibernate interview.
This book covers enough details of a Java/Spring topic that will surely help the absolute beginners and if
you are already familiar with Java & Spring, then this book will help you to brush-up on the concepts.
The book has more than 200 questions that are frequently asked during an interview for Java, Spring,
SpringBoot & Hibernate profile. Some of the important topics like Multi-threading, Collection framework,
Singleton Pattern, SpringBoot Annotations and many more are covered in detail. Most of these topics are
explained with code examples that will help you to quickly grasp the concept.
This book contains a lot of code examples, most of the code snippets are displayed in image format that
you can zoom-in and out of. However, if some image is not clearly visible on your device, you can also refer
to the GitHub repository for this book. The GitHub repo contains all of the snippets shown in this book and
it can be found at:
https://github.com/reachjatin/Grokking-The-Java-Developer-Interview
Contact Information
I would love to hear from you.
For feedback or queries, you can contact me at
jatinarora208@gmail.com
To Sumit, for his patience in reading through various preliminary versions of this book, and his vital
suggestions. Thank you brother for never saying no to my numerous feedback requests and providing all
the constructive criticism. I dedicate this book to him.
I would like to express my sincere gratitude to my family, friends, and everyone who motivated me
throughout. Thanks for the support, the honest feedback, and for everything else that has helped to make
this book possible in its current form.
-Jatin Arora
Table of Content s
Preface
Acknowledgements
Question 1: What are the 4 pillars of OOPS?
Question 2: What is an abstract class?
Question 3: Does Abstract class have constructor?
Question 4: What is an Interface?
Question 5: Difference between abstract class and interface
Question 6: What to choose – interface or abstract class
Question 7: Why Java 8 has introduced default methods?
Question 8: Why Java 8 has introduced static methods?
Question 9: Why Java does not allow multiple inheritance?
Question 10: What are the rules for Method Overloading and Method Overriding?
Question 11: Can we override final methods?
Question 12: Can constructors and private methods be overridden?
Question 13: What is final keyword and where it can be used?
Question 14: What is exception and exception handling?
Question 15: Difference between error and exception
Question 16: What are the different types of exceptions?
Question 17: How exception handling is done in java?
Question 18: Can we write a try block without catch block?
Question 19: How to handle multiple exceptions together?
Question 20: When finally block will not get executed
Question 21: Difference between throw and throws keyword. And discuss Exception Propagation
Question 22: Exception handling w.r.t. method overriding
Question 23: Programs related to Exception handling and return keyword
Question 24: How to make your own custom exception class?
Question 25: How to make custom checked / unchecked exception?
Question 26: What happens when you throw an exception from finally block?
Question 27: What will be Output of below program related to try-catch-finally?
Question 28: Explain try-with-resources
Question 29: Why String is Immutable?
Question 30: What does the equals() method of String class do?
Question 31: Explain StringBuffer and StringBuilder
Question 32: Explain the output of below program related to equals() method of StringBuilder
Question 33: When to use String/StringBuffer/StringBuilder
Question 34: Explain equals and hashcode contract
Question 35: What is Marker Interface?
Question 36: Can you write your own custom Marker interface?
Question 37: What is Comparable and Comparator?
Question 38: How to compare a list of Employees based on name and age such that if name of the
employee is same then sorting should be based on age
Question 39: Difference between Comparable and Comparator
Question 40: Different methods of Object class
Question 41: What type of arguments are allowed in System.out.println() method?
Question 42: Explain System.out.println() statement
Question 43: Explain Auto-boxing and Un-boxing
Question 44: Find the output of below program
Question 45: Can you pass primitive long value in switch statement?
Question 46: Explain static keyword in Java
Question 47: What is an Inner Class in Java, how it can be instantiated and what are the types of Inner
Classes?
Question 48: What is Constructor Chaining in java?
Question 49: What is init block?
Question 50: What is called first, constructor or init block?
Question 51: What is Variable shadowing and Variable hiding in Java?
Question 52: What is a constant and how we create constants in Java?
Question 53: Explain enum
Question 54: What is Cloneable?
Question 55: What is Shallow Copy and Deep Copy?
Question 56: What is Serialization and De-serialization?
Question 57: What is SerialVersionUID?
Question 58: Serialization scenarios with Inheritance
Question 59: Stopping Serialization and De-serialization
Question 60: What is Externalizable Interface?
Question 61: Externalizable with Inheritance
Question 62: Difference between Serializable and Externalizable
Question 63: How to make a class Immutable?
Question 64: Explain Class loaders in Java
Question 65: What is Singleton Design Pattern and how it can be implemented?
Question 66: What are the different ways in which a Singleton Design pattern can break and how to
prevent that from happening?
Question 67: What are the different design patterns you have used in your projects?
Question 68: Explain Volatile keyword in java
Question 69: What is Garbage Collection in Java, how it works and what are the different types of Garbage
Collectors?
Question 70: Explain Generics in Java
Question 71: What is Multi-threading?
Question 72: How to create a thread in Java?
Question 73: Which way of creating threads is better: Thread class or Runnable interface
Question 74: What will happen if I directly call the run() method and not the start() method to execute a
thread
Question 75: Once a thread has been started can it be started again
Question 76: Why wait, notify and notifyAll methods are defined in the Object class instead of Thread class
Question 77: Why wait(), notify(), notifyAll() methods must be called from synchronized block
Question 78: difference between wait() and sleep() method
Question 79: join() method
Question 80: yield() method
Question 81: Tell something about synchronized keyword
Question 82: What is static synchronization?
Question 83: What will be output of below program where one synchronized method is calling another
synchronized method?
Question 84: Programs related to synchronized and static synchronized methods
Question 85: What is Callable Interface?
Question 86: How to convert a Runnable to Callable
Question 87: Difference between Runnable and Callable
Question 88: What is Executor Framework in Java, its different types and how to create these executors?
Question 89: Tell something about awaitTermination() method in executor
Question 90: Difference between shutdown() and shutdownNow() methods of executor
Question 91: What is Count down latch in Java?
Question 92: What is Cyclic Barrier?
Question 93: Atomic classes
Question 94: What is Collection Framework?
Question 95: What is Collections?
Question 96: What is ArrayList?
Question 97: What is default size of ArrayList?
Question 98: Which data structure is used internally in an ArrayList?
Question 99: How add() method works internally or How the ArrayList grows at runtime
Question 100: How to make an ArrayList as Immutable
Question 101: What is LinkedList?
Question 102: When to use ArrayList / LinkedList
Question 103: What is HashMap?
Question 104: Explain the internal working of put() and get() methods of HashMap class and discuss
HashMap collisions
Question 105: equals and hashCode method scenarios in HashMap when the key is a custom class
Question 106: How to make a HashMap synchronized?
Question 107: What is Concurrent HashMap?
Question 108: What is HashSet class and how it works internally?
Question 109: Explain Java’s TreeMap
Question 110: Explain Java’s TreeSet
Question 111: Difference between fail-safe and fail-fast iterators
Question 112: Difference between Iterator and ListIterator
Question 113: Difference between Iterator.remove and Collection.remove()
Question 114: What is the difference between a Monolith and Micro-service architecture?
Question 115: What is Dependency Injection in Spring?
Question 116: What are the different types of Dependency Injection?
Question 117: Difference between Constructor and Setter injection
Question 118: What is @Autowired annotation?
Question 119: What is the difference between BeanFactory and ApplicationContext?
Question 120: Explain the life-cycle of a Spring Bean
Question 121: What are the different scopes of a Bean?
Question 122: What is the Default scope of a bean?
Question 123: What happens when we inject a prototype scope bean in a singleton scope bean?
Question 124: How to inject a prototype scope bean in a singleton scope bean?
Question 125: Explain Spring MVC flow
Question 126: What is the difference between <context:annotation-config> and <context:component-
scan>?
Question 127: What is the difference between Spring and SpringBoot?
Question 128: What is auto-configuration in SpringBoot?
Question 129: What are SpringBoot starters?
Question 130: What is @SpringBootApplication Annotation?
Question 131: Where does a Spring Boot application start from?
Question 132: How to remove certain classes from getting auto-configured in SpringBoot?
Question 133: How to autowire a class which is in a package other than SpringBoot application class’s
package or any of its sub-packages
Question 134: What is application.properties file in a SpringBoot application?
Question 135: How to configure the port number of a SpringBoot application?
Question 136: Which jar builds our springboot application automatically whenever we change some code
just like a node.js application?
Question 137: What default embedded server is given in spring boot web starter and how we can change
the default embedded server to the one of our choice
Question 138: Where should we put our html and javascript files in a spring boot application?
Question 139: What are the different stereotype annotations?
Question 140: Difference between @Component, @Controller, @Service, @Repository annotations?
Question 141: Difference between @Controller and @RestController annotation
Question 142: What is @RequestMapping and @RequestParam annotation?
Question 143: How to define a Get or Post endpoint?
Question 144: Which annotation is used for binding the incoming json request to the defined pojo class?
Question 145: What is @Qualifier annotation?
Question 146: What is @Transactional annotation?
Question 147: What is @ControllerAdvice annotation?
Question 148: What is @Bean annotation?
Question 149: Difference between @Component and @Bean
Question 150: How to do profiling in a SpringBoot application
Question 151: What is RestTemplate?
Question 152: What is Spring Data JPA?
Question 153: What is the difference between JPARepository, CRUDRepository, PagingAndSortingRepository
and which one you have used in your applications?
Question 154: What is Spring AOP?
Question 155: Have you used Spring Security in your application
Question 156: What do you know about Spring Batch framework?
Question 157: Difference between SOAP and REST
Question 158: What is Restful api?
Question 159: What is a stateless object?
Question 160: What is the difference between Web Server and Application Server?
Question 161: What do you know about CommandLineRunner and ApplicationRunner?
Question 162: What do you know about Eureka Naming Server?
Question 163: What do you know about Zuul?
Question 164: What do you know about Zipkin?
Question 165: What do you know about Hysterix?
Question 166: What is JPA?
Question 167: What is Hibernate?
Question 168: Difference between JPA and Hibernate
Question 169: What is @Entity?
Question 170: How to give a name to a table in JPA?
Question 171: What is @Id, @GeneratedValue?
Question 172: How to use a custom database sequence in Hibernate to generate primary key values?
Question 173: How to give names to the columns of a JPA Entity
Question 174: How to define a @OneToMany relationship between entities
Question 175: Why annotations should be imported from JPA and not from Hibernate?
Question 176: What is the difference between get() and load() method of Hibernate Session?
Question 177: What is the difference between save(), saveOrUpdate() and persist() method of Hibernate
Session?
Question 178: What is Session and SessionFactory in Hibernate?
Question 179: What is First Level and Second Level Cache in Hibernate?
Question 180: What is session.flush() method in Hibernate?
Question 181: How can we see the SQL query that gets generated by Hibernate?
Question 182: What is Hibernate Dialect and why we need to configure it?
Question 183: What do you know about hibernate.hbm2ddl.auto property in Hibernate?
Question 184: What is Maven?
Question 185: What is pom.xml?
Question 186: What is local repo and central repo?
Question 187: Where we define our local repo path?
Question 188: Where do we define proxies so that maven can download jars from the internet in a
corporate environment?
Question 189: Explain Maven build life-cycle
Question 190: What do you know about SQL Joins?
Question 191: Difference between TRUNCATE & DELETE statements
Question 192: Difference between Function and Stored Procedure
Question 193: What is DDL, DML statements?
Question 194: How to find the nth highest salary from Employee table
Question 195: Difference between UNION and UNION ALL commands in SQL
Question 196: Difference between Unique Key and Primary Key in SQL
Question 197: What is the difference between Primary and Foreign key in SQL?
Question 198: What is the difference between clustered and non-clustered index?
Question 199: What is the difference between WHERE and HAVING clause in SQL
Question 200: How to change the gender column value from Male to Female and Female to Male using
single Update statement
Question 201: Find first 3 largest numbers in an array
Question 202: Move all negative numbers at the beginning of an array and all positive numbers at the end
About the Author
Question 1: What are the 4 pillars of OOPS?
Answer: 4 pillars of OOPS are:
1. Abstraction
2. Encapsulation
3. Inheritance
4. Polymorphism
Let’s take a look at them:
Example:
Java Bean, where all data members are made private and you define certain public methods
to the outside world to access them.
3. Inheritance : Using inheritance means defining a parent-child relationship between classes,
by doing so, you can reuse the code that is already defined in the parent class. Code
reusability is the biggest advantage of Inheritance.
Java does not allow multiple inheritance through classes but it allows it through interfaces.
4. Polymorphism : Poly means many and Morph means forms. Polymorphism is the process in
which an object or function takes different forms. There are 2 types of Polymorphism :
In Method overloading, two or more methods in one class have the same method name but
different arguments. It is called as Compile time polymorphism because it is decided at compile time which
overloaded method will be called.
Overriding means when we have two methods with same name and same parameters in parent and child
class. Through overriding, child class can provide specific implementation for the method which is already
defined in the parent class.
- An abstract class cannot be instantiated, which means you are not allowed to create an
object of the abstract class. This also means, an abstract class has no use unless it is
extended by some other class
- If there is any abstract method in a class then that class must be declared abstract
- The first non-abstract class which is extending from an abstract class will have to give
implementation of the abstract methods defined in abstract class
Example:
Output:
Output:
Example 2:
Output:
Question 4: What is an Interface?
Answer:
- Abstract class can have both abstract and concrete methods but interface can only have
abstract methods (Java 8 onwards, it can have default and static methods as well)
- Abstract class methods can have access modifiers other than public but interface
methods are implicitly public and abstract
- Abstract class can have final, non-final, static and non-static variables but interface
variables are only static and final
- A subclass can extend only one abstract class but it can implement multiple interfaces
- An Abstract class can extend one other class and can implement multiple interfaces but
an interface can only extend other interfaces
In this question, the interviewer may try to confuse you by saying that from Java 8 onwards, you can have
static and default methods in an Interface so now what is the difference between abstract class and
interface and the answer you should tell is – We can still extend only one class but can implement multiple
interfaces.
So, to avoid this error, it is mandatory to provide implementation for common default methods of interfaces
Output:
Question 10: What are the rules for Method Overloading and Method
Overriding?
Answer: Method Overloading Rules: Two methods can be called overloaded if they follow below rules:
Output:
Output:
Question 15: Difference between error and exception
Answer: Error : Errors in a program are irrecoverable, they indicate that something severe has gone wrong
in the application and the program gets terminated in case of error occurrence e.g. running out of memory:
OutOfMemoryError , making too many recursive calls: StackOverflowError etc.
Exception : Exceptions on the other hand are something that we can recover from by handling them
properly e.g.: trying to access a property/method from a null object: NullPointerException , dividing an
integer by zero: ArithmeticException etc.
- Checked Exceptions: All exceptions other than RuntimeException and Error are known
as Checked exception. These exceptions are checked by the compiler at the compile
time itself. E.g. when you are trying to read from a file, then compiler enforces us to
handle the FileNotFoundException because it is possible that the file may not be present.
Some other checked exceptions are SQLException , IOException etc.
Suppose, your method is throwing more than one exception and you want to perform some specific action
based on the exception thrown, you should use multiple catch blocks in this case.
Example using multiple catch blocks:
When using pipe (|) symbol:
Question 21: Difference between throw and throws keyword. And discuss
Exception Propagation
Answer:
- throw is a keyword which is used to explicitly throw an exception in the program, inside
a function or inside a block of code, whereas throws is a keyword which is used with the
method signature to declare an exception which might get thrown by the method while
executing the code
- throw keyword is followed by an instance of an Exception class whereas throws is
followed by Exception class names
- You can throw one exception at a time but you can declare multiple exceptions using
throws keyword
- Using throw keyword, only unchecked exceptions are propagated, whereas using throws
keyword both checked and unchecked exceptions can be propagated.
Exception propagation :
An exception is first thrown from the top of the stack and if it is not caught, it drops down the call stack to
the previous method, If not caught there, the exception again drops down to the previous method, and so
on until they are caught or until they reach the very bottom of the call stack. This is called exception
propagation.
- When method m1( ) calls method m2() which calls method m3(), a stack is formed which
gets unfold from the top, so if method m3() throws an exception and it is not handled
there, it will drop down the call stack to method m2(), if it is not handled there, it will
drop down the call stack to method m1(), this happens until we reach the bottom of the
stack or until the exception is caught. This is called Exception Propagation in java.
Example: unchecked exception is thrown and it can be seen from the call stack that it is propagated
Output:
Example: checked exceptions are not propagated down the call chain by default ,
You have to use throws keyword if you want to propagate the checked exception, like
Notice in the above example that the checked exception is propagated and now it is the responsibility of
the caller method to either handle the exception or throw it further. Below example is showing that the
checked exception is handled ,
Output:
throws can be used with unchecked exceptions also, though it is of no use because unchecked exceptions
are by default propagated. See this in the below program:
Output:
Output:
- If the parent class method does not declare an exception then child class overridden
method cannot declare checked exceptions but it can declare unchecked exceptions
- If the parent class method declares an exception, then child class overridden method
- can declare no exception
- can declare same exception
- can declare a narrower exception (more broader exception declaration than
parent one is not allowed)
Example when parent class method does not declare an exception and child class declares
checked exception :
Example when parent class method does not declare an exception and child class declares
unchecked exception :
Output:
Example when Child class overridden method throws a broader exception than the parent one :
Example when child class overridden method throws same exception as the parent one :
Output:
Example when child class overridden method declares a narrower exception than the parent
one :
Output:
Example when parent class method declares an exception and child class overridden method
does not declare any exception :
Output:
One thing you should remember is, if you write anything after return statement / throw exception
statement, then that will give Compile time error as ‘Unreachable code’.
Program 1:
Program 2 : finally block is always executed
Output:
Program 5 :
Output:
Question 26: What happens when you throw an exception from finally block?
Answer: When exception is thrown from finally block, then it takes precedence over the exceptions that are
thrown from try/catch block
1. String Pool : String Pool is possible only because String is Immutable in Java. String pool is
a special storage area in Java heap. If the string is already present in the pool, then instead
of creating a new object, old object’s reference is returned. This way different String
variables can refer to the same reference in the pool, thus saving a lot of heap space also. If
String is not immutable then changing the string with one reference will lead to the wrong
values to other string variables having the same reference.
2. Security : String parameters are used in network connections, database URL’s, username
and passwords etc. Because String is immutable, these values can’t be changed. Otherwise
any hacker could change the referenced values which will cause severe security issues in
the application.
3. Multi-threading : Since String is immutable, it is safe for multithreading. A single String
instance can be shared across different threads. This avoids the use of synchronization for
thread safety. Strings are implicitly thread-safe.
4. Caching : The hashcode of string is frequently used in Java. Since string is immutable, the
hashcode will remain the same, so it can be cached without worrying about the changes.
This makes it a great candidate for using it as a Key in Map.
5. Class Loaders : Strings are used in Java ClassLoaders and since String is made immutable,
it provides security that correct class is being loaded.
Question 30: What does the equals() method of String class do?
Answer: As we know, Object class is the parent of all classes, and Object class has a equals() method that
compares the reference of two objects, but String class has overridden this method, and String class’s
equals() method compares the contents of two strings.
Program:
Output:
Question 32: Explain the output of below program related to equals() method
of StringBuilder
Output:
Answer: This is another very famous interview question. If you were expecting ‘Equal’ as output, then you
were wrong. The output is not ‘Equal’ because StringBuffer and StringBuilder does not override equals and
hashcode methods. In the above program, Object’s class equals() method is getting used and as it
compares the reference of two objects, the output of above program is ‘Not Equal’.
Since hashcode is used in data structures that use hashing algorithm to store the objects. Examples are
HashMap, HashSet, HashTable, ConcurrentHashMap etc. and all these data structures requires their keys
not to be changed so that stored values can be found by using hashcode method but
StringBuffer/StringBuilder are mutable objects. This makes them a very poor choice for this role.
You must have heard about the equals and hashcode contract in Java, which states that if two objects are
equals according to equals() method then their hashcode must be same, vice-versa is not true. Now, had
the equals method for StringBuilder/StringBuffer be overridden, their corresponding hashcode method
would also need to be overridden to follow that rule. But as explained earlier, these classes don’t need to
have their own hashcode implementation and hence same is with their equals method.
Question 36: Can you write your own custom Marker interface?
Answer: Yes. As you already know that Marker interfaces have got nothing to do with indicating some signal
to JVM or compiler, instead it is just a mere check of using instanceOf operator to know whether the class
implements Marker interface or not.
In your method, you can put a statement like: object instanceOf MyMarkerInterface.
You can use Marker interface for classification of your code.
Output:
String class already implements Comparable interface and provides a lexicographic implementation for
compareTo() method which compares 2 strings based on contents of characters or you can say in lexical
order. Here, Java will determine whether passed String object is less than, equal to or greater than the
current object.
ComparatorDemo.java :
Output:
SalaryComparator.java :
ComparatorDemo.java :
Output:
Question 38: How to compare a list of Employees based on name and age
such that if name of the employee is same then sorting should be based on
age
Answer: When comparing by name, if both names are same, then comparison will give 0. If the compare
result is 0, we will compare based on age.
NameAgeComparator.java :
ComparatorDemo.java :
Output:
Answer: Here, the compiler is confused as to which method to be called, so it throws Compile Time error.
Question 45: Can you pass primitive long value in switch statement?
Answer: No, switch works only with 4 primitives and their wrappers, as well as with the enum type and
String class:
- Variable
- Method
- Block
- Nested
class
Static Variable : if any variable is declared as static, then it is known as ‘static variable’. Only single copy
of the variable gets created and all instances of the class share same static variable. The static variable
gets memory only once in the class area at the time of class loading.
When to use static variable : static variables should be used to declare common property of all objects as
only single copy is created and shared among all class objects, for example, the company name of
employees etc.
Static Method : When a method is declared with static keyword then it is known as static method. These
methods belong to the class rather than the object of the class. As a result, a static method can be directly
accessed using class name without the need of creating an object.
One of the basic rules of working with static methods is that you can’t access a non-static method or field
from a static method because the static method doesn’t have an instance of the class to use to reference
instance methods or fields. Another restriction is, ‘this’ and ‘super’ cannot be used in static context.
For example: main() method is static, Java Runtime uses this method to start an application without
creating an object.
Static Block : Static block gets executed exactly once when the class is first loaded, use static block to
initialize the static variables.
Output:
If you have static members in your Static Inner class then there is no need to create the inner class object:
Output:
Question 47: What is an Inner Class in Java, how it can be instantiated and
what are the types of Inner Classes?
Answer: In Java, when you define one non-static class within another class, it is called Inner Class/Nested
Class. Inner class enables you to logically group classes that are only used in one place, thus, this increases
the use of encapsulation and creates more readable and maintainable code.
Java inner class is associated with the object of the class and they can access all the variables and
methods of the outer class. Since inner classes are associated with the instance, we can’t have any static
variables in them.
The object of java inner class is part of the outer class object and to create an instance of the inner class,
we first need to create an instance of outer class.
Java Inner classes can be instantiated like below:
OuterClass outerObject = new OuterClass();
OuterClass.InnerClass innerObject = outerObject.new InnerClass();
Example:
Output:
Compile time error when static variable and static method is present in Inner class:
There are 2 special types of Inner Classes:
- local inner class cannot be instantiated from outside of the block where they are defined
- local inner class has access to the members of the enclosing class
- till Java 1.7, local inner class can access only final local variable of the enclosing block
where they are defined. But from Java 1.8 onwards, it is possible to access the non-final
local variable of the enclosing block
- the scope of local inner class is restricted to the block where they are defined
- A local inner class can extend an abstract class or can implement an interface
Example:
Output:
Remember, you can only access the block level variables, and cannot change them. You will get compile
time error if you try to change them:
A variable whose value is not changed once initialized is called as effectively final variable .
When to use :
Example 1 : Let’s understand this by an example, Suppose you are want to return a list of employee class
objects and they should be sorted based on employee name, now for this you can write a comparator in a
separate class and pass its object inside the Collections.sort(list, comparatorObject)
Instead, you can use the anonymous inner class and you don’t have to create a new class just for writing a
comparator that you are not going to use later on.
Program:
Employee.java :
AnonymousInnerDemo.java :
Output:
Example 2 : Using anonymous inner class, you can implement a Runnable also
Output:
Example 3 : You can use anonymous inner class in situations where you want to override the parent class
method without creating a separate child class:
Output:
- anonymous class does not have a constructor as it does not have any class name
- in anonymous class, we cannot have static members except static constants
- an anonymous class has access to the members of its enclosing class
- an anonymous class cannot access local variables in its enclosing scope(block) that are
not final or effectively final
Compile time error in case of using static variable which is not final :
super() example:
Output:
Output:
Example 2:
Output:
Example 3:
Output:
Order of execution :
1. The code in static initialization block will be executed at class load time (and yes,
that means only once per class load), before any instances of the class are
constructed and before any static methods are called.
2. The instance initialization block is actually copied by the Java compiler into every
constructor the class has. So, the code in instance initialization block is
executed exactly before the code in constructor.
If you want to access instance variables then you can do so using ‘this’ keyword like below:
Example 2:
Output:
Variable Hiding : When the child and parent classes both have a variable with the same name, the child
class variable hides the parent class variable.
Example 1:
Output:
If you want to access parent’s class variable then you can do this using super keyword:
Example 2:
Output:
Output:
Output:
Example 2:
Output:
Question 54: What is Cloneable?
Answer: Cloneable is an interface in Java which needs to be implemented by a class to allow its objects to
be cloned.
A class implements the Cloneable interface to indicate to the Object.clone() method that it is legal for that
method to make a field-for-field copy of instances of that class.
If you try to Clone an object which doesn’t implement the Cloneable interface, it will throw
CloneNotSupportedException.
Output:
Here, we have created Employee object e1 with new keyword but then we created another object
Employee e2 which has the same reference as of e1. So, any change in e2 object will reflect in e1 object
and vice-versa.
Now, let’s implement Cloneable interface in our Employee class and invoke the clone() method on e1
object to make its clone:
Program 2:
Output:
In the above example, we have only primitive types in our Employee class, what if we have an object type
i.e. another class object reference, see the example below:
Program 3:
Can you guess the output of the last 2 sysout? Here is the output:
If you are surprised with the above output, then let me make it clear by saying that, by default Object’s
clone() method provide Shallow copy. This brings us to the next interview question: What is shallow copy
and deep copy
Deep Copy : in Deep copy, the non-primitive types are also cloned to make the original and cloned object
fully independent of each other.
Program 1:
Output:
In above example, we have overridden the clone method in our employee class and we called the clone
method on mutable company object.
We can also use Copy constructor to perform deep copy:
Program 2:
Output:
There are 2 other methods by which you can perform deep copy:
- By using Serialization, where you serialize the original object and returns the
deserialized object as a clone
- By using external library of Apache Commons Lang. Apache Common Lang comes with
SerializationUtils.clone() method for performing deep copy on an object. It expects all
classes in the hierarchy to implement Serializable interfaces else SerializableException is
thrown by the system
Here, while de-serializing the employee object, salary is 0, that is because we have made salary variable to
be ‘transient’. ‘static’ and ‘transient’ variables do not take part in Serialization process. During de-
serialization, transient variables will be initialized with their default values i.e. if objects, it will be null and if
“int”, it will be 0 and static variables will be having the current value.
And if you look at the file present in C:/temp/bytestream.txt, you can see how the object is serialized into
this file,
Output:
java.io.InvalidClassException : com.serialization.demo.Employee; local class incompatible: stream
classdesc serialVersionUID = -3697389390179909057, local class serialVersionUID = -3759917827722067163
at java.io.ObjectStreamClass.initNonProxy(Unknown Source)
at java.io.ObjectInputStream.readNonProxyDesc(Unknown Source)
at java.io.ObjectInputStream.readClassDesc(Unknown Source)
at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.readObject(Unknown Source)
at com.serialization.demo.DeserializationTest.main( DeserializationTest.java:13 )
Hence, it is strongly recommended that all serializable classes explicitly declare serialVersionUID value, in
case you are using an IDE and not giving any serialVersionUID, compiler will give you a warning like below:
SerializationDemo.java:
Output:
Now, let’s add one more field ‘company’ and remove the transient keyword from our Employee class. Here,
as we are changing the class structure, let’s see if we get the error of InvalidClassException again:
Program 3:
DeserializationTest.java:
Output:
- If a parent class has implemented Serializable interface then child class doesn’t need to
implement it but the reverse is not true
- Static data members and transient data members are not saved via Serialization process
(serialVersionUID is an exception). So, if you don’t want to save value of a non-static
data member then make it transient
- Constructor of serialized class is never called when the serialized object is deserialized
(in case of inheritance, no-arg constructor of parent gets called during de-serialization)
(Note: serializeObject() and deserializeObject() remains same as the Question 58 - Case 1 program)
Output:
Serialization and De-serialization process can be customized also by providing writeObject() and
readObject() methods in the class that we want to serialize.
Declaring both methods as private is necessary (public methods will not work), so other than the JVM
nothing else can see them. This also proves that neither method is not inherited nor overridden or
overloaded. The JVM automatically checks these methods and calls them during the serialization-
deserialization process. The JVM can call these private methods, but other objects cannot. Thus, the
integrity of the class is maintained and the serialization protocol can continue to work as normal.
For example, you can have encryption and decryption logic in these methods.
Now, one thing to remember here is that the public no-arg constructor gets called before readExternal()
method, so we have to provide this no-arg constructor or else we will get an exception during run-time.
Comment the public no-arg constructor from Employee.java:
Program 2:
- Using Externalizable interface, we can implement custom logic for serialization and
deserialization of object
- When using Externalizable, we have to explicitly mention what fields or variables we
want to serialize
- When using Externalizable, a public no-arg constructor is required
- Using Externalizable, we can also serialize transient and static variables
- readExternal() method must read the values in the same sequence and with the same
types as were written by writeExternal() method
Here, in the overridden writeExternal() and readExternal() methods in child class Student, we are also
calling super.writeExternal() and super.readExternal() methods to serialize and de-serialize fields of parent
class Department.
ExternalizableDemo.java:
Output:
The capacity and age variable values are 0 because we did not serialize these two variables.
Case 2 : When only child class is implementing the Externalizable interface
Department.java:
Student.java:
Here, we are using getters and setters of parent class, Department, to serialize and de-serialize its fields.
ExternalizableDemo.java:
Output:
Question 62: Difference between Serializable and Externalizable
Answer:
- Serializable is a marker interface which means it does not contain any method whereas
Externalizable is a child interface of Serializable and it contains two methods
writeExternal() and readExternal()
- When using Serializable, JVM takes full responsibility for serializing the class object but in
case of Externalizable, the programmer has full control over serialization logic
- Serializable interface is a better fit when we want to serialize the entire object whereas
Externalizable is better suited for custom serialization
- Default serialization is easy to implement but it comes with some issues and
performance cost whereas in case of Externalizable, the programmer has to provide the
complete serialization logic which is a little hard but results in better performance
- Default serialization does not call any constructor whereas a public no-arg constructor is
needed when using Externalizable interface
- When a class implements Serializable interface, it gets tied with default serialization
which can easily break if structure of the class changes like adding/removing any
variable whereas using Externalizable, you can create your own binary format for your
object
- Thread-safe: With immutable classes, we don’t have to worry about the thread-safety in
case of multi-threaded environment as these classes are inherently thread-safe
- Cacheable: An immutable class is good for Caching because while we don’t have to
worry about the value changes
How to create an Immutable class in java:
Employee.java:
TestImmutable.java:
Here, after creating Employee object, the first change is done in local address object and then we used the
employee’s getter method to access the address object and tried to change the value in it.
Output:
As, you can see that the value remained the same.
If we don’t follow the rule about mutable object reference present in the class, let’s see what will happen in
that case.
Let’s change the Employee class constructor and getter method:
Employee.java:
Now, if we run our TestImmutable.java class, below is the output:
- When you assign the actual address object in the constructor, then remember it is
storing the reference of address object, so if you change the value in this address object,
it will reflect in the employee object
Why we don’t return original reference from the getter:
-
When you return the original address object from the getter method then you can use the
returned object reference to change the values in employee object
1. Bootstrap class loader : it loads JDK class files from jre/lib/rt.jar and other core classes. It is
the parent of all class loaders, it is also called Primordial classloader.
2. Extensions class loader : it loads classes from JDK extensions directory, it delegates class
loading request to its parent, Bootstrap and if the loading of class is unsuccessful, it loads
classes from jre/lib/ext directory or any other directory pointed by java.ext.dirs system
property.
3. System class loader : It loads application specific classes from the CLASSPATH. We can set
classpath while invoking the program using -cp or classpath command line options. It is a
child of Extension ClassLoader.
1. Delegation principle: It forwards the request for class loading to its parent class loader. It
only loads the class if the parent does not find or load the class.
2. Visibility principle: According to Visibility principle, the child ClassLoader can see all the
classes loaded by parent ClassLoader. But the parent class loader cannot see classes loaded
by the child class loader.
3. Uniqueness principle: According to this principle, a class loaded by Parent should not be
loaded by Child ClassLoader again. It is achieved by delegation principle.
Suppose, you have created a class Employee.java and compiled this class and Emloyee.class file is created.
Now, you want to use this class, the first request to load this class will come to System/Application
ClassLoader, which will delegate the request to its parent, Extension ClassLoader which further delegates
to Primordial or Bootstrap class loader
Now, Bootstrap ClassLoader will look for this class in rt.jar, since this class is not there, the request will
come to Extension ClassLoader which looks in jre/lib/ext directory and tries to locate this class there, if this
class is found there then Extension ClassLoader will load this class and Application ClassLoader will not
load this class, this has been done to maintain the Uniqueness principle. But if the class is not loaded by
Extension ClassLoader, then this Employee.class will be loaded by Application ClassLoader from the
CLASSPATH.
Employee.java:
Output:
If you are thinking why null is printed when we tried to know which classloader is loading the
java.lang.System class then take a look at the Javadoc :
We can also create our own custom class loader by extending the ClassLoader class.
Test.java:
Output:
We can also access the instance by using the classname like A.instance because of static keyword but we
will have to change its access modifier to ‘public’, so that it is visible outside the singleton class.
Let’s suppose you are creating a large object by using a lot of resources, there may be a chance that object
creation may throw an exception but the above way of creating a singleton class does not provide any
option for exception handling as you can write try-catch only inside a block of code. There is a solution to
tackle this particular problem where you can create the class instance inside a static block.
Both the above approaches create the object even before it is used (initialized at the time of class loading
because of static variable and static block), but there are other approaches where we can create a
Singleton class instance in a lazy initialization way i.e. only when someone asks for it. These approaches
are discussed below.
Lazy Initialization: using this way of creating Singleton class, the object will not get created unless
someone asks for it. Here we will create the class instance inside the global access method.
This approach is suitable for only single-threaded application, suppose there are 2 threads and both have
checked that the instance is null and now they are inside the “if(…)” condition, it will destroy our singleton
pattern and both threads will have different instances. So, we must overcome this problem so that our
singleton pattern doesn’t break in case of multi-threaded environment.
Thread Safe Singleton implementation: here the easiest way to prevent multiple threads from creating
more than one instance is to make the global access method ‘synchronized’, this way threads will acquire a
lock first before entering the getInstance() method.
Synchronizing the entire method comes with performance degradation, also acquiring the lock and
releasing the lock on every call to getInstance() method seems un-necessary, because only first few calls
to getInstance() method needs to be synchronized, what I mean to say by this statement is: let’s suppose
there are 10 threads that are trying to call getInstance() method, now you need to apply synchronization to
only these 10 threads at this time and the thread which first acquires the lock will create the object. After
that, every thread will get the same object because of null check in if condition, so we can optimize the
above code by using double-checked locking principle , where we will use a synchronized block inside
the if condition, like shown below:
The reason of second if condition inside the synchronized block : suppose there are 2 threads and
both called the getInstance() method at the same time, now they will both be inside the first if condition as
instance is null at this time, and the first thread which acquires the lock will create the object and as soon
as it exits the synchronized block, other thread which was waiting, will acquire the lock and it will also
create another object thus breaking the singleton pattern. This is why it is called “double-checked locking”.
Now, some people have faced issues with the above approach in java 1.4 and earlier versions, which was
solved in later versions by using ‘volatile’ keyword with the above approach like below:
localRef variable is there for the cases where instance is already initialized (discussed above), the volatile
field is only accessed once because we have written return localRef not return instance .
There is another approach where an inner static class is used to create the Singleton class instance and it
is returned from the global access method. This approach is called Bill Pugh Singleton Implementation
.
Bill Pugh Singleton Implementation Program:
The inner class does not get loaded at the time of class A loading, only when someone calls getInstance()
method, it gets loaded and creates the Singleton instance.
Question 66: What are the different ways in which a Singleton Design
pattern can break and how to prevent that from happening?
Answer: There are 3 ways which can break Singleton property of a class, they are discussed below with
examples:
Reflection : Reflection API in java is used to change the runtime behavior of a class. Hibernate, Spring’s
Dependency injection also uses Reflection. So, even though in the above singleton implementations, we
have defined the constructor as private, but using Reflection, even private constructor can be accessed, so
Reflection can be used to break the singleton property of a class.
A.java:
Notice, I am using public access modifier with the only instance of singleton class so that it can be
accessed outside this class using just the class name.
Now, let’s see how Reflection can break Singleton:
Test.java:
Output:
As we can see from the output, the 2 instances have different hashcode, thus destroying Singleton.
Now to prevent Singleton from Reflection, one simple solution is to throw an exception from the private
constructor, so when Reflection tries to invoke private constructor, there will be an error.
The other solution to prevent Singleton from Reflection is using Enums , as its constructor cannot be
accessed via Reflection, JVM internally handles the creation and invocation of enum constructor
SingletonEnum.java:
TestSingletonEnum.java:
Output:
Output:
To prevent our Singleton class from Serialization, there is a method called readResolve() which is called
when ObjectInputStream has read an object from the stream and is preparing to return it to the caller, so
we can return the only instance of this class from this method, and this way the only instance of singleton
will be assigned to instance2, see below:
A.java:
Test.java:
Output:
You can also throw an exception from the readResolve() method, but returning the only instance approach
is better as your program execution will not stop.
One last way which can break Singleton property of a class is:
Cloning : As we know, Cloning is used to create duplicate objects (copy of the original object). If we create
a clone of the instance of our Singleton class then a new instance will be created thus breaking our
Singleton pattern.
See the program below:
TestSingleton.java:
Output:
As you can see, both instances have different hashcodes indicating our Singleton pattern is broken, so to
prevent this we can override clone method in our Singleton class and either return the same instance or
throw CloneNotSupportedException from it.
See the program changes below:
Output:
clone() returning the same instance, see the program changes below:
Output:
Question 67: What are the different design patterns you have used in your
projects?
Answer: You will be asked this question almost in all interviews nowadays. So, be prepared with some
design patterns that are used in mostly all projects, like:
Now, let’s suppose 2 threads are working on this class and both threads are running on different processors
having their own local copy of variable x. if any thread modifies its value, the change will not be reflected
back in the original variable x in the main memory leading to data inconsistency because the other thread
is not aware of the modification.
So, to prevent data inconsistency, we can make variable x as volatile:
Now, all the threads will read and write the variable x from/to the main memory. Using volatile, also
prevents compiler from doing any reordering or any optimization to the code.
Question 69: What is Garbage Collection in Java, how it works and what are
the different types of Garbage Collectors?
Answer: Garbage collection in java is the process of looking at heap memory, identifying which objects are
in use and which are not and deleting the unused objects. An unused object or unreferenced object, is no
longer referenced by any part of your program.
Garbage collector is a daemon thread that keeps running in the background, freeing up heap memory by
destroying the unreachable objects.
There was an analysis done on several applications which showed that most objects are short lived, so this
behavior was used to improve the performance of JVM. In this method, the heap space is divided into
smaller parts or generations. These are, Young Generation , Old or Tenured Generation and
Permanent Generation .
The Young Generation is where all new objects are allocated and aged. The young generation is further
divided into 3 parts: Eden Space, Survivor space S0 and Survivor space S1. When the young generation fills
up, this causes a minor garbage collection . Some surviving objects are aged and eventually move to
the old generation. All minor garbage collections are "Stop the World" events. This means that all
application threads are stopped until the operation completes. Minor garbage collections are always Stop
the World events.
The Old Generation is used to store long surviving objects. Typically, a threshold is set for young
generation object and when that age is met, the object gets moved to the old generation. Eventually the
old generation needs to be collected. This event is called a major garbage collection . Major garbage
collection are also Stop the World events. Often a major collection is much slower because it involves all
live objects. So, for Responsive applications, major garbage collections should be minimized. Also note that
the length of the Stop the World event for a major garbage collection is affected by the kind of garbage
collector that is used for the old generation space.
The Permanent generation contains metadata required by the JVM to describe the classes and methods
used in the application. The permanent generation is populated by the JVM at runtime based on classes in
use by the application. In addition, Java SE library classes and methods may be stored here.
Classes may get collected (unloaded) if the JVM finds they are no longer needed and space may be needed
for other classes. The permanent generation is included in a full garbage collection. And Perm Gen was
available till Java 7, it is removed from Java 8 onwards and JVM uses native memory for the representation
of class metadata which is called MetaSpace.
There is a flag MaxMetaspaceSize, to limit the amount of memory used for class metadata. If we do not
specify the value for this, the Metaspace re-sizes at runtime as per the demand of the running application.
Parallel/Throughput GC:
Parallel garbage collector uses multiple threads to perform the garbage collection. By default, on a host
with N CPUs, this collector uses N garbage collector threads for collection. The number of collector threads
can be controlled with the command line option: -XX:ParallelGCThreads=<N>
It is called Throughput collector as it uses multiple CPUs to speed up the application throughput. A
drawback of this collector is that it pauses the application threads while performing minor or full GC, so it is
best suited for applications where long pauses are acceptable. It is the default collector in JDK 8.
It can be turned on by using below 2 options:
-XX:+UseParallelGC
With this command line option, you get a multi-thread young generation collector with a single-threaded
old generation collector. The option also does single-threaded compaction of old generation.
java -Xmx12m -Xms3m -Xmn1m -XX:PermSize=20m -XX:MaxPermSize=20m -XX:+UseParallelGC -jar
C:\temp\test.jar
-XX:+UseParallelOldGC
With this option, the GC is both a multithreaded young generation collector and multithreaded old
generation collector. It is also a multithreaded compacting collector.
Compacting describes the act of moving objects in a way that there are no holes between objects. After a
garbage collection sweep, there may be holes left between live objects. Compacting moves objects so that
there are no remaining holes. This compacting of memory makes it faster to allocate new chunks of
memory to the heap.
java -Xmx12m -Xms3m -Xmn1m -XX:PermSize=20m -XX:MaxPermSize=20m -XX:+UseParallelOldGC -jar
C:\temp\test.jar
Concurrent Mark Sweep (CMS) Collector:
The CMS collector, also called as the concurrent low pause collector, collects the tenured generation. It
attempts to minimize the pauses due to garbage collection, by doing most of the garbage collection work
concurrently with the application threads.
It can be turned on by passing -XX:+UseConcMarkSweepGC in the command line option.
If you want to set number of threads with this collector, pass -XX:ParallelCMSThreads=<N>
java -Xmx12m -Xms3m -Xmn1m -XX:PermSize=20m -XX:MaxPermSize=20m -XX:+UseConcMarkSweepGC -
XX:ParallelCMSThreads=2 -jar C:\temp\test.jar
G1 Garbage Collector:
The Garbage First or G1 collector is a parallel, concurrent and incrementally compacting low-pause garbage
collector
G1 collector partitions the heap into a set of equal-sized heap regions. When G1 performs garbage
collection then a concurrent global marking phase is performed to determine the liveliness of objects
throughout the heap. After this mark phase is complete, G1 knows which regions are mostly empty. It
collects unreachable objects from these regions first, which usually yields a large amount of free space,
also called Sweeping. So G1 collects these regions (containing garbage) first, and hence the name
Garbage-First.
It can be turned on by passing -XX:+UseG1GC in the command line options
java –Xmx25g –Xms5g -XX:+UseG1GC -jar C:\temp\test.jar
Java 8 has introduced one JVM parameter for reducing the unnecessary use of memory by creating too
many instances of the same String. This optimizes the heap memory by removing duplicate String values
to a global single char[] array. We can use the -XX:+UseStringDeduplication JVM argument to enable this
optimization.
G1 is the default garbage collector in JDK 9.
After Generics:
-
When using Generics, there is no need of type-casting.
Before Generics:
After Generics:
-
By using generics, programmers can implement generic algorithms that work on collections
of different types, can be customized and are type safe and easier to read.
Output:
Multi-threading: you will be asked many questions on multi-threading, so, read as much as you can and
whatever you can. Here, I am including some of the important questions that are mostly asked in every
interview.
Output:
Here a Task class extends Thread class and overrides the run() method which contains the business logic,
then we make an object of this Task and call the start() method, which starts the thread execution. start()
method internally calls run() method .
Output:
If you see the outputs of this and previous program, you will see that they are different, because any
thread can get a chance to execute its run() method, when the CPU resources are available.
- As you know, Java does not allow multiple inheritance through classes (because of
Diamond problem discussed in Question 9), so if you are creating threads by extending
Thread class then you will not be able to extend any other class.
- When we are working with multi-threading, we are not looking to overwrite any existing
functionality of Thread class, we just want to execute the code with multiple threads, so
in that way also, Runnable is a good choice.
- One more reason to choose Runnable is that, most people don’t work with just Raw
Threads, they use the Executor framework that is provided from Java 5, that separates
the task from its execution and we can execute Runnables using execute(Runnable
Task) method of Executor interface .
Question 74: What will happen if I directly call the run() method and not the
start() method to execute a thread
Answer: if run() method is called directly, then a new thread will not be created instead the code will run on
the current thread which is main thread. Calling run() method directly will make it behave as any other
normal method call. Only a call to start() method creates separate thread.
Question 75: Once a thread has been started can it be started again
Answer: No. A thread can be started only once in its lifetime. If you try to start a thread which has already
been started, an IllegalThreadStateException is thrown, which is a runtime exception. A thread in runnable
state or a dead thread cannot be restarted.
Question 76: Why wait, notify and notifyAll methods are defined in the
Object class instead of Thread class
Answer: This is another very famous multi-threading interview question. The methods wait, notify and
notifyAll are present in the Object class, that means they are available to all class objects, as Object class is
the parent of all classes.
wait() method – it tells the current thread to release the lock and go to sleep until some other thread enters
the same monitor and calls notify()
notify() method – wakes up the single thread that is waiting on the same object’s monitor
notifyAll() method – wakes up all the threads that called wait() on the same object
if these methods were in Thread class, then thread T1 must know that another thread T2 is waiting for this
particular resource, so T2 can be notified by something like T2.notify()
But in java, the object itself is shared among all the threads, so one thread acquires the lock on this
object’s monitor, runs the code and while releasing the lock, it calls the notify or notifyAll method on the
object itself, so that any other thread which was waiting on the same object’s monitor will be notified that
now the shared resource is available. That is why these methods are defined in the Object class.
Threads have no specific knowledge of each other. They can run asynchronously and are independent.
They do not need to know about the status of other threads. They just need to call notify method on an
object, so whichever thread is waiting on that resource will be notified.
Let’s consider this with a real-life example:
Suppose there is a petrol pump and it has a single washroom, the key of which is kept at the service desk.
This washroom is a shared resource for all. To use this shared resource, the user must acquire the key to
the washroom lock. So, the user goes to service desk, acquires the key, opens the door, locks it from the
inside and use the facility.
Meanwhile if another user arrives at the petrol pump and wants to use the washroom, he goes to the
washroom and found that it is locked. He goes to the service desk and the key is not there because it is
with the current user. When the current user finishes, he unlocks the door and returns the key to the
service desk. He does not bother about the waiting users. The service desk gives the key to waiting user. If
there are more than one user waiting to use the facility, then they must form a queue.
Now, apply this analogy to Java, one user is one thread and the washroom is the shared resource which the
threads wish to execute. The key will be synchronized keyword provided by Java, through which thread
acquires a lock for the code it wants to execute and making other threads wait until the current thread
finishes. Java will not be as fair as the service station, because any of the waiting threads may get a
chance to acquire the lock, regardless of the order in which the threads came. The only guarantee is that
all the waiting threads will get to use the shared resource sooner or later.
In this example, the lock can be acquired on the key object or the service desk and none of them is a
thread. These are the objects that decide whether the washroom is locked or not.
Question 77: Why wait(), notify(), notifyAll() methods must be called from
synchronized block
Answer: these methods are used for inter-thread communication. So, a wait() method only makes sense
when there is a notify() method also.
If these methods are not called from a synchronized block then
Output:
Now, let’s understand how a race condition can occur:
Producer-Consumer problem : The problem describes two processes, the producer and the consumer,
who share a common, fixed-size buffer used as a queue. The producer's job is to generate data, put it into
the buffer and start again. At the same time, the consumer is consuming the data (i.e. removing it from the
buffer), one piece at a time. The problem is to make sure that the producer won't try to add data into the
buffer, if it's full and that the consumer won't try to remove data from an empty buffer.
The solution for the producer is to either go to sleep or discard data if the buffer is full. The next time the
consumer removes an item from the buffer, it notifies the producer, who starts to fill the buffer again. In
the same way, the consumer can go to sleep if it finds the buffer empty. The next time the producer puts
data into the buffer, it wakes up the sleeping consumer.
Pseudo code:
In the code, if you don’t write t2.join(), then current thread will not wait from the t2 thread to die, see the
output below when t2.join() statement is commented from the code :
- join(long milliseconds) : when this method is called, then the current thread will wait at
most for the specified milliseconds
- join(long milliseconds, long nanoseconds) : when this method is called, then the current
thread will wait at most for the specified milliseconds plus nanoseconds.
These join methods are dependent on the underlying Operating system for timing. So, you should not
assume that join() will wait exactly as long as you specify.
You can execute threads in a sequence using CountDownLatch also.
A Task class which implements Runnable and its run() method simply calls the synchronized method of
Hello class:
Our main class:
We have 2 objects of our Hello class, one object is shared among First and Second thread, and one object is
shared among Third and Fourth thread, and we are starting these threads.
Output:
As you can see from the output, the First and Second thread are not having any thread interference. Same
way, Third and Fourth thread does not have any thread interference but First and Third thread are entering
the synchronized method at the same time with their own object locks (Hello obj1 and obj2).
Lock which is hold by First thread will only stop the Second thread from entering the synchronized block,
because they are working on the same instance i.e. obj1, but it cannot stop Third or Fourth thread as they
are working on another instance i.e. obj2.
If we want our synchronized method to be accessed by only one thread at a time then we have to use a
static synchronized method/block to have the synchronization on the class level rather than on the
instance level.
Question 83: What will be output of below program where one synchronized
method is calling another synchronized method?
Output:
One thing to remember here is that Java synchronized keyword is re-entrant in nature, it means if a
synchronized method calls another synchronized method which requires same lock then current thread
which is holding the lock can enter into that method without acquiring lock.
Output:
You can call e.getCause() to get the original exception.
Question 88: What is Executor Framework in Java, its different types and
how to create these executors?
Answer: Executor Framework is an abstraction to managing multiple threads by yourself. So, it decouples
the execution of a task and the actual task itself. Now, we just have to focus on the task that means, only
implement the Runnables and submit them to executor. Then these runnables will be managed by the
executor framework. It is available from Java 1.5 onwards.
Also, we don’t have to create new threads every time. With executor framework, we use Thread pools.
Think of Thread Pool as a user-defined number of threads which are called worker threads, these are kept
alive and reused. The tasks that are submitted to the executor will be executed by these worker threads. If
there are more tasks than the threads in the pool, they can be added in a Queue and as soon as one of
thread is finished with a task, it can pick the next one from this Queue or else, it will be added back in the
pool waiting for a task to be assigned.
So, it saves the overhead of creating a new thread for each task. If you are thinking about what is the
problem with creating a new thread every time we want to execute a task, then you should know that
creating a thread is an expensive operation. Thread objects use a significant amount of memory, and in a
large-scale application, allocating and deallocating many thread objects creates a significant memory
management overhead and new threads without any throttling will lead to the creation of large number of
threads. These threads will cause wastage of resources.
There are 2 main interfaces that you must know, one is Executor and the other is ExecutorService .
Executor interface contains execute(Runnable task) method through which you can execute only
Runnables. Also, the return type of execute() method is void, since you are passing a Runnable to it and it
does not return any result back.
ExecutorService interface contains the submit() method which can take both Runnable and Callable, and its
return type is Future object. ExecutorService extends the Executor Interface, so it also has the execute()
method.
Now, we have an idea of what is an Executor Framework, let’s look at different types of Executors:
SingleThreadExecutor :
This executor has only one thread and is used to execute tasks in a sequential manner. If the thread dies
due to an exception while executing the task, a new thread is created to replace the old thread and the
subsequent tasks are executed in the new thread.
How to create a SingleThreadExecutor:
ExecutorService executor = Executors.newSingleThreadExecutor ();
Executors is a utility class which contains many factory methods to create different types of
ExecutorService, like the one called SingleThreadExecutor, we just created.
FixedThreadPoolExecutor :
As its name suggests, this is an executor with a fixed number of threads. The tasks submitted to this
executor are executed by the specified number of threads and if there are more tasks than the number of
threads, then those tasks will be added in a queue (e.g. LinkedBlockingQueue).
How to create a FixedThreadPoolExecutor:
ExecutorService executor = Executors.newFixedThreadPool (5);
Here, we have created a thread pool executor of 5 threads, that means at any given time, 5 tasks can be
managed by this executor. If there are more active tasks, they will be added to a queue until one of the 5
threads becomes free.
An important advantage of the fixed thread pool is that applications using it degrade gracefully. To
understand this, consider a web server application where each HTTP request is handled by a separate
thread. If the application simply creates a new thread for every new HTTP request, and the system receives
more requests than it can handle immediately, the application will suddenly stop responding to all requests
when the overhead of all those threads exceed the capacity of the system. With a limit on the number of
the threads that can be created, the application will not be servicing HTTP requests as quickly as they
come in, but it will be servicing them as quickly as the system can sustain.
CachedThreadPoolExecutor :
This executor is mainly used when there are many short-lived tasks to be executed. If you compare this
with the fixed thread pool, here the number of threads of this executor pool is not bounded. If all the
threads are busy executing the assigned tasks and if there is a new task, then a new thread will be created
and added to the pool. If a thread remains idle for close to sixty seconds, it is terminated and removed
from the cache.
Use this one, if you are sure that the tasks will be short-lived, otherwise there will be a lot of threads in the
pool which will lead to performance issues.
How to create a CachedThreadPoolExecutor:
ExecutorService executor = Executors.newCachedThreadPool ();
ScheduledExecutor :
Use this executor, when you want to schedule your tasks, like run them at regular intervals or run them
after a given delay. There are 2 methods which are used for scheduling tasks: scheduleAtFixedRate and
scheduleWithFixedDelay .
How to create ScheduledExecutor:
ExecutorService executor = Executors.newScheduledThreadPool (4);
ScheduledExecutorService interface extends the ExecutorService interface.
Now, apart from using Executors class to create executors, you can use ThreadPoolExecutor and
ScheduledThreadPoolExecutor class also. Using these classes, you can manually configure and fine-tune
various parameters of the executor according to your need. Let’s see at some of those parameters:
BlockingQueue:
The queue to use for holding tasks before they are executed. This queue will hold only the Runnable tasks
submitted by the execute method, you can use a ArrayBlockingQueue or LinkedBlockingQueue like:
BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(100);
ThreadFactory:
The factory to use when the executor creates a new thread. Using thread factories removes hardwiring of
calls to new Thread , enabling applications to use special thread subclasses, priorities, etc.
RejectedExecutionHandler:
This handler is used when a task is rejected by the executor because all the threads are busy and the
queue is full.
When this handler is not provided and the task submitted to execute() method is rejected, then an
unchecked RejectedExecutionException is thrown.
But adding a handler is a good practice to follow, there is a method:
void rejectedExecution(Runnable r , ThreadPoolExecutor executor );
This method will be invoked by ThreadPoolExecutor when execute() cannot accept a task.
CountDownLatch can also be used to start multiple threads at the same time, you can create a
CountDownLatch of size 1, make all the other threads wait by calling countDownLatch.await(), then a
single call to countDownLatch.countDown() method will resume execution for all the waiting threads at the
same time.
CountDownLatch cannot be reused once the count reaches to zero, therefore in those scenarios,
CyclicBarrier is used.
The CyclicBarrier uses an all-or-none breakage model for failed synchronization attempts: If a thread leaves
a barrier point prematurely because of interruption, failure, or timeout, all other threads waiting at that
barrier point will also leave abnormally via BrokenBarrierException (or InterruptedException if they too
were interrupted at about the same time).
Example: One thread is adding first 5 natural numbers to the list, the other thread is adding next 5
numbers to the list and we will perform an addition of all these numbers to compute the sum of first 10
natural numbers
Output:
As, you can see, the output is as expected because only one thread is accessing the count, let’s see what
will happen in case the count variable is accessed by more than one thread, un-comment the code
regarding second thread t2 and run the main class:
Output:
The expected output was 100 but we got a different output, if you run the above program you will see a
different output and it will be anywhere between 50 and 100. The reason for this is that 2 threads are
accessing a mutable variable without any synchronization. One solution that will be coming to your mind
will be using synchronization block, and yes this problem can be solved using that but it will have a
performance impact, as threads will acquire the lock, update the value and release the lock, and then
giving other threads access to the shared mutable variable.
But java has provided Atomic wrapper classes for this purpose that can be used to achieve this atomic
operation without using Synchronization.
Let’s see the change in our Runnable:
Output:
Question 94: What is Collection Framework?
Answer: Collection framework represents an architecture to store and manipulate a group of objects. All the
classes and interfaces of this framework are present in java.util package.
Some points:
- Iterable interface is the root interface for all collection classes, it has one abstract method
iterator()
- Collection interface extends the Iterable interface
Question 99: How add() method works internally or How the ArrayList grows
at runtime
Answer: this is what happens when we create an ArrayList object using its default constructor,
/**
* Constructs an empty list with an initial capacity of ten.
*/
public ArrayList() {
this .elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA ;
}
Here, elementData is a transient variable and DEFAULTCAPACITY_EMPTY_ELEMENTDATA is an empty
Object[] array:
transient Object[] elementData ;
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
Now, let’s see Javadoc of add() method
/**
* Appends the specified element to the end of this list.
*
* @param e element to be appended to this list
* @return <tt> true </tt> (as specified by {@link Collection#add} )
*/
public boolean add(E e ) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData [size ++] = e ;
return true ;
}
Here size is a private variable
/**
* The size of the ArrayList (the number of elements it contains).
*
* @serial
*/
private int size ;
The default value of size will be 0, so call to ensureCapacityInternal() will have value 1, now let’s see
ensureCapacityInternal() Javadoc:
private void ensureCapacityInternal(int minCapacity ) {
ensureExplicitCapacity(calculateCapacity (elementData ,minCapacity ));
}
Here minCapacity is holding value 1, calculateCapacity() method is:
private static int calculateCapacity(Object[] elementData , int minCapacity ) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA ) {
return Math.max (DEFAULT_CAPACITY , minCapacity );
}
return minCapacity ;
}
Now, as both elementData and DEFAULTCAPACITY_EMPTY_ELEMENTDATA are same (see the default
ArrayList constructor above), if condition will be true and then Math.max(10,1) will return 10 from
calculateCapacity() method
Output:
Although, we have made the list as final but still we are able to add elements into it, remember applying
final keyword to a reference variable ensures that it will not be referenced again meaning you cannot give
a new reference to list variable:
So, to make the list as unmodifiable, there is a method unmodifiableList() in Collections utility class,
Program 2:
Output:
Here, if you assign Collections.unmodifiableList (list); to a new reference then you will be able to change
the original list which will in turn change the new list also, see below:
Program 3:
Output:
Guava library also provides certain ways to make immutable list and Java 9 has List.of() method.
There are other utility methods also, to make unmodifiable collections:
Question 101: What is LinkedList?
Answer: Java LinkedList class is an implementation of linked list data structure and it uses a doubly linked
list to store the elements. In Java LinkedList, elements are not stored in contiguous locations, they are
stored at any available space in memory and they are linked with each other using pointers and addresses.
As Java LinkedList internally uses doubly linked list, so LinkedList class represents its elements as Nodes. A
Node is divided into 3 parts:
Previous, Data, Next
Where Previous points to the previous Node in the list, Next points to the next Node in the list and Data is
the actual data.
Some points about LinkedList class:
- LinkedList class maintains insertion order
- LinkedList class can contain duplicate elements
- LinkedList class is not synchronized
- LinkedList class can be used as list, stack or queue
- You can add any number of null elements in LinkedList
Time complexity of LinkedList’s get(), add() and remove():
get(): As LinkedList does not store its elements in contiguous block of memory, random access is not
supported here, elements can be accessed in sequential order only, so get() operation in LinkedList is O(n).
add() and remove(): Both add and remove operations in LinkedList is O(1), because no elements shifting
is needed, just pointer modification is done (although remember getting to the index where you want to
add/remove will still be O(n)).
Here, I am showing some portions of LinkedList Javadoc’s:
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
transient int size = 0;
/**
* Pointer to first node.
* Invariant: (first == null && last == null) ||
* (first.prev == null && first.item != null)
*/
transient Node<E> first ;
/**
* Pointer to last node.
* Invariant: (first == null && last == null) ||
* (last.next == null && last.item != null)
*/
transient Node<E> last ;
/**
* Constructs an empty list.
*/
public LinkedList() {
}
We can see that the LinkedList class implements List and Deque interfaces. There are first and last Node
references also.
Let’s see the add() method:
public boolean add(E e ) {
linkLast(e );
return true ;
}
void linkLast(E e ) {
final Node<E> l = last ;
final Node<E> newNode = new Node<>(l , e , null );
last = newNode ;
if (l == null )
first = newNode ;
else
l .next = newNode ;
size ++;
modCount ++;
}
Here, in linkLast() method, Node class is used, let’ see that:
private static class Node<E> {
E item ;
Node<E> next ;
Node<E> prev ;
Node(Node<E> prev , E element , Node<E> next ) {
this .item = element ;
this .next = next ;
this .prev = prev ;
}
}
Here, we can see that Node class has 3 fields: item, prev and next.
- Keys should be unique in HashMap, if you try to insert the duplicate key, then it will override
the corresponding key’s value
- HashMap may have one null key and multiple null values
- HashMap does not guarantee the insertion order (if you want to maintain the insertion order,
use LinkedHashMap class)
- HashMap is not synchronized
- HashMap uses an inner class Node<K, V> for storing map entries
- Hashmap has a default initial capacity of 16, which means it has 16 buckets or bins to store
map entries, each bucket is a singly linked list. The default load factor in HashMap is 0.75
- Load factor is that threshold value which when crossed will double the hashmap’s capacity
i.e. when you add 13th element in hashmap, the capacity will increase from 16 to 32
Question 104: Explain the internal working of put() and get() methods of
HashMap class and discuss HashMap collisions
Answer: If you are giving a Core java interview, then you must prepare for this question, as you will most
likely be asked about this. So, let’s get right into it:
put() method internal working:
When you call map.put(key,value), the below things happens:
- Key’s hashCode() method is called
- Hashmap has an internal hash function which takes the key’s hashCode and it calculates the
bucket index
- If there is no element present at that bucket index, our <key, value> pair along with hash is
stored at that bucket
- But if there is an element present at the bucket index, then key’s hashCode is used to check
whether this key is already present with the same hashCode or not.
If there is key with same hashCode, then equals method is used on the key. If equals
method returns true, then the key’s previous value is replaced with the new value otherwise a
new entry is appended to the linked list.
Load factor:
/**
* The load factor used when none specified in constructor.
*/
static final float DEFAULT_LOAD_FACTOR = 0.75f;
Node class:
static class Node<K,V> implements Map.Entry<K,V> {
final int hash ;
final K key ;
V value ;
Node<K,V> next ;
Node(int hash , K key , V value , Node<K,V> next ) {
this .hash = hash ;
this .key = key ;
this .value = value ;
this .next = next ;
}
Output:
Program showing that hashmap’s capacity gets doubled after load factor’s threshold value
breaches :
Output:
Change the for loop condition from i<13 to i<=13, see below:
Output:
Question 105: equals and hashCode method scenarios in HashMap when the
key is a custom class
Answer: equals and hashCode methods are called when we store and retrieve values from hashmap. So,
when the interviewer asks this question, it is mostly asked with an example, where the hashmap’s key is a
custom class and you are given some situations where either equals() is implemented or hashCode() is
implemented, sometimes properly, sometimes not. We will discuss all combinations with programs below
so you can give the correct answer in any situation.
Before we continue, just remember if in your custom class, you are not implementing equals() and
hashCode(), then the Object class equals() and hashCode() will be called, and also remember about the
contract between these 2 methods. It says when 2 objects are equal according to equals() method, then
their hashCode must be same, reverse may not be true.
Scenario 1: when custom class does not implement both equals and hashCode methods
Here, Employee class has not given equals() and hashCode() method implementation, so Object’s class
equals() and hashCode() methods will be used when we use this Employee class as hashmap’s key, and
remember, equals() method of Object class compares the reference.
TestHashMap.java:
Can you predict the output of this one?
Output:
Here, Employee objects e1 and e2 are same but they are both inserted in the HashMap because both are
created using new keyword and holding a different reference, and as the Object’s equals() method checks
reference, they both are unique.
And as for objects e3 and e4, they both are pointing to same reference (e4 = e3), so they are equal
according to Object’s equals() method hence the value of e3 which was 300 gets replaced with the value
400 of the same key e4, and finally size of HashMap is 3.
Scenario 2: when only equals() method is implemented by Employee class
Well, now we have same hashCode for e1 and e2, but Object’s equals method still checks the references
and as references are different, both are not equal and are inserted in the hashmap.
Here, both e1 and e2 are equals as we are comparing the contents of them in our equals() method, so their
hashCodes must be same, which they are. So value of e1 which was 100 got replaced by 200, and size of
hashmap is 2.
You can be asked to write the equals() and hashCode() methods implementation by hand also, so you
should pay attention to how these are implemented.
- map.put() is called where key is the element and value is the dummy value (the map.put()
method internal working has already been discussed above)
- if value is added in the map then put method will return null which will be compared with null,
hence returning true from hashSet.add() method indicating the element is added
- however if the element is already present in the map, then the value associated with the
element will be returned which in turn will be compared with null, returning false from
hashSet.add() method
set.contains() method:
public boolean contains(Object o ) {
return map .containsKey(o );
}
The passed object is given to map.containsKey() method, as the HashSet’s values are stored as the keys of
internal map.
NOTE: If you are adding a custom class object inside the HashSet, do follow equals and hashCode contract.
You can be asked the equals and hashCode scenarios questions, just like we discussed in HashMap
(Question 105).
- TreeMap entries are sorted based on the natural ordering of its keys. This means if we are
using a custom class as the key, we have to make sure that the custom class is implementing
Comparable interface
- TreeMap class also provides a constructor which takes a Comparator object, this should be
used when we want to do a custom sorting
- TreeMap provides guaranteed log(n) time complexity for the methods such as containsKey(),
get(), put() and remove()
- TreeMap iterator is fail-fast in nature, so any concurrent modification will result in
ConcurrentModificationException
- TreeMap does not allow null keys but it allows multiple null values
- TreeMap is not synchronized, so it is not thread-safe. We can make it thread-safe by using
utility method, Collections.synchronizedSortedMap(treeMap)
- TreeMap internally uses Red-Black tree based NavigableMap implementation.
Output:
Here, Integer class already implements Comparable interface, so the keys are sorted based on the
Integer’s natural sorting order (ascending order).
Let’s see, when key is a custom class:
Program 2:
Output:
We get ClassCastException at runtime. Now, let’s implement Comparable interface in Employee class and
provide implementation of its compareTo() method:
Program 3:
Here, we are sorting based on Employee name,
Output:
Let’s look at a program where we pass a Comparator in the TreeMap constructor, and sort the Employee
object’s based on age in descending order:
Program 4:
Output:
TreeSet Javadoc:
public class TreeSet<E> extends AbstractSet<E>
implements NavigableSet<E>, Cloneable, java.io.Serializable
public TreeSet() {
this (new TreeMap<E,Object>());
}
Output:
But they don’t throw the exception, if the collection is modified by Iterator’s remove() method.
Program 2:
Output:
Javadoc:
arrayList.iterator() method:
public Iterator<E> iterator() {
return new Itr();
}
Itr is a private nested class in ArrayList:
private class Itr implements Iterator<E> {
int cursor ; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount ;
Itr() {}
public boolean hasNext() {
return cursor != size ;
}
Itr.next() method:
@SuppressWarnings ("unchecked" )
public E next() {
checkForComodification();
int i = cursor ;
if (i >= size )
throw new NoSuchElementException();
Object[] elementData = ArrayList.this .elementData ;
if (i >= elementData .length )
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData [lastRet = i ];
}
On the other hand, Fail-safe iterators does not throw ConcurrentModificationException , because they
operate on the clone of the collection, not the actual collection. This also means that any modification done
on the actual collection goes unnoticed by these iterators. The last statement is not always true though,
sometimes it can happen that the iterator may reflect modifications to the collection after the iterator is
created. But there is no guarantee of it. CopyOnWriteArrayList, ConcurrentHashMap are the examples of
fail-safe iterators.
Program 1: ConcurrentHashMap example
Output:
Here, iterator is reflecting the element which was added during the iteration operation.
- Iterator can traverse the collection only in one direction i.e. forward direction but ListIterator
can traverse the list in both directions, forward as well as backward, using previous() and
next() method
- Iterator cannot add element to a collection while iterating over it, but ListIterator can add
elements while iterating over the list
- Iterator cannot modify an element while iterating over a collection, but ListIterator has set(E
e) method which can be used to modify the element
- Iterator can be used with List, Set or Map, but ListIterator only works with List
- Iterator has no method to obtain an index of the collection elements but ListIterator has
methods like previousIndex() and nextIndex() which can be used to obtain the index
Java Collection framework is very important topic when preparing for the interviews, apart from the above
questions, you can read about Stack, Queue topics also, but if you are short on time, what we have
discussed so-far should be enough for the interview.
Question 114: What is the difference between a Monolith and Micro-service
architecture?
Answer: In monolithic architecture, applications are built as one large system, whereas in micro-service
architecture we divide the application into modular components which are independent of each other.
Monolithic architecture has some advantages:
- Development is quite simple
- Testing a monolith is also simple, just start the application and do the end-to-end testing,
Selenium can be used to do the automation testing
- These applications are easier to deploy, as only one single jar/war needs to be deployed
- Scaling is simple when the application size is small, we just have to deploy one more instance
of our monolith and distribute the traffic using a load balancer
- Network latency is very low/none because of one single codebase
However, there are various disadvantages of monolith architecture as well:
We have discussed both advantages and disadvantages of monolith and micro-services, you can easily
figure out the differences between them, however, I am also stating them below.
The differences are:
- In a monolithic architecture, if any fault occurs, it might bring down the entire application as
everything is tightly coupled, however, in case of micro-service architecture, a fault affects
only that micro-service and its consumers
- Each micro-service can be scaled independently according to requirement. For example, if
you see that one of your micro-service is taking more traffic, then you can deploy another
instance of that micro-service and then distribute the traffic between them. Now, with the
help of cloud computing services such as AWS, the applications can be scaled up and down
automatically. However, in case of monolith, even if we want to scale one service within the
monolith, we will have to scale the entire monolith
- In case of monolith, the entire technology stack is fixed at the start. It will be very difficult to
change the technology at a later stage in time. However, as micro-services are independent
of each other, they can be coded in any language, taking the advantage of different
technologies according to the use-case. So micro-services gives you the freedom to choose
different technologies, frameworks etc.
- Deploying a new version of a service in monolith requires more time and it increases the
application downtime, however, micro-services entails comparatively lesser downtime
- By Constructor
- By Setter
method
Constructor-based DI : when the required dependencies are provided as arguments to the constructor,
then it is known as constructor-based dependency injection, see the examples below:
Using XML based configuration:
Injecting a dependency is done through the bean-configuration file, for this <constructor-arg> xml tag is
used:
In case of more than 1 dependency, the order sequence of constructor arguments should be followed to
inject the dependencies.
Java Class A:
Java Class B:
Setter-method injection: in this, the required dependencies are provided as the field parameters to the
class and the values are set using setter methods of those properties. See the examples below.
Using XML based configuration:
Injecting a dependency is done through the bean configuration file and <property> xml tag is used where
‘name’ attribute defines the name of the field of java class.
Java class A:
Java class B:
- BeanFactory is the most basic version of IOC containers which should be preferred when
memory consumption is critical whereas ApplicationContext extends BeanFactory, so you get
all the benefits of BeanFactory plus some advanced features for enterprise applications
- BeanFactory instantiates beans on-demand i.e. when the method getBean(beanName) is
called, it is also called Lazy initializer whereas ApplicationContext instantiates beans at the
time of creating the container where bean scope is Singleton, so it is an Eager initializer
- BeanFactory only supports 2 bean scopes, singleton and prototype whereas
ApplicationContext supports all bean scopes
- ApplicationContext automatically registers BeanFactoryPostProcessor and BeanPostProcessor
at startup, whereas BeanFactory does not register these interfaces automatically
- Annotation based dependency injection is not supported by BeanFactory whereas
ApplicationContext supports it
- If you are using plain BeanFactory, features like transactions and AOP will not take effect (not
without some extra steps), even if nothing is wrong with the configuration whereas in
ApplicationContext, it will work
- ApplicationContext provides additional features like MessageSource access (i18n or
Internationalization) and Event Publication
Use an ApplicationContext unless you have a really good reason for not doing so.
You can give any name to your initialization and destroy methods, and here is our Test class
By implementing InitializingBean and DisposableBean interfaces
InitializingBean interface has afterPropertiesSet() method which can be used to execute some initialization
task for a bean and DisposableBean interface has a destroy() method which can be used to execute some
cleanup task.
Here is our Test class,
- Injecting an ApplicationContext in Singleton bean and then getting the new instance of
prototyped scoped bean from this ApplicationContext
- Lookup method injection using @Lookup
- Using scoped proxy
Injecting ApplicationContext:
To inject the ApplicationContext in Singleton bean, we can either use @Autowired annotation or we can
implement ApplicationContextAware interface,
Here, whenever the getPrototypeBean() method is called, it will return a new instance of PrototypeBean.
But this approach contradicts with Spring IOC (Inversion of Control), as we are requesting the dependencies
directly from the container.
Spring uses CGLIB to create the proxy object and the proxy object delegates method calls to the real
object. In the above example, we are using ScopedProxyMode.TARGET_CLASS which causes an AOP proxy
to be injected at the target injection point. The default Proxy mode is ScopedProxyMode.NO .
To avoid CGLIB usage, configure the proxy mode with ScopedProxyMode.INTERFACES and it will use JDK
dynamic proxy.
We can also define the port number that our embedded server will run on, using
server.port=9000
We can have different application.properties file for different environments like dev, stage and prod.
Question 137: What default embedded server is given in spring boot web
starter and how we can change the default embedded server to the one of
our choice
Answer: The default embedded server is Tomcat, that comes with Spring boot web starter, if you want to
change this, then use <exclusion> tag in web starter and add a separate dependency of the server that
you want.
When you add the exclusion tag and save the pom.xml, you will see that the tomcat dependency will be
removed from Maven Dependencies, then you can add another server’s dependency like the one below:
Question 138: Where should we put our html and javascript files in a spring
boot application?
Answer: If you are adding html and javascript files, then you should put them in static folder in
src/main/resources/ . You should also make separate folders for html, css, javascript files.
- @Controller annotation is used to mark a class as Spring MVC controller where the response
is a view name which will display the Model object prepared by controller, whereas
@RestController annotation is a specialization of @Controller and it is used in RESTful web
services where the response is usually JSON/XML.
- @RestController is made up of 2 annotations, @Controller and @ResponseBody.
@ResponseBody annotation is used to attach the generated output directly into the body of
http response.
- @Controller can be used with @ResponseBody which will have same effect as
@RestController. @ResponseBody annotation can be used at the class level or at the
individual methods also. When it is used at the method level, Spring will use HTTP Message
Converters to convert the return value to HTTP response body (serialize the object to
response body).
Question 144: Which annotation is used for binding the incoming json
request to the defined pojo class?
Answer: @RequestBody annotation is used to bind the incoming json request to the pojo class,
Behind the scenes, Spring uses Jackson library (that comes with spring-boot-starter-web) to map the json
request to the pojo class. MappingJackson2HttpMessageConverter is used when the incoming request is of
content-type application/json.
Now, to resolve this you can give names to your Rectangle and Circle class, like:
And you will use @Qualifier annotation to specify which bean should be autowired, like:
Now, Spring will not get confused as to what bean it has to autowire.
NOTE , you can also use @Qualifier annotation to give names to your Rectangle and Circle classes, like
Also, you can specify a ‘rollbackFor’ attribute and specify which exception types must cause a transaction
rollback (a transaction with Runtime exceptions and errors are by default rolled back).
If your process() method is calling another bean method, then you can also annotate that method with
@Transactional and set the propagation level to decide whether this method should execute in the same
transaction or it requires a new transaction.
Or a specific controller,
Here, we have defined a global exception handler using @ControllerAdvice. If a SQLException gets thrown
from a controller, then handleSQLException() method will be called. In this method, you can customize the
exception and send a particular error page/error code. Also, custom exceptions can be handled.
If you don’t want to create a global exception handler, then you can also define some @ExceptionHandler
methods in a particular controller itself.
In this example, we are consuming a GET web service and converting the response to the object of User
class.
Similarly, there are other methods to consume POST, DELETE web services like exchange() and delete()
respectively.
AOP terminology :
Aspect : Aspect is a class that implements the application concerns that cuts across multiple classes, such
as transaction management and logging. Aspects can be a normal class configured through Spring XML
configuration or we can use @Aspect annotation.
Join Point : a point during the execution of a program, such as the execution of a method or the handling
of an exception. In Spring AOP, a join point always represents a method execution.
Advice : advices are actions that are taken for a particular join point. There are different types of advices,
like, before, after and around advice.
Pointcut : pointcut is an expression that is matched with join points to determine whether advice needs to
be applied or not.
Target Object : objects on which advices are applied by one or more aspects. Since Spring AOP is
implemented using runtime proxies, this object will always be a proxied object.
AOP Proxy : an object created by the AOP framework in order to implement the aspect contracts (advise
method executions and so on). In the Spring Framework, an AOP proxy will be a JDK dynamic proxy or a
CGLIB proxy.
Weaving : It is the process of linking aspects with other objects to create the advised proxy objects. This
can be done at compile time, load time or at runtime. Spring AOP performs weaving at the runtime.
- SOAP stands for Simple Object Access Protocol and REST stands for Representational State
Transfer
- SOAP is a protocol whereas REST is an architectural style
- SOAP cannot use REST because it is a protocol whereas REST can use SOAP web services as
the underlying protocol, because it is just an architectural pattern
- SOAP uses service interfaces to expose its functionality to client applications whereas REST
uses URI to expose its functionality
- SOAP defines standards that needs to be strictly followed for communication to happen
between client and server whereas REST does not follow any strict standard
- SOAP requires more bandwidth and resources than REST because SOAP messages contain a
lot of information whereas REST requires less bandwidth than SOAP because REST messages
mostly just contains a simple JSON message
- SOAP only works with XML format whereas REST allows different data formats like Plain text,
HTML, XML, JSON etc.
- SOAP defines its own security whereas REST inherits the security
Question 160: What is the difference between Web Server and Application
Server?
Answer: The differences are:
- Web server provides environment to run only web related applications, whereas Application
Server provides environment to run Java J2EE applications (enterprise applications)
- Web server is used to deliver static contents like static html pages, whereas through
Application server, you can deliver dynamic content
- Web servers can be used for Servlets, JSPs whereas Application servers can be used for
Servlets, JSPs, EJBs, JMS etc. (Application servers have an internal web server inside it to
serve web applications)
- Web servers support HTTP protocol, whereas Application servers support HTTP as well as
RPC/RMI protocols
- Web server consume less resources than Application servers
- Tomcat, Jetty are examples of Web Servers, whereas GlassFish, JBoss, WebLogic, WebSphere
are some examples of Application servers
Knowing these topics well should be enough to crack a Spring/SpringBoot interview, if you want to really
impress the interviewer, you can prepare the below topics as well:
All the above topics are advanced but I will explain about them a little, so you can go out and read more
about it.
If the GET service is getting failed, then the fallback method will be executed.
JPA / Hibernate
In mappedBy attribute, the field name of Item entity is passed, see below,
Item Entity:
@JoinColumn annotation is used to define the name of foreign key column that represents the entity
association.
Question 175: Why annotations should be imported from JPA and not from
Hibernate?
Answer: If you see @Entity annotation, it is present in javax.persistence package and also in
org.hibernate.annotations package:
You should choose the one from javax.persistence package, because if you choose the Hibernate one, then
in future, if by any chance, you have to remove Hibernate and use some other JPA implementation, like
iBatis, then you will have to change your code (imports). As you remember, JPA is just a specification, like
an interface. You can plug any of its implementations as long as you use the imports from
javax.persistence package.
Question 176: What is the difference between get() and load() method of
Hibernate Session?
Answer: Hibernate Session class provides two methods to access object, session.get() and session.load()
The differences are:
- get() method involves a database hit, if the object does not exist in Session cache and it
returns a fully initialized object which may involve several database calls, whereas load()
method returns a proxy object and it only hit the database if any method other than getId() is
called on the entity object
- load() method results in slightly better performance as it can return a proxy object, it will only
hit the database when a non-identifier getter method is called, whereas get() method returns
a fully initialized object when it does not exist in Session cache which may involve multiple
database calls based on entity relationships
- get() method returns null if the object is not found in the cache as well as the database
whereas load() method will throw ObjectNotFoundException but never return null
- If you are not sure whether the object exists or not, then use get() as it will return null but if
you are sure that the object exists, then use load() method as it is lazily initialized
- Return type of persist() method is void while return type of save() method is Serializable
object
- Both persist() and save() methods makes a transient instance persistent. But persist()
method does not guarantee that the identifier value will be assigned to the persistent
instance immediately, the assignment might happen at flush time
- Both behave differently when they are executed outside the transaction boundaries. persist()
method ensures that it will not execute an INSERT when it is called outside of a transaction
boundary whereas save() method does not guarantee this, it returns an identifier and if an
INSERT query has to be executed to get the identifier then this INSERT happens immediately
and it does not matter if the save() is called inside or outside of a transaction
- persist() method is useful in long-running conversation with an extended Session context
because it does not execute an INSERT outside of a transaction. On the other hand, save()
method is not good in a long-running conversation with an extended Session context
Question 178: What is Session and SessionFactory in Hibernate?
Answer: SessionFactory creates and manages the Session objects.
Some points about SessionFactory:
- it is one instance per datasource/database
- it is thread-safe
- it is an immutable and heavy-weight object as it maintains Sessions, mappings, hibernate
configurations etc.
- SessionFactory provides second level cache in hibernate also called application-level cache
Some points about Session:
Question 179: What is First Level and Second Level Cache in Hibernate?
Answer: Hibernate framework provides caching at two levels, first-level cache which is at the Session level
and second-level cache which is at the application level.
The first level cache minimizes the database access for the same object if it is requested from the same
Session. The first level cache is by default enabled. When you call session.get() method then it hits the
database, and while returning, it also saves this object in the first-level cache. So, the subsequent requests
for this same object from the same session will not hit the database and the object from cache will be used.
But, since this cache is associated with the Session object, which is a short-lived object in Hibernate, as
soon as the session is closed, all the information held in the cache is also lost. So, if we try to load the
same object using the get() method, Hibernate will go to the database again and fetch the record.
This poses a significant performance challenge in an application where multiple sessions are used,
Hibernate provides second-level cache for this and it can be shared among multiple sessions.
The second level cache is maintained at the SessionFactory level, this cache is by default disabled, to
enable second level cache in hibernate, it needs to be configured in hibernate configuration file, i.e.
hibernate.cfg.xml file. There are various providers of second level cache, like EhCache, OSCache etc.
Once second level cache is configured, then object request will first go to the first-level cache, if it is not
found there, then it will look for this object in second-level cache, if found then it will be returned from the
second-level cache and it will also save a copy in first-level cache.
But, If the object is not found in the second-level cache also, then it will hit the database and if it
present in database, this object will be put into both first and second level cache, so that if any other
session requests for this object then it will be returned from the cache.
Question 181: How can we see the SQL query that gets generated by
Hibernate?
Answer: If you are using hibernate.cfg.xml file, then use the below property:
< property name ="show_sql" > true</ property >
If you are using Spring Data JPA, then you can set this property in application.properties file, like:
spring.jpa.show-sql=true
Question 182: What is Hibernate Dialect and why we need to configure it?
Answer: The Dialect specifies the type of database that our application is using. As we know, Hibernate is
database agnostic and it can work with many databases. However, each database has some variations and
standard implementations. We need to tell Hibernate about it, so that Hibernate can generate the database
specific SQL wherever it is necessary.
You can configure this dialect in hibernate.cfg.xml file, like:
< property name ="dialect" > org.hibernate.dialect.PostgreSQLDialect</ property >
And in SpringBoot, you can configure it in application.properties file, like:
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
Question 188: Where do we define proxies so that maven can download jars
from the internet in a corporate environment?
Answer: settings.xml file is used to define proxies which helps in connecting to a network while working in
a corporate environment.
1. Inner join : Inner join selects all records from Table A and Table B, where the join condition
is met.
Syntax:
SELECT Table1.column1, Table1.column2, Table2.column1, …..
FROM Table1
INNER JOIN Table2
On Table1.MatchingColumnName = Table2.MatchColumnName;
(Note: Use either INNER JOIN or JOIN for this operation)
2. Left Join : Left join selects all records from Table A along with records of Table B for which
the join condition is met.
Syntax:
SELECT Table1.column1, Table1.column2, Table2.column1, …..
FROM Table1
LEFT JOIN Table2
On Table1.MatchingColumnName = Table2.MatchColumnName;
3. Right Join : Right join selects all records from Table B along with records of Table A for which
the join condition is met.
Syntax:
SELECT Table1.column1, Table1.column2, Table2.column1, …..
FROM Table1
RIGHT JOIN Table2
On Table1.MatchingColumnName = Table2.MatchColumnName;
4. Full Join : Full join selects all records from Table A and Table B, regardless of whether the
join condition is met or not.
Syntax:
SELECT Table1.column1, Table1.column2, Table2.column1, …..
FROM Table1
FULL JOIN Table2
On Table1.MatchingColumnName = Table2.MatchColumnName;
DML: DML stands for Data Manipulation language. These statements allows us to manage the data stored
in the database. DML commands are not auto-committed, so they can be rolled back.
Examples of DML commands are: INSERT, UPDATE, DELETE, SELECT
Question 194: How to find the nth highest salary from Employee table
Answer: The query to find nth highest salary is:
SELECT name, salary
FROM Employee e1
WHERE N-1 = (SELECT COUNT(DISTINCT salary) FROM Employee e2
WHERE e2.salary > e1.salary);
Here, to find the 3rd highest salary, replace N with 3, for 5th highest salary, replace N with 5 and so on.
The DISTINCT keyword is used to deal with the duplicate salaries in the table. The highest salary means no
salary is higher than it, the second highest salary means only one salary is higher than it, and similarly Nth
highest salary means N-1 salaries are higher than it. This is a generic solution and works in all databases,
however it is a little slow because the inner query will run for every row processed by the outer query.
Question 195: Difference between UNION and UNION ALL commands in SQL
Answer: Both UNION and UNION ALL are used to combine results of two separate queries, it could be on a
same table or a different table but number of columns should be same in both queries.
The Key difference between them is UNION removes duplicates, whereas UNION ALL keeps the duplicates.
Because of this, UNION ALL takes less time, as there is no extra step of removing duplicate rows.
Question 196: Difference between Unique Key and Primary Key in SQL
Answer: Both Unique and Primary keys uniquely identifies each row of a table.
The differences between them are:
- There can be only one primary key in a table, whereas there can be multiple unique keys in
the table
- Primary key cannot be null, whereas Unique Keys can be null
- In Primary key, default index is clustered, whereas in Unique key, default index is non-
clustered
Question 197: What is the difference between Primary and Foreign key in
SQL?
Answer: Primary key is used to uniquely identify a row in the table. A table can have only one primary
key. Primary key is of two types, simple and composite primary key. A Simple Primary key is made up of
just one column, whereas a composite primary key is made up of more than one column.
Primary key also enforces some constraints, like UNIQUE and NOT NULL, which means a table cannot have
duplicate primary keys and the key cannot be null.
A Foreign key in a table is the primary key of another table. For example, consider 2 tables, Employee &
Department. Department table have a primary key dept_id and this primary key can be used as foreign key
in Employee table to identify that this employee belongs to this department.
The differences between Primary key and Foreign key are given below:
- Primary key uniquely identify a record in the table, whereas Foreign key is the field in the
table that is the primary key of another table
- By default, a clustered index is created on primary key, whereas foreign key do not
automatically create an index
- We can have only one primary key in a table, whereas we can have more than one foreign
key in a table
- Primary keys does not allow duplicate or Null values, whereas Foreign keys allows both
- A clustered index defines the order in which data is physically sorted in a table, whereas non-
clustered index does not sort the physical data inside the table
- By default, clustered index is automatically created on primary key, whereas non-clustered
index can be created on any key
- There can be only one clustered index in a table, whereas there can be any number of non-
clustered index in a table
- Data Retrieval is faster using Clustered index than non-clustered index
- Data Update is faster using Non-clustered index than clustered index
- Clustered index does not need any extra space, whereas non-clustered index requires extra
space to store the index separately
- The size of clustered index is quite large as compared to non-clustered index
Question 199: What is the difference between WHERE and HAVING clause in
SQL
Answer: The differences are:
- WHERE clause can be used with SELECT, INSERT, UDPATE and DELETE statements, whereas
HAVING clause can only be used with SELECT statement
- WHERE clause is used for filtering the rows and it applies on each and every row, whereas
HAVING clause is used to filter groups
- WHERE clause is used before GROUP BY clause, whereas HAVING clause is used after GROUP
BY clause. It means that WHERE clause is processed before GROUP BY clause while HAVING
clause is executed after groups are created
- Aggregate functions cannot be used in WHERE clause, whereas we can use aggregate
functions in HAVING clause
Question 200: How to change the gender column value from Male to Female
and Female to Male using single Update statement
Answer: This is also a very common interview question. Mostly, this question is asked in a telephonic round.
The question is like, you are given a table, say Employee which has a column named ‘Gender’ having only
“Male” or “Female” strings as values. You have to swap these values like wherever the value is Male, it
should become Female, and wherever the value is Female, it should become Male. And you have to do this
by writing only one Update statement.
The Update query for this is:
UPDATE Employee SET Gender =
CASE Gender WHEN ‘Male’ THEN ‘Female’ WHEN ‘Female’ THEN ‘Male’ ELSE Gender END;
Other than these common questions, you can be asked to write a lot of queries which mostly contains
Joins, so you should also prepare for those types of database queries.
Question 201: Find first 3 largest numbers in an array
In this question, the interviewer will most probably ask you to not use sorting and pick the first/last 3
numbers from the array. Instead he will ask you to use one “for loop” to solve this problem.
Output:
Question 202: Move all negative numbers at the beginning of an array and
all positive numbers at the end
Here, also the interviewer will ask not to use any additional data structure like an extra array and this
question can be asked in two ways, whether the sequence of original array elements should be maintained
or not, so let’s see the program where the sequence is not maintained:
Output:
-9 -2 -15 -3 1 7 12 5 2
Here, the idea is to iterate through the array and when a negative number is found, then bring that number
to the beginning of the array by swapping it with the first positive number.
As you can see that the output is not maintaining the original sequence of array elements.
Now, let’s take a look at the solution which maintains the element sequence:
Output:
-9 -2 -15 -3 5 1 7 12 2
Now, the output is maintaining the original sequence of array elements.
There are many programmatic, puzzle problems that the interviewer can ask. If you are a beginner, then
prepare for programs like Palindrome, Fibonacci, Array problems, String problems, Linked list programs etc.
First, try to solve them with whatever brute-force solution that comes to your mind, then try to find its time
and space complexity, then try to optimize it. If you are not able to think of a better solution, no problem,
look for the optimal solution on the internet.
About the Author
Jatin Arora is a Computer Science graduate. He holds an expertise in Java & SpringBoot. He has worked on
a variety of interesting projects across different domains like Inventory management, DevOps, cloud &
financial domain.