I've got an interface containing a method with this signature :
<P extends MergeProperty<T> & RestartApplicant> List<P> loadPropertiesFrom(T p1, T p2);
Basically, MergeProperty
is a class which does NOT implement RestartApplicant
, and RestartApplicant
is a functional interface containing a method that does not really matter for the understanding of this problem.
Here is the catch. When I create a class implementing this interface, Java allows me to run without any compiling error the following code :
public class MyImplementation implements MyInterfacePreviouslyDescribed {
@Override
public List<MergeProperty<MathObject>> loadPropertiesFrom(MathObject p1, MathObject p2) {
return Arrays.asList(
// some random instances of MergeProperty that do not implement RestartApplicant
);
}
}
Obviously, I don't respect the restrictions of the implementation there. Given this signature, the list I return using Arrays.asList(...)
does NOT need to contain elements that implement RestartApplicant
. Remember, MergeProperty
doesn't implement RestartApplicant
. So this will most likely end up causing some casting error somewhere.
Still, I get a warning :
Type safety: The return type List<Main.MergeProperty<Main.MathObject>> for
loadPropertiesFrom(Main.MathObject, Main.MathObject) (...) needs unchecked
conversion to conform to List<Main.MergeProperty&Main.RestartApplicant> from the
type Main.Test<Main.MathObject>
My question is: why do I only get a warning? It seems to me that I should not be able to compile my code. Is there any particular reason for that?
Thanks in advance.
EDIT
After playing a little with my code, I figured that if I moved the "generics declaration" to the class level, which would lead to :
interface MyInterfacePreviouslyDescribed<T, P extends MergeProperty<T> & RestartApplicant>
instead of just
interface MyInterfacePreviouslyDescribed<T>
and obviously
List<P> loadPropertiesFrom(T p1, T p2);
instead of
<P extends MergeProperty<T> & RestartApplicant> List<P> loadPropertiesFrom(T p1, T p2);
then I actually get a compilation error if I try the same "illegal" implementation as before. It seems even more strange...
You can even do:
@Override
public List<String> loadPropertiesFrom(MathObject p1, MathObject p2) {
return Arrays.asList(
// some random instances of MergeProperty that do not implement RestartApplicant
);
}
in the first case. This is because the overridden method is not generic and erasure for these is going to be List
. Why is this allowed? I frankly don't know, may be something to do with backwards compatibility.
In your second example, it seems it should really be:
interface MyInterfacePreviouslyDescribed<T, P extends MergeProperty<T> & RestartApplicant> {
and in the implementation you are forcing the types to be correct. Actually, the second example is the intuitive one - as it does not compile; and that is expected. The first one, on the other hand relies on some compatibility rule for non-generic methods that allows to override to the same erasure.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With