I am about to create a factory which creates objects of a certain type T which extends a certain class A and another interface I. However, T must not be known. Here are the minimum declarations:
public class A { }
public interface I { }
This is the factory method:
public class F {
public static <T extends A & I> T newThing() { /*...*/ }
}
This compiles all fine.
When I try to use the method the following works fine:
A $a = F.newThing();
...while this does not:
I $i = F.newThing();
The compiler complains:
Bound mismatch: The generic method newThing() of type F is not applicable for the arguments (). The inferred type I&A is not a valid substitute for the bounded parameter
I can't understand why. It is clearly stated that "newThing returns something of a certain type T which does extend the class A and implement the interface I". When assigning to A everything works (since T extends A) but assigning to I does not (because of what?, clearly the thing returned is both an A and an I)
Also: When returning an object, say B of the type class B extends A implements I
, I need to cast it to the return type T, although B matches the bounds:
<T extends A & I> T newThing() {
return (T) new B();
}
However, the compiler does not throw any warnings like UncheckedCast or the like.
Thus my question:
--
EDIT: Here the complete code snippet which totally works using Eclipse 3.7, project set up for JDK 6:
public class F {
public static class A { }
public static interface I { }
private static class B extends A implements I { }
public static <T extends A & I> T newThing() {
return (T) new B();
}
public static void main(String... _) {
A $a = F.newThing();
// I $i = F.newThing();
}
}
EDIT: Here is a complete example with methods and invocation which does work at runtime:
public class F {
public static class A {
int methodA() {
return 7;
}
}
public static interface I {
int methodI();
}
private static class B extends A implements I {
public int methodI() {
return 12;
}
}
public static <T extends A & I> T newThing() {
return (T) new B();
}
public static void main(String... _) {
A $a = F.newThing();
// I $i = F.newThing();
System.out.println($a.methodA());
}
}
Whenever you want to restrict the type parameter to subtypes of a particular class you can use the bounded type parameter. If you just specify a type (class) as bounded parameter, only sub types of that particular class are accepted by the current generic class. These are known as bounded-types in generics in Java.
To declare a bounded type parameter, list the type parameter's name, followed by the extends keyword, followed by its upper bound, which in this example is Number . Note that, in this context, extends is used in a general sense to mean either "extends" (as in classes) or "implements" (as in interfaces).
Multiple BoundsBounded type parameters can be used with methods as well as classes and interfaces. Java Generics supports multiple bounds also, i.e., In this case, A can be an interface or class. If A is class, then B and C should be interfaces. We can't have more than one class in multiple bounds.
Generics means parameterized types. The idea is to allow type (Integer, String, … etc., and user-defined types) to be a parameter to methods, classes, and interfaces. Using Generics, it is possible to create classes that work with different data types.
As for the second question:
Consider this case:
class B extends A implements I {}
class C extends A implements I {}
Now, the following uses type inference:
<T extends A & I> T newThing() {
return (T) new B();
}
So you could call this:
C c = F.newThing(); //T would be C here
You see that T
could be anything that extends A
and I
you can't just return an instance of B
. In the case above the cast could be written as (C)new B()
. This would clearly result in an exception and thus the compiler issues a warning: Unchecked cast from B to T
- unless you're supressing those warnings.
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