We are all taught Java has single inheritance (each class may extend 0 or 1 class). We're also taught about the keyword final meaning no class may extend this one. Finally, we all know that abstract classes cannot be instantiated.
I'm now asking you to call TypePuzzle.puzzle with objects that get it to print "Good solution". The method classPuzzle does a number of checks:
child directly extends Object
child has (at least) two more supertypes
those supertypes are unrelated abstract final classes, whose instances are parent1 and parent2, respectively
Have fun! :-)
This message was edited 1 time. Last update was at by Istvan Kovacs
Ernest Friedman-Hill
author and iconoclast
Marshal
Don't think that because no one has replied, no one is interested. This is a good one! I'm waiting for my old buddy Mike to stop by and tell us the answer though...
Campbell Ritchie wrote:Unrelated abstract final classes? Can you have an abstract final class at all?
The compiler won't let you create one, but that doesn't mean the JVM can't make one for you.
Istvan Kovacs
Ranch Hand
Joined: May 06, 2010
Posts: 98
posted
0
Campbell Ritchie wrote: abstract final classes? Can you have an abstract final class at all?
That's not the only weirdness here :-)
Those classes are final, yet they'll have a subclass. They're also abstract, yet you'll need to pass an instance of each. You can even instantiate such a class without using the keyword new, but if you wish, you can use it.
If there's no solution within a few days, I'll post an even more specific pointer to the relevant section of the JLS. After that, the solution becomes trivial.
Mike Simmons
Ranch Hand
Joined: Mar 05, 2008
Posts: 1941
posted
0
Nice one, Istvan!
This message was edited 1 time. Last update was at by Mike Simmons
Mike Simmons
Ranch Hand
Joined: Mar 05, 2008
Posts: 1941
posted
0
(And hi, EFH!)
Istvan Kovacs
Ranch Hand
Joined: May 06, 2010
Posts: 98
posted
0
Mike Simmons wrote:
Nice one, Istvan!
Glad you liked it :-)
The idea came while I was writing an in-house training material on generics, and I wanted to show participants the differences between class hierarchies of arrays and typed ArrayList.
Campbell Ritchie wrote:Unrelated abstract final classes? Can you have an abstract final class at all?
The compiler won't let you create one, but that doesn't mean the JVM can't make one for you.
but how can i tell JVM that i want one ?
Preparing SCJP 1.6
Istvan Kovacs
Ranch Hand
Joined: May 06, 2010
Posts: 98
posted
0
Anil Bharadia wrote:but how can i tell JVM that i want one ?
You cannot ask the JVM to create one, they will be created automatically. Read on to find out why:
The abstract, final classes in question are arrays.
When you create a type (e.g. MyClass), the JVM creates the corresponding array class automatically.
So, for each type (class or interface, what's more, even primitive types, like int), you have an array class that corresponds to it:
int.class -> int[].class
String.class -> String[].class
MyClass.class -> MyClass[].class
(If you are confused with the .class thing, it denotes the object representing the type. For example:
The solution Mike has posted here used pre-defined types, but to understand what's going on, you can create ones of your own.
By defining those interfaces and the class, you (get the JVM to) also implicitly define the corresponding array classes.
A.class -> A[].class
B.class -> B[].class
C.class -> C[].class
According to the Java Language Specification (JLS), if for two types it is true that
then it also holds that
Since class C implements both interfaces A and B, both will become supertypes (not superclasses!) of C, which means that a reference of interface A or B may be set to point to an instance of class C:
This means that
will hold, and thus
will also hold.
You cannot extend an array class, which made me suspect that they are final. Upon examining their modifiers (see lines 25-27 of the original puzzle code where superIsFinalAbstractClass is calculated), I found they were also abstract, which just made for a confusing-enough puzzle to post here.
So
is a valid solution.
In Mike's answer, he used pre-defined types Integer, Serializable and Comparable, because the Integer class implements the interfaces Serializable and Comparable, just like class C implements interfaces A and B.
Vlado Zajac
Ranch Hand
Joined: Aug 03, 2004
Posts: 243
posted
0
Istvan Kovacs wrote:
You cannot extend an array class, which made me suspect that they are final. Upon examining their modifiers (see lines 25-27 of the original puzzle code where superIsFinalAbstractClass is calculated), I found they were also abstract, which just made for a confusing-enough puzzle to post here.
They may not be abstract in other JREs. According to getModifiers() API documentations, it is not defined if array classes have abstract modifier or not.
This message was edited 1 time. Last update was at by Vlado Zajac
Ernest Friedman-Hill
author and iconoclast
Marshal
I think you just have to ignore the modifiers here. It really makes no sense for them to be abstract, as I can directly create instances with "new", and it makes no sense for them to be final because, as this puzzle shows, they enter into inheritance relationships. Maybe the "final" is helpful for a compiler, as the compiler won't let you the programmer extend such a class, and actually, the normal "new" bytecode isn't used for array objects, but rather there's a "newarray" bytecode, so perhaps the "abstract" makes sense as a signal to the compiler too.
I was also surprised to see that array classes are abstract. I was not too surprised about them being final, for the exact reason you mention, to prevent this:
Arrays forming a type hierarchy is a necessary evil: before generics, we didn't have wildcards. If Java wanted to be able to handle arrays of related classes (like being able to provide a method that can sum arrays containing Number or any of its subtypes), there was no other way but to twist the type system to allow such hierarchies. The side effect is ArrayStoreException, and multiple superclasses for some classes in a language that advocates single inheritance between classes. :-(
With generics and collections, we have a better way in the form of bounds and wildcards (T extends Number, ? extends Number). However, some generic code can look really frightening, e.g. Collections.min is defined as:
Or (generified Observer/Observable from the book 'Java Generics and Collections'):
But I'm getting off-topic :-)
This message was edited 1 time. Last update was at by Istvan Kovacs