I want to implement a function with signature
static boolean checkAnyOutOfBoundary(int[] index,ArrayList<ArrayList<T>> list)
Where I want to substitute T with other self-created class(DocScore). I tried to substitute T with Object. But when I try to instantiate the list instance, like
ArrayList<ArrayList<Object>> DocScoreList = new ArrayList<ArrayList<Object>>();
for (int i = 0; i < index.length; i++)
DocScoreList.add(root.children.get(i).docList);
The type of root.children.get(i).docList is ArrayList<DocScore>
I can not add element into DocScoreList. Does anybody know how can I implement this?
So you are adding an ArrayList<DocScore> to a ArrayList<ArrayList<Object>> but the add method expects an ArrayList<Object>.
Can you provide an ArrayList<DocStore> where ArrayList<Object> is required? No, because A bag of banana is not a bag of fruit
So DocScoreList has to be an ArrayList of something to which a ArrayList<DocStore> can be added. Some examples are:
ArrayList<DocStore> actual type
List<DocStore> because ArrayList<T> is a List<T>
ArrayList<? extends Object> a list of some unknown type that (directly or indirectly) extends Object. Since DocStore meets the criteria ? extends Object this will work.
List<? extends Object>
etc. You get the idea.
static <T> boolean checkAnyOutOfBoundary(int[] index,ArrayList<ArrayList<T>> list)
Example of calling it:
boolean b = checkAnyOutOfBoundary( new int[]{0,1}, new ArrayList<ArrayList<String>>());
Because even in the case that Bar is a subclass of Foo, an ArryList is not a superclass of ArrayList.
Change
ArrayList<ArrayList<Object>> DocScoreList = new ArrayList<ArrayList<Object>>();
to
ArrayList<ArrayList<? extends Object>> DocScoreList = new ArrayList<ArrayList<? extends Object>>();
Related
regarding the following code:
public class Test <T extends Comparable>{
public static void main(String[] args){
List<String> lst = Array.asList("abc","def");
System.out.println(func(lst));
}
public static boolean func(List<**here**> lst){
return lst.get(0).compareTo(lst.get(1)) == 0;
}
}
why writing " ? extends Comparable" here would compile , and writing "Comparable" would not compile?
thanks in advance.
This happens because generics are invariant. Even if String is a Comparable, meaning:
String s = "";
Comparable c = s; // would work
Generics of these would not work:
List<Comparable> listC = List.of();
List<String> listS = List.of();
listC = listS; // will fail
And this would not work no matter what is the relationship between Comparable and String.
When you change the definition of that method to:
public static boolean func(List<? extends Comparable> lst) {
...
}
This is said that: wildcard with an extends-bound makes the type covariant.
This means that :
List<? extends Comparable> listC = List.of();
List<String> listS = List.of();
listC = listS; // would work here
Or in simpler words it means that List<String> is a subtype of List<? extends Comparable>.
There is a small price to pay now, because listC is now a producer of elements, meaning you can take elements out of it, but you can not put anything into it.
And well after you understand this, you are not done yet, because the definition of that method would be entirely correct, when written like this:
public static <T extends Comparable<? super T>> boolean func(List<T> lst) {
.....
}
This is because List<SubClass> cannot be cast to List<BaseClass>. Let us suppose that it could
List<String> sList = new ArrayList<>();
List<Comparable> cList = (List<Comparable>) sList;
cList.add(5);
This would be a problem because the integer 5 is not a String and should not be placed in a List<String>.
By using ? extends Comparable you are saying that the function can take a list of anything that has Comparable as a base class (e.g. List<Comparable>, List<String>, List<Integer>, etc.)
To more correctly define your function you should do the following:
public static <T extends Comparable<T>> boolean func(List<T> lst) {}
This enforces that the type is comparable with itself. Your function compares the first and second element in the list, so it is best to ensure that each element in the list is actually comparable with every other element.
Because
List<String> lst = Array.asList("abc","def");
lst list has generic type String, not Comparable.
String class, hovewer, implement Comparable<String> interface, so it fits in ? extends Comparable generic type.
List<? extends String> list = new Arraylist<String>();
list.add("foo");
Given piece of code gives me compile time error.i don't get it why i can't add string in list.
but the code means that we can add the String class object and it's derived class object in the list
still i am getting the error why
List<?> should only be used when you are not concerned with the data type of the items and interested in operations such as getting size of list etc.
For Example,
public int getSize(List<?> itemList) {
return itemList.size();
}
It is more of a Read Only list.
You should be using the following if you intend to make a new list of String items.
List<String> list = new Arraylist<>();
list.add("foo");
Alternatively, you can use this:
List<Object> list = new Arraylist<>();
list.add("foo");
This will work:
List<? super String> list = new ArrayList<String>();
list.add("foo");
Then your compiler will now, that the caller is to pass a list of objects that are String or a super type.
When you say <? extends String> it means it can be of any type which extends String. That means somebody can pass List and it will accept it.
Look also here:
Difference for <? super/extends String> in method and variable declaration
Essentially List<? extends String> is a List of an unknown type, all that is known is that this type extends String. It does not matter that the variable contains an instance of List<String>.
Now String is final, so there is no subclass... so let's consider:
List<? extends A> list = new ArrayList<A>();
where A is some class with a subclass B. When used, a variable of type List<? extends A> might be an instance of List<B>. We can not add A to it because there is the possibility that an A is not a B.
But you know it will be right? Well, the compiler doesn't, nor does it anticipate the logical connections between the unknown type and what you've instantiated, because in general you may change that variable at runtime.
A similar example exist in the tutorial optimistically named More Fun with Wildcards, where a method accepts (Set<T>, T) and an illegal call is preposed using (Set<?>, String) though the Set<?> variable contains an instance of Set<String>. The issue is the same here, despite the addition of extends.
Arraylist with List<interfaceI> and List<? extends InterfaceI> both will have objects of classes implementing interfaceI. Then when what should be used?
Suppose Foo and Bar are two classes implementing InterfaceI.
The second one (List<? extends InterfaceI>) doesn't allow adding anything to the list (except null), since the type that the list contains is unknown: it could be a List<Foo> or a List<Bar>: you just don't know.
So you usually use this notation for a method argument, when you want the method to read the elements of the list passed as argument, and want the caller to be able to call your method with a List<InterfaceI>, a List<Foo> or a List<Bar>. Using List<InterfaceI> as argument would only accept lists of type List<InterfaceI>.
Let's take a concrete example: you want to compute the maximum double value of a list of numbers. Such a method doesn't need to add or set anything to the list. All it does is iterating on the elements, get each number and compute their maximum. The signature could be
public double max(List<Number> list);
But then, you won't be able to do
List<Integer> ints = new ArrayList<>();
max(ints);
The only way to call this method is to do
List<Number> ints = new ArrayList<>();
max(ints);
Whereas if you declare the method as
public double max(List<? extends Number> list);
then you can do
List<Integer> ints = new ArrayList<>();
List<Long> longs = new ArrayList<>();
max(ints);
max(longs)
The difference is that if you declare your list as List<? extends S> myList, the myList variable can by list of any type that extends S so associations like shown below will work:
public class Clazz implements S{}
List<? extends S> myList = new List<Clazz>(); // its fine as Clazz extends S
List<? extends S> myList = new List<S>(); // its fine as well
List<? extends S> myList = new List<Object>(); // ooooops it wil not work
But in such case you will not be abe to PUT anything to such list as you cannot guarantee the exact type of object that is held by list implementation assigned to myList
If you declare List<S> myList than you will be able to PUT and GET objects from list, as you are sure what is in it, however assignments from above will not work!
public class Clazz implements S{}
List<S> myList = new List<Clazz>(); // no way!
List<S> myList = new List<S>(); //thats perfectly fine! - You can PUT new S in it;
List<S> myList = new List<Object>(); //known result;
here in place of this
public double max(List<? extends Number> list){
if you do like-
public List myList(List<? extends String> list){
list.add("string");// No, can not add anything in list except null
list.add(null);
}
For practicing purposes I am trying to write a general method to display the elements of an ArrayList by calling its .toString() method. Let's please assume .toString() does what I want it to do.
I came up with this solution below where my input ArrayList is of type Object:
public void printArralyList(ArrayList<Object> list){
for(Object o:list){
System.out.print(o.toString());
}
System.out.println();
}
However it would not work!
printArralyList(new ArrayList<Integer>(Arrays.asList(1,2,3,5,8,13,21)));
The compilation error I get is
The method printArralyList(ArrayList<Object>) is not applicable
for the arguments (ArrayList<Integer>
how can I address that?
An ArrayList<Integer> is not an ArrayList<Object>, even though an Integer is an Object.
You need a wildcard in your method's parameter, because you don't care what type the generic type parameter is.
public void printArralyList(ArrayList<?> list){
Incidentally, you can have your method take a List instead of an ArrayList, and there would be no need to wrap the return of Arrays.asList in an ArrayList:
public void printArralyList(List<?> list){
and
printArralyList(Arrays.asList(1,2,3,5,8,13,21));
would work.
You dont need Generics or wildcard. All you need is a simple method which does not specify any type for the argument so that you can pass in an ArrayList of anytime.
public void printArralyList(ArrayList list){
for (Object o:list){
System.out.print(o.toString());
}
System.out.println();
}
The reason for the error was explained by rgettman in https://stackoverflow.com/a/21996188/
However, if it is for practicing purposes, you should consider practicing polymorphism and programming to an interface
public static void printIterable(Iterable<?> iterable)
{
for (Object object : iterable)
{
System.out.print(object);
}
System.out.println();
}
This can be used with an ArrayList<Integer> parameter, as well as with an LinkedHashSet<JComponent>, or anything else that implements the Iterable interface....
Answering your question.
The declaration ArrayList does not equal to ArrayList. Even if an Integer is delivered from Object in type hierarchy.
Important thing to remember is that when you declare Collection<String> myStrings, you tell to compiler, that to variable myString can be assigned only instances of class that are created upon String type and are Collections.
Collection<Object> myObjects;
myObjects = new ArrayList<String>(); //Exception
myObjects = new HashSet<String>(); //Exception
myObjects = new HashSet<Object>(); //Valid
myObjects = new ArrayList<Object>(); //Valid
myObjects = new ArrayList<Integer>(); //Exception
To solve problems like that, java provide set of Wildcars that allow you to pass this.
There are three type of will card that support various variances.
<? extends T> - Covariance
<? super T> - Contravariance
<?> - Invariance/
The rule about them is called PECS
As we want to consume the list elements, to remove the compilations errors you should use Covariance.
Collection<? extends Object> myObjects;
myObjects = new ArrayList<String>(); //Valid
myObjects = new HashSet<String>(); //Valid
myObjects = new HashSet<Object>(); //Valid
myObjects = new ArrayList<Object>(); //Valid
myObjects = new ArrayList<Integer>(); //Valid
As in Java every class is delivered from object so <? extends> is functionally equal to <?>, and that is what rgettman has proposed as answer
The collection framework in Java is supported with generics. You should get familiar with them to fully benefit from the framework.
A different way to solve is is to benefit from generic methods like this:
public static <T> void printList<Iterable<T> iterable) {
for(T element : iterable){
System.out.printf("%s ",element);
}
System.out.println();
}
Why static ?
The call to static method are faster and this method is not related to any class member.
What is ?
This is declaration of an generic method. It allow you to define the value for generic parameter. And Java is so keen that it can extract it by itself is most cases in version 7.
If you call the method with Iterable<String> then the value of T will be String if Iterable then `Integer'.
Why Iterable ?
The Iterable is a simple interface that allows you to use for-each look. This mean you will be able to iterate through all object that classes definition implements it.
Why printf ?
The printf function use Formatter, the benefits from it are two
- In case when instance of element is assigned with null, you will not get null pointer exception that will occur if you call it o.toString().
What is missing ?
In that implementation is still missing two things
- The input validation
- The proper output format that will separate the elements with a coma.
I have a basic question regarding assignment of a list of subclass to a list of superclass.
So I have something like the following:
Class B extends A;
List <B> bList = new ArrayList<B>();
List <A> aList = bList;
Why does this last assignment fail? Sorry for the newbie question
To explain this, let me substitute "B" with Integer and "A" with Number. This is just to make it a little easier to explain.
Class Integer extends Number;
List <Integer> iList = new ArrayList<Integer>();
List <Number> nList = iList // will fail
The reason this would fail is because nList can take any Number -- it can take Integer, it can take Double, or for that matter any subclass of Number. However, this is not true for iList. You cannot add a Double to iList because it accepts only Integer and its subclasses. Hope this helps explain it to you.
When you declare a List of items of type A, only items of type A can be added or removed from the List. If you need to include subclasses of A, use the generic wildcard ? extends A to indicate so. Your code should therefore be:
List <? extends A> aList = bList;
List<B> is not List<A>:
Through example: let say you have class B1 extends A{} and class B2 extends A{}
then (if you would be able to do that:
List<B1> b1 = new AList<B1>();
List<A> a = b1;
List<B2> b2 = new AList<B2>();
by the hypothesis, you should be able to do
a.add(new B2())
but this is wrong.
If you try the same thing but using arrays instead of lists, it will compile and throw exception in runtime.
We say that arrays are covariant and generics are invariant.
to make the code compile you have the wite it:
List<? extends A> a = b;
this says that a is a list of some subtype of A. _But you don know which one. Because of that you can't do a.put(X)
List<B> and List<A> are invariant type. What you need is covariant type. In this case, it is List<? extends A>.
Because generics are strict type safe.
You can have
List<? extends A> aList = bList;
It says aList can hold list of any type which is an A
Because List<B> does not extend List<A>. For example, Integer extends Number and so does Long. So List<Number> can contain both Integer and Long. So if you assign List<Integer> to List<Number> you will be able to add Long to your list of integers.
You can declare
List<? super B> superB;
And that would allow assignment to superB of any list that contains B and its super classes.
But it's not the same as in your case aList=bList.
or
List<? extends A> extendsA;
Examples
List<? super Integer> superA;
superA = new ArrayList<Number>();
List<? extends Number> extendsNumber;
extendsNumber = new ArrayList<Integer>();
While at first glance you might think that
Class B extends A;
List <B> bList = new ArrayList<B>();
List <A> aList = bList;
should work, the problem is obvious when you imagine actually using these lists:
A something = new A();
aList.add( something ); // Should work because aList is a list of A's
but aList was assigned to bList, so that should be the same as
bList.add( something ); // Here's the problem
bList.add() takes a B, but something is an A, and an A is not a B!
And that's why generics should be (and are) strict type safe.