I have a question about generics. So lets say I have 3 classes "Foo", "Bar" (which is a subclass of Foo), a class "Factory" and an interface "TestInterface". I want to write a generic method, that only allows objects which "directly" implement the interface, so no subclasses. It is pretty hard for me, since Java8 seems to be "smarter" than Java7.
So heres an example:
public interface TestInterface<T extends TestInterface<T>> {
}
public class Foo implements TestInterface<Foo>{
}
public class Bar extends Foo {
}
public class Factory {
public static <T extends TestInterface<T>> T doSth(T arg) {
return arg;
}
}
Okay, these are my classes. Now in the doSth(T arg)
method I want to allow Foo-objects in this case, since it's the only class which "directly" implements the Interface.
Obviously sth like this won't compile now:
Bar b = Factory.doSth(new Bar());
since Bar doesnt implement TestInterface<Bar>
.
Okay my problem now is, that this line will compile without any issues:
Foo f = Factory.doSth(new Bar());
Even tho the generic parameter is T and T should implement the interface with its own class (sorry, dont really know how to say it, hope you know what I mean), the compiler accepts "Bar" as a parameter.
So the compiler must behave like "okay Bar doesn't fit, but maybe a superclass would fit." And then it "sees" that it works with the superlcass "Foo". And then the Bar will be treated like a Foo, since every Bar is some kind of a Foo or sth like that?? At least that's how I imagine it.
Well, if I try to compile the line with Java7, it fails. So it seems like Java8 is a little bit smarter with the type-erasure?!
Is there any way in Java8 to not allow subclasses, so that this won't compile?:
Foo f = Factory.doSth(new Bar());
Hope you understand my problem, I'm rarely writing in English.
Greets
The reason why Foo f = Factory.doSth(new Bar());
works in Java 8 and not Java 7 is because Java 8 has better type inference. In Java 7 the type is inferred to:
Foo f = Factory.<Bar>doSth(new Bar());
Bar
doesn't implement TestInterface<Bar>
, but it does implement TestInterface<Foo>
by inheritance. Java 8's type inference got a boost, and the type will be inferred to:
Foo f = Factory.<Foo>doSth(new Bar());
Note that Factory.<Foo>doSth()
expects a Foo
as argument so new Bar()
is implicitly cast to Foo
which works fine.
I'm afraid there's no way around this. You will always be able to upcast an object to its super class. You could make Foo
final
, but that disallows subclassing of Foo
entirely.
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