I think that, for the most part, I understand bounded types, and the differences between, for example, List<? extends MyClass>
, List<? super MyClass>
and List<MyClass>
. But when it comes to the implementation of classes and generic methods, I do not understand what <T extends MyClass>
brings to the table.
Taken from the docs in Oracle:
[...] a method that operates on numbers might only want to accept instances of Number or its subclasses. This is what bounded type parameters are for.
public class Box<T> { private T t; public void set(T t) { this.t = t; } public T get() { return t; } public <U extends Number> void inspect(U u){ System.out.println("T: " + t.getClass().getName()); System.out.println("U: " + u.getClass().getName()); } public static void main(String[] args) { Box<Integer> integerBox = new Box<Integer>(); integerBox.set(new Integer(10)); integerBox.inspect("some text"); // error: this is still String! } }
This doesn't make much sense to me. If I removed the generic from the method and made the parameter type just Number
...
public void inspect(Number u){
System.out.println("T: " + t.getClass().getName());
System.out.println("Second: " + u.getClass().getName());
}
it would still work just fine. I don't see where I'm gaining or losing type safety, although maybe that's not the point?
Same in something like this:
class A { void foo() { } }
class B extends A { void bar() { } }
class Generic<T extends B> {
void baz(T obj) {
obj.foo();
obj.bar();
}
}
// vs
class NonGeneric {
void baz(B obj) {
obj.foo();
obj.bar();
}
}
What's the difference between these?
In your examples there is no practical difference.
The main practical difference is when you have return types using the generic.
But even without that, Generic<T extends B>
and NonGeneric
are not the same, because if we have class C extends B
, then Generic<C>
is not the same as NonGeneric
, since the NonGeneric
would allow non-C objects in the call to baz
, and that's wrong.
In Generic
class baz
function only accept T
type value but in NonGeneric
class you can give any object those can cast to B.
Example:
public class Main {
public static void main(String[] args) throws Exception {
Generic<C> generic = new Generic<C>();
generic.baz(new B()); // error
generic.baz(new C()); // works fine
generic.baz(new D()); // error
NonGeneric nonGeneric = new NonGeneric();
nonGeneric.baz(new B()); // works fine
nonGeneric.baz(new C()); // works fine
nonGeneric.baz(new D()); // works fine
}
static class A {
void foo() {}
}
static class B extends A {
void bar() {}
}
static class C extends B {}
static class D extends B {}
static class Generic<T extends B> {
void baz(T obj) {
obj.foo();
obj.bar();
}
}
static class NonGeneric {
void baz(B obj) {
obj.foo();
obj.bar();
}
}
}
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