I know that array generic array creation is not allowed because arrays need to know their type at run-time but since generic erase their type information at run-time it is not possible to create generic array.
But how come it allows generic array declaration as follow :
private E[] genericArray;// this line does not prevent the class from compiling
private E[] genericArrayTwo= new E[][10];// this line prevents the class from compiling
private E[] genericArray;// this line does not prevent the class from compiling
private E[] genericArrayTwo= new E[][10];// this line prevents the class from compiling
Your first example was compile time evaluation to ensure proper
typing. Simply says that this array may contain something of type E.
Your second example would need to be executed at run time when E has
already been erased. Can't create an array of type E because E is no longer available.
Allowing generic array declarations ensures that appropriate types are matched at compile time.
Integer[] ints1 = null;
String[] str1 = null;
// both requires cast or it won't compile
Integer[] ints = (Integer[])doSomething1(ints1);
String[] str = (String[])doSomething1(str1);
//but that could result in a runtime error if miscast.
//That type of error might not appear for a long time
// Generic method caters to all array types.
// no casting required.
ints = doSomething2(ints1);
str = doSomething2(str1);
}
public static Object[] doSomething1(Object[] array) {
return array;
}
public static <T> T[] doSomething2(T[] array) {
return array;
}
It allows examples such as the following:
public <T> void copy(List<T> list, T[] array) {
for (T e : array) {
list.add(e);
}
}
You could then assign a value from either the list or the array to some variable of type T without getting a class cast exception or without having to to an instanceof test.
If E is a formal generic of the current class, yes you can do that :
List<E> e = new ArrayList<E>();
but you cannot do that :
E[] e = new E[10];
But declaring the E[] e variable makes sense all the same.
because no one prevents you from valuing the array from the client side that knows the real type of the array :
Foo<E> class{
private E[] array;
Foo(E[] array) {
this.array = array;
}
}
And to use it as :
Foo<String> foo = new Foo<>(new String[] { "a", "b" });
Or as alternative you could also pass the class of the array to instantiate from the client side :
Foo<String> foo = new Foo<>(String.class);
So you see that declaring E[] array is not so helpless.
I was going through this link provided by Java Oracle regarding generics. Now under section Generic Methods, it explains that Generic T can take different parameters at same time.
Example Code
public static void main(String[] args)
{
Object [] arrObjects = new Object[1];
List<String> stringList = new ArrayList<>();
List<Object> objectList = new ArrayList<>();
String [] arrString = new String[1];
fromArrayToCollection(arrString, objectList); // Works properly
fromArrayToCollection(arrObjects, stringList); // Gives compilation error
}
private static <T> void fromArrayToCollection(T[] a, Collection<T> c) {
for (T o : c) {
a[0] = o; // Correct
}
}
Here in the example fromArrayToCollection method call is right in one case, but throws compilation error in other case.
Also the link also says similar line
We can call this method with any kind of collection whose element type is a supertype of the element type of the array.
It says collection element type should be supertype of array element but why not otherwise.
I want to make a function which returns a List of a data type the same as the data type of the parameter that was passed in. For example, I would call the function like this:
Object a = new Object();
List<Object> aList = foo(a);
Integer b = 5;
List<Integer> bList = foo(b);
Because I passed an Object to foo, it returned a List<Object> to me. When I pass an Integer, a List<Integer> is provided.
If this is not possible, I'm also okay with syntax like:
Object a = new Object();
List<Object> aList = foo(Object.class, a);
I've used generics plenty of times before but I don't know how to define a data type in the return type, and then say that the same data type will be used for the parameter.
List<T> foo(T data)
{
...
}
Or would it have to be like.... List<T extends Object>? I've never done generics this advanced before.
You need to specify the generic type right before the return type of the function say:
public static <T> List<T> foo(T data) {
return new ArrayList<>();
}
I forgot you could add a type before the return type.
<T> List<T> foo(T bar)
{
...
}
If I have a Collection defined as Collection collection = new ArrayList() which contains String instances, how can I convert it to a String[]? collection.toArray() returns an Object[]. Alternatively, how can I instantiate an ArrayList<String> using reflection?
Note that I cannot hardcode String, the method doing this only knows about the Class that it can work with.
Example:
Object test(Class classToCastTo, Object[] values) {
Collection collection = new ArrayList();
for (Object value : values) {
collection.add(classToCastTo.cast(value));
}
return collection.toArray();
}
If I call this with test(String.class, ...), then it will return an Object[]. How can I make it return a String[]?
Use theCollection.toArray((T[])java.lang.reflect.Array.newInstance(theClass, theCollection.size())), where T is the element type. The cast is safe as long as T is an unparameterized type.
If you have the class, you can write a method like this:
public static <T> T[] arrayBuilder(Class<T> classToCastTo, Collection c) {
return (T[]) c.toArray((T[]) Array.newInstance(classToCastTo, 0));
}
Iterate over the Collection and store it in a String array.
Try this example from my code:
Collection c = new ArrayList();
c.add("Vivek");
c.add("Vishal");
String[] arr = new String[ c.size()];
int j = 0;
for (Object s : c){
arr[j] = (String)s;
j++;
}
The following method is what are you looking for
public <T> T[] test(Class<T> classToCastTo, Object[] values) {
Collection<T> collection = new ArrayList<T>();
for (Object value : values) {
collection.add(classToCastTo.cast(value));
}
return collection.toArray((T[])Array.newInstance(classToCastTo, collection.size()));
}
Based on Ben’s answer, the following code snippet works (compiles without warnings and runs):
private static Object test(Class<?> classToCastTo, Object[] values) {
Collection<Object> collection = new ArrayList<Object>();
for (Object value : values) {
collection.add(classToCastTo.cast(value));
}
return collection.toArray(
(Object[]) java.lang.reflect.Array.newInstance(
classToCastTo, collection.size())
);
}
Now you can call the method via
String[] result = (String[]) test(String.class, someValues);
The trick is casting the array that was created via reflection to Object[] so that it satisfies the static type check and matches the parameter type required by toArray.
That said, I don’t understand why you can’t call the method with a generic parameter. If you don’t have a generic type somewhere, the result of this method will be useless anyway.
This seems to do what you need:
public static void main(String[] args) {
Object[] originalArray = {"abc", "def"};
Class clazz = String.class;
Object[] newArray = test(clazz, originalArray);
System.out.println(newArray.getClass()); //class [Ljava.lang.String;
System.out.println(Arrays.toString(newArray)); //[abc, def]
}
static Object[] test(Class classToCastTo, Object[] values) {
Object[] o = (Object[]) Array.newInstance(classToCastTo, values.length);
System.arraycopy(values, 0, o, 0, values.length);
return o;
}
You will get a java.lang.ArrayStoreException if the original array contains something that is not a String.
If you know your collection only contains Strings, this method
public static <T> T[] toArray(Collection collection, Class<T> clazz) {
T[] array = (T[]) Array.newInstance(clazz, collection.size());
return ((Collection<T>) collection).toArray(array);
}
called as
String[] result = toArray(collection, String.class);
will do what you need, though it will give some warnings about unchecked casts.
If you know your collection can only contain strings though, you ought to be able to declare it as a Collection<String> and avoid this sort of mess.
Can somebody explain in Java Collection Framework what the importance is of <T> in the signature
<T> T[] toArray(T array[]).
I know that <T> represents generic. But an elaborate explanation based on an example will be a great deal of help.
This method allows you to create array of required type. The default toArray() returns Object[] which is cumbersome if you have list of Strings and you want a String[] from it.
For example:
List<String> list = new ArrayList<>();
list.add("A");
String[] listToArray;
listToArray = list.toArray(); // This won't compile as to Array gives Object[]
listToArray = list.toArray(new String[list.size()]); // This works when I want String[]
The <T> is the way Java says "in the method declaration that follows, T is a generic parameter rather than a specific class with the name T.
For example:
class T {
public int x;
}
<T> T f(T x) { return x; }
T g(T x) { return new T(); }
The method f can be used with arguments of any type (such as String), whereas g can only be passed arguments of the class T defined above. That is, one can call
f("dog")
but NOT g("dog") because a string is not a T.
Runnable example at ideone showing how f and g are used.