Core Java Tricky Interview Questions

1. How to ensure that instance is never garbage collected?

We can use singleton pattern. There’s a static reference to a singleton, so it won’t be eligible for garbage collection until the classloader is eligible for garbage collection.

2. Can constructors having return statment?

Yes.

public GeneralCodeTest() {
    return;
}   ==> Valid for both Default and Parameterized Constructor.
3. Note: Scenario 1:
String ssss = new String(null);  // Compile Time Error, because string constructor accepts string, stringbuilder, stringbuffer so jvm cant detect which constructor to call. So ambiguous error. 
Integer iiii = new Integer(null); // Run Time Exception : NumberFormatException.
4. Note: Scenario 2:
Map m = new HashMap<>();
System.out.println("M = " + m.get(1));   // ==> M = null 
// Also, note, even though the map is of type string, we are able to pass integer.
OR
Map m = new HashMap<>();
System.out.println("M = " + m.get(new SomeClassName));   // ==> M = null 
// Also, note, even though the map is of type string, we are able to pass any class Object.
5. Note: Scenario 3: StackOverFlow Error: 
public class Test {
     Test() {
         System.out.println("Hello");
     }
     public static void main(String[] args) {
         Test t = new Test();
     }
 }

Output : Hello. ==> Everything works fine as expected.

Now run below code:

public class Test {
     Test t = new Test();
     Test() {
         System.out.println("Hello");
     }
     public static void main(String[] args) {
         Test t = new Test();
     }
 }

 Output : Exception in thread "main" java.lang.StackOverflowError.
This is because above code :
     Test t = new Test();
     Test() {
         System.out.println("Hello");
     }
 is Similar to below code:
     Test() {
         Test t = new Test();
         System.out.println("Hello");
     }

Now as you can see, the constructor is getting called in an loop, so it gives StackOverFlowError.

Now if we change the above code as below:

public class Test { 
 static Test t = new Test(); // ==> Note. We made this object as  static.
    Test() {
        System.out.println("Hello");
    }
}
 
Output: 
 Hello 
 Hello

This is printed because now we created the variable as static, and since static variables are loaded when class is loaded. Now when the Test class is loaded, the constructor is called ans Hello is printed. And second Hello is printed from main method when it creates an object in main method.

6. Note: Scenario 4: Static Final Working: Compiler Optimization: 
public class Test {
     public static void main(String[] args) {
         System.out.println(T.x); // line 3
     }
 }
 class T {
     public static final int x = 100;
     static{
         System.out.println("Static Block Executed");
     }
 }

 Output : 100

We expected the static block sysout will get printed because static block is executed first when the class is loaded, and since line 3 when we wrote T.x, we expected T class to be loaded and static block to be executed, but this didn’t happen, and static block never got executed, this is because of variable x defined as static and final. Since the variable x is defined as static final, the compiler optimizes the code and replace the line 3 from

Compiler Converts
      System.out.println(T.x); // line 3
TO
      System.out.println(100); // line 3

in the .class file. As you can see above, the .class file is not having any reference to T class, so it doesn’t load the T class and hence it doesn’t execute the static block. Note: Every time a static final variable is always replaced with the actual value in the .class file. This concept is also useful for serialization and deserialization.

7. Scenario 5: Ternary Operator with null:

int a = (50<10?null:50);  // ==> Output : 50
int a = (5<10?null:5);    // ==> Output : null pointer exception as null cannot be assigned to int.
 
Note: Above code is not giving compile time error, as the null part will be executed only if ternary operator returns true., so it gives error at run-time on basis of ternary operator output.
8. Scenario 6: IntegerCache Class and Autoboxing:

Integer i1 = 127; // line 1.
Integer i2 = 127;
System.out.println(i1 == i2); // Line 3 ==> True. ==> As expected. 
Integer i3 = 128;
Integer i4 = 128;
System.out.println(i3 == i4); // Line 6 ==> False. ==> Not As expected.

Now, as we saw above, the second time(line 6) the output is false whereas we expected that to return true as return by line 3.
This is because, in the .class file line 1 is converted into ===>

Integer i1 = Integer.valueOf(127);

(Autoboxing is done internally automatically by JVM). Now if we check internal implementation of valueOf method, we can see it using IntegerCache class and it check if value is between -128 to 127, if the value is between -128 and 127, it return the value from IntegerCache class else it returns new Integer.
Above high range 127 is configurable, we can pass max range value through vm arguments as below:
-XX.AutoBoxCacheMax=256
In this case IntegerCache will check if value is between -128 to 256, and hence now it will return true for both line 3 and line 6.

Internal Implementation of ValueOf method:

