25
public class TestMain {

    public static void methodTest(Exception e) {
        System.out.println("Exception method called");
    }

    public static void methodTest(Object e) {
        System.out.println("Object method called");
    }

    public static void methodTest(NullPointerException e) {
        System.out.println("NullPointerException method called");
    }

    public static void main(String args[]) {
        methodTest(null);
    }   
}

Output: NullPointerException method called

xehpuk
  • 7,814
  • 3
  • 30
  • 54
Anil Gowda
  • 446
  • 3
  • 12
  • 6
    What happens if you use `methodTest((Object)null);`? or `methodTest((Exception)null);`? – MadProgrammer Feb 12 '15 at 06:15
  • 1
    if methodTest((Object)null) is used then output is "Object method called". if methodTest((Exception)null) is used then output is "Exception method called". – Anil Gowda Feb 12 '15 at 06:19
  • So `null` isn't a `NullPointerException`, why the compiler is choosing to call that method when the call is ambiguous, I don't know. – MadProgrammer Feb 12 '15 at 06:20
  • There really should be a compiler warning here... – helb Feb 12 '15 at 06:22
  • Compiler warning is not thrown and should be fine with methodTest(null). However, methodTest((Object)null) and methodTest((Exception)null) should get a compiler warning but even that is missing – Anil Gowda Feb 12 '15 at 06:23
  • Note: The term for this is [method overloading](https://en.wikipedia.org/wiki/Function_overloading). – sleske Feb 12 '15 at 09:39
  • Why do you believe that should that get a compiler warning? Can you explain your thinking here? Suppose that instead of exceptions, the methods took Object, Fruit and Banana, where Fruit derives from Object and Banana derives from Fruit. Would you expect a warning in that case too? – Eric Lippert Feb 12 '15 at 17:10

2 Answers2

38

If there are several overloaded methods that might be called with a given parameter (null in your case) the compiler chooses the most specific one.

See http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.12.2.5

In your case methodTest(Exception e) is more specific than methodTest(Object e), since Exception is a subclass of Object. And methodTest(NullPointerException e) is even more specific.

If you replace NullPointerException with another subclass of Exception, the compiler will choose that one.

On the other hand, if you make an additional method like testMethod(IllegalArgumentException e) the compiler will throw an error, since it doesn't know which one to choose.

Runcorn
  • 5,144
  • 5
  • 34
  • 52
Thomas Stets
  • 3,015
  • 4
  • 17
  • 29
  • Wrong when `IllegalArgumentException` is used it will call the `methodTest(Exception e)`. – Runcorn Feb 12 '15 at 06:24
  • 2
    @Runcorn Did you actually try that? It works as described by my answer here. – Thomas Stets Feb 12 '15 at 06:28
  • Complier throws an error if both public static void methodTest(NullPointerException e) { System.out.println("NullPointerException method called"); } public static void methodTest(ArrayIndexOutOfBoundsException e) { System.out.println("ArrayIndexOutOfBoundsException method called"); } are present and prints "ArrayIndexOutOfBoundsException method called " if only public static void methodTest(ArrayIndexOutOfBoundsException e) { System.out.println("ArrayIndexOutOfBoundsException method called"); } is present – Anil Gowda Feb 12 '15 at 06:31
  • Ah!!! Sorry I thought you were talking about the Parameter not the Method. So, you are right!! – Runcorn Feb 12 '15 at 06:31
  • But why is `NullPointerException` "more specific" to `null` than `Exception`? Does `null` inherit from `Exception`? Does `null` inherit from everything? – Patrick Collins Feb 12 '15 at 07:08
  • 5
    @PatrickCollins NullPointerException is not more specific to null, it is more specific than Exception, meaning a smaller subset of all possible parameters are valid for this one than for Exception. null is just a possible value for all three methods. – Thomas Stets Feb 12 '15 at 07:15
  • @PatrickCollins *"Does null inherit from everything?"* The null type has a single value, `null`, which can be converted to any other reference type. That's how it works in Java. – Radiodef Feb 12 '15 at 07:57
  • @ThomasStets Ah, okay. So `null` will convert to whatever is farthest away from `Object` in the inheritance hierarchy? – Patrick Collins Feb 12 '15 at 10:01
  • @PatrickCollins yes, if you have only one path through the hierarchy. If there are several possible hierarcies (A extends Object, B extends A, C extends Object) the compiler will balk, since it doesn't know which branch to choose. – Thomas Stets Feb 12 '15 at 11:47
  • I believe the answer should also explain *why*, when using null as argument, this ends up in having NullPointerException as the most specific match. John Jaques's answer adds this information. – Shivan Dragon Feb 12 '15 at 14:48
  • 2
    @PatrickCollins: You are using the word "inherit" in a strange way; a type *inherits* from another when a derived type has all the members of a base type. I think you are using "inherit" to mean "is implicitly convertible to", which is a very different thing. Null is *implicitly convertible* to many types but that doesn't mean that a null expression is of a type that has all the *members* of every other type. – Eric Lippert Feb 12 '15 at 17:12
  • 2
    @PatrickCollins: To address our question "null will convert to whatever is farthest away from object?" -- sort of. The better way to think about it is: null is convertible to many types. Of those conversions, some are *better* than others. A conversion to a *more specific* type is *better* than a conversion to a *less specific* type. The job of overload resolution is to deduce the *best* method given a bunch of -- possibly contradictory -- "betterness" relationships amongst the various conversions. – Eric Lippert Feb 12 '15 at 17:16
  • 1
    @PatrickCollins: So for example if you had types Object, Animal, Turtle, and Banana, with the obvious relationships between them, and overloads that took Object, Turtle and Banana, Turtle does not win because it is farther from Object than Banana. Rather, neither would win. Turtle is more specific than Object, so that eliminates Object, but neither Turtle nor Banana is more specific than the other, so neither would be "best", and overload resolution would give an error. – Eric Lippert Feb 12 '15 at 17:19
9

The compiler will try to match with the most specific parameter, which in this case is NullPointerException. You can see more info in the Java Language Specification, section 15.12.2.5. Choosing the Most Specific Method :

If more than one member method is both accessible and applicable to a method invocation, it is necessary to choose one to provide the descriptor for the run-time method dispatch. The Java programming language uses the rule that the most specific method is chosen.

The informal intuition is that one 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.

[...]

sleske
  • 81,358
  • 34
  • 189
  • 227
John Jaques
  • 560
  • 4
  • 17
  • In [Java Puzzlers](http://www.javapuzzlers.com/) by Joshua Bloch and Neal Gafter, there is a puzzle dedicated to this "most-specific method" behavior. – Timmos Feb 12 '15 at 12:03