4

I'm practicing some examples in Java. The code looks like this:

public class NullPassing {
    public static void main(String[] args) {
        method1(null);
    }
    public static void method1(Exception e) {
        System.out.println(e);
    }
    public static void method1(ArithmeticException e) {
        System.out.println(e);
    }
}

I have few questions regarding this,

1) The above code executes and prints null by using method1(ArithmeticException e), Why isn't it using Exception(Since its tops the hierarchy) ?

Guess: Is it because of more specific variable ArithmeticException specific compared to Exception. If that's the case, why Question-2

2) By introducing the following method to the existing code, program shows compile time exception. Why?

public static void method1(NullPointerException e) {
    System.out.println(e);
}

Help me learn. Thanks

srikanth
  • 958
  • 16
  • 37
  • Your second question is really unclear to me. You already know that the compiler will select the overloaded version with the more specific type, but you wonder why it can't determine which type is more specific between `NullPointerException` and `ArithmeticException`? – Tom Feb 19 '16 at 12:35

3 Answers3

2

We have two candidates,

 public static void method1(Exception e) {
 }
 public static void method1(ArithmeticException e) {
 }

We pass a null and both methods accept nulls, so we choose the more specific one, ArithmeticException is an Exception but the opposite is not true, and hence ArithmeticException is more specific.

Now we have three candidates

public static void method1(Exception e) {
}
public static void method1(ArithmeticException e) {
}
public static void method1(NullPointerException e) {
}

The first one is out of the equation because there are more specific ones, so we are left with two candidates, one that takes NullPointerException and the other takes ArithmeticException, both are on the same level, and hence we have an ambiguous call.

Sleiman Jneidi
  • 22,907
  • 14
  • 56
  • 77
  • 1
    Wow, never occured to me that the more specific overload is always the chosen one. – Pieter De Bie Feb 19 '16 at 12:24
  • @PieterDeBie Although it is not exactly comparable (since the dispatch still is static), overloading behaves similar to polymorphism: if you override a method in a subclass, then this more specific method gets chosen. I would therefore argue that overloading would cause lots of surprises (or bugs) if it behaved the other way round. – nd. Feb 19 '16 at 12:36
2

Your answer to 1 is correct. Given the choice where two or more overloads are candidate, and one of them is more specific than all of the others, the most specific one is chosen.

The JLS says this (Section 15.12.2.5):

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 error.

(It then explains formally what "more specific" means.)


In your second case / question, you have this:

public class NullPassing {
    public static void main(String[] args) {
        method1(null);
    }
    public static void method1(Exception e) {
        System.out.println(e);
    }
    public static void method1(ArithmeticException e) {
        System.out.println(e);
    }
    public static void method1(NullPointerException e) {
        System.out.println(e);
    }  
}

Now we have three candidates (methods that are "accessible and applicable"). The first one is less specific than the other two, but neither of the two remaining candidates is more specific than the other. Therefore this is a compilation error.

Obviously, you can disambiguate the call by casting the null; e.g.

  method1((NullPointerException)null)
Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
1

1. Why does it use ArithmeticException?

Java tries to select the most specific overloaded method for any object type. The null object is of type "[special null type]" which is a subtype of all non-primitive type; therefore the most specific subtype is ArithmeticException.

For more information on how the Java compiler does resolve overloading, see this answer: https://stackoverflow.com/a/7199189/112964

2. Why does the program not compile if you add a NullPointerException?

Once you have serveral overloads that are not in the same inheritance hierarchy, the Java compiler gets more than one possible candidate for the most specific overload: both method1(NullPointerException) and method1(ArithmeticException) are the most specific candidates. Therefore, you must tell the compiler what you actually want by casting null to the overloaded type: e.g. method1((NullPointerException)null).

For more information about ambiguous overloads, see https://stackoverflow.com/a/5229890/112964

Community
  • 1
  • 1
nd.
  • 8,699
  • 2
  • 32
  • 42