Make Arraylist.Toarray() Return More Specific Types

make arrayList.toArray() return more specific types

Like this:

List<String> list = new ArrayList<String>();

String[] a = list.toArray(new String[0]);

Before Java6 it was recommended to write:

String[] a = list.toArray(new String[list.size()]);

because the internal implementation would realloc a properly sized array anyway so you were better doing it upfront. Since Java6 the empty array is preferred, see .toArray(new MyClass[0]) or .toArray(new MyClass[myList.size()])?

If your list is not properly typed you need to do a cast before calling toArray. Like this:

    List l = new ArrayList<String>();

String[] a = ((List<String>)l).toArray(new String[l.size()]);

Type specific java.util.List.toArray()

Try this:

return result.toArray(new String[result.size()]);

casting ArrayList.toArray() with ArrayList of Generic Arrays

The problem on your second code sample is caused because of your T[] typeVar: Input is a two dim array, so input[0] will return a one dim array (a String[], instead a String, as expected).

If your are to convert your List<T> to a T[], you'll need a T typeVar,

To fix it:

public static <T> T[] unTreeArray(T[][] input) {
java.util.List<T> outList = new ArrayList<T>();
java.util.List<T> tempList;

if (input.length == 0) {
return null;
}

T typeVar=null;
for (T[] subArray : input) {
if(typeVar==null && subArray.length>0) {
typeVar=subArray[0];
}
tempList = java.util.Arrays.asList(subArray);
outList.addAll(tempList);
}

return outList.toArray((T[]) Array.newInstance(typeVar.getClass(),0));
}

public static void main(String[] args) {
String[][] lines = { { "111", "122", "133" }, { "211", "222", "233" } };
String[] result=unTreeArray(lines);

System.out.println(result);

System.out.println(result.getClass());

//added for completion:
System.out.println( Arrays.toString(result));

}

The resulting output:

[Ljava.lang.String;@5a405a4 class

[Ljava.lang.String;

[111, 122, 133, 211, 222, 233]

Java generics in ArrayList.toArray()

If you look at the implementation of toArray(T[] a) of ArrayList<E> class, it is like:

public <T> T[] toArray(T[] a) {
if (a.length < size)
// Make a new array of a's runtime type, but my contents:
return (T[]) Arrays.copyOf(elementData, size, a.getClass());
System.arraycopy(elementData, 0, a, 0, size);
if (a.length > size)
a[size] = null;
return a;
}

Problem with this method is that you need to pass array of the same generic type. Now consider if this method do not take any argument then the implementation would be something similar to:

public <T> T[] toArray() {
T[] t = new T[size]; // compilation error
return Arrays.copyOf(elementData, size, t.getClass());
}

But the problem here is that you can not create generic arrays in Java because compiler does not know exactly what T represents. In other words creation of array of a non-reifiable type (JLS §4.7) is not allowed in Java.

Another important quote from Array Store Exception (JLS §10.5):

If the component type of an array were not reifiable (§4.7), the Java Virtual Machine could not perform the store check described in the
preceding paragraph. This is why an array creation expression with a
non-reifiable element type is forbidden (§15.10.1).

That is why Java has provided overloaded version toArray(T[] a).

I will override the toArray() method to tell it that it will return an
array of E.

So instead of overriding toArray(), you should use toArray(T[] a).

Cannot Create Instances of Type Parameters from Java Doc might also be interesting for you.

Java List T T[] toArray(T[] a) implementation

From the javadocs:

Like the toArray() method, this method acts as bridge between
array-based and collection-based APIs. Further, this method allows
precise control over the runtime type of the output array, and may,
under certain circumstances, be used to save allocation costs.

This means that the programmer is in control over what type of array it should be.

For example, for your ArrayList<Integer> instead of an Integer[] array you might want a Number[] or Object[] array.

Furthermore, the method also checks the array that is passed in. If you pass in an array that has enough space for all elements, the the toArray method re-uses that array. This means:

Integer[] myArray = new Integer[myList.size()];
myList.toArray(myArray);

or

Integer[] myArray = myList.toArray(new Integer[myList.size()]);

has the same effect as

Integer[] myArray = myList.toArray(new Integer[0]);

Note, in older versions of Java the latter operation used reflection to check the array type and then dynamically construct an array of the right type. By passing in a correctly sized array in the first place, reflection did not have to be used to allocate a new array inside the toArray method. That is no longer the case, and both versions can be used interchangeably.

ArrayList.toArray() method in Java

Two reasons I can think of:

  1. Erasure means that the generic parameters aren't available at runtime, so an ArrayList<String> doesn't know that it contains strings, it's just the raw type ArrayList. Thus all invocations of toArray() would have to return an Object[], which isn't strictly correct. You'd have to actually create a second array of String[] then iterate over the first, casting all of its parameters in turn to come out with the desired result type.
  2. The way the method is defined means that you can pass in a reference to an existing array, and have this populated via the method. In some cases this is likely very convenient, rather than having a new array returned and then copying its values elsewhere.

Transforming an ArrayList to an Array using toArray() method

When you pass an array that is too small to the toArray method, it creates an array of the same class but with the correct size. An empty array (length 0) is perfect for that.

Is it possible to return an array of type E in a method in Java rather than an array of objects when using Generics?

All arrays have a public clone() method, which returns the same type as the original array:

return shuffledList.toArray(list.clone());

why does ListString.toArray() return Object[] and not String[]? how to work around this?

You need to pass in an array so its runtime type can be used as a hint by toArray. Try toArray(new String[0]) instead. You can also pass in a pre-sized array.

To understand, consider what type erasure would have to do to make

new T[4]

work. If Java allowed that, the best it could do post erasure is

new Object[4]

Most toArray implementations use java.lang.reflect.Array to construct an output array of the right type given a type hint passed as a Class.

Having problems w/ Arraylist.toArray

Firstly, your ArrayList<byte[]> is a list of byte[]. T is byte[], therefore toArray(T[]) is toArray(byte[][]). E.g. byte[][] arrr = photolist.toArray(new byte[][0]).

What you want to do is a bit more complex because you can't make lists of primitives, so you can't simply use ArrayList<byte> ... photolist.toArray(phofin), you would need to use ArrayList<Byte> ... photolist.toArray(new Byte[0]) and then iterate over the Byte[] to copy the values to phofin.



Related Topics



Leave a reply



Submit