List<? Extends Mytype>

List? extends MyType

You cannot do a "put" with extends . Look at Generics - Get and Put rule.

Filling a List? extends Foo

The only safe way is by adding a Class parameter to support type checking at runtime:

private <T extends Foo> List<T> getFooesByType(EnumType type, Class<T> type) {
List<T> result = new ArrayList<>();
for(Foo f : foes) {
if(f.getType() == type) {
switch(type) {
case TYPE1:
// do something, cast is not necessary
break;
case TYPE2:
/*...*/
}
result.add(type.cast(f)); // safe cast
}
}
return result;
}

to be called like

List<FooType1> foesType1 = getFooesByType(TypeEnum.TYPE1, FooType1.class);

This is the only way to ensure that the list elements are of the caller specified type. On the other hand, this makes the requirement that T is a subtype of Foo obsolete.

You could change <T extends Foo> to <T> raising the flexibility of the method,

e.g. List<Object> list = getFooesByType(TYPE1, Object.class); would be legal as well.

? super E and ? extends E for List

"? extends A" means "some type derived from A (or A itself)". So for instance, a List<ByteArrayOutputStream> is compatible with List<? extends OutputStream> - but you shouldn't be able to add a FileOutputStream to such a list - it's meant to be a List<ByteArrayOutputStream>! All you know is that anything you fetch from the list will be an OutputStream of some kind.

"? super A" means "some type which is a superclass of A (or A itself)". So for instance, a List<OutputStream> is compatible with List<? super ByteArrayOutputStream>. You can definitely add a ByteArrayOutputStream to such a list - but if you fetch an item from the list, you can't really guarantee much about it.

See Angelika Langer's Generics FAQ for much more information.

List? extends Object what I can store into it?

even though while declaring, java allowed me to give new ArrayList<Integer>.

Yes. However, it also allows you to assign an ArrayList<String>.

Since you don't know what the list is supposed to store, you can't add anything (except null).

how to instanceof ListMyType?

That is not possible because the datatype erasure at compile time of generics. Only possible way of doing this is to write some kind of wrapper that holds which type the list holds:

public class GenericList <T> extends ArrayList<T>
{
private Class<T> genericType;

public GenericList(Class<T> c)
{
this.genericType = c;
}

public Class<T> getGenericType()
{
return genericType;
}
}

How to return a list of generic type T that extends something

It is dangerous to say a list holds items of type B and allow an item of type C to exist inside of it. It is safer to say that the list contains an interface or super-class instead.

Here is a dangerous example that throws a runtime exception.

import java.util.*;

public class Main {
public static class A {
public String getA() { return "A"; }
@Override public String toString() { return getA(); }
};
public static class B extends A {
public String getB() { return "B"; }
@Override public String toString() { return getB(); }
}
public static class C extends A {
public String getC() { return "C"; }
@Override public String toString() { return getC(); }
}

public static void main(String[] args) {
List<B> ls1 = new Main().method3();
List<C> ls2 = new Main().method3();

// Will work, because toString() for each class is handled by each class.
System.out.println(ls1);
System.out.println(ls2);

// Runtime errors!
ls1.stream().map(B::getB).forEach(System.out::println);
ls2.stream().map(C::getC).forEach(System.out::println);
}

public static <T extends A> List<T> method3() {
return Arrays.asList((T) new A(), (T) new B(), (T) new C());
}
}

The type of your list should be a common ancestor e.g. List<A> ls1 so that you can safely call common methods as you iterate through the list.

public static void main(String[] args) {
List<A> ls3 = new Main().method3();

ls3.stream().map(A::toString).forEach(System.out::println);
}

Adding data to generic ? extends list

I guess that ? extends B1 means any type that extends from B1.

No. It means "a specific, but unknown, type that extends from B1". As the specific type is unknown, the compiler cannot enforce it, therefore operations like add don't work.*

See the tutorial on wildcards.

how to make it so that it can be added?

Basically, don't use wildcards for this. You probably want this:

List<B1> l3 = new ArrayList<B1>();


* Well, they do work, but only for null (and a few other cases, see @Marko's comment below).

Compile-time error using List.addAll to add a List? extends BaseClass to another one

You could make a new List<BaseClass> and add both lists to that:

List<BaseClass> merged = new ArrayList<>();
merged.addAll(list1);
merged.addAll(lise2);

But it might be a better idea to have getList return a List<BaseClass>.



Related Topics



Leave a reply



Submit