Using generics in ArrayList (Java, "cannot be applied" error) - java

In my Android Studio project I have simple structure of classes:
public class P{}
public class A extends P{}
public class B extends P{}
And in another class I have a List:
private List<? extends P> data;
private List<A> listA;
private List<B> listB;
But when I try to do that:
data = listA; //it's ok
data.addAll(listB); //it calls error
The second line is red in Android Studio and error is:
addAll(java.util.Collection<capture<? extends com.mydomain.P>>)
in List cannot be applied to (java.util.List<com.mydomain.subclass.B>)
How can I solve this problem?

When you declare private List<? extends P> data; You require a specific type that extends p for the content of your list, which is not necessary. You can simply use:
private List<P> data;
As any class that extends P (B and A alike) will be accepted.
(That prevent you from assigning data = listA, though)

When you use a parameterized type like List, the compiler does some type binding and type checking at compilation time.
So with a variable declared as
List<A> listA;
any use of listA will be with the type argument A.
With a variable declared as
List<?> data;
any use of data will be with the type argument ? which is the wildcard, but the actual type is unknown.
Given that it doesn't know the actual type, the compiler can't let you make use of it. The add(E) method of List depends on the type variable. So
List<A> listA = ...;
listA.add(someA);
would be fine since someA is of type A.
Now you may think
List<?> data = listA;
data.add(someA); // theoretically fine
should word, but like this
List<?> data = someMethod();
data.add(someA);
it doesn't. What if the referenced List isn't meant to hold A objects?
The compiler simply can't allow this. That is what type-checking all about with generics.

Try this one if you are using ArrayList only.
public class P {}
public class A extends P {}
public class B extends P {}
public class MyList<T extends P> extends ArrayList<P> {
private static final long serialVersionUID = 1L;
...
}
private static MyList<? extends P> data;
private static MyList<A> listA;
private static MyList<B> listB;
public static void main(String[] args) throws IOException {
data = listA; // it's ok
data.addAll(listB); // it's ok
}

Related

class with generic type variable List