public static Integer valueOf(int i) {
     if (i >= IntegerCache.low && i <= IntegerCache.high)
         return IntegerCache.cache[i + (-IntegerCache.low)];
     return new Integer(i);
}
8. Note: Scenario 6: Static Method: 

class A {
     static void display() {
         Syso("Hello");
     }
 }
 class B {
     pvsm() {
         A a = null;
         a.display(); // line 9
     }
 }
 
Output : Hello
This is because .class file replaces line 9 from a.display() to A.display().
9. Note: Scenario 7: Null Constructor Ambiguity Check:

Integer i = new Integer(null); ==> No Compile Error but gives run time error. // Line 1 => Number Format Exception.
String s = new String(null); ==> Compile Time Error. // Line 2

Here, line 1 is compliled successfully, because if we check integer class there is only one constructor that accepts string, so at line1 that constructor is called. There is one more constructor, that accepts int, but int cant be null, so there is no ambiguity over here.
Whereas, if we check String class constructors, there are multiple constructors like new String(StringBuilder sb) or new String(StringBuffer sb) or new String(String s), all of these constructor can accept null values, so compiler is confused to call which constructor, hence give compile time error saying there is ambiguity. Exact error : Constructor String(String) is ambigous.

11. Scenario 9: Operator Precendence:

String s = "One" + 1 * 2 + "Two" + 3 + 4 + "Four"; // line 1
Syso(s);  // ==> One2Two34Four ===> Note: First 1*2 got executed, so above string is converted into  "One" + 2 + "Two" + 3 + 4 + "Four", and hence the output.

int i = 10 + + 11 - - 12 + + 13; // line 3
Syso(i)  // ==> 46. This is because line 3 is converted into 10 + (+11) - (-12) + (+13) which in turn converts into 10 + 11 + 12 + 13 which is equal to 46.

12. Finally Block Power:

If you return some value from try block or catch block, and you also write a return statement in finally block, the method will always return the value returned by finally block, because after the try block or catch block returns a value, finally blocks get executed and there whatever is returned is the final return statement.

public void display() {
     try {
         return "Hello";
     }
     finally {
         return "Hi";
     }
 }
 pvsm() {
     Syso(display()); ==> Hi
 }
 Example2:
 public void display() {
     try {
         throw new RuntimeException("Hello");
     }
     finally {
         return "Hi";
     }
 }
 pvsm() {
     Syso(display()); ==> Hi
 }

13. Long, Float, Double, Int Wrapper Equal() Methods:

Long l = new Long(0); 
      OR 
Long l = 0l; 
      OR
Long l = 0L;

Syso(l.equals(0)); // ===> False.
Syso(l.equals(0l)); // ===> True.

// Here all above 3 l are equal and returns true if checked using equals method. 

Here we expected true but program returns false because if we check equals method of long, it checks the instanceOf the object passed to the method, here we are passing int which is not of type long, so it returns false.

Below is internal Implementation of Equals method of Long class:
 
public boolean equals(Object obj) {
    if (obj instanceof Long) {
       return value == ((Long)obj).longValue();
    }
    return false;
 }
If code is changed as below:
 
Long l = new Long(0); OR Long l = 0l; OR Long l = 0L;
Syso(l.equals(0l)); OR Syso(l.equals(0L)); ===> True.

Same is the case for Float and Double.

14. Method Hiding: Static Method Overriding:

class Super{
     static void display() {
         Syso("Harshit");
     }
 }
 class Sub extends Super{
     static void display() {
         Syso("Jain");
     }
 }
 pvsm() {
     Super super1 = new Sub():
     super1.display(); // Line 2 ==> Harshit --> This is because display is not overriden by subclass because it is a static method, it is just hidden.
     Sub sub = new Sub():
     sub.display(); // Line 4==> Jain
 }

15. Hiding Superclass Variable:

class Super{
     public static name = "Base";
}
class Sub {
     private static name = "Derived";
}
pvsm() {
     Syso(new Sub().name); 
}

Output==> Compile Time error Saying Field Sub.name is not visible. 

So even though we are having name variable in supper class which is public but it is not getting called because we are having same name variable in derived class which is private because of which it is not accessible outside that class. So this is one way to hide a variable of super class.

  • Now, if we change the variable name of variable in superclass, for example:
class Super{
     public static name1 = "Base";
}
class Sub {
     private static name = "Derived";
}
pvsm() {
     Syso(new Sub().name1);
}

Output==> Base. This is because name1 variable is inherited by derived class from base class.
18. Autoboxing, Inheritance and Overriding:
class Super{ 
     void method(int i) { 
         syso("int called");
     }
 } 
 class Sub { 
     // @Override           // line 1 
     void method(Integer i) { 
         syso("Integer called");
     }
 }
 pvsm() {
     Super sup = new Sub():
     sup.method(new Integer(10)); // Line 14 
     sup.method(10); // line 15
     Sub sub = new Sub():
     sub.method(new Integer(10)); // line 17
     sub.method(10); // line 18
 }

