Back to Methods & Varargs
Q3Question 3 of 3

With overloaded methods taking Object and String, which is called for null?

Key Concepts
  • Java picks the MOST SPECIFIC matching method – String is more specific than Object
  • process(null) calls process(String) because String is a subclass of Object
  • If two overloads are equally specific (e.g., String and Integer), the call is ambiguous and does not compile
  • To force a specific overload, cast null: process((Object) null) or process((String) null)
  • This is called the most specific method rule in the Java Language Specification

Definition

The String overload is called because String is more specific than Object. Java always picks the most specific matching method.

The overload resolution rule:

  • null is assignable to any reference type. Both process(Object) and process(String) accept null.
  • Java picks the most specific match. String extends Object, so String is more specific.
  • Result: process(null) calls process(String).
  • Ambiguity: If neither type is a subtype of the other (e.g., String and Integer), the call does not compile.

A bank form with two acceptance windows: one for "any document" (Object) and one for "passport only" (String). When you bring a null document, the bank sends you to the more specific window (passport) because it is a narrower match.

Understanding the Concepts

What happens with Object and String overloads?

JAVA
public class Dispatcher {
    public static void process(Object o)  { System.out.println("Object: " + o); }
    public static void process(String s)  { System.out.println("String: " + s); }

    public static void main(String[] args) {
        process(null);         // "String: null" – String is more specific
        process("hello");      // "String: hello" – exact match
        process((Object) null); // "Object: null" – cast forces Object overload
        process(42);           // "Object: 42" – int autoboxed to Integer, only Object matches
    }
}

null is assignable to both Object and String. The compiler picks String because it is a subclass of Object (more specific).

What happens with two equally specific types?

JAVA
public static void process(String s)  { System.out.println("String"); }
public static void process(Integer i) { System.out.println("Integer"); }

// process(null);  // COMPILE ERROR: ambiguous
// Neither String nor Integer is a subtype of the other

// Fix: cast to the desired type
process((String) null);   // "String"
process((Integer) null);  // "Integer"

What about three overloads: Object, String, CharSequence?

JAVA
public static void process(Object o)       { System.out.println("Object"); }
public static void process(CharSequence cs) { System.out.println("CharSequence"); }
public static void process(String s)        { System.out.println("String"); }

process(null);  // "String" – String is the most specific (String extends CharSequence extends Object)

The compiler walks the type hierarchy and picks the most specific type that null could be.

How does this work with varargs?

JAVA
public static void process(Object o)       { System.out.println("Object"); }
public static void process(String... args)  { System.out.println("Varargs"); }

process(null);  // "Object" – non-varargs is preferred over varargs
process((String[]) null);  // "Varargs" – explicit cast to String[]

Overload resolution prefers non-varargs over varargs when both match.

What are the resolution rules in order?

  1. Phase 1: Find exact matches without boxing or varargs.
  2. Phase 2: Allow autoboxing/unboxing but no varargs.
  3. Phase 3: Allow varargs.
  4. Among matches: Pick the most specific type.
  5. If tied: Compile error (ambiguous).

What are common mistakes?

  • Assuming null goes to Object. It goes to the most specific type, which is usually not Object.
  • Overloading with sibling types (String, Integer). Calling with null is ambiguous. Avoid this design.
  • Forgetting that varargs has lowest priority. Non-varargs matches are tried first.

What should a senior engineer know?

  • This is JLS Section 15.12.2. The "most specific method" rule is formally defined in the Java Language Specification.
  • IDE support: IntelliJ shows which overload is selected when you hover over a method call. Use it to verify.
  • Avoid overloading with null-ambiguous signatures. If two overloads can both match null, the API is confusing. Use different method names instead.

Visual Overview

DIAGRAM
  process(Object o)    process(String s)
       │                      │
       └──── null ────────────┘
             │
             ▼
    Both match. String is more specific than Object.
    → calls process(String)

  process(String s)    process(Integer i)
       │                      │
       └──── null ────────────┘
             │
             ▼
    Both match. Neither is subtype of other.
    → COMPILE ERROR: ambiguous

  Resolution order:
    1. Exact match (no boxing, no varargs)
    2. Boxing/unboxing allowed
    3. Varargs allowed
    4. Most specific type wins
    5. Tie → ambiguous → compile error

Key Takeaway

When overloaded methods accept Object and String, calling with null invokes the String version because String is more specific than Object. Java always picks the most specific matching method during overload resolution.

If two overloads have types that are neither a subtype of the other (like String and Integer), calling with null is ambiguous and does not compile. The fix is to cast: process((String) null).

This follows the JLS most specific method rule. In practice, avoid designing APIs where null could match multiple overloads. If it happens, use different method names.

One sentence to remember: Java picks the most specific overload – process(null) calls process(String) over process(Object) because String is a subtype of Object.

---

Share
Use ← → arrow keys to navigate