Cast ArrayList in Java [duplicate] - java

This question already has answers here:
Java Generics: Cannot cast List<SubClass> to List<SuperClass>? [duplicate]
(10 answers)
Closed 4 years ago.
I am using two class
Class TestClassOne{
//Some methods
//Some methods
//Some methods
}
Class TestClassTwo extends TestClassOne{
//Some Variable
//Some Variable
//Some Variable
}
Now I am having TestClassOne object and can cast to TestClassTwo.
TestClassOne classOne = new TestClassOne();
TestClassTwo classTwo = (TestClassTwo)classOne;
Can I do this same for ArrayList?
For example
ArrayList<TestClassOne> testList1 = new ArrayList<>();
ArrayList<TestClassTwo> testList2 = (ArrayList<TestClassTwo>) testList1;
But I am getting error that can not cast. Is there any other way to cast the ArrayList?

Generic types can't be converted to each other like that. T<A> cannot be casted to T<B> even though B inherits from A.
In this particular case, what you could do is cast each individual element in the array list, and use these to create a new array list.
ArrayList<TestClassTwo> testList2 = testList1.stream().map(x -> (TestClassTwo)x)
.collect(Collectors.toCollection(ArrayList::new))
Obviously, this will only work when the objects stored in the array list are all actually instances of TestClassTwo.

Simple casting TestClassOne-> TestClassTwo will not work, unless your testList1 collection holds instances of TestClassTwo, and only them.
Casting that you want to achieve is impossible, because even though TestClassTwo extends TestClassOne, there is no gurantee, that class TestClassTwo would have a suficient constructor. TestClassTwo may have additional variables, that JVM would not know what to do with. So as you can see this would be problematic even for humans.
==========================================================================
Casting in other way is possible. Because TestClassTwo will have same methods as TestClassOne, because it extends it.
==========================================================================
If you want to hold elements of both TestClassOne and TestClassTwo in same collction, then you can use generic wildcards:
List<? extends TestClassOne> testList1 = new ArrayList<>();
But you will have to check if given element is of type TestClassTwo, before casting.
TestClassOne one = testLis.get(1);
if(one instanceOf TestClassTwo.class) {
(TestClassTwo) one; // handle me
}
one; // can't be casted, but can be adapted
==========================================================================
Other solution would be to use an adapter constructor in TestClassTwo. It will accept TestClassOne as an argument (and optionaly insert additional parameters, if needed). The creation of TestClassTwo objects should be managed by you.
class TestClassTwo extends TestClassOne{
TestClassTwo(TestClassOne in) {...}
}
Then you can use simply adapt:
List<TestClassOne> testList1 = new ArrayList<>();//add some arguments
List<TestClassTwo> testList2 = testList1.stream().map(TestClassTwo::new).collect(toList());

You can use generic class
class TestClassOne<T>
{
}
class TestClassTwo
{
}
Casting like this
List<TestClassOne<TestClassTwo>> list = new List<TestClassOne<TestClassTwo>>();

You can't. Inheritance with Type parameters are not supported.
Instead create a static helper method, which will iterate over one of the list, and cast each individual element, and return the new list. e.g.
public static convert(ArrayList<ClassOne>) {
ArrayList<ClassTwo> b = new ArrayList<ClassTwo>();
forEach(classOne) {
b.add((ClassTwo)classOne);
}
return b;
}

Related

Generic list conversion to an array

