15

Recently I was playing around with some simple Java code using main methods to quickly test the code I wrote. I ended up in a situation where I had two classes similar to those:

public class A {
    public static void main(String[] args) {
        // code here
    }
}



public class B extends A {
    public static void main(String[] args) throws IOException {
        // code here
    }
}

I was quite surprised that the code stopped compiling and Eclipse complained that Exception IOException is not compatible with throws clause in A.main(String[]).

Well, both methods are static and the main function in B is just hiding the one from A, so I thought that there is completely no relation between them. In static methods we have no polymorphism and the call is bound to the concrete method implementation during the compilation, therefore I cannot understand why main in B cannot throw exception that is not declared in main signature in A.

Why Java designers decided to enforce a constraint like this and in what situations it would cause problems if the constraint was not enforced by the compiler?

Paweł Chorążyk
  • 3,584
  • 3
  • 27
  • 33

4 Answers4

6

For what it's worth, here is the relevant portion of the JLS that enforces this rule.

First, §8.4.8.2. Hiding (by Class Methods) gives a definition for method hiding that applies here:

If a class C declares or inherits a static method m, then m is said to hide any method m', where the signature of m is a subsignature (§8.4.2) of the signature of m', in the superclasses and superinterfaces of C that would otherwise be accessible to code in C.

Then, §8.4.8.3. Requirements in Overriding and Hiding states that:

A method that overrides or hides another method, including methods that implement abstract methods defined in interfaces, may not be declared to throw more checked exceptions than the overridden or hidden method.

More precisely, suppose that B is a class or interface, and A is a superclass or superinterface of B, and a method declaration m2 in B overrides or hides a method declaration m1 in A. Then:

  • If m2 has a throws clause that mentions any checked exception types, then m1 must have a throws clause, or a compile-time error occurs.

  • For every checked exception type listed in the throws clause of m2, that same exception class or one of its supertypes must occur in the erasure (§4.6) of the throws clause of m1; otherwise, a compile-time error occurs.

In other words, the error message is not some oversight in the compiler, or a misinterpretation of the spec; the JLS makes the specific effort to mention that throws clause conflicts are an error with method hiding (i.e., with static methods). There is equivalent language to this in every version of the JLS back to 1.0.

However, I can't definitively answer your question of why the constraint is present in this case. I can't conceive of any situation in which the constraint is necessary, since the issue of which static method implementation is invoked is always completely resolved at compile-time, unlike for instance methods.

I'd bet a small amount of money that whoever first put that constraint in the langspec was simply being over-cautious, figuring it was safer to prevent something than to allow it and then later discover it causes problems. The Java language design is/was not without its fair share of flawed features (checked exceptions being one of them), and this could credibly be another, but this is just a guess.

Community
  • 1
  • 1
Boann
  • 48,794
  • 16
  • 117
  • 146
2

I've never have realised about this fact, but after analyzing it accurately, I see no reason why the compiler should enforce such a constraint. Altough it didn't, there would be no possible incoherence when matching the main method, for the linking of a static method is also static. No overriding is allowed in this case.

Little Santi
  • 8,563
  • 2
  • 18
  • 46
  • 1
    Your post looks like confirmation of problem described by OP rather than answer (unless I missed something - it is late where I live). – Pshemo Aug 10 '15 at 22:53
  • 3
    The author asks "In what situations would it cause problems" and I answered "I can't see anyone". That's an answer. – Little Santi Aug 10 '15 at 23:04
  • 2
    I see what you mean, but that still doesn't seem to explain a lot, it simply confirms OP suspicions that there shouldn't be any problem. So for me it looks like "I agree" which is more like comment than answer. – Pshemo Aug 10 '15 at 23:11
1

The point is that we are talking about static methods, which indeed are not supposed to be impacted by polymorphism. However, it seems to me that static methods belong to a Class object, which just like any other object should obey to polymorphism, right ?

Francis Toth
  • 1,595
  • 1
  • 11
  • 23
  • Polymorphism applies only to method which are not private, final or static. – Pshemo Aug 10 '15 at 22:30
  • By the way, this seems to be a duplicate of this [question](http://stackoverflow.com/questions/2223386/why-doesnt-java-allow-overriding-of-static-methods) – Francis Toth Aug 10 '15 at 22:31
  • 1
    It's not a duplicate as I'm not wondering why overriding static methods is not possible - I know that static methods are completely different from instance methods and the polymorphism doesn't work there, which is the main discussion point in the thread you link to. – Paweł Chorążyk Aug 10 '15 at 22:36
-3

The 'extends' keyword means that you are inheriting the methods from Class A when you declare Class B. Since you Class A is the parent class of Class B, the main method's declaration still lies in Class A despite the fact that you are redefining it in Class B.

When you are dealing with static methods, the parent class method is not overwritten by the subclass, it is simply hidden.

http://docs.oracle.com/javase/tutorial/java/IandI/override.html

Can provide more detail but here is an excerpt:

The distinction between hiding a static method and overriding an instance method has important implications:

The version of the overridden instance method that gets invoked is the one in the subclass. The version of the hidden static method that gets invoked depends on whether it is invoked from the superclass or the subclass.


original answer

This constraint is forced by the compiler to help simplify inheritance in more complicated hierarchies.

Take the toString() method for example. It is inherited by every object in Java, imagine if you were able to override the declaring of this method to allow subclasses to throw different exceptions. That is a recipe for disaster in terms of handling all of those potentially new exceptions.

TLDR- The compiler forces you to obey the parent class function definition so other programmers can sleep at night.

dbenson
  • 326
  • 1
  • 4
  • 5
    The key here is that main is a `static` method, seems like you've overlooked that part of the question entirely. Polymorphism does not apply to `static` methods. EDIT: I remember hearing this changed in Java 8, which for full disclosure I have not used. – Charles Durham Aug 10 '15 at 22:23