Output:
int called ==> Line 14 makes call to super class method(int) because here autoboxing is done, as super class don't have any method with Integer argument

int called ==> Line 15 makes call to super class method(int) which is already present in super class.

Integer called ==> Line 17 makes call to sub class method(Integer) which is already present in sub class.

int called ==> Line 18 makes call to super class method(int) which is inherited by sub class.
  • Note: At line 14, the JVM tries to find a method method(integer) in super class, but since it finds a method method(int), so it auto-box the argument from integer to int and makes call to method(int). If both class would have method signature with int or with integer , then overriding would have taken place.
  • Even if we try to uncomment @override at line 1, we get compile time error saying ” The method method(Integer) of type Sub must override or implement supertype method. Hence we can say, subclass is not overriding super class method.
19. Constructor overloading with null:
public class Test {
     public Test(Object 0) { // line 1
         syso("Object")
     }
     public Test(double[] dArray) { // line 2
         syso("Double Array");
     }
     public void display(String s) { // line 3
         syso("String")
     }
     public void display(Integer i) { // line 3
         syso("Integer");
     }
 pvsm() {
     Test t = new Test(null);  // line 4 ==> Double Array
     t.display(null);   // line 5 ==> Compile time error 
  }   
}
  • line 4 ==> Double Array because double is more specific than object and JVM always first calls the more specific constructor or method.
  • line 5==> Compile time error because JVM don’t know which display method to call whether to call display method with string argument or display method with integer argument, because there is no relationship between integer and string, neither of any is more specific.

Also if we add one more constructor as below:

public Test(String s) { // line 6
         syso("String");
}

Then, in this case, above object creation line 4 will give compile time error because again string and double neither of them is more specific. so compiler is confused to call which constructor.

20. Character Addition:

Syso("H" + "i"); ==> Hi
Syso('H'+'i'); ==> 177 because character are converted into ascii values.
int x = 'H'; ==> 72
int y = 'i'; ==> 105
syso(x+ "," + y); ==> 72,105
syso('H'); ==> H ==> Since here there is no addition or subtraction.
21. Double VS Big Decimal Subtraction:

double d = 1.10 - 10;
syso(d == .10) ==> False because if we check the value of d, it is 0.10000000000009
syso(d) ==> 0.10000000000009
BigDecimal bd = new BigDecimal("1.10").subtract(new BigDecimal("10");
syso(bd); ==> .10
syso(bd == .10) ==> True.

So, it is best to use BigDecimal.
22. StringBuffer Constructors with Character Parameter:

pvsm() {
     StringBuffer word = null;
     switch(1) {
         Case 1 : word = new StringBuffer('P'); // Line 1
         default: word = new StringBuffer('M'); // Line 2
     }
      // Blank Line 
     word.append('a'); // Line 3
     word.append('i'); // Line 4
     word.append('n'); // Line 5
     // Line 6
     syso(word);      // Line 7 ==> ain
     new String('M'); // Line 8  ==> Compile Time Error
 }
  • Line 7 ==> ain. This is because when we check stringBuffer constructor, there is no constructor present in stringbuffer which accepts character, but there is one constructor which accepts int in stringbuffer, so in above case the characters are converted into ascii value, ie StringBuffer(int capacity) constructor is called. So Line 1 and Line 2 both gets executed as there is no break statement in the case, but JVM understands it as the capacity of stringbuffer.
  • Line 8 ===> Compile time error because there is no constructor in string which accepts int or char.

If we add, below line at line 6, it will print the capacity of word.

syso(word.capacity()); // 77 (ascii value of M)

Or, If we add, below line at blank line, It will display empty string.

syso(word); // "" ==> Empty String.
23. Compiler Overloading Optimization:

public class Test {
     public static void main(String[] args) {
         foo(null);
     }
     public static void foo(Object o) {
         System.out.println("Object Impl");
     }
     public static void foo(String s) {
         System.out.println("String Impl");
     }
 }

Output: String Impl

As we know that we can assign null to any object, so doesn’t compiler complains about this program? According to java specs, in case of overloading, compiler picks the most specific function. Obviously String class is more specific than Object class, hence it will print “String Impl”.

What if we have another method in the class like below:

public static void foo(StringBuffer i){
         System.out.println("StringBuffer Impl");
 }

In this case, java compiler will throw an error as “The method foo(String) is ambiguous for the type Test” because String and StringBuffer, none of them are more specific to others.

A method is more specific than another if any invocation handled by the first method could be passed on to the other one without a compile-time type error.

We can pass String as a parameter to Object argument and String argument but not to StringBuffer argument method.

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.