Assuming that I have the following class
public class A <T>{
private T [] datas;
// more code here ...
}
And I desire to take advantage of the constructor to initialize the array. Suppose that I have the following constructor
public A(T element){....}
Java does not allow me to use something like
datas = new T[10]
And it will complain that I cannot create a generic array of T
But I can still use a work around like:
#SuppressWarnings("unchecked")
public A(T element){
List<T> datasList = new ArrayList<T>();
datasList.add(element);
datas =(T[]) datasList.toArray();
}
I have a warning from the compiler that's why I had to add the #SuppressWarnings, but my point is related to the following comment from the toArray method documentation (Please take a look at the picture)
It talks about the returned array being safe. So does that means it is safe to use this method? If not why? And what would be a better way to do such an initialisation in a constructor? I would like to also consider the case of a variable list of T elements in an overloaded constructor like
public A(T... elements){....}.
You can create an instance of a generic array using the following:
public A(T element){
int length = 10;
datas = (T[])Array.newInstance(element.getClass(), length);
}
However, there's a problem if element would be a subclass of T, e.g. if you'd call it like this:
A<Number> numberA = new A<>( Integer.valueOf(1) );
Here T would be Number but the class of element would be Integer.
To mitigate that you could pass a vararg array of type T, e.g. like this:
//firstElement only exists to force the caller to provide at least one element
//if you don't want this then just use the varargs array
A(T firstElement, T... furtherElements){
int length = 10;
Class<?> elementClass = furtherElements.getClass().getComponentType();
datas = (T[])Array.newInstance( elementClass, length);
}
Since varargs always result in an array (even of length 0) you'll get an array of type T and can get the component type of that.
So in the case above numberA.datas would be a Number[] array and not an Integer[] array.
You can pass generics, but you can't call new T (or new T[ ]).
Keep in mind that generics are gone after compilation, so it actually only helps when writing the code. Knowing it's gone during runtime, it's also obvious that new T( ) can't be called as generic, T is removed in runtime.
It's safe to do, because you create that list in full control, accepting only objects of your generic type.
A nicer way (imho) is to create a static method as it is purely input-->output. You have to declare your generics before the method return type:
public < T > T[ ] toArray(T... objects) { ... }

Wildcard in a list - Java Generics [duplicate]

