πΉ Part 11: Output-Based Java Questions
π― Why It Matters
Section titled βπ― Why It MattersβOutput-based questions are high-frequency interview favorites, especially in online assessments and coding rounds. They test:
- Deep understanding of execution order
- Tricky edge cases with inheritance, static blocks, overloading, etc.
- Mastery of Java quirks beyond syntax
- Memory management and object lifecycle
- Exception handling scenarios
π§ͺ Example 1: Static Blocks Execution Order
Section titled βπ§ͺ Example 1: Static Blocks Execution Orderβclass Test { static { System.out.println("Static Block 1"); }
static { System.out.println("Static Block 2"); }
public static void main(String[] args) { System.out.println("Main Method"); }}β Output:
Section titled ββ Output:βStatic Block 1Static Block 2Main Methodπ Key Points:
- Static blocks run once when the class is loaded, before the
main()method- Multiple static blocks execute in order of appearance
- Static blocks run even if
main()is never called
π§ͺ Example 2: main() Overloading and Variants
Section titled βπ§ͺ Example 2: main() Overloading and Variantsβpublic class Test { public static void main(String args) { System.out.println("Overloaded main with String"); }
public static void main(String[] args) { System.out.println("Main Method with String array"); }
public static void main(int[] args) { System.out.println("Main Method with int array"); }
public static void main() { System.out.println("Main Method with no args"); }}β Output:
Section titled ββ Output:βMain Method with String arrayπ Key Points:
- Only the signature
public static void main(String[] args)is treated as the entry point by JVM- Other overloaded versions are just regular methods
- JVM looks for the exact signature, not the most specific one
π§ͺ Example 3: Static Method Hiding vs Method Overriding
Section titled βπ§ͺ Example 3: Static Method Hiding vs Method Overridingβclass Parent { static void display() { System.out.println("Parent static method"); }
void show() { System.out.println("Parent instance method"); }}
class Child extends Parent { static void display() { System.out.println("Child static method"); }
@Override void show() { System.out.println("Child instance method"); }}
public class Main { public static void main(String[] args) { Parent p = new Child(); p.display(); // Static method - resolved at compile time p.show(); // Instance method - resolved at runtime
Child c = new Child(); c.display(); // Child's static method c.show(); // Child's instance method }}β Output:
Section titled ββ Output:βParent static methodChild instance methodChild static methodChild instance methodπ Key Points:
- Static methods are resolved at compile time based on reference type (method hiding)
- Instance methods are resolved at runtime based on actual object type (method overriding)
- This is a classic interview question to test understanding of static vs dynamic binding
π§ͺ Example 4: finally vs return - Tricky Scenarios
Section titled βπ§ͺ Example 4: finally vs return - Tricky Scenariosβpublic class Test { public static int getValue1() { try { return 1; } finally { return 2; } }
public static int getValue2() { try { return 1; } finally { System.out.println("Finally block executed"); // No return in finally } }
public static int getValue3() { try { throw new RuntimeException("Exception"); } finally { return 3; } }
public static void main(String[] args) { System.out.println("getValue1(): " + getValue1()); System.out.println("getValue2(): " + getValue2()); System.out.println("getValue3(): " + getValue3()); }}β Output:
Section titled ββ Output:βgetValue1(): 2Finally block executedgetValue2(): 1getValue3(): 3π Key Points:
finallyblock always executes (except System.exit())- If
finallyhas areturn, it overrides the try blockβs return- If
finallyhas noreturn, the try blockβs return value is preservedfinallycan suppress exceptions if it has a return
π§ͺ Example 5: Null and Method Overloading - Advanced Cases
Section titled βπ§ͺ Example 5: Null and Method Overloading - Advanced Casesβclass A { void method(Object o) { System.out.println("Object method"); }
void method(String s) { System.out.println("String method"); }
void method(Integer i) { System.out.println("Integer method"); }
void method(String... strings) { System.out.println("Varargs String method"); }
public static void main(String[] args) { A a = new A(); a.method(null); // Ambiguous - String vs Integer a.method((Object) null); // Object method a.method((String) null); // String method a.method((Integer) null); // Integer method }}β Output:
Section titled ββ Output:βCompilation error: reference to method is ambiguousπ Key Points:
nullcan be assigned to any reference type- When multiple overloaded methods can accept
null, Java canβt determine which one to call- Most specific type wins when thereβs no ambiguity
- Explicit casting resolves ambiguity
π§ͺ Example 6: Constructor Chaining and Initialization Order
Section titled βπ§ͺ Example 6: Constructor Chaining and Initialization Orderβclass A { static { System.out.println("A static block"); } { System.out.println("A instance block"); }
A() { System.out.println("A constructor"); }}
class B extends A { static { System.out.println("B static block"); } { System.out.println("B instance block"); }
B() { System.out.println("B constructor"); }}
class C extends B { static { System.out.println("C static block"); } { System.out.println("C instance block"); }
C() { System.out.println("C constructor"); }}
public class Test { public static void main(String[] args) { System.out.println("Creating C object:"); new C();
System.out.println("\nCreating another C object:"); new C(); }}β Output:
Section titled ββ Output:βA static blockB static blockC static blockCreating C object:A instance blockA constructorB instance blockB constructorC instance blockC constructor
Creating another C object:A instance blockA constructorB instance blockB constructorC instance blockC constructorπ Key Points:
- Static blocks execute once per class when class is loaded
- Instance blocks execute before each constructor
- Constructor chaining: super() β instance blocks β constructor body
- Static blocks run in parent β child order
- Instance blocks run in parent β child order
π§ͺ Example 7: Exception in Static Block and Class Loading
Section titled βπ§ͺ Example 7: Exception in Static Block and Class Loadingβclass Test { static { System.out.println("Static block 1"); try { int a = 5 / 0; } catch (Exception e) { System.out.println("Caught exception in static block: " + e.getMessage()); } }
static { System.out.println("Static block 2"); }
public static void main(String[] args) { System.out.println("Main method"); }}β Output:
Section titled ββ Output:βStatic block 1Caught exception in static block: / by zeroStatic block 2Main methodπ Key Points:
- Exception in static block doesnβt always prevent class loading
- If exception is caught, class loading continues
- If exception is uncaught, class loading fails and main() never executes
- ErrorInInitializerError is thrown for uncaught exceptions in static blocks
π§ͺ Example 8: String Pool and Object Creation
Section titled βπ§ͺ Example 8: String Pool and Object Creationβpublic class StringTest { public static void main(String[] args) { String s1 = "Hello"; String s2 = "Hello"; String s3 = new String("Hello"); String s4 = new String("Hello");
System.out.println("s1 == s2: " + (s1 == s2)); // true System.out.println("s1 == s3: " + (s1 == s3)); // false System.out.println("s3 == s4: " + (s3 == s4)); // false System.out.println("s1.equals(s3): " + s1.equals(s3)); // true
String s5 = "Hello" + "World"; String s6 = "HelloWorld"; System.out.println("s5 == s6: " + (s5 == s6)); // true (compile-time concatenation)
String s7 = s1 + "World"; String s8 = "HelloWorld"; System.out.println("s7 == s8: " + (s7 == s8)); // false (runtime concatenation) }}β Output:
Section titled ββ Output:βs1 == s2: trues1 == s3: falses3 == s4: falses1.equals(s3): trues5 == s6: trues7 == s8: falseπ Key Points:
- String literals are stored in String Pool
- new String() creates new objects in heap
- Compile-time concatenation creates pooled strings
- Runtime concatenation creates new objects
- == compares references, equals() compares content
π§ͺ Example 9: Autoboxing and Unboxing Pitfalls
Section titled βπ§ͺ Example 9: Autoboxing and Unboxing Pitfallsβpublic class AutoboxingTest { public static void main(String[] args) { Integer i1 = 100; Integer i2 = 100; Integer i3 = 200; Integer i4 = 200;
System.out.println("i1 == i2: " + (i1 == i2)); // true System.out.println("i3 == i4: " + (i3 == i4)); // false
Boolean b1 = true; Boolean b2 = true; System.out.println("b1 == b2: " + (b1 == b2)); // true
Character c1 = 'A'; Character c2 = 'A'; System.out.println("c1 == c2: " + (c1 == c2)); // true
Long l1 = 100L; Long l2 = 100L; System.out.println("l1 == l2: " + (l1 == l2)); // true }}β Output:
Section titled ββ Output:βi1 == i2: truei3 == i4: falseb1 == b2: truec1 == c2: truel1 == l2: trueπ Key Points:
- Integer cache: -128 to 127 (inclusive) are cached
- Boolean, Character, Long have similar caching for small values
- Always use equals() for wrapper class comparisons
- == works for cached values but fails for others
π§ͺ Example 10: Thread Execution Order
Section titled βπ§ͺ Example 10: Thread Execution Orderβpublic class ThreadTest { public static void main(String[] args) { System.out.println("Main thread: " + Thread.currentThread().getName());
Thread t1 = new Thread(() -> { System.out.println("Thread 1: " + Thread.currentThread().getName()); });
Thread t2 = new Thread(() -> { System.out.println("Thread 2: " + Thread.currentThread().getName()); });
t1.start(); t2.start();
System.out.println("Main thread ending"); }}β Output (order may vary):
Section titled ββ Output (order may vary):βMain thread: mainMain thread endingThread 1: Thread-0Thread 2: Thread-1π Key Points:
- Thread execution order is not guaranteed
- Main thread may complete before or after other threads
- Thread scheduling is controlled by OS
- join() can be used to wait for thread completion
π₯ Pro Interview Tips
Section titled βπ₯ Pro Interview Tipsβ| Trick | How to Handle |
|---|---|
finally overriding return | Mention explicitly |
null method overloading | Look for the most specific type |
| Static vs instance | Know which resolves at compile vs runtime |
| Constructor chain | Trace parent β child |
main() variants | JVM only calls main(String[] args) |
| String pool behavior | Understand literal vs new String() |
| Autoboxing cache | Know the cached ranges |
| Thread execution order | Order is not guaranteed |
| Exception in static blocks | Check if caught or uncaught |
π― Common Interview Patterns
Section titled βπ― Common Interview Patternsβ- Static vs Instance: Always check if method is static or instance
- Null handling: Look for null pointer scenarios
- Exception flow: Trace exception handling carefully
- Object lifecycle: Understand when objects are created/destroyed
- Memory management: Know about string pool, autoboxing cache
- Thread behavior: Remember thread execution is unpredictable
- Constructor chaining: Always trace parent β child order
- Method resolution: Static at compile time, instance at runtime