Create Generic General Array in Java
1 Introduction
We may want to use arrays as part of a class or function that supports generics. This can be difficult due to the way Java handles generics.
In this tutorial, we will understand the challenges of using generics on arrays. Then, we will create an example of a generic array.
We will also look at where the Java API solves similar problems.
2.Precautions when using general-purpose arrays
The important difference between arrays and generics is how they perform type checking. Specifically, the array stores and checks type information at runtime. However, generics check for type errors at compile time, and there is no type information at runtime.
The syntax of Java suggests that we might be able to create a new universal array:
T[] elements = new T[size];
However, if you try to do so, you will get a compilation error.
To understand why, consider the following:
public <T> T[] getArray(int size) {
T[] genericArray = new T[size]; // suppose this is allowed
return genericArray;
}
When the unbound generic type T
resolves to Object,
our method at runtime, it will be:
public Object[] getArray(int size) {
Object[] genericArray = new Object[size];
return genericArray;
}
Then, if we call the method and store the result in String
an array:
String[] myArray = getArray(5);
The code can compile normally, but it fails at runtime with ClassCastException
. This is because we just Object[]
assigned to the String[]
reference. Specifically, the compiler's implicit cast will not be able to Object[]
convert to the String[]
type we need .
Although we cannot directly initialize a general-purpose array, it is still possible to achieve equivalent operations if the calling code provides accurate information types.
3.Create a general array
For our example, let us consider a bounded stack data structure MyStack
in which the capacity is fixed to a certain size. In addition, since we hope that the stack can use any type, a reasonable implementation choice will be a general-purpose array.
First, let's create a field to store stack elements, which is E
a generic array of type :
private E[] elements;
Second, let's add a constructor:
public MyStack(Class<E> clazz, int capacity) {
elements = (E[]) Array.newInstance(clazz, capacity);
}
Note that we java.lang.reflect.Array#newInstance
initialize our general array , which requires two parameters. The first parameter specifies the type of objects in the new array. The second parameter specifies how much space to create for the array. Array#newInstance
The result of is the Object
type, and we need to use it E[]
to create our general array.
We should also pay attention to the convention of naming type parameters clazz
instead class,
of, which is a reserved word in Java.
4.ConsiderArrayList
4.1. Use ArrayList
array
In general, ArrayList
it is easier to use general instead of general arrays. Let's see how to change it MyStack
to use ArrayList
.
First, let's create a field to store the elements:
private List<E> elements;
Second, in our stack constructor, we can use the initial capacityArrayList
elements = new ArrayList<>(capacity);
It makes our classes simpler because we don't have to use reflection. In addition, when creating the stack, we do not need to pass the class text. Finally, because ArrayList
of the initial capacity we can set, we can get the same benefits as arrays.
Therefore, it is only necessary to construct a generic array in rare cases or when establishing an interface with an external library that requires an array.
4.2. ArrayList
accomplish
The interesting thing is that ArrayList
it is implemented using a general-purpose array. Let's take a peek and ArrayList
see how.
First, let's look at the list element fields:
transient Object[] elementData;
Note the ArrayList
use Object
as an element type. Because our general type is not known until runtime, it is Object
used as a superclass of any type.
ArrayList
Almost all operations in can use this general array, because toArray
they do not need to provide a strongly typed array to the outside world except for one method .
5.Build an array from a collection
5.1. LinkedList example
Let's take a look at the use of generic arrays in the Java Collections API.We will build a new array in a collection.
First, let's use the type parameter String
LinkedList
and add items to it:
List<String> items = new LinkedList();
items.add("first item");
items.add("second item");
Second, let's build the array of the items we just added:
String[] itemsAsArray = items.toArray(new String[0]);
To build our array List
. toArray
The method requires an input array. It uses this array purely to obtain type information to create a return array of the correct type.
In the above example, we used new String[0]
as the input array to build the result String
array.
5.2. LinkedList.toArray
accomplish
Let us LinkedList.toArray
see how it is implemented in Java JDK.
First, let's look at the method signature:
public <T> T[] toArray(T[] a)
Second, let's see how to create a new array when needed:
a = (T[])java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), size);
Note how it is used Array#newInstance
to construct a new array, just like the previous stack example. Also, please pay attention to how to use parameters to a
Array#newInstance.
provide types. Finally, Array#newInstance
the result is cast to T[]
create a universal array.
Six, conclusion
In this article, we first studied the difference between arrays and generics, and then introduced an example of creating generic arrays. Then, we showed that it ArrayList
may be easier to use than to use general-purpose arrays. Finally, we also studied the use of general arrays in the Collections API.
0 Comments