This question already has answers here:
Lists with wildcards cause Generic voodoo error
(5 answers)
Closed 8 years ago.
ArrayList<? extends A> array = new ArrayList<A>();
array.add(new A());
Why wouldnt this compile?
Relevant part from the Java tutorial (http://docs.oracle.com/javase/tutorial/java/generics/wildcardGuidelines.html):
A list defined by List can be informally thought of as
read-only, but that is not a strict guarantee. Suppose you have the
following two classes:
class NaturalNumber {
private int i;
public NaturalNumber(int i) { this.i = i; }
// ...
}
class EvenNumber extends NaturalNumber {
public EvenNumber(int i) { super(i); }
// ...
}
Consider the following code:
List<EvenNumber> le = new ArrayList<>();
List<? extends NaturalNumber> ln = le;
ln.add(new NaturalNumber(35)); // compile-time error
Because List<EvenNumber> is a subtype of List<? extends
NaturalNumber>, you can assign le to ln. But you cannot use ln to add
a natural number to a list of even numbers.
The following operations on the list are possible:
You can add null.
You can invoke clear.
You can get the iterator and invoke remove.
You can capture the wildcard and write elements that you've read from the list.
You can see that the list defined by List is
not read-only in the strictest sense of the word, but you might think
of it that way because you cannot store a new element or change an
existing element in the list.
Another relevant explanation can be found here (his link also explains the issue of wildcards - http://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html):
...
It isn't safe to add arbitrary objects to it however:
Collection<?> c = new ArrayList<String>();
c.add(new Object()); // Compile time error
Since we don't know what the element type of c stands for, we cannot
add objects to it. The add() method takes arguments of type E, the
element type of the collection. When the actual type parameter is ?,
it stands for some unknown type. Any parameter we pass to add would
have to be a subtype of this unknown type. Since we don't know what
type that is, we cannot pass anything in. The sole exception is null,
which is a member of every type.
On the other hand, given a List, we can call get() and make use of
the result. The result type is an unknown type, but we always know
that it is an object. It is therefore safe to assign the result of
get() to a variable of type Object or pass it as a parameter where the
type Object is expected.
Since we don't know what the element type of array stands for, we cannot add objects to it.
Instead, use a temporary list:
ArrayList<A> tempArray = new ArrayList<A>();
tempArray.add(new A())
tempArray.add(new A())
ArrayList<? extends A> array = tempArray;
An example of how to use it
//Vehicle
public abstract class Vehicle {
}
//Car
public class Car extends Vehicle {
}
//HandlerVehicle
public class HandlerVehicle {
private List<? extends Vehicle> _vehicles;
public void addVehicles(List<? extends Vehicle> vehicles) {
_vehicles = vehicles;
//perform operations with Vehicle objects
}
}
//HandlerCar
public class HandlerCar {
private HandlerVehicle _handlerVehicle;
private List<Car> _cars;
public HandlerCar() {
_cars = getCars();
_handlerVehicle = new HandlerVehicle();
_handlerVehicle.addVehicles(_cars);
}
private List<Car> getCars() {
return new ArrayList<Car>();
}
}
You cannot add an A to a List<? extends A>. In order to fix your problem you should simply declare your list as
ArrayList<A> array = new ArrayList<A>();
Note that it is preferable to use an interface for the declaration:
List<A> array = new ArrayList<A>();
This allows you to easily change the concrete type at a later time because you only need to make a single change.

Why can't we create an array of "Concrete" class inside a generic class?

public class GenericClass<T> {
class MyClass {
}
public GenericClass(final T[] param) {
MyClass myObject = new MyClass(); // OK
MyClass[] myArray = { new MyClass(), new MyClass() }; // Cannot create a generic array of GenericClass<T>.MyClass
}
}
This is not creating a generic array. The compiler should have no problems understanding/determining MyClass, isn't it?
Inner classes "know" which instance of the enclosing class created them, and can access fields/members of this instance. It is as if they have a second this variable whose type is the concrete type of the enclosing class (such as GenericClass<String>).
To overcome this predicament you can make MyClass static. This will make it completely decoupled of any instance of the enclosing class (that is: it will not have that second this) so they can be instantiated freely:
public class GenericClass<T> {
static class MyClass {
}
public GenericClass(final T[] param) {
MyClass myObject = new MyClass(); // OK
MyClass[] myArray = { new MyClass(), new MyClass() };
}
}
Here's some additional information. From the link ...
Java arrays carry runtime type information that identifies the type of
the elements contained
to the compiler your code looks like this:
MyClass[] myArray = {new GenericClass<T>.MyClass(), ..} //T is unknown
The JLS section that covers this is 10.6. Specifically, it's because:
It is a compile-time error if the ClassOrInterfaceType does not denote a reifiable type (§4.7). Otherwise, the ClassOrInterfaceType may name any named reference type, even an abstract class type (§8.1.1.1) or an interface type (§9).
The rules above imply that the element type in an array creation expression cannot be a parameterized type, other than an unbounded wildcard.
Because MyClass is non-static it is dependent on the outer class; it's actually GenericClass<T>.MyClass and therefore a parameterized type. Declaring it static removes that dependency and solves the problem.
Where it gets weird is if you do this;
class MyClass<T> {
}
public GenericClass(final T[] param) {
MyClass[] myArray = { new MyClass(), new MyClass() };
}
It's legal. Screwy, kind of clumsy, but legal. Because you redeclare the type, it hides the outer one. Then ... arrays and generics don't mix ... unless you use raw types. For backward compatibility you can have a rawtype array which ends up holding MyClass<Object>. It's a really awful thing, but it does compile. You can get away with creative casting here but in the end ... just ... don't.
{ new MyClass(), new MyClass() }; //new MyClass() => new GenericClass<T>.MyClass()
Above code will be treated as array of object as T is unknown ,due to the way generics are implemented (by erasure), the type of the array is not well-defined. On one hand, it should be an array of MyClass , on the other hand, it should be an array of Object
Create array of object type and cast it to your type
Object[] arr=new Object[]{this.new MyClass(), this.new MyClass()};
MyClass[] myArray = Arrays.copyOf(arr,arr.length, Item.MyClass[].class);
If you make it static it will work because-
A static nested class or nested interface (which is always static, by the way) has no relation to its outer class (or interface) apart from namespace nesting and access to private variables.
As an example in the standard API, look for the interface Map.Entry, nested inside the interface Map, yet has no access to its type parameters and needs to declare them again.
The problem here is that the compiler cannot determine at compile time the information of the array myArray. It is considered generic because (as eclipse shows you) it is converted in {new GenericClass<T>.MyClass(), ...}. This is because you're putting the class MyClass inside a generic class.
This code doesn't work either:
package my.stuff;
public class GenericClass<T> {
class MyClass {
static MyClass[] myArray = { new MyClass(), new MyClass() };;
}
public GenericClass(final T[] param) {
MyClass myObject = new MyClass();
}
}
but this code works:
package my.stuff;
public class GenericClass<T> {
public GenericClass(final T[] param) {
MyClass myObject = new MyClass();
MyClass[] myArray = { new MyClass(), new MyClass() };
}
}
class MyClass {
}
Because you're not using generics in your MyClass, the best thing to do is probably the second one.
If you declare it static, the compiler knows that MyClass is not generic and it knows what to do.
Besides, the only way to create a generic array in java is create a raw type and then cast it to generics (see here: "Cannot create generic array of .." - how to create an Array of Map<String, Object>?). So, if you absolutely need myClass inside the generic one, you should turn it in MyClass<T>, and then you use the trick: create a raw type and cast it to MyClass<T>:
package my.stuff;
public class GenericClass<T> {
class MyClass<T> {
}
#SuppressWarnings("unchecked")
public GenericClass(final T[] param) {
MyClass<T> myObject = new MyClass<T>();
MyClass<T>[] myArray = new MyClass[]{ new MyClass<T>(), new MyClass<T>() };
}
}
even it you don't use T inside the class MyClass.
#ItayMaman has the right reason. Basically, MyClass is not a reifiable type.
MyClass is a non-static inner class. Since it is non-static, it is within the scope of the type parameters of its enclosing class. And every time you write MyClass by itself in an instance method of GenericClass, it is actually short for GenericClass<T>.MyClass. So even though it may not look it, MyClass (by itself) is actually a parameterized type (parameterized by T), similar to List<String>. And so when you do new MyClass[2], you are trying to create an array of a parameterized type, just like new List<String>[2]. And I think you already know that this is not allowed.
What should you do? It all depends on what your intention is. One thing that people suggest is to make MyClass static. Of course, that will take it out of the scope of T. But that may or may not be what you want, because it completely changes its relation to GenericClass. A non-static inner class has access to an instance of the enclosing class, which is perhaps why you made it that way in the first place. If you never intended for it to be non-static (and did it by mistake), then this is obviously the way to go.
If a non-static inner class is what you want, and you simply wants to create an array of this type, let's consider how you would usually deal with arrays of parameterized types, e.g. List<String>[].
One solution is to instead create an array of the raw type, e.g. List[] foo = new List[2];. The equivalent way to do this for our case would be GenericClass.MyClass[] foo = new GenericClass.MyClass[2];. Notice what we did here. In order to write the raw type, we had to explicitly qualify MyClass with the unparameterized outer class name. If we didn't explicitly qualify it, then it would be implicitly qualified with GenericClass<T>, as explained above, which is not what we want. Translating this to the code in your example, you would write GenericClass.MyClass[] myArray = { new MyClass(), new MyClass() };
Similarly, if we want to avoid raw types, we could create an array of the wildcarded type, e.g. List<?>[] foo = new List<?>[2];. The equivalent way to do this for our case would be GenericClass<?>.MyClass[] foo = new GenericClass<?>.MyClass[2];. So translating this to the code in your example, you would write GenericClass<?>.MyClass[] myArray = { new MyClass(), new MyClass() };
Finally, we might instead want to create an array of the wildcarded type, but then cast back into an array of the parameterized type, for convenience of use later on. e.g. List<String>[] foo = (List<String>[])new List<?>[2];. The equivalent way to do this for our case would be MyClass[] myArray = (MyClass[])new GenericClass<?>.MyClass[] { new MyClass(), new MyClass() };. Note the the cast is an unchecked cast. The advantage of this is now when you get things out of myArray, it will be type MyClass, instead of raw type GenericClass.MyClass or wildcarded type GenericClass<?>.MyClass from the methods above.

Iterating through ArrayList and returning an ArrayList of the objects that meet an instanceof check

I'm having a problem with class types. I have a super class "Edible" and an interface "Colorful". Not all edible items are colorful so colorful is only implemented on certain Edible objects. I'm trying to take an ArrayList of Edible items, loop through it, and return a new ArrayList that contains only the colorful ones. The error I'm receiving now is
"The method add(Colorful) in the type ArrayList is not applicable for the arguments (Edible)"
How can I get around this restriction?
private ArrayList<Edible> elist;
private ArrayList<Colorful> clist;
public List<Colorful> getColorfulItems(){
for(Edible x : elist)
if(x instanceof Colorful){
clist.add(x);
}
return clist;
}
You need to typecast your Edible to Colorful: -
if(x instanceof Colorful){
clist.add((Colorful)x);
}
Or, if you want to avoid typecase, declare your ArrayList with WildCard: -
private ArrayList<? extends Colorful> clist;
By declaring your ArrayList like this, you can add anything that is a subtype of Colorful without typecasting
Also, you don't need to return your modified list everytime, since your list is declared as instance variable. So the change will be reflected in the list, without returning the list.
Change your list to accept any object of type Colorful. Read Generics, Inheritance, and Subtypes to understand more.
Example:
private ArrayList<? extends Colorful> clist;
I would resist using fields as return values. In this case, the list will grow every time you call the method which is likely to be undesirable.
You can make the method more generic with
#SuppressWarnings("unchecked")
public <T> List<T> selectItems(Class<T> clazz) {
List<T> ret = new ArrayList<T>();
for (Edible x : elist)
if (clazz.isInstance(x))
ret.add((T) x);
return ret;
}
which can be used to select different types.
List<Serializable> serializableList = x.selectItems(Serializable.class);
List<Colorful> colorfulList = x.selectItems(Colorful.class);

I'm studying Head First Java, but I can't understand Page 544

"When you declare a type parameter for the class, you can simply use that type any place that you'd use a real class or interface type. The type declared in the method argument is essentially replaced with the type you use when you instantiate the class.
If the class itself doesn't use a type parameter, you can still specify one for a method, by declaring it in a really unusual (but available) space-before the return type, This method says that T can be "any type of Animal"."
Can you explain?
What it means is that in a generic class, you can write methods like so:
public T doSomething () {
}
Note that the return type is 'T'.
At compile-time, the return type of that method will be whatever you have passed to the generic class when you instantiated it.
class Zoo<T> {
static void putAnimal(T animal) {
// do stuff
}
}
Zoo<Ape> apeZoo = new Zoo<Ape>(); // you can now put apes (and chimps) here
Zoo<Reptile> monkeyZoo = new Zoo<Reptile>(); // this zoo takes reptiles
apeZoo.putAnimal(new Chimp());
monkeyZoo.putAnimal(new Tortoise());
For the first paragraph, this is just how generics work for classes. For instance, for list, you can create a list of a generic type, such as integer, e.g.:
ArrayList<Integer> list = new ArrayList<Integer>();
(in real code you'd use List<Integer> of course)
Now ArrayList will be defined as:
public class Arraylist<T> { // implements....
// ...
public T get(int index) {
// ...
}
}
Which is what makes it possible to use the get method on list and get an Integer (because we made a class of type ArrayList<Integer> so T = Integer). Otherwise the compiler would have no idea what types of objects the list was storing and you'd have to get the method to return an Object, which is how it used to be.
What the second paragraph means is that you can add type parameters to methods just as you can to classes. e.g.:
public <T> void noOp(T element) {
// code here
}
This would allow you, for instance, to create a static utility method that returns something of type T. To return the first element of a List of T's:
public static <T> T getFirst (List<T> list) {
return list.get(0);
}
And you could use this method in a strongly typed fashion. Suggestions for better examples welcome. :-)
edit: I just realised I once wrote something that uses this functionality. I was using the JPA API and getting really annoyed at all the times you have to return something (a list, or a single item) from a query, and running into unchecked type warnings because there's no way to infer the type here. If you're like me and trying to avoid warnings in your code, you'd have to suppress the warnings every single time. So I wrote this method to suppress the warnings for me:
#SuppressWarnings("unchecked")
public static <T> List<T> returnResultList(Query query) {
return (List<T>)query.getResultList();
}
Which through the magic of type inference works on:
List<Integer> list = returnResultList(query);

Categories