I have the following interface and class definitions...
abstract interface I{}
class Foo implements I{}
abstract class A<T extends I> {
List<T> list;
}
class B extends A<Foo> {}
All the definitions work fine. I then want to do the following:
A b = new B();
List<? extends I> iList = b.list;
The compiler will indeed give me an Unchecked Assignment warning... but why? Won't all of A's lists be of type <? extends I>? b.list always has elements that extend I, so I am having trouble seeing why there would be an error
The variable A b is of a raw type. Perhaps you meant to use A<Foo> b instead.
Related
In Java Generics, given a generic class/interface Foo<T>,
What's the difference between declaring a new generic class:
Foobar<T extends Foo<T>> or simply Foobar<T extends Foo>, also why can I instantiate a generic class Foo<T> without instantiating the type parameter T?, i.e. why can i write the following:
Foo var = new Foo();, does this mean that the class is instantiated with an object, through which i can only use the non-generic method?
please forgive me if the question is not so clear, the example i was working on is the following:
MyClass<T extends Comparable<T>>
class Foo<T> {}
is your class.
Foo yourVariable = new Foo();
equals Foo<Object> yourFoo = new Foo<Object>();
class Foobar<T> extends Foo {}
equals class Foobar<T> extends Foo<Object> {}
the answer to your question
class YourClass<T extends Comparable<T>> {}
means YourClass's type T is able to compare itself to objects of T (its class), whereas
class YourClass<T extends Comparable> {}
's type T is able to compare itself to objects of class Object, which is not what you want
Suppose we have a class A that has two subclasses A1, A2.
Suppose we have another class B, that also has two subclasses, B1 an B2:
class B{
List<? extends A> myGenericList;
B(List<? extends A> myGenericList){
this.myGenericList = myGenericList;
}
public List<? extends A> getMyGenericList(){
return myGenericList;
}
}
class B1 extends B{
B1(List<A1> a1List){
super(a1List);
}
}
class B2 extends B{
B2(List<A2> a2List){
super(a2List);
}
}
Now, if we have a class C1 like this:
class C1{
...
public void doSomethingWithB1(B1 b1){
List<A1> a1list = (List<A1>)b1.getMyGenericList();
}
...
}
How can I implement getMyGenericList of class B so I can avoid the unchecked casting warning?
I tried something like this:
public <T extends A> List<T> getMyGenericList() {
return this.myGenericList;
}
but the compiler complains with cannot convert from List<capture#3-of ? extends A> to List<T>
Is there any way to do it?
Thanks in advance.
With the current way you've defined the B class, the myGenericList instance variable could hold a List of any subtype of A, so the unchecked cast warning you get when casting to List<A1> is justified. It could be a List<A> or a List<A2>.
If you don't really care which A you get in the list back, you can just assign it to a List<? extends A>.
List<? extends A> a1list = b1.getMyGenericList();
But if you really want to get a List<A1> back from a B1, then generics on the B class is your answer. Define T at the class level with an upper bound of A. Use it throughout your class to replace your wildcards.
class B<T extends A>
{
List<T> myGenericList;
B(List<T> myGenericList){
this.myGenericList = myGenericList;
}
public List<T> getMyGenericList(){
return myGenericList;
}
}
Your subclasses of B will define what T is respectively.
class B1 extends B<A1> // rest of class is the same
class B2 extends B<A2> // rest of class is the same
This way you have eliminated the unchecked cast warning and even the need to cast at all.
List<A1> a1list = b1.getMyGenericList();
You should move your generic definition to class level as following:
class B<T extends A> {
List<T> myGenericList;
B(List<T> myGenericList){
this.myGenericList = myGenericList;
}
public List<T> getMyGenericList(){
return myGenericList;
}
}
Now the subclass is defined with concrete parameter A1:
class B1 extends B<A1>{
B1(List<A1> a1List){
super(a1List);
}
}
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 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>
I found a method like the one below.
public void simpleTest(Class <? extends ParentClass> myClass){
}
I didn't understand the expression : Class <? extends ParentClass> myClass here.
Can anyone explain it?
Class <? extends ParentClass> myClass is a method argument whose type is a Class that is parameterized to ensure that what's passed is a Class that represents some type that is a subtype of ParentClass.
i.e. given:
class ParentParentClass {}
class ParentClass extends ParentParentClass {}
class ChildClass extends ParentClass {}
class ChildChildClass extends ChildClass {}
public void simpleTest(Class <? extends ParentClass> myClass) {}
These are valid:
simpleTest(ParentClass.class);
simpleTest(ChildClass.class);
simpleTest(ChildChildClass.class);
These aren't valid because the argument doesn't "fit" inside the required type:
simpleTest(ParentParentClass.class);
simpleTest(String.class);
simpleTest(Date.class);
simpleTest(Object.class);
Class myClass - means that myClass should be a a sub type of ParentClass.
class MyClass extends ParentClass {
}
simpleTest(ParentClass.class); // this is ok
simpleTest(MyClass.class); // this is ok
class SomeOtherClass {
}
simpleTest(SomeOtherClass.class); // will result in compiler error
From the javadoc of java.lang.Class<T>:
T - the type of the class modeled by this Class object. For example, the type of String.class is Class<String>. Use Class<?> if the class being modeled is unknown.
Now replace String with your class: it's a Class of a type which is a ParentClass or a subclass of ParentClass.
It's a generic method taking a parametrized class.
It might be helpful to first consider a simpler generics example: List<? extends ParentClass> means it's a List that only takes objects that fulfill the is-a relationship with ParentClass. I.e. the parameter of the List implementation is-a ParentClass, but the type of the whole thing List<? extends ParentClass> is List.
In your example, just substitute "Class" instead of "List". myClass is a Class, i.e. you can call the method with something like "MyClassName.class". Further, the parameter of the Class of my Class is-a ParentClass. This basically means that you can only pass the Class of ParentClass or its subclasses to the method.
See also: http://docs.oracle.com/javase/7/docs/api/java/lang/Class.html