Matthew Brown wrote:Hi. Welcome to The Ranch!
Remember that when you override a method and want to change the return type, you can only change it to something more specific. Number is not more specific than N extends Number, it's less.
For a concrete example, consider this implementation:
If Number was allowed as a return type, that would be a perfectly valid implementation. But what happens when I do this?
Also, should be valid. But in that last line, obj.get() is returning a Double object. So we've lost the type safety. So the compiler can't allow it.
I haven't confirmed it, but I suspect class SubClass<N super Number> will allow Number as a return type.
Edit: See UbbCode for details about what formatting is available.
If debugging is the process of removing bugs, then programming must be the process of putting them in. -- Edsger Dijkstra
Dennis Deems wrote:SubClass extends SuperClass<N>. So get() must return N, not Number.
OCPJP 6.
In Your Pursuit Towards Certification, NEVER Give Up.
Sarah Rising wrote:As has already been discussed, according to the compiler, SubClass.get() is not a valid override of SuperClass.get() and that is because the return type of Sub Class.get() is not return-type substitutable for the return type of SuperClass.get(). The confusion, for me, is why that is, beings it seems the return type of Super Class.get() is (N extends Number) whose erasure is Number.
Sarah Rising wrote:
- SubClass.get2() is a valid override of Super Class.get2(). The only difference between SubClass.get() and SubClass.get2() is the name. But in SuperClass, get2() has been made a generic method with a type variable "U" with an upper bound of Number. So the compiler knows Super Class.get2()'s return type is bounded from above by Number. Therefore, in the terminology of the definition of return-type-substitutability R2 = N extends Number, its erasure is Number and, since the compiler recognizes SubClass.get2() a valid override of Super Class.get(), it is clearly saying the return types of the get2() methods are return-type-substitutable. Yet it didn't do that for the (2) get() methods. Note that the type parameter for SuperClass.get2() could also just be "U" without the "extends Number" and it would still be validly overriden by SubClass.get2().
Henry Wong wrote:Actually, I don't think that this is a valid override either.... however, it looks like you only get off with a warning error, in this case. Not completely sure why.
Ikpefua Jacob-Obinyan wrote:Hello Sarah,
This is my personal point of view, observe VERY CAREFULLY:
Superclass:
public T get() { ... }
This method accepts T and anything that Is-a T. (covariant returns, in accordance with the java specification).
When you you say:
Subclass:
class SubClass<N extends Number> extends SuperClass<N> { }
The superclass's method now looks like This:
public N get() { ... }
This method accepts N and anything that Is-a N. (covariant returns, in accordance with the java specification).
Your subclass's method returns Number and 'Number' IS-NOT-A 'N' so the compiler complains!.
I hope this helps.![]()
Henry Wong wrote:
Sarah Rising wrote:As has already been discussed, according to the compiler, SubClass.get() is not a valid override of SuperClass.get() and that is because the return type of Sub Class.get() is not return-type substitutable for the return type of SuperClass.get(). The confusion, for me, is why that is, beings it seems the return type of Super Class.get() is (N extends Number) whose erasure is Number.
The type after erasure is Object -- and the reason for erasure is that generics doesn't exist in the class files. That is the only reason that it is erased. It doesn't mean that the type is an Object during compile time though. So.... everything you said (with the exception of the erasure part) is correct. All type information is kept during compilation, just pretend that erasure doesn't exist when looking at this.
Henry
Sarah Rising wrote:
Note that SubClass is parameterized with (N extends Number) and extends Superclass<N>. If Superclass<N>.get() looks like "N get()" then why does SuperClass<N>.add() look like "void add( N extends Number)" (which it would have to do so that SubClass.add() would be a subsignature of SuperClass.add() and thereby be an override of SuperClass.add() )?
Sarah Rising wrote:
That is, why does the compiler only consider "T" to be "N" for the return type of SuperClass.get() but the "T" of SuperClass.add() is taken to be "N extends Number". That's my confusion. If I can get that answered, I think there's a good chance all this might make sense?
Henry Wong wrote:
Sarah Rising wrote:
- SubClass.get2() is a valid override of Super Class.get2(). The only difference between SubClass.get() and SubClass.get2() is the name. But in SuperClass, get2() has been made a generic method with a type variable "U" with an upper bound of Number. So the compiler knows Super Class.get2()'s return type is bounded from above by Number. Therefore, in the terminology of the definition of return-type-substitutability R2 = N extends Number, its erasure is Number and, since the compiler recognizes SubClass.get2() a valid override of Super Class.get(), it is clearly saying the return types of the get2() methods are return-type-substitutable. Yet it didn't do that for the (2) get() methods. Note that the type parameter for SuperClass.get2() could also just be "U" without the "extends Number" and it would still be validly overriden by SubClass.get2().
Actually, I don't think that this is a valid override either.... however, it looks like you only get off with a warning error, in this case. Not completely sure why.
Henry
Sarah Rising wrote:
I believe it is a valid override, at least as defined in the JLS. (http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.4.8.1) The definition only concerns itself with whether the subclass method signature is a subsignature of the superclass method signature, and a few other items that the situation here clear satisfies. And clearly the get()'s in SubClass and SuperClass satisfy the definition. Return types only come into the picture later on in the JLS when the spec is defining various compiler errors. I suppose semantic hairs could be split, but... Anyway, if I'm unconvinced on whether my own calculations of whether one method should override another one, I just check with the @Override annotation. In this case, it tells me, it's an override. You're right, though, there is an unchecked warning. Still, I take that as an indication that the compiler is passing it as a valid override.
Regards