I'm reading about generic types. I'm able to understand that generic types can be used to specify the type of content can be consumed by objects or collections to avoid runtime error and solve it while compile time only.
I want to know how can I create a generic class whose type variable(T = List) is List. For example in below example its String.
import java.util.ArrayList;
import java.util.List;
public class Test<T> {
T string;
public Test(T in) {
this.string = in;
}
public static void main(String args[]) {
Test<String> o = new Test<String>("Generic");
}
}
I want to know how can I create a generic class whose type variable(T
= List) is List.
Specify the List as parameterized type.
To have a generic Test of List<String> do for example :
List<String> myList = new ArrayList<>();
...
Test<List<String>> o = new Test<>(myList);
Just déclare your T like an extends of List
Change this:
public class Test<T> {
to this
public class Test<T extends List> {
In this case, you will not be able to write this:
Test<String> o = new Test<String>();
If you want your list strictly to be a list of strings. Then simply declare your list as List<String>
in this way obliges the developer to use a class that belongs to the Collection es (List, ArrayList, Vector, ...)
public class Test<T extends Collection>{ ... }
UPDATE
public class Test<E,T extends Collection<E>>{ ... }

Java Generics Wildcard Capture Warning

The SCCE below shows 2 classes (B and C) implementing the interface Marker. For each class that implements Marker there is a corresponding class implementing the generic Handler interface (B_Handler, C_Handler). A map is used to associate the Class type of Pair.second to it's associated Handler. The code executes as anticipated; however, I get a compile-time warning:
warning: [unchecked] unchecked cast
Handler h1 = (Handler) (dispatch.get(p1.second.getClass()));
required: Handler
found: Handler
where CAP#1 is a fresh type-variable:
CAP#1 extends Marker from capture of ? extends Marker
What's the cleanest way to resolve this besides #SuppressWarnings(value = "unchecked")?
package genericpair;
import java.util.HashMap;
import java.util.Map;
import javax.swing.SwingUtilities;
public class GenericPair
{
public class A
{
}
public interface Marker
{
}
public class B implements Marker
{
}
public class C implements Marker
{
}
public Pair<A, Marker> getTarget()
{
A a = new A();
C c = new C();
return new Pair<>(a, c);
}
public interface Handler<T extends Marker>
{
void handle(Pair<A, T> target);
}
public class B_Handler implements Handler<B>
{
#Override
public void handle(Pair<A, B> target)
{
System.out.println("B");
}
}
public class C_Handler implements Handler<C>
{
#Override
public void handle(Pair<A, C> target)
{
System.out.println("C");
}
}
public class Pair<F, S>
{
public final F first;
public final S second;
public Pair(F first, S second)
{
this.first = first;
this.second = second;
}
}
private void executeSCCE()
{
// register a handler for each Marker type
Map<Class, Handler<? extends Marker>> dispatch = new HashMap<>();
dispatch.put(B.class, new B_Handler());
dispatch.put(C.class, new C_Handler());
// get a target (e.g., Pair<A,C>)
Pair<A, Marker> p1 = getTarget();
// select handler based on the class type of the second parameter
Handler<Marker> h1 = (Handler<Marker>) (dispatch.get(p1.second.getClass()));
h1.handle(p1);
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(() -> new GenericPair().executeSCCE());
}
}
Consider the following example:
List<? extends List> test1 = new ArrayList<>();
List<List> test2 = (List<List>) test1;
Here we get the warning:
warning: [unchecked] unchecked cast
List<List> test2 = (List<List>) test1;
^
required: List<List>
found: List<CAP#1>
where CAP#1 is a fresh type-variable:
CAP#1 extends List from capture of ? extends List
This happens because there is no way to ensure that the generic constraint of List<List> will match List<? extends List>. Imagine that we rewrite this example to the following:
List<? extends List> test1 = new ArrayList<ArrayList>();
List<List> test2 = (List<List>) test1;
test1.add(new LinkedList<>());//ERROR no suitable method found for add(LinkedList<Object>)
test2.add(new LinkedList<>());//Will work fine!!
Here it is more obvious that the initial contract is broken. The list defined to contain ArrayList now contains a LinkedList. This is unsafe, and is why you are getting this warning. So there is no way to cast from Handler<? extends Marker> to Handler<Marker> safely.
There are several issues.
The first is that your Map is not able to express the type relationship between each key and its value. So if you pass a Class<T> to dispatch.get(), you only get a Handler<? extends Marker> back, not Handler<T>. In fact, there is no type you can give dispatch to make that work. Instead, you have to make a wrapper class to enforce this relationship via its API:
public class ClassToHandlerMap
{
private final Map<Class<?>, Handler<?>> map = new HashMap<>();
public <T extends Marker> void put(Class<T> clazz, Handler<T> handler) {
map.put(clazz, handler);
}
#SuppressWarnings("unchecked")
public <T extends Marker> Handler<T> get(Class<T> clazz) {
return (Handler<T>)map.get(clazz);
}
}
Note that you do still have to suppress unchecked warnings inside this class, but at least here you know it's provably correct, based on how things are allowed to be put into the map. The unchecked cast is just an implementation detail that the user of this class doesn't need to know about.
The second issue is that getTarget() should probably return Pair<A, ? extends Marker> instead of Pair<A, Marker>. You don't ever have a Handlers of Marker; rather, you have Handlers of particular types of Marker. So it makes sense that you only use Pairs of particular types of Marker too.
public Pair<A, ? extends Marker> getTarget()
{
A a = new A();
C c = new C();
return new Pair<>(a, c);
}
The last part of your function basically is using p1 to operate on itself, so we need to use a capture helper to "capture" the ? in the type of p1 into a useful type variable for what we need to do.
However, this is more complicated in this case, because you are using .getClass(). foo.getClass() has the type Class<? extends |X|> where |X| is the erasure of the compile-time type of foo. So no matter if p1 had the type Pair<A, ?> or Pair<A, T>, p1.second.getClass() would still return the type Class<? extends Marker>. So capturing on the ? in Pair<A, ?> is not enough; instead, we should capture on the ? in the return of .getClass():
#SuppressWarnings("unchecked")
private static <T extends Marker> void captureHelper(Class<T> clazz,
Pair<A, ? extends Marker> p, ClassToHandlerMap dispatch) {
Pair<A, T> p1 = (Pair<A, T>)p;
Handler<T> h1 = dispatch.get(clazz);
h1.handle(p1);
}
Unfortunately, we will have to do an unchecked cast here also. Due to the peculiar return type of .getClass() we are unable to connect the types of the return of .getClass() and the expression it is called on. And we can't use runtime casting like .cast() to cast between parameterized types (we could use .cast() to get rid of unchecked casts if we were taking an instance of the given class as an argument, but not here). There may be some edge cases in which this is incorrect, but as long as you always use Pair with the second type argument being a final implementing class, it should be correct.
And finally the primary method looks like this:
private void executeSCCE()
{
// register a handler for each Marker type
ClassToHandlerMap dispatch = new ClassToHandlerMap();
dispatch.put(B.class, new B_Handler());
dispatch.put(C.class, new C_Handler());
// get a target (e.g., Pair<A,C>)
Pair<A, ? extends Marker> p1 = getTarget();
// select handler based on the class type of the second parameter
captureHelper(p1.second.getClass(), p1, dispatch);
}

Java generic method optional type

I have a generic method in Java:
public static <T extends C> ArrayList<<MyClass<T>> methodOne(parameter1)
Currently, I use this method to get an ArrayList of a specific type of MyClass as follows (A and B are subclasses of C):
ArrayList<MyClass<A>> result = methodOne<A>(param1);
or
ArrayList<MyClass<B>> result = methodOne<B>(param1);
Now I have another need and it's for an ArrayList that holds MyClass of both types:
ArrayList<MyClass> result = methodOne<MyClass>(param1);
However, I cannot return ArrayList<MyClass> from methodOne because it declares that it returns an ArrayList<MyClass<T>> Object.
I can fix this by changing methodOne to non-generic:
pubic static ArrayList<MyClass> methodOne(parameter1)
However, I feel safer when I can specify the type of MyClass when possible. And if I use the above declaration then I will not be able to do something like:
ArrayList<MyClass<A>> result = methodOne<A>(param1);
Is there any way I can keep the current generic method and be able to specify a type for MyClass when I want and be able to leave out the type in other situations (i.e.: when the method call fills the ArrayList with both types of MyClass)?
However, the ArrayList that will hold MyClass of both types will hold MyClass<A> Objects and MyClass<B> Objects (not MyClass<superclass> Objects)
A list that holds both MyClass<A> and MyClass<B> should have the type:
List<MyClass<? extends C>>
You can then add MyClass<A> and MyClass<B> elements to your list.
If you need your method to return a different type at different times, it must depend in some way on the parameters to the method. So for instance, if methodOne() takes a MyClass instance as an argument, you could define a method like this (note the <T> declaration, making this a generic method):
public <T> List<MyClass<T>> methodOne(MyClass<T> param, ...)
Then you can have methodOne() return lists of the same type as the object that is passed:
List<MyClass<A>> result1 = methodOne(instanceOfA, ...);
List<MyClass<C>> result = methodOne((MyClass<C>)instanceOfA, ...);
If you do not intend to pass in an instance of the desired type, you can still get away with it by passing in the Class of that type, like so:
public <T> List<MyClass<T>> methodOne(Class<T> clazz, ...)
And calling:
List<MyClass<A>> result1 = methodOne(A.class, ...);
List<MyClass<C>> result = methodOne(C.class, ...);
Which alternative you prefer depends on your use case.
You have to use this method signature:
<T extends C> ArrayList<MyClass<? extends T>> methodOne(int param1)
which will return a List of MyClass-objects of C and its subclasses.
Use it like this:
ArrayList<MyClass<? extends C>> resultC = methodOne(123);
resultC.add(new MyClass<A>());
resultC.add(new MyClass<B>());
Full example code:
import java.util.ArrayList;
interface C {}
class A implements C {}
class B implements C {}
class MyClass<X> {}
public class Generic {
public static void main(String[] args) {
ArrayList<MyClass<? extends A>> resultA = methodOne(123);
resultA.add(new MyClass<A>());
ArrayList<MyClass<? extends B>> resultB = methodOne(123);
resultB.add(new MyClass<B>());
ArrayList<MyClass<? extends C>> resultC = methodOne(123);
resultC.add(new MyClass<A>());
resultC.add(new MyClass<B>());
}
static <T extends C> ArrayList<MyClass<? extends T>> methodOne(int param1) {
return null;
}
}
You cannot do that, because even if class A extends class B, List<A> does not extends List<B>. This is because a A object supports all attributes and methods of B with same signature.
But List<B> has a add method accepting a B object, where List<A> only accepts A elements.
But the addAll method has a nice signature (for a List<E>) :
boolean addAll(Collection<? extends E> c)
So if it is acceptable, you could do :
ArrayList<MyClass<? extends abstractAncestor>> l = new ArrayList<MyClass<? extends abstractAncestor>>();
l.addAll(method1<MyClass<A>>(param1));
l.addAll(method1<MyClass<B>>(param1));

Java generic collection, cannot add list to list

Why does the following
public class ListBox {
private Random random = new Random();
private List<? extends Collection<Object>> box;
public ListBox() {
box = new ArrayList<>();
}
public void addTwoForks() {
int sizeOne = random.nextInt(1000);
int sizeTwo = random.nextInt(1000);
ArrayList<Object> one = new ArrayList<>(sizeOne);
ArrayList<Object> two = new ArrayList<>(sizeTwo);
box.add(one);
box.add(two);
}
public static void main(String[] args) {
new ListBox().addTwoForks();
}
}
Not work? Just toying around with generics for the purpose of learning and I expected that I would be able to insert anything that extends Collection in there but I get this error:
The method add(capture#2-of ? extends Collection<Object>) in the type List<capture#2-of ? extends Collection<Object>> is not applicable for the arguments (ArrayList<Object>)
The method add(capture#3-of ? extends Collection<Object>) in the type List<capture#3-of ? extends Collection<Object>> is not applicable for the arguments (ArrayList<Object>)
at ListBox.addTwoForks(ListBox.java:23)
at ListBox.main(ListBox.java:28)
You've declared box to be a List of something that extends Collection of Object. But according to the Java compiler, it could be anything that extends Collection, i.e. List<Vector<Object>>. So it must disallow add operations that take the generic type parameter for this reason. It can't let you add an ArrayList<Object> to a List that could be List<Vector<Object>>.
Try removing the wildcard:
private List<Collection<Object>> box;
This should work because you can certainly add an ArrayList<Object> to a List of Collection<Object>.

Generic instance variable in non-generic class

I'm trying to write a class that has a generic member variable but is not, itself, generic. Specifically, I want to say that I have an List of values of "some type that implements comparable to itself", so that I can call sort on that list... I hope that makes sense.
The end result of what I'm trying to do is to create a class such that I can create an instance of said class with an array of (any given type) and have it generate a string representation for that list. In the real code, I also pass in the class of the types I'm passing in:
String s = new MyClass(Integer.class, 1,2,3).asString();
assertEquals("1 or 2 or 3", s);
String s = new MyClass(String.class, "c", "b", "a").asString();
assertEquals("\"a\" or \"b\" or \"c\"", s);
Originally I didn't even want to pass in the class, I just wanted to pass in the values and have the code examine the resulting array to pick out the class of the values... but that was giving me troubles too.
The following is the code I have, but I can't come up with the right mojo to put for the variable type.
public class MyClass {
// This doesn't work as T isn't defined
final List<T extends Comparable<? super T>> values;
public <T extends Comparable<? super T>> MyClass (T... values) {
this.values = new ArrayList<T>();
for(T item : values) {
this.values.add(item);
}
}
public <T extends Comparable<? super T>> List<T> getSortedLst() {
Collections.sort(this.values);
return this.values;
}
}
error on variable declaration line:
Syntax error on token "extends", , expected
Any help would be very much appreciated.
Edit: updated code to use List instead of array, because I'm not sure it can be done with arrays.
#Mark: From everything I've read, I really want to say "T is a type that is comparable to itself", not just "T is a type that is comparable". That being said, the following code doesn't work either:
public class MyClass {
// This doesn't work
final List<? extends Comparable> values;
public <T extends Comparable> MyClass (T... values) {
this.values = new ArrayList<T>();
for(T item : values) {
this.values.add(item);
}
}
public <T extends Comparable> List<T> getSortedLst() {
Collections.sort(this.values);
return this.values;
}
}
error on add line:
The method add(capture#2-of ? extends Comparable) in the type List<capture#2-of ? extends Comparable> is not applicable for the arguments (T)
error on sort line:
Type mismatch: cannot convert from List<capture#4-of ? extends Comparable> to List<T>
Conclusion:
What it comes down to, it appears, is that Java can't quite handle what I want to do. The problem is because what I'm trying to say is:
I want a list of items that are
comparable against themselves, and I
create the whole list at once from the
data passed in at creation.
However, Java sees that I have that list and can't nail down that all the information for my situation is available at compile time, since I could try to add things to the list later and, due to type erasure, it can't guarantee that safety. It's not really possible to communicate to Java the conditions involved in my situation without applying the generic type to the class.
I think that the simple answer is that you cannot do that. If the type of one of a classes attributes depends on a type parameter, that parameter has to be declared at the class level. And I don't think that it "makes sense" any other way.
If T in your example is not a type parameter of the class, what is it? It cannot be the type parameter of the method, because that type is determined by how the method is called. (If the method is called in different static contexts with different inferred types for T, what is the notional type of T in the context of the attribute declaration?)
So to bring this back to what you are trying to do here, an instance of MyClass will hold elements of some type, and you want to be able to insert and remove elements in a statically typesafe fashion. But at the same time you don't want to be able to say what that type is. So how is the compiler supposed to statically distinguish between a MyClass instance that holds (say) Integer objects and one that holds String objects?
I don't even think you could implement this with explicit dynamic typechecks. (I think that type erasure means that the implementation of the getSortedList() method cannot find out what actual type is bound to its return type.)
No. The real solution is to make MyClass a generic class that declares the type parameter T; e.g.
public class MyClass <T extends Comparable<T>> {
and remove the declaration of the method-level type parameter T from the two methods.
There's plenty of unchecked warnings in this, but in principle it's not necessary to keep the List as anything but something containing things you know are Comparable. You enforce the rules you need to in the constructor, and everything else should be fine. How about something like this:
public class MyClass {
final private List<Comparable> values;
public <T extends Comparable<? super T>>MyClass(T... values){
this.values = new ArrayList<Comparable>();
for(T item : values) {
this.values.add(item);
}
}
public <T extends Comparable<? super T>> List<T> getSortedLst() {
Collections.sort(this.values);
return (List<T>)this.values;
}
}
A quick test using the following shows that for classes that implement Comparable (like Integer and String) MyClass behaves as expected, but will throw a compilation error for classes that do not implement Comparable:
class Junk { }
public static void main(String[] args){
MyClass s = new MyClass(1,2,3);
System.out.println(s.getSortedLst());
MyClass a = new MyClass("c", "a", "b");
System.out.println(a.getSortedLst());
MyClass c = new MyClass(new Junk());
}
I believe the following will achieve what you want (stronger typing of Comparable). This will prevent people adding Comparable objects which are not from your interface to the list and allow multiple implementations.
public class test<T extends ComparableType> {
final List<T> values = new ArrayList<T>();
public test (T... values) {
for(T item : values) {
this.values.add(item);
}
}
public List<T> getSortedLst() {
Collections.sort(this.values);
return Collections.unmodifiableList(this.values);
}
}
public interface ComparableType extends Comparable<ComparableType> {}
public class ConcreteComparableA implements ComparableType {
#Override
public int compareTo(ComparableType o) {
return 0;
}
}
public class ConcreteComparableB implements ComparableType {
#Override
public int compareTo(ComparableType o) {
return 0;
}
}
edit:
I know this may be obvious; but if you do not wish the class to be Generic this solution will also work with:
public class test {
final List<ComparableType> values = new ArrayList<ComparableType>();
public test (ComparableType... values) {
for(ComparableType item : values) {
this.values.add(item);
}
}
public List<ComparableType> getSortedLst() {
Collections.sort(this.values);
return Collections.unmodifiableList(this.values);
}
}
Consider it like this (what I am about to say isn't reality. but it illustrates why you need to do what you need to do):
class Foo<T>
{
private T value;
T getValue() { return value; }
void setValue(T val) {value = val; }
}
// some code that uses the above class
Foo<Integer> iFoo = new Foo<Integer>();
Foo<String> sFoo = new Foo<String>();
iFoo.setValue(5);
sFoo.setValue("Hello");
When this happens the compiler (DOES NOT REALLY DO WHAT I AM ABOUT TO SAY!) generates the following code:
class IntegerFoo
{
private Integer value;
Integer getValue() { return value; }
void setValue(Integer val) {value = val; }
}
class StringFoo
{
private String value;
String getValue() { return value; }
void setValue(String val) {value = val; }
}
// some code that uses the above class
IntegerFoo iFoo = new IntegerFoo();
StringFoo< sFoo = new StringFoo();
iFoo.setValue(5);
sFoo.setValue("Hello");
If you were able to have the instance variables/methods parameterized without parameterizing the class the above thing (WHICH IS NOT REALITY!) wouldn't work.
What you are trying to do should be possible with static methods, but I don't think that is what you want.
Can you explain why you want to do the code you are trying to do? Perhaps we can figure out a better way to do what you want to do that works within the language.
I'd do it this way (I did it as a list or as an array), unless you really need the instance variable/methods:
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class MyClass
{
public static <T extends Comparable<T>> List<T> asSortedList(final T ... vals)
{
final List<T> temp;
temp = new ArrayList<T>(vals.length);
temp.addAll(Arrays.asList(vals));
Collections.sort(temp);
return (Collections.unmodifiableList(temp));
}
public static <T extends Comparable<T>> T[] asSortedArray(final Class<?> clazz,
final T ... vals)
{
final T[] temp;
temp = (T[])Array.newInstance(clazz,
vals.length);
System.arraycopy(vals,
0,
temp,
0,
vals.length);
Arrays.sort(temp);
return (temp);
}
public static void main(final String[] argv)
{
final List<String> list;
final String[] array;
list = MyClass2.asSortedList("c", "a", "b");
System.out.println(list);
array = MyClass2.asSortedArray(String.class, "z", "y", "x");
System.out.println(Arrays.deepToString(array));
}
}
the type constraint you want on the variable can't be expressed directly. you can introduce a new type to bridge the problem.
static class MyList<T extends Comparable<? super T>> extends ArrayList<T>{}
final MyList<?> values;
however, there is no point to be extremely type safe in a private piece of code. Generic is there to help you clarify your types, not to obfuscate them.
public class MyClass<T extends Comparable<? super T>> {
// This doesn't work as T isn't defined
final List<T> values;
public MyClass (T... values) {
this.values = new ArrayList<T>(Arrays.asList(values));
}
public List<T> getSortedLst() {
Collections.sort(this.values);
return this.values;
}
}

Categories