Top 50 Core Java Interview questions you can't afford to get wrong
Core Java Interview Questions and Answers
Q1. What is the difference between “==” and equals in comparing Java String objects?
A1. Comparing two String objects using “==” instead of “equals( )”. When you use “==”, you are actually comparing two object references, to see if they point to the same object. For example:
public class StringEquals { public static void main(String[ ] args) { String s1 = "Hello"; String s2 = new String(s1); String s3 = "Hello"; System.out.println(s1 + " equals " + s2 + " -> " + s1.equals(s2)); //true System.out.println(s1 + " == " + s2 + " -> " + (s1 == s2)); //false System.out.println(s1 + " == " + s3+ " -> " + (s1 == s3)); //true } }
The variable s1 refers to the String instance created by "Hello". The object referred to by s2 is created with s1 as an initializer, thus the contents of the two String objects are identical, but they are distinct objects having distinct references s1 and s2. This means that s1 and s2 do not refer to the same object and are, therefore, not ==, but equals( ) as they have the same value "Hello". The s1 == s3 is true, as they both point to the same object due to internal caching. The references s1 and s3 are interned and points to the same object in the string pool.
Q2. Can you explain how Strings are interned in Java?
A2. String class is designed with the Flyweight design pattern in mind. Flyweight is all about re-usability without having to create too many objects in memory. A pool of Strings is maintained by the String class. When the intern( ) method is invoked, equals(..) method is invoked to determine if the String already exist in the pool. If it does then the String from the pool is returned instead of creating a new object. If not already in the string pool, a new String object is added to the pool and a reference to this object is returned. For any two given strings s1 & s2, s1.intern( ) == s2.intern( ) only if s1.equals(s2) is true.
Two String objects are created by the code shown below. Hence s1 == s2 returns false.
//Two new objects are created. Not interned and not recommended. String s1 = new String("A"); String s2 = new String("A");
Instead use:
String s1 = "A"; String s2 = "A";
s1 and s2 point to the same String object in the pool. Hence s1 == s2 returns true.
Since interning is automatic for String literals String s1 = “A”, the intern( ) method is to be used on Strings constructed with new String(“A”).
Q3. Why String class has been made immutable in Java?
A3. For security and performance.
Security: The main reason for immutability is security. In Java you pass file names, host names, login names, passwords, customer account numbers, etc as a string object. For example, had String been mutable, 'user 1' could log into a Java application using his user-name and password credentials, and then possibly change the name of his password file name, which is a String object from 'password1' to 'password2' before JVM actually places the native OS system call to open the file. This is a serious security breach allowing 'user 1' to open user 2's password file.
Performance: Immutable classes are ideal for representing values of abstract data (i.e. value objects) types like numbers, enumerated types, etc. If you need a different value, create a different object. In Java, Integer, Long, Float, Character, BigInteger and BigDecimal are all immutable objects. Immutable classes are inherently thread-safe, hence they are less error prone and can be used safely in a multi-threaded environment for better scalability. Optimization strategies like caching of hashcode, string pooling, etc can be easily applied to improve performance.
Q4. In Java, what purpose does the key words final, finally, and finalize fulfill?
A4. 'final' makes a variable reference not changeable, makes a method not over-ridable, and makes a class not inheritable.
'finally' is used in a try/catch statement to almost always execute the code. Even when an exception is thrown, the finally block is executed. This is used to close non-memory resources like file handles, sockets, database connections, etc till Java 7. This is is no longer true in Java 7.
Java 7 has introduced the AutoCloseable interface to avoid the unsightly try/catch/finally(within finally try/catch) blocks to close a resource. It also prevents potential resource leaks due to not properly closing a resource.
// pre Java 7
BufferedReader br = null; try { File f = new File("c://temp/simple.txt"); InputStream is = new FileInputStream(f); InputStreamReader isr = new InputStreamReader(is); br = new BufferedReader(isr); String read; while ((read = br.readLine()) != null) { System.out.println(read); } } catch (IOException ioe) { ioe.printStackTrace(); } finally { //Hmmm another try catch. unsightly try { if (br != null) br.close(); } catch (IOException ex) { ex.printStackTrace(); } }
Java 7 – try can have AutoCloseble types. InputStream and OutputStream classes now implements the Autocloseable interface.
try (InputStream is = new FileInputStream(new File("c://temp/simple.txt")); InputStreamReader isr = new InputStreamReader(is); BufferedReader br2 = new BufferedReader(isr);) { String read; while ((read = br2.readLine()) != null) { System.out.println(read); } } catch (IOException ioe) { ioe.printStackTrace(); }
try can now have multiple statements in the parenthesis and each statement should create an object which implements the new java.lang.AutoClosable interface. The AutoClosable interface consists of just one method. void close() throws Exception {}. Each AutoClosable resource created in the try statement will be automatically closed without requiring a finally block. If an exception is thrown in the try block and another Exception is thrown while closing the resource, the first Exception is the one eventually thrown to the caller. Think of the close( ) method as implicitly being called as the last line in the try block.
'finalize' is called when an object is garbage collected. You rarely need to override it. It should not be used to release non-memory resources like file handles, sockets, database connections, etc because Java has only a finite number of these resources and you do not know when the garbage collection is going to kick in to release these non-memory resources through the finalize( ) method.
So, final and finally are used very frequently in your Java code, but the key word finalize is hardly or never used.
Q5. What value will the following method return?
public static int getSomeNumber( ){ try{ return 2; } finally { return 1; } }
A5. 1 is returned because 'finally' has the right to override any exception/returned value by the try..catch block. It is a bad practice to return from a finally block as it can suppress any exceptions thrown from a try..catch block. For example, the following code will not throw an exception.
public static int getSomeNumber( ){ try{ throw new RuntimeException( ); } finally { return 12; } }
Q6. What can prevent execution of a code in a finally block?
A6. a) An end-less loop.
public static void main(String[ ] args) { try { System.out.println("This line is printed ....."); //endless loop while(true){ //... } } finally{ System.out.println("Finally block is reached."); // won't reach } }
b) System.exit(1) statement.
public class Temp { public static void main(String[ ] args) { try { System.out.println("This line is printed ....."); System.exit(1); } finally{ System.out.println("Finally block is reached.");// won't reach } } }
c) Thread death or turning off the power to CPU.
d) An exception arising in a finally block itself.
e) Process p = Runtime.getRuntime( ).exec("
If using Java 7 or later editions, use AutoCloseable statements within the try block.
Q7. Can you describe “method overloading” versus “method overriding”? Does it happen at compile time or runtime?
A7. Method overloading: Overloading deals with multiple methods in the same class with the same name but different method signatures. Both the below methods have the same method names but different method signatures, which mean the methods are overloaded.
public class { public static void evaluate(String param1); // method #1 public static void evaluate(int param1); // method #2 }
This happens at compile-time. This is also called compile-time polymorphism because the compiler must decide how to select which method to run based on the data types of the arguments. If the compiler were to compile the statement:
evaluate(“My Test Argument passed to param1”);
it could see that the argument was a string literal, and generate byte code that called method #1.
Overloading lets you define the same operation in different ways for different data.
Method overriding: Overriding deals with two methods, one in the parent class and the other one in the child class and has the same name and signatures. Both the below methods have the same method names and the signatures but the method in the subclass MyClass overrides the method in the superclass BaseClass.
public class A { public int compute(int input) { //method #3 return 3 * input; } }
public class B extends A { @Override public int compute(int input) { //method #4 return 4 * input; } }
This happens at runtime. This is also called runtime polymorphism because the compiler does not and cannot know which method to call. Instead, the JVM must make the determination while the code is running.
The method compute(..) in subclass “B” overrides the method compute(..) in super class “A”. If the compiler has to compile the following method,
public int evaluate(A reference, int arg2) { int result = reference.compute(arg2); }
The compiler would not know whether the input argument 'reference' is of type “A” or type “B”. This must be determined during runtime whether to call method #3 or method #4 depending on what type of object (i.e. instance of Class A or instance of Class B) is assigned to input variable “reference”.
A obj1 = new B( ); A obj2 = new A( ); evaluate(obj1); // method #4 is invoked as stored object is of type B evaluate(obj2); // method #3 is invoked as stored object is of type A
Overriding lets you define the same operation in different ways for different object types.
Q8. What do you know about class loading? Explain Java class loaders? If you have a class in a package, what do you need to do to run it? Explain dynamic class loading?
A8. Class loaders are hierarchical. Classes are introduced into the JVM as they are referenced by name in a class that is already running in the JVM. So, how is the very first class loaded? The very first class is specially loaded with the help of static main( ) method declared in your class. All the subsequently loaded classes are loaded by the classes, which are already loaded and running. A class loader creates a namespace. All JVMs include at least one class loader that is embedded within the JVM called the primordial (or bootstrap) class loader. The JVM has hooks in it to allow user defined class loaders to be used in place of primordial class loader. Let us look at the class loaders created by the JVM.
classloader
|
Reloadable
|
Explanation
|
Bootstrap
(primordial)
|
No
|
Loads JDK internal
classes, java.* packages as defined by the sun.boot.class.path
system property. Typically loads the rt.jar and i18n.jar
archives.
|
Extensions
|
No
|
Loads jar files from JDK
extensions directory as defined by the java.ext.dirs system
property. Usually from the lib/ext directory of the JRE.
|
System
|
No
|
Loads classes from the
system classpath as defined by the java.class.path property, which
is set by the CLASSPATH environment variable or command line
options -classpath or -cp as discussed earlier. The developers are
responsible for providing the necessary classpath information.
|
Class loaders are hierarchical and use a delegation model when loading a class. Class loaders request their parent to load the class first before attempting to load it themselves. When a class loader loads a class, the child class loaders in the hierarchy will never reload the class again. Hence uniqueness is maintained. Classes loaded by a child class loader have visibility into classes loaded by its parents up the hierarchy but the reverse is not true as explained in the above diagram.
Q9. Explain static vs. dynamic class loading?
A9. Classes are statically loaded with Java’s “new” operator.
class MyClass { public static void main(String args[]) { Car c = new Car( ); } }
Dynamic loading is a technique for programmatically invoking the functions of a class loader at run time. Let us look at how to load classes dynamically.
//static method which returns a Class Class.forName (String className);
The above static method returns the class object associated with the class name. The string className can be supplied dynamically at run time. Unlike the static loading, the dynamic loading will decide whether to load the class Car or the class Jeep at runtime based on a properties file and/or other runtime conditions. Once the class is dynamically loaded the following method returns an instance of the loaded class. It’s just like creating a class object with no arguments.
// A non-static method, which creates an instance of a // class (i.e. creates an object). class.newInstance ( );
Static class loading throws “NoClassDefFoundError” if the class is not found and the dynamic class loading throws “ClassNotFoundException” if the class is not found.
Q10. What tips would you give to someone who is experiencing a class loading or “Class Not Found” exception?
A10. “ClassNotFoundException” could be quite tricky to troubleshoot. When you get a ClassNotFoundException, it means the JVM has traversed the entire classpath and not found the class you've attempted to reference.
1) Stand alone Java applications use -cp or -classpath to define all the folders and jar files to look for. In windows separated by ";" and in Unix separated by ":".
java -classpath "C:/myproject/classes;C:/myproject/lib/my-utility.jar;C:/myproject/lib/my-dep.jar" MyApp
2) Determine the jar file that should contain the class file within the classpath -- war/ear archives and application server lib directories. Search recursively for the class.
$ find . -name "*.jar" -print -exec jar -tf '{}' \; | grep -E "jar$|String\.class"
You can also search for the class at www.jarfinder.com
3) Check the version of the jar in the manifest file MANIFEST.MF, access rights (e.g. read-only) of the jar file, presence of multiple versions of the same jar file and any jar corruption by trying to unjar it with "jar -xvf ...". If the class is dynamically loaded with
Class.forName("com.myapp.Util")
, check if you have spelled the class name correctly.
4) Check if the application is running under the right JDK? Check the JAVA_HOME environment property
$ echo $JAVA_HOME
Core Java Interview Questions and Answers
Labels: Core Java