I have created a custom ArrayList object and recieve an error when trying to cast to this object. I think I have misunderstood something as I expected this to work. If I have a custom ArrayList object that will only treat an ArrayList of Integers:
public class CustomArrayList extends ArrayList<Integer>{
public void customMethod() {
// do things with integer arraylist
}
}
I expect that I could cast a List of Integers like the following:
List<Integer> myList = new ArrayList<>();
((CustomArrayList) myList).customMethod();
But this results in a cast class exception. Can someone please explain what I am doing wrong and how to successfully achieve the cast? Thanks
Your CustomArrayList is an ArrayList<Integer>, but an ArrayList<Integer> is not a CustomArrayList.
If you want to convert an arbitrary ArrayList<Integer> to a CustomArrayList, you can write:
List<Integer> myList = new ArrayList<>();
CustomArrayList customList = new CustomArrayList(myList);
customList.customMethod();
This will require adding a constructor to CustomArrayList that accepts a Collection<Integer> and passes it to ArrayList's public ArrayList(Collection<? extends E> c constructor.
public CustomArrayList(Collection<Integer> c) {
super(c);
}
Note that the CustomArrayList instance created with this constructor is a copy of the original ArrayList, so changes in that instance won't be reflected in the original List.
Related
having
class BaseClass implements IData ();
class ChildClassA() extends BaseClass;
class ChildClassB() extends BaseClass;
since cannot do
List<BaseClass> aList = new ArrayList<ChildClassA>()
so there is a
List<? extends IData> aList
for pointint to either
ArrayList<ChildClassA>(),
or
ArrayList<ChildClassB>()
the aList is built by other routing at runtime, and that part of code has a function to take a List<IData> from the the aList
the question is if the List<? extends IData> aList is point to ArrayList<ChildClassA>() or ArrayList<ChildClassB>(),
can it do ListData<IData> outputList = (List<IData>) aList? something like below:
(seems it is working, but not sure if there is better way to assign the generics array other than casting.)
Edit: the output of the List<IData> outputList is for read only use (immutable), no insert/delete on it, it will only iterate the IData to react on what the IData really is.
List<? extends IData> aList = new ArrayList<ChildClassA>();
ListData<IData> outputList = (List<IData>)aList
List<? extends IData> aList = new ArrayList<ChildClassB>();
ListData<IData> outputList = (List<IData>)aList
tl;dr Use Collections#unmodifiableList:
List<IData> outputList = Collections.unmodifiableList(aList);
For more information on this topic, you might want to get familiar with the PECS principle.
It's not possible, because the two types are incompatible.
A List<BaseClass> is just what it is declared, a list of BaseClass objects. More precisely, it makes two guarantees:
objects retrieved from it are assignable to BaseClass
every object that is assignable to BaseClass can be added to it (and no other)
A List<? extends BaseClass> is a more loose declaration. Precisely, it simply does not make the second guarantee. However, not only the guarantee is gone, but it is now impossible to add items to it, since the exact generic type of the list is undefined. It might even change for the same list declaration (not the same list object) at runtime.
As a consequence, a List<? extends BaseClass> is not assignable to a List<BaseClass>, since the latter makes a guarantee the first is unable to fulfill.
Practically speaking, consider the following method:
public List<BaseClass> makeList() {
// TODO implement method
return null;
}
If someone implements this method, returning a List<? extends BaseClass>, a client using this method would be unable to add items to it, although its declaration indicates otherwise.
Because of that, such an assignment results in a compilation error.
To fix the example problem the loose declaration can be added to the method:
public List<? extends BaseClass> makeList() {
// TODO implement method
return null;
}
This will signal every client, that the list returned from this method is not meant for adding items to it.
Now let's get back to your use case. In my opinion the most appropriate fix is to the rephrase the function that
take[s] a List from the the aList.
As it seems it is currently declared as
public void useList(List<BaseClass> list);
but since it does not add items to the list, it should be declared as
public void useList(List<? extends BaseClass> list);
However, if that method is part of a currently unchangeable API, you can still do:
List<? extends BaseClass> list;
....
List<BaseClass> tmp = Collections.unmodifiableList(list);
useList(tmp);
No, it is unsafe.
After that cast it would be legit to add to the list that is supposed to contain only ChildClassA typed elements, element of the other child type ChildClassB type and vice-versa.
We can simply your code a bit to make it more obvious why this should not be allowed:
List<ChildClassA> aList = new ArrayList<ChildClassA>();
aList.add(a1);
aList.add(a2);
//...
List<IData> iDataList = (List<IData>) aList;
iDataList.add(b1);
iDataList.add(b2);
//...
for (ChildClassA a : aList) {
// a some point a is going to be assigned b1 or b2 and they results in cast
// exception.
}
Note that iDataList makes reference to the very same list object as aList.
If that cast was allowed then you would be able to add elements to aList that are not ChildClassA instances.
The best solution is on the details.
If the problem is that a third-party library requires a List<IData> typed reference and as long as it is only for reading you can use a unmodifiable proxy as returned by Collections.unmodifiableList:
import java.util.Collections;
//...
final List<ChildClassA> aList = new ArrayList<>();
//... add stuff to aList
final List<IData> readOnlyIDataList = Collections.unmodifiableList(aList);
//... read only access operations readOnlyIDataList
This is my code for the class, ListOfLists. The constructor should make an array of type NameList.
public class ListOfLists {
private int capacity;
private NameList[] listOfLists;
private int size = 0;
public ListOfLists(int capacity) {
listOfLists = new NameList[capacity];
}
My NameList class looks something like this..
public class NameList{
public NameList(String initial){
i = initial;
}
public void add(String data){
...
}
If I make a new object in the Main of ListOfLists called k..
ListOfLists k = new ListOfLists(5);
How come I cannot do..
k.add("Whatever") ?
I get the error..
The type of the expression must be an array type but it resolved to ListOfLists
How come I cannot do..
because you don't have add method in ListOfLists class.
If you want to use add method of class NameList then get the value of listOfLists which is of type NameList and then add the Whatever.
k which is of type ListOfLists is something you wrote yourself, and doesn't extend anything. If you didn't write an add method, you can't call it. If you want a list that also has other properties, try extending ArrayList in your ListOfLists class.
The method signature looks like this:
public void addThemAll(Collection<? extends T> c)
Which essentially just adds every element of the collection to my LinkedList. But I keep trying to feed this method an Array or a Linked List and I always get an error. For example:
double[] myarray = new double[]{3.4, 4.5, 8.6};
mylist.addThemAll(myarray);
I'm sure this is something straightforward, but I can't find an example online that just passes an array/linked list into a method like this.
Your code has two problems:
An array is not a collection. It does not extend Collection. Therefore, you can't pass it into a method whose signature specifies a collection parameter.
You have not defined <T> (or, at least, you have not shown us where you are defining <T>). You can either define <T> in your class, or in your method signature.
To define it in your class, do it like this:
public class MyClass<T> {
// contents
}
To define <T> in your method, do it like this:
public <T> void addThemAll(Collection<? extends T> c) {
// method logic
}
For what you are doing, this would work:
List<Double> myArray = Arrays.asList(3.4, 4.5, 8.6);
mylist.addThemAll(myarray);
The reason being is that you are passing in a list (which is a collection). Currently you are passing in an Array, which is not a collection.
To pass in the array to collection:
Double[] myarray = new Double[]{3.4, 4.5, 8.6};
mylist.addThemAll(Arrays.asList(myarray));
if you don't want it as list but want it as LinkedList or etc
LinkedList<Double> linkedlist = new LinkedList(Arrays.asList(myarray));
mylist.addThemAll(linkedlist);
if you want to use set or treeset
TreeSet <Double> treeset = new TreeSet(linkedlist);
Difference between set and list is that set does not have duplicate and not ordered, and list is ordered but contains duplicates.
After you pass in to your method:
public void addThemAll(Collection<? extends T> c)
if(c instanceof LinkedList){
LinkedList a = (LinkedList) c //you can invoke methods from LinkedList
....
}
I have two questions, actaully...
First off, Why cant I do this:
List<Object> object = new List<Object>();
And second, I have a method that returns a List<?>, how would I turn that into a List<Object>, would I be able to simply cast it?
Thank you!
Why cant I do this:
List<Object> object = new List<Object>();
You can't do this because List is an interface, and interfaces cannot be instantiated. Only (concrete) classes can be. Examples of concrete classes implementing List include ArrayList, LinkedList etc.
Here is how one would create an instance of ArrayList:
List<Object> object = new ArrayList<Object>();
I have a method that returns a List<?>, how would I turn that into a List<Object>
Show us the relevant code and I'll update the answer.
List<Object> object = new List<Object>();
You cannot do this because List is an interface and you cannot create object of any interface or in other word you cannot instantiate any interface. Moreover, you can assign any object of class which implements List to its reference variable. For example you can do this:
list<Object> object = new ArrayList<Object>();
Here ArrayList is a class which implements List, you can use any class which implements List.
List is an interface so you can't instanciate it. Use any of its implementatons instead e.g.
List<Object> object = new List<Object>();
About List :
you can use any object as a generic param for it instance:
List<?> list = new ArrayList<String>();
or
List<?> list = new ArrayList<Integer>();
While using List<Object> this declaration is invalid because it will be type missmatch.
To answer your second question, yes, you can cast the List<?> as a List<Object> or a List<T> of any type, since the ? (Wildcard) parameter indicates that the list contains a homogenous collection of an any Object. However, there's no way to know at compile what the type is since it's part of the exported API only - meaning you can't see what's being inserted into the List<?>.
Here's how you would make the cast:
List<?> wildcardList = methodThatReturnsWildcardList();
// generates Unchecked cast compiler warning
List<Object> objectReference = (List<Object>)wildcardList;
In this case you can ignore the warning because in order for an object to be used in a generic class it must be a subtype of Object. Let's pretend that we're trying to cast this as a List<Integer> when it actually contains a collection of Strings.
// this code will compile safely
List<?> wildcardList = methodThatReturnsWildcardList();
List<Integer> integerReference = (List<Integer>)wildcardList;
// this line will throw an invalid cast exception for any type other than Integer
Integer myInteger = integerRefence.get(0);
Remember: generic types are erased at runtime. You won't know what the collection contains, but you can get an element and call .getClass() on it to determine its type.
Class objectClass = wildcardList.get(0).getClass();
package com.test;
import java.util.ArrayList;
import java.util.List;
public class TEst {
public static void main(String[] args) {
List<Integer> ls=new ArrayList<>();
ls.add(1);
ls.add(2);
List<Integer> ls1=new ArrayList<>();
ls1.add(3);
ls1.add(4);
List<List<Integer>> ls2=new ArrayList<>();
ls2.add(ls);
ls2.add(ls1);
List<List<List<Integer>>> ls3=new ArrayList<>();
ls3.add(ls2);
m1(ls3);
}
private static void m1(List ls3) {
for(Object ls4:ls3)
{
if(ls4 instanceof List)
{
m1((List)ls4);
}else {
System.out.print(ls4);
}
}
}
}
Can somebody please explain me why I can't cast List<> to ArrayList<> with first approach and I do with second one? Thank you.
First approach:
ArrayList<Task> tmp = ((ArrayList<Task>)mTrackytAdapter.getAllTasks(token));
Second approach:
ArrayList<Task> tmp = new ArrayList<Task>(mTrackytAdapter.getAllTasks(token));
When you do the second one, you're making a new arraylist, you're not trying to pretend the other list is an arraylist.
I mean, what if the original list is implemented as a linkedlist, or some custom list? You won't know. The second approach is preferred if you really need to make an arraylist from the result. But you can just leave it as a list, that's one of the best advantages of using Interfaces!
When you are using second approach you are initializing arraylist with its predefined values.
Like generally we do
**ArrayList listofStrings = new ArrayList<>();
**
Let's say you have an array with values, now you want to convert this array into arraylist.
you need to first get the list from the array using Arrays utils.
Because the ArrayList is concrete type that implement List interface. It is not guaranteed that method asList, will return this type of implementation.
List<String> listofOptions = (List<String>) Arrays.asList(options);
then you can user constructoru of an arraylist to instantiate with predefined values.
ArrayList<String> arrlistofOptions = new ArrayList<String>(list);
So your second approach is working that you have passed values which will intantiate arraylist with the list elements.
More over
ArrayList that is returned from Arrays.asList is not an actual arraylist, it is just a wrapper which doesnt allows any modification in the list.
If you try to add or remove over Arrays.asList it will give you
UnsupportedOperationException
Try running the following code:
List<String> listOfString = Arrays.asList("Hello", "World");
ArrayList<String> arrayListOfString = new ArrayList(listOfString);
System.out.println(listOfString.getClass());
System.out.println(arrayListOfString.getClass());
You'll get the following result:
class java.util.Arrays$ArrayList
class java.util.ArrayList
So, that means they're 2 different classes that aren't extending each other. java.util.Arrays$ArrayList signifies the private class named ArrayList (inner class of Arrays class) and java.util.ArrayList signifies the public class named ArrayList. Thus, casting from java.util.Arrays$ArrayList to java.util.ArrayList and vice versa are irrelevant/not available.
The second approach is clearly wrong if you want to cast. It instantiate a new ArrayList.
However the first approach should work just fine, if and only if getAllTasks return an ArrayList.
It is really needed for you to have an ArrayList ? isn't the List interface enough ? What you are doing can leads to Runtime Exception if the type isn't correct.
If getAllTasks() return an ArrayList you should change the return type in the class definition and then you won't need a cast and if it's returning something else, you can't cast to ArrayList.
Just try this :
ArrayList<SomeClass> arrayList;
public SomeConstructor(List<SomeClass> listData) {
arrayList.addAll(listData);
}
You can cast List<> to ArrayList<> if you understand what you doing. Java compiler won't block it.
But:
It's bad practice to casting parent type to child type (or interface to implementation type) without checking.
This way better:
if (list instanceof ArrayList<Task>) {
ArrayList<Task> arraylist = (ArrayList<Task>) list;
}
Maybe you don't need implementation type as reference. Look SonarQube warning https://sbforge.org/sonar/rules/show/squid:S1319. You can avoid this casting in the most cases.
You can use Guava method:
ArrayList<Task> arraylist = Lists.newArrayList(list);
The first approach is trying to cast the list but this would work only if the List<> were an ArrayList<>. That is not the case. So you need the second approach, that is building a new ArrayList<> with the elements of the List<>
Because in the first one , you're trying to convert a collection to an ArrayList.
In the 2nd one , you just use the built in constructor of ArrayList
May be:
ArrayList<ServiceModel> services = new ArrayList<>(parking.getServices());
intent.putExtra("servicios",services);
import java.util.List;
import java.util.Arrays;
import java.util.*;
public class Merge
{
public static void main(String[] args) {
// This is normal way
// List<Integer> l1 = new ArrayList<Integer>(); l1.add(2); l1.add(5); l1.add(10); l1.add(22);
// List<Integer> l2 = new ArrayList<Integer>(); l2.add(3); l2.add(8); l2.add(15);
//Array.asList only have the list interface, but ArrayList is inherited from List Interface with few more property like ArrayList.remove()
List<Integer> templ1 = Arrays.asList(2,5,10,22);
List<Integer> templ2 = Arrays.asList(3,8,12);
//So creation of ArrayList with the given list is required, then only ArrayList.remove function works.
List<Integer> l1 = new ArrayList<Integer>(templ1);
List<Integer> l2 = new ArrayList<Integer>(templ2);
List<Integer> l3 = new ArrayList<Integer>();
Iterator itr1 = l1.iterator();
while(itr1.hasNext()){
int x = (Integer) itr1.next();
Iterator itr2 = l2.iterator();
while(itr2.hasNext()) {
int y = (Integer) itr2.next();
if(x < y) {
l3.add(x);
break;
}
else{
l3.add(y);
itr2.remove();
}
}
}
Iterator it = l1.iterator();
while (it.hasNext()){
int k = (Integer) it.next();
if (l3.contains(k)){
continue;
}
else{
l3.add(k);
System.out.println(k);
}
}
Iterator itr2 = l2.iterator();
while (itr2.hasNext()){
int k = (Integer) itr2.next();
l3.add(k);
}
System.out.println(l3);
}
}