Please, consider my code:
class A {
}
class B extends A {
}
class AWrapper<T extends A> {
}
class BWrapper<T extends B> extends AWrapper<T> {
}
So, I have C extends B etc, and CWrapper<T extends C> extends BWrapper<T> etc.
Now, I use these classes this way:
class Test {
private Class<? extends AWrapper<? extends A>> klass;//LINE X
public Test() {
this.klass = BWrapper.class;//LINE Z
}
}
At LINE X I need to set different classes - AWrapper, BWrapper, CWrapper etc. However, at LINE Z I get an error. Could anyone help to fix it?
imho, what you are looking for is :
private Class<? extends AWrapper> klass;
even if AWrapper is raw. At least this way you could say that your parameter takes "a class that is subtype (or self) of AWrapper". But that should be the thing you care about anyway. Generics are not preserved at runtime, so no matter what Class you have there, it is going to be without its inferred parameters.
Related
I have classes that are structured like the ones below:
interface Z {}
interface Y extends Z {}
interface X extends Y {}
private static class A<T extends Z> {}
private static class B<T extends Y> extends A<T> {}
private static class C extends B<X> {}
Why is the first one valid while the second one is not?
private Class<? extends A<? extends Z>> clazz = C.class; // valid
private Class<? extends A<? extends Z>> clazzb = B.class; // error: Type mismatch: cannot convert from Class<TEST.B> to Class<? extends TEST.A<? extends TEST.Z>>
I guess it is because the type of Y is unclear in the second example but how would you be able to clarify it?
Thank you
Java Class literal constraint
Simply said; no you can't bound the Class literal assignment as B<T> is a generic type, i.e. you can have:
Class<? extends A<? extends Z>> clazzb = B<X>.class; // illegal statement
// OR
Class<? extends A<? extends Z>> clazzb = B<W>.class; // assuming W is a sub-type of X
as there is only one class literal (in terms of byte code (runtime) and in terms of language constraints (compile-time)): B.class
And since the compiler won't be able to know of which type the type parameter T would be for the B class, it won't allow such an assignment.
Legal assignment
Below assignment statement would be legal (compiles fine):
Class<? extends A> clazzb = B.class;
but with warnings and that would perfectly complies with the Generic Class and Type Parameters Java Language Specification.
I've seen many times a Java specific-pattern where developers work-around the compiler type-check with a generic utility method inferring its return type to match the assigned reference type:
<!-- language : lang-java -->
#SuppressWarnings("unchecked")
public static <T> Class<T> inferType(Class<?> clazz) {
return (Class<T>) clazz;
}
Then you would be able to perform what used to be forbidden:
Class<? extends A<? extends Z>> clazzb = generify(B.class);
Note that this should be nothing but a non-recommended workaround. Just to let you be more sure, here down a quite confusing statement that compiles just fine:
Class<C> clazzb = generify(A.class);
At first glance, that should not work, but it will as you are assigning a class literal to a class reference after all.
I'm really confused of how upper bounded types work in Java generics.
Let's say I have
interface IModel<T>
interface I
class A implements I
class B implements I
class C implements I
then I have a method with parameter as follows
foo(IModel<Map<? extends I, Map<? extends I, List<? extends I>>>> dataModel)
calling that method like
IModel<Map<A, Map<B, List<C>>>> model = ...
foo(model)
ends with compilation error
Error:(112, 49) java: incompatible types: IModel<java.util.Map<A,java.util.Map<B,java.util.List<C>>>> cannot be converted to IModel<java.util.Map<? extends I,java.util.Map<? extends I,java.util.List<? extends I>>>>
I have read docs about Java generics from the Oracle web, trying to google it, but there must be something I totally misunderstood.
This question can be shorted as why
foo(IModel<List<? extends I>> dataModel)
can not accept argument like
IModel<List<A>> model
Explanation
List<A> is a subtype of List<? extends I>, so it is ok:
public void bar(List<? extends I> list);
List<A> listA;
bar(listA);
But, it does not make IModel<List<A>> a subtype of IModel<List<? extends I>>, just like IModel<Dog> is not a subtype of IModel<Animal>, so the code you posted can not be compiled.
Solution
You can change it to:
foo(IModel<? extends Map<? extends I, ? extends Map<? extends I, ? extends List<? extends I>>>> dataModel)
or
<FIRST extends I, SECOND extends I, THIRD extends I> void foo(IModel<Map<FIRST, Map<SECOND, List<THIRD>>>> dataModel)
to make it compile.
First of all, I wonder how much effort it would have been for you (one person) to sort out the code to be in this form:
import java.util.List;
import java.util.Map;
interface IModel<T> {}
interface I {}
class A implements I {}
class B implements I {}
class C implements I {}
public class UpperBounds
{
public static void main(String[] args)
{
IModel<Map<A, Map<B, List<C>>>> model = null;
foo(model);
}
static void foo(IModel<Map<? extends I, Map<? extends I, List<? extends I>>>> dataModel)
{
}
}
instead of letting hundreds of people (who want to help you) do this on their own, in order to have something that they can compile and have a look at in their IDE. I mean, it's not that hard.
That being said: Technically, you're missing a few more extends clauses here. This compiles fine:
import java.util.List;
import java.util.Map;
interface IModel<T> {}
interface I {}
class A implements I {}
class B implements I {}
class C implements I {}
public class UpperBounds
{
public static void main(String[] args)
{
IModel<Map<A, Map<B, List<C>>>> model = null;
foo(model);
}
static void foo(IModel<? extends Map<? extends I, ? extends Map<? extends I, ? extends List<? extends I>>>> dataModel)
{
}
}
But you should
not
implement it like that. That's obscure. Whatever this dataModel parameter is, you should consider creating a proper data structure for that, instead of passing along such a mess of deeply nested generic maps.
The reason of why the original version did not compile was already mentioned in other answers. And it can be made clearer by showing an example using a much simpler method call. Consider this example:
interface IModel<T> {}
interface I {}
class A implements I {}
class B implements I {}
class C implements I {}
public class UpperBounds
{
public static void main(String[] args)
{
List<List<A>> lists = null;
exampleA(lists); // Error
exampleB(lists); // Works!
}
static void exampleA(List<List<? extends I>> lists)
{
}
static void exampleB(List<? extends List<? extends I>> lists)
{
}
}
The exampleA method cannot accept the given list, whereas the exampleB method can accept it.
The details are explained nicely in Which super-subtype relationships exist among instantiations of generic types? of the generics FAQ by Angelika Langer.
Intuitively, the key point is that the type List<A> is a subtype of List<? extends I>. But letting the method accept only a List<List<? extends I>> does not allow you to pass in a list whose elements are subtypes of List<? extends I>. In order to accept subtypes, you have to use ? extends.
(This could even be simplified further: When a method accepts a List<Number>, then you cannot pass in a List<Integer>. But this would not make the point of List<A> being a subtype of List<? extends I> clear here)
Having a method method1(Map<I> aMap>) and A being a class implementing I doesn't allow you to call the method with a Map<A> and that's for a reason.
Having the method:
public static void foo2(IModel<I> dataModel) {
System.out.println("Fooing 2");
}
Imagine this code:
IModel<A> simpleModel = new IModel<A>() {};
foo2(simpleModel);
This shouldn't work because you supply a more specific type to a method that requires a generic type. Now imagine foo2 does the following:
public static void foo2(IModel<I> dataModel) {
dataModel = new IModel<B>() {};
System.out.println("Fooing 2 after we change the instance");
}
Here you will try to set IModel to IModel which is valid - because B extends I, but if you were able to call that method with IModel it wouldn't work
Create your model like:
IModel<Map<I, Map<I, List<I>>>> model = ...
and in the corresponding maps and lists add objects of type A, B and C which will be valid and then call the function foo(model)
No, this question is not about the difference between ? and T; it is about how I turn a < ? > argument into a named < T >.
Consider this example code:
import java.io.Serializable;
class A<T extends Serializable> {
<S extends Serializable> void bar(S arg) { }
void bar2(T arg) { }
}
public class B {
A<? extends Serializable> myA = null;
<T extends Serializable> void foo(T arg) {
myA.bar(arg);
myA.bar2(arg);
}
}
My problem is the fact that the above doesn't compile; the call to bar2() gives me
The method bar2(capture#2-of ? extends Serializable) in the type
A<capture#2-of ? extends Serializable> is not applicable for the arguments (T)
I guess the "reason" for that is that myA is a < ? extends Serializable >; but the T in B.foo ... is well, a named T; and not the wildcard ?.
One way to "fix" this would be to make < T extends Serializable > a type parameter for class B ... but that basically conflicts with my other usage of that class. Meaning: I ended up writing down B and its member myA like this - exactly because I don't want to parameterize the B class. So, I started with only the bar2() method; and then added bar() later on ... but that doesn't really help either.
So - is there a way to for my class B to use A.bar2() as "intended" in my example code?
EDIT: and just to be precise - the bar() method doesn't help me; as the "S" there ... isn't compatible with the "T" that I am really using in my A class.
You're in a dead end.
A<? extends Serializable> myA = ...;
So myA is a A of something unknown. It could be a A<String>, or a A<Integer> or a A<Banana>. You just don't know. Let's say it's a A<Banana>.
<T extends Serializable> void foo(T arg) {
So foo() accepts any serializable: String, Integer, Banana, Apple, anything. Let's say it's called with an Integer as argument.
myA.bar2(arg);
So, based on the assumptions above, that would call bar2() with an Integer as argument, although myA is a A<Banana>. That can't be accepted by the compiler: it's clearly not type-safe. B must be made generic.
#JBNizet already explains why this can't be done. This answer aims to explain the possible options you have (one of them being rightly pointed out by in your question but that's not the only option).
Make B take a type parameter
class B<T extends Serializable> {
A<T> myA = null;
void foo(T arg) {
myA.bar(arg);
myA.bar2(arg);
}
}
Make B extend from A (If B passes the is-a test for A)
class B extends A<String> {
public void foo(String arg) {
bar2(arg);
bar(1);
}
}
The difference between the two options is that in 1) both bar and bar2 need to be passed the same type where as in 2) bar and bar2 can be passed different types since bar2 is bound by the type parameter declared for A where as bar is bound by the type parameter declared for the method.
I have a very specific problem with java generics. The follwowing classes and interfaces have been predefined:
public interface IFirst<R, T> {...}
public abstract class AbstractFirst<T extends AbstractFirst, L extends IFirst<String, T>> {...}
public interface ISecond extends IFirst<String, AbstractSecond> {...}
public abstract class AbstractSecond extends AbstractFirst<AbstractSecond, ISecond> {...}
Now I've created a following repo definition which seems to be valid:
public abstract class AbstractRepo<T extends AbstractFirst<T, IFirst<String,T>>> {...}
But now that i want to extend it:
public class RepoFirst extends AbstractRepo<AbstractSecond> {...}
I get the following error:
Bound mismatch: The type AbstractSecond is not a valid substitute for the bounded parameter
<T extends AbstractFirst<T,IFirst<String,T>>> of the type AbstractRepo<T>
I cannot change the first four (at least not radically) beacuse they are too heavily ingrained with the rest of the application, but the second two are new and up for change if need be.
Also intrestingly it allows the following (with raw type warnings):
public class RepoFirst extends AbstractRepo {
...
#Override
AbstractFirst someAbstractMethod() {
return new AbstractSecond() {...};
}
...
}
But for code clarity I would like to implement it with clearly defining AbstractSecond as the generic type for Abstract Repo.
What am I missing?
Your AbstractRepo expects an instance of IFirst and not a subtype of IFirst. But your AbstractSecond is clearly not IFirst. (I mean it is, from a OO standpoint but for generics, List<Number> is not the same as List<Integer>). It's ISecond. It might work if you could change your AbstractRepo from IFirst to ? extends IFirst as you did for AbstractFirst.
I know it is possible to wildcard with multiple types in case of methods and classes but what about variables? E.g. can I require an ArrayList to only take elements that implement both of two different interfaces that are not in the same type hierarchy? See code below for what I am trying to do.
import java.util.ArrayList;
interface A {}
interface B{}
interface AB extends A, B{}
class D <T extends A & B> { //This works but this is a class
T variable;
}
public class C {
ArrayList<AB> myList1 = new ArrayList<AB>(); // compiles
ArrayList<? extends AB> myList3 = new ArrayList<AB>(); //compiles
//The following does not compile.
ArrayList<? extends A & B> myList4 = new ArrayList<AB>();
//This works but this is a method:
public static <T extends A & B> T someMethod(ArrayList<? extends T> list) {
return null;
}
}
Yes:
class C<T extends A & B> {
ArrayList<T> field;
public <T2 extends A & B> void method() {
ArrayList<T2> localVar;
}
}
It looks a bit odd that you have to define an alias for the generic "type" outside of the scope where you use it but it works. I find it's easiest to see with the method: T2 is never used in the method declaration. It's solely used inside of the method.
It's unfortunate that these inner type limits become part of the public API this way but that's the only way I know to make this work.
If you don't want this, then try an inner, private interface (AB) in your example.
Java does not support multiple inheritance of classes - a class can extend only one single class (although a class can implement multiple interfaces). Hence I believe the
ArrayList<? extends A & B>
doesn't work.
Solution would be create a super type that extends both A & B and then pass the type to your method. Something like
inteface C extends A,B{}
ArrayList<? extends C>