Monday, February 12, 2007

No way to access overridden methods of superclass of superclass in Java

Let us consider an example:

public class Test2 {
static class TestClass1 {
int x = 1;
String test() {
return "1";
}
}

static class TestClass2 extends TestClass1 {
int x = 2;
String test() {
return "2";
}
}

static class TestClass3 extends TestClass2 {
int x = 3;
int testX() {
return ((TestClass1)this).x;
}
String test() {
return super.test();
}
}

public static void main(String[] args) {
TestClass3 obj = new TestClass3();
System.out.println(obj.testX());
System.out.println(obj.test());
}
}

It produces expected output

1
2


The point is that there is no way to call test() method of TestClass1 class!

super.super.test()

won't compile but

((TestClass1)this).test()

will produce java.lang.StackOverflowError.

Despite on we can access superclass members of any level by casting this to appropriate class (see The Java Language Specification at http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.11.2), polymorphism allows us to access immediate superclass only, not overridden methods of higher levels (see The Java Language Specification at http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.12.4.9).

Break and continue statements will stop exception flow

As it is said in The Java Language Specification (http://java.sun.com/docs/books/jls/third_edition/html/statements.html#14.15):
"The preceding descriptions say "attempts to transfer control" rather than just "transfers control" because if there are any try statements within the break target whose try blocks contain the break statement, then any finally clauses of those try statements are executed, in order, innermost to outermost, before control is transferred to the break target. Abrupt completion of a finally clause can disrupt the transfer of control initiated by a break statement."
Let's look into next example:

public class Test {
private static void test() throws Exception {
for (int i = 0; i < 3; i++) {
try {
throw new Exception("Exception text");
} finally {
System.out.println("Finally exception " + i);
continue;
}
}
System.out.println("Impossible");
}

public static void main(String[] args) throws Exception {
test();
System.out.println("Impossible 2");
}
}

will produce output:

Finally exception 0
Finally exception 1
Finally exception 2
Impossible
Impossible 2


So, be extremely careful with your breaks!