Generic list conversion to an array - java

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) { ... }

Related

Why do the new Java 8 streams return an Object Array on toArray calls?

Whilst I was working on a project involving Java 8's new streams, I noticed that when I called Stream#toArray() on a stream, it return an Object[] instead of a T[]. Surprised as I was, I started digging into the source code of Java 8 and couldn't find any reason why they didn't implement Object[] toArray(); as T[] toArray();. Is there any reasoning behind this, or is it just an (in)consistency?
EDIT 1:
I noticed in the answers that a lot of people said this would not be possible, but this code snippet compiles and return the expected result?
import java.util.Arrays;
public class Test<R> {
private Object[] items;
public Test(R[] items) {
this.items = items;
}
public R[] toArray() {
return (R[]) items;
}
public static void main(String[] args) {
Test<Integer> integerTest = new Test<>(new Integer[]{
1, 2, 3, 4
});
System.out.println(Arrays.toString(integerTest.toArray()));
}
}
Try:
String[] = IntStream.range(0, 10).mapToObj(Object::toString).toArray(String[]::new);
The no-arg toArray() method will just return an Object[], but if you pass an array factory (which can be conveniently represented as an array constructor reference), you can get whatever (compatible) type you like.
This is the same problem that List#toArray() has. Type erasure prevents us from knowing the type of array we should return. Consider the following
class Custom<T> {
private T t;
public Custom (T t) {this.t = t;}
public T[] toArray() {return (T[]) new Object[] {t};} // if not Object[], what type?
}
Custom<String> custom = new Custom("hey");
String[] arr = custom.toArray(); // fails
An Object[] is not a String[] and therefore cannot be assigned to one, regardless of the cast. The same idea applies to Stream and List. Use the overloaded toArray(..) method.
About the reason why toArray() returns Object[]: it is because of type erasure. Generic types lose their type parameters at runtime so Stream<Integer>, Stream<String> and Stream become the same types. Therefore there is no way to determine component type of array to create. Actually, one could analyze types of array's elements using reflection and then try to find their least upper bound, but this is too complicated and slow.
There is a way to get R[] array by using overloaded toArray(IntFunction<A[]> generator) method. This method gives the caller an opportunity to choose type of the array. See this SO question for code examples: How to Convert a Java 8 Stream to an Array?.

Generic Types & the toArrayMethod

I have a class MyStack<T> which defines the following
public T[] toArray(){
int s=size();
#SuppressWarnings("unchecked")
T[] result=(T[])new Object[s];
Node n=first;
for (int i=0; i<s; i++){
result[i]=n.data;
n=n.next;
}
return result;
}
Since this returns an array of type T, I would think that if I declared this instance: MyStack<String> s=new MyStack<>, that the following would be perfectly valid: String[] test=s.toArray(). I think this because since s is of type String, toArray should return an array of type String, since String has basically been substituted in for every T in this class (only for this particular instantiation, I know). The only way this runs without errors is if I do this: Object[] test=s.toArray().
Why is this?
In a word, type erasure. Taken from the Java website:
Replace all type parameters in generic types with their bounds or Object if the type parameters are unbounded. The produced bytecode, therefore, contains only ordinary classes, interfaces, and methods.
What this means is that, when your code is compiled, MyStack<String> is compiled into MyStack<Object>. This is to make sure that generics do not incur an overhead by needing to create new classes. How does this apply to you? Well..
MyStack<String> s = new MyStack<>();
is converted into..
MyStack<Object> s = new MyStack<>();
Now, this means that when you call the toArray method, the only type that can be guarenteed is the Object type. The compiler can't be sure that everything it returns is of type String, so it won't let you treat it as a String, due to the strong typing in Java. So, what is the only variable type left?
Object[] array = s.toArray();
Extra Reading
Type Erasure in Java.
Well, hold on a minute. Suppose your hypothesis were correct that String were substituted for every T.
Would the following cast be valid?
String[] result = (String[])new Object[s];
No, it would not. We can be sure that a new Object[] is not a String[].
Now sometimes you will see something like (T[])new Object[n] but it only works because the cast actually becomes erased inside the generic class. (It is a deceptive idiom.)
When the class gets compiled, what actually happens is that references to T are replaced with its upper bound (probably Object unless you had something like <T extends ...>):
public Object[] toArray(){
int s=size();
Object[] result=new Object[s];
Node n=first;
for (int i=0; i<s; i++){
result[i]=n.data;
n=n.next;
}
return result;
}
And the cast is moved to the call site:
MyStack stack = new MyStack();
String[] arr = (String[])stack.toArray();
So in fact, while the cast is erased inside the class, the cast does happen once the value is returned to outside the class, where ClassCastException is thrown.
The inability to instantiate arrays (and objects in general) generically is why the Collections framework defines their toArray method to take the return array as an argument. A simple version of this for you would be like the following:
public T[] toArray(T[] inArray){
int s = size();
Node n = first;
for (int i = 0; i < s; i++){
inArray[i] = n.data;
n = n.next;
}
return inArray;
}
For some ideas on how to create an array generically, you may see 'How to create a generic array in Java?'; however you will need the caller to pass some argument to the method.

How do I pass dynamic number of lists to a varargs method? [duplicate]

Due to the implementation of Java generics, you can't have code like this:
public class GenSet<E> {
private E a[];
public GenSet() {
a = new E[INITIAL_ARRAY_LENGTH]; // error: generic array creation
}
}
How can I implement this while maintaining type safety?
I saw a solution on the Java forums that goes like this:
import java.lang.reflect.Array;
class Stack<T> {
public Stack(Class<T> clazz, int capacity) {
array = (T[])Array.newInstance(clazz, capacity);
}
private final T[] array;
}
But I really don't get what's going on.
I have to ask a question in return: is your GenSet "checked" or "unchecked"?
What does that mean?
Checked: strong typing. GenSet knows explicitly what type of objects it contains (i.e. its constructor was explicitly called with a Class<E> argument, and methods will throw an exception when they are passed arguments that are not of type E. See Collections.checkedCollection.
-> in that case, you should write:
public class GenSet<E> {
private E[] a;
public GenSet(Class<E> c, int s) {
// Use Array native method to create array
// of a type only known at run time
#SuppressWarnings("unchecked")
final E[] a = (E[]) Array.newInstance(c, s);
this.a = a;
}
E get(int i) {
return a[i];
}
}
Unchecked: weak typing. No type checking is actually done on any of the objects passed as argument.
-> in that case, you should write
public class GenSet<E> {
private Object[] a;
public GenSet(int s) {
a = new Object[s];
}
E get(int i) {
#SuppressWarnings("unchecked")
final E e = (E) a[i];
return e;
}
}
Note that the component type of the array should be the erasure of the type parameter:
public class GenSet<E extends Foo> { // E has an upper bound of Foo
private Foo[] a; // E erases to Foo, so use Foo[]
public GenSet(int s) {
a = new Foo[s];
}
...
}
All of this results from a known, and deliberate, weakness of generics in Java: it was implemented using erasure, so "generic" classes don't know what type argument they were created with at run time, and therefore can not provide type-safety unless some explicit mechanism (type-checking) is implemented.
You can do this:
E[] arr = (E[])new Object[INITIAL_ARRAY_LENGTH];
This is one of the suggested ways of implementing a generic collection in Effective Java; Item 26. No type errors, no need to cast the array repeatedly. However this triggers a warning because it is potentially dangerous, and should be used with caution. As detailed in the comments, this Object[] is now masquerading as our E[] type, and can cause unexpected errors or ClassCastExceptions if used unsafely.
As a rule of thumb, this behavior is safe as long as the cast array is used internally (e.g. to back a data structure), and not returned or exposed to client code. Should you need to return an array of a generic type to other code, the reflection Array class you mention is the right way to go.
Worth mentioning that wherever possible, you'll have a much happier time working with Lists rather than arrays if you're using generics. Certainly sometimes you don't have a choice, but using the collections framework is far more robust.
Here's how to use generics to get an array of precisely the type you’re looking for while preserving type safety (as opposed to the other answers, which will either give you back an Object array or result in warnings at compile time):
import java.lang.reflect.Array;
public class GenSet<E> {
private E[] a;
public GenSet(Class<E[]> clazz, int length) {
a = clazz.cast(Array.newInstance(clazz.getComponentType(), length));
}
public static void main(String[] args) {
GenSet<String> foo = new GenSet<String>(String[].class, 1);
String[] bar = foo.a;
foo.a[0] = "xyzzy";
String baz = foo.a[0];
}
}
That compiles without warnings, and as you can see in main, for whatever type you declare an instance of GenSet as, you can assign a to an array of that type, and you can assign an element from a to a variable of that type, meaning that the array and the values in the array are of the correct type.
It works by using class literals as runtime type tokens, as discussed in the Java Tutorials. Class literals are treated by the compiler as instances of java.lang.Class. To use one, simply follow the name of a class with .class. So, String.class acts as a Class object representing the class String. This also works for interfaces, enums, any-dimensional arrays (e.g. String[].class), primitives (e.g. int.class), and the keyword void (i.e. void.class).
Class itself is generic (declared as Class<T>, where T stands for the type that the Class object is representing), meaning that the type of String.class is Class<String>.
So, whenever you call the constructor for GenSet, you pass in a class literal for the first argument representing an array of the GenSet instance's declared type (e.g. String[].class for GenSet<String>). Note that you won't be able to get an array of primitives, since primitives can't be used for type variables.
Inside the constructor, calling the method cast returns the passed Object argument cast to the class represented by the Class object on which the method was called. Calling the static method newInstance in java.lang.reflect.Array returns as an Object an array of the type represented by the Class object passed as the first argument and of the length specified by the int passed as the second argument. Calling the method getComponentType returns a Class object representing the component type of the array represented by the Class object on which the method was called (e.g. String.class for String[].class, null if the Class object doesn't represent an array).
That last sentence isn't entirely accurate. Calling String[].class.getComponentType() returns a Class object representing the class String, but its type is Class<?>, not Class<String>, which is why you can't do something like the following.
String foo = String[].class.getComponentType().cast("bar"); // won't compile
Same goes for every method in Class that returns a Class object.
Regarding Joachim Sauer's comment on this answer (I don't have enough reputation to comment on it myself), the example using the cast to T[] will result in a warning because the compiler can't guarantee type safety in that case.
Edit regarding Ingo's comments:
public static <T> T[] newArray(Class<T[]> type, int size) {
return type.cast(Array.newInstance(type.getComponentType(), size));
}
This is the only answer that is type safe
E[] a;
a = newArray(size);
#SafeVarargs
static <E> E[] newArray(int length, E... array)
{
return Arrays.copyOf(array, length);
}
To extend to more dimensions, just add []'s and dimension parameters to newInstance() (T is a type parameter, cls is a Class<T>, d1 through d5 are integers):
T[] array = (T[])Array.newInstance(cls, d1);
T[][] array = (T[][])Array.newInstance(cls, d1, d2);
T[][][] array = (T[][][])Array.newInstance(cls, d1, d2, d3);
T[][][][] array = (T[][][][])Array.newInstance(cls, d1, d2, d3, d4);
T[][][][][] array = (T[][][][][])Array.newInstance(cls, d1, d2, d3, d4, d5);
See Array.newInstance() for details.
In Java 8, we can do a kind of generic array creation using a lambda or method reference. This is similar to the reflective approach (which passes a Class), but here we aren't using reflection.
#FunctionalInterface
interface ArraySupplier<E> {
E[] get(int length);
}
class GenericSet<E> {
private final ArraySupplier<E> supplier;
private E[] array;
GenericSet(ArraySupplier<E> supplier) {
this.supplier = supplier;
this.array = supplier.get(10);
}
public static void main(String[] args) {
GenericSet<String> ofString =
new GenericSet<>(String[]::new);
GenericSet<Double> ofDouble =
new GenericSet<>(Double[]::new);
}
}
For example, this is used by <A> A[] Stream.toArray(IntFunction<A[]>).
This could also be done pre-Java 8 using anonymous classes but it's more cumbersome.
You do not need to pass the Class argument to the constructor.
Try this.
public class GenSet<T> {
private final T[] array;
#SafeVarargs
public GenSet(int capacity, T... dummy) {
if (dummy.length > 0)
throw new IllegalArgumentException(
"Do not provide values for dummy argument.");
this.array = Arrays.copyOf(dummy, capacity);
}
#Override
public String toString() {
return "GenSet of " + array.getClass().getComponentType().getName()
+ "[" + array.length + "]";
}
}
and
GenSet<Integer> intSet = new GenSet<>(3);
System.out.println(intSet);
System.out.println(new GenSet<String>(2));
result:
GenSet of java.lang.Integer[3]
GenSet of java.lang.String[2]
This is covered in Chapter 5 (Generics) of Effective Java, 2nd Edition, item 25...Prefer lists to arrays
Your code will work, although it will generate an unchecked warning (which you could suppress with the following annotation:
#SuppressWarnings({"unchecked"})
However, it would probably be better to use a List instead of an Array.
There's an interesting discussion of this bug/feature on the OpenJDK project site.
Java generics work by checking types at compile time and inserting appropriate casts, but erasing the types in the compiled files. This makes generic libraries usable by code which doesn't understand generics (which was a deliberate design decision) but which means you can't normally find out what the type is at run time.
The public Stack(Class<T> clazz,int capacity) constructor requires you to pass a Class object at run time, which means class information is available at runtime to code that needs it. And the Class<T> form means that the compiler will check that the Class object you pass is precisely the Class object for type T. Not a subclass of T, not a superclass of T, but precisely T.
This then means that you can create an array object of the appropriate type in your constructor, which means that the type of the objects you store in your collection will have their types checked at the point they are added to the collection.
Although the thread is dead, I would like to draw your attention to this.
Generics are used for type checking during compile time. Therefore, the purpose is to check
What comes in is what you need.
What you return is what the consumer needs.
Check this:
Don't worry about typecasting warnings when you are writing a generic class; worry when you are using it.
What about this solution?
#SafeVarargs
public static <T> T[] toGenericArray(T ... elems) {
return elems;
}
It works and looks too simple to be true. Is there any drawback?
The example is using Java reflection to create an array. Doing this is generally not recommended, since it isn't typesafe. Instead, what you should do is just use an internal List, and avoid the array at all.
Look also to this code:
public static <T> T[] toArray(final List<T> obj) {
if (obj == null || obj.isEmpty()) {
return null;
}
final T t = obj.get(0);
final T[] res = (T[]) Array.newInstance(t.getClass(), obj.size());
for (int i = 0; i < obj.size(); i++) {
res[i] = obj.get(i);
}
return res;
}
It converts a list of any kind of object to an array of the same type.
I have found a quick and easy way that works for me. Note that i have only used this on Java JDK 8. I don't know if it will work with previous versions.
Although we cannot instantiate a generic array of a specific type parameter, we can pass an already created array to a generic class constructor.
class GenArray <T> {
private T theArray[]; // reference array
// ...
GenArray(T[] arr) {
theArray = arr;
}
// Do whatever with the array...
}
Now in main we can create the array like so:
class GenArrayDemo {
public static void main(String[] args) {
int size = 10; // array size
// Here we can instantiate the array of the type we want, say Character (no primitive types allowed in generics)
Character[] ar = new Character[size];
GenArray<Character> = new Character<>(ar); // create the generic Array
// ...
}
}
For more flexibility with your arrays you can use a linked list eg. the ArrayList and other methods found in the Java.util.ArrayList class.
Passing a list of values...
public <T> T[] array(T... values) {
return values;
}
I made this code snippet to reflectively instantiate a class which is passed for a simple automated test utility.
Object attributeValue = null;
try {
if(clazz.isArray()){
Class<?> arrayType = clazz.getComponentType();
attributeValue = Array.newInstance(arrayType, 0);
}
else if(!clazz.isInterface()){
attributeValue = BeanUtils.instantiateClass(clazz);
}
} catch (Exception e) {
logger.debug("Cannot instanciate \"{}\"", new Object[]{clazz});
}
Note this segment:
if(clazz.isArray()){
Class<?> arrayType = clazz.getComponentType();
attributeValue = Array.newInstance(arrayType, 0);
}
for array initiating where Array.newInstance(class of array, size of array). Class can be both primitive (int.class) and object (Integer.class).
BeanUtils is part of Spring.
The forced cast suggested by other people did not work for me, throwing an exception of illegal casting.
However, this implicit cast worked fine:
Item<K>[] array = new Item[SIZE];
where Item is a class I defined containing the member:
private K value;
This way you get an array of type K (if the item only has the value) or any generic type you want defined in the class Item.
Actually an easier way to do so, is to create an array of objects and cast it to your desired type like the following example:
T[] array = (T[])new Object[SIZE];
where SIZE is a constant and T is a type identifier
No one else has answered the question of what is going on in the example you posted.
import java.lang.reflect.Array;
class Stack<T> {
public Stack(Class<T> clazz, int capacity) {
array = (T[])Array.newInstance(clazz, capacity);
}
private final T[] array;
}
As others have said generics are "erased" during compilation. So at runtime an instance of a generic doesn't know what its component type is. The reason for this is historical, Sun wanted to add generics without breaking the existing interface (both source and binary).
Arrays on the other hand do know their component type at runtime.
This example works around the problem by having the code that calls the constructor (which does know the type) pass a parameter telling the class the required type.
So the application would construct the class with something like
Stack<foo> = new Stack<foo>(foo.class,50)
and the constructor now knows (at runtime) what the component type is and can use that information to construct the array through the reflection API.
Array.newInstance(clazz, capacity);
Finally we have a type cast because the compiler has no way of knowing that the array returned by Array#newInstance() is the correct type (even though we know).
This style is a bit ugly but it can sometimes be the least bad solution to creating generic types that do need to know their component type at runtime for whatever reason (creating arrays, or creating instances of their component type, etc.).
I found a sort of a work around to this problem.
The line below throws generic array creation error
List<Person>[] personLists=new ArrayList<Person>()[10];
However if I encapsulate List<Person> in a separate class, it works.
import java.util.ArrayList;
import java.util.List;
public class PersonList {
List<Person> people;
public PersonList()
{
people=new ArrayList<Person>();
}
}
You can expose people in the class PersonList thru a getter. The line below will give you an array, that has a List<Person> in every element. In other words array of List<Person>.
PersonList[] personLists=new PersonList[10];
I needed something like this in some code I was working on and this is what I did to get it to work. So far no problems.
Generic array creation is disallowed in java but you can do it like
class Stack<T> {
private final T[] array;
public Stack(int capacity) {
array = (T[]) new Object[capacity];
}
}
According to vnportnoy the syntax
GenSet<Integer> intSet[] = new GenSet[3];
creates an array of null references, to be filled as
for (int i = 0; i < 3; i++)
{
intSet[i] = new GenSet<Integer>();
}
which is type safe.
You could create an Object array and cast it to E everywhere. Yeah, it's not very clean way to do it but it should at least work.
try this.
private int m = 0;
private int n = 0;
private Element<T>[][] elements = null;
public MatrixData(int m, int n)
{
this.m = m;
this.n = n;
this.elements = new Element[m][n];
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
this.elements[i][j] = new Element<T>();
}
}
}
An easy, albeit messy workaround to this would be to nest a second "holder" class inside of your main class, and use it to hold your data.
public class Whatever<Thing>{
private class Holder<OtherThing>{
OtherThing thing;
}
public Holder<Thing>[] arrayOfHolders = new Holder<Thing>[10]
}
Maybe unrelated to this question but while I was getting the "generic array creation" error for using
Tuple<Long,String>[] tupleArray = new Tuple<Long,String>[10];
I find out the following works (and worked for me) with #SuppressWarnings({"unchecked"}):
Tuple<Long, String>[] tupleArray = new Tuple[10];
I'm wondering if this code would create an effective generic array?
public T [] createArray(int desiredSize){
ArrayList<T> builder = new ArrayList<T>();
for(int x=0;x<desiredSize;x++){
builder.add(null);
}
return builder.toArray(zeroArray());
}
//zeroArray should, in theory, create a zero-sized array of T
//when it is not given any parameters.
private T [] zeroArray(T... i){
return i;
}
Edit: Perhaps an alternate way of creating such an array, if the size you required was known and small, would be to simply feed the required number of "null"s into the zeroArray command?
Though obviously this isn't as versatile as using the createArray code.
You could use a cast:
public class GenSet<Item> {
private Item[] a;
public GenSet(int s) {
a = (Item[]) new Object[s];
}
}
I actually found a pretty unique solution to bypass the inability to initiate a generic array. What you have to do is create a class that takes in the generic variable T like so:
class GenericInvoker <T> {
T variable;
public GenericInvoker(T variable){
this.variable = variable;
}
}
and then in your array class just have it start like so:
GenericInvoker<T>[] array;
public MyArray(){
array = new GenericInvoker[];
}
starting a new Generic Invoker[] will cause an issue with unchecked but there shouldn't actually be any issues.
To get from the array you should call the array[i].variable like so:
public T get(int index){
return array[index].variable;
}
The rest, such as resizing the array can be done with Arrays.copyOf() like so:
public void resize(int newSize){
array = Arrays.copyOf(array, newSize);
}
And the add function can be added like so:
public boolean add(T element){
// the variable size below is equal to how many times the add function has been called
// and is used to keep track of where to put the next variable in the array
arrays[size] = new GenericInvoker(element);
size++;
}
If you really want to wrap a generic array of fixed size you will have a method to add data to that array, hence you can initialize properly the array there doing something like this:
import java.lang.reflect.Array;
class Stack<T> {
private T[] array = null;
private final int capacity = 10; // fixed or pass it in the constructor
private int pos = 0;
public void push(T value) {
if (value == null)
throw new IllegalArgumentException("Stack does not accept nulls");
if (array == null)
array = (T[]) Array.newInstance(value.getClass(), capacity);
// put logic: e.g.
if(pos == capacity)
throw new IllegalStateException("push on full stack");
array[pos++] = value;
}
public T pop() throws IllegalStateException {
if (pos == 0)
throw new IllegalStateException("pop on empty stack");
return array[--pos];
}
}
in this case you use a java.lang.reflect.Array.newInstance to create the array, and it will not be an Object[], but a real T[].
You should not worry of it not being final, since it is managed inside your class.
Note that you need a non null object on the push() to be able to get the type to use, so I added a check on the data you push and throw an exception there.
Still this is somewhat pointless: you store data via push and it is the signature of the method that guarantees only T elements will enter. So it is more or less irrelevant that the array is Object[] or T[].

What's the reason I can't create generic array types in Java?

What's the reason why Java doesn't allow us to do
private T[] elements = new T[initialCapacity];
I could understand .NET didn't allow us to do that, as in .NET you have value types that at run-time can have different sizes, but in Java all kinds of T will be object references, thus having the same size (correct me if I'm wrong).
What is the reason?
It's because Java's arrays (unlike generics) contain, at runtime, information about its component type. So you must know the component type when you create the array. Since you don't know what T is at runtime, you can't create the array.
Quote:
Arrays of generic types are not
allowed because they're not sound. The
problem is due to the interaction of
Java arrays, which are not statically
sound but are dynamically checked,
with generics, which are statically
sound and not dynamically checked.
Here is how you could exploit the
loophole:
class Box<T> {
final T x;
Box(T x) {
this.x = x;
}
}
class Loophole {
public static void main(String[] args) {
Box<String>[] bsa = new Box<String>[3];
Object[] oa = bsa;
oa[0] = new Box<Integer>(3); // error not caught by array store check
String s = bsa[0].x; // BOOM!
}
}
We had proposed to resolve this
problem using statically safe arrays
(aka Variance) bute that was rejected
for Tiger.
-- gafter
(I believe it is Neal Gafter, but am not sure)
See it in context here: http://forums.sun.com/thread.jspa?threadID=457033&forumID=316
By failing to provide a decent solution, you just end up with something worse IMHO.
The common work around is as follows.
T[] ts = new T[n];
is replaced with (assuming T extends Object and not another class)
T[] ts = (T[]) new Object[n];
I prefer the first example, however more academic types seem to prefer the second, or just prefer not to think about it.
Most of the examples of why you can't just use an Object[] equally apply to List or Collection (which are supported), so I see them as very poor arguments.
Note: this is one of the reasons the Collections library itself doesn't compile without warnings. If this use-case cannot be supported without warnings, something is fundamentally broken with the generics model IMHO.
The reason this is impossible is that Java implements its Generics purely on the compiler level, and there is only one class file generated for each class.
This is called Type Erasure.
At runtime, the compiled class needs to handle all of its uses with the same bytecode. So, new T[capacity] would have absolutely no idea what type needs to be instantiated.
The answer was already given but if you already have an Instance of T then you can do this:
T t; //Assuming you already have this object instantiated or given by parameter.
int length;
T[] ts = (T[]) Array.newInstance(t.getClass(), length);
Hope, I could Help,
Ferdi265
The main reason is due to the fact that arrays in Java are covariant.
There's a good overview here.
I like the answer indirectly given
by Gafter. However, I propose it is wrong. I changed Gafter's code a little. It compiles and it runs for a while then it bombs where Gafter predicted it would
class Box<T> {
final T x;
Box(T x) {
this.x = x;
}
}
class Loophole {
public static <T> T[] array(final T... values) {
return (values);
}
public static void main(String[] args) {
Box<String> a = new Box("Hello");
Box<String> b = new Box("World");
Box<String> c = new Box("!!!!!!!!!!!");
Box<String>[] bsa = array(a, b, c);
System.out.println("I created an array of generics.");
Object[] oa = bsa;
oa[0] = new Box<Integer>(3);
System.out.println("error not caught by array store check");
try {
String s = bsa[0].x;
} catch (ClassCastException cause) {
System.out.println("BOOM!");
cause.printStackTrace();
}
}
}
The output is
I created an array of generics.
error not caught by array store check
BOOM!
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
at Loophole.main(Box.java:26)
So it appears to me you can create generic array types in java. Did I misunderstand the question?
From Oracle tutorial:
You cannot create arrays of parameterized types. For example, the following code does not compile:
List<Integer>[] arrayOfLists = new List<Integer>[2]; // compile-time error
The following code illustrates what happens when different types are inserted into an array:
Object[] strings = new String[2];
strings[0] = "hi"; // OK
strings[1] = 100; // An ArrayStoreException is thrown.
If you try the same thing with a generic list, there would be a problem:
Object[] stringLists = new List<String>[]; // compiler error, but pretend it's allowed
stringLists[0] = new ArrayList<String>(); // OK
stringLists[1] = new ArrayList<Integer>(); // An ArrayStoreException should be thrown,
// but the runtime can't detect it.
If arrays of parameterized lists were allowed, the previous code would fail to throw the desired ArrayStoreException.
To me, it sounds very weak. I think that anybody with a sufficient understanding of generics, would be perfectly fine, and even expect, that the ArrayStoredException is not thrown in such case.
In my case, I simply wanted an array of stacks, something like this:
Stack<SomeType>[] stacks = new Stack<SomeType>[2];
Since this was not possible, I used the following as a workaround:
Created a non-generic wrapper class around Stack (say MyStack)
MyStack[] stacks = new MyStack[2] worked perfectly well
Ugly, but Java is happy.
Note: as mentioned by BrainSlugs83 in the comment to the question, it is totally possible to have arrays of generics in .NET
class can declare an array of type T[], but it cannot directly instantiate such an array. Instead, a common approach is to instantiate an array of type Object[], and then make a narrowing cast to type T[], as shown in the following:
public class Portfolio<T> {
T[] data;
public Portfolio(int capacity) {
data = new T[capacity]; // illegal; compiler error
data = (T[]) new Object[capacity]; // legal, but compiler warning
}
public T get(int index) { return data[index]; }
public void set(int index, T element) { data[index] = element; }
}
It is because generics were added on to java after they made it, so its kinda clunky because the original makers of java thought that when making an array the type would be specified in the making of it. So that does not work with generics so you have to do
E[] array=(E[]) new Object[15];
This compiles but it gives a warning.
There surely must be a good way around it (maybe using reflection), because it seems to me that that's exactly what ArrayList.toArray(T[] a) does. I quote:
public <T> T[] toArray(T[] a)
Returns an array containing all of the
elements in this list in the correct order; the runtime type of the
returned array is that of the specified array. If the list fits in the
specified array, it is returned therein. Otherwise, a new array is
allocated with the runtime type of the specified array and the size of
this list.
So one way around it would be to use this function i.e. create an ArrayList of the objects you want in the array, then use toArray(T[] a) to create the actual array. It wouldn't be speedy, but you didn't mention your requirements.
So does anyone know how toArray(T[] a) is implemented?
If we cannot instantiate generic arrays, why does the language have generic array types? What's the point of having a type without objects?
The only reason I can think of, is varargs - foo(T...). Otherwise they could have completely scrubbed generic array types. (Well, they didn't really have to use array for varargs, since varargs didn't exist before 1.5. That's probably another mistake.)
So it is a lie, you can instantiate generic arrays, through varargs!
Of course, the problems with generic arrays are still real, e.g.
static <T> T[] foo(T... args){
return args;
}
static <T> T[] foo2(T a1, T a2){
return foo(a1, a2);
}
public static void main(String[] args){
String[] x2 = foo2("a", "b"); // heap pollution!
}
We can use this example to actually demonstrate the danger of generic array.
On the other hand, we've been using generic varargs for a decade, and the sky is not falling yet. So we can argue that the problems are being exaggerated; it is not a big deal. If explicit generic array creation is allowed, we'll have bugs here and there; but we've been used to the problems of erasure, and we can live with it.
And we can point to foo2 to refute the claim that the spec keeps us from the problems that they claim to keep us from. If Sun had more time and resources for 1.5, I believe they could have reached a more satisfying resolution.
As others already mentioned, you can of course create via some tricks.
But it's not recommended.
Because the type erasure and more importantly the covariance in array which just allows a subtype array can be assigned to a supertype array, which forces you to use explicit type cast when trying to get the value back causing run-time ClassCastException which is one of the main objectives that generics try to eliminate: Stronger type checks at compile time.
Object[] stringArray = { "hi", "me" };
stringArray[1] = 1;
String aString = (String) stringArray[1]; // boom! the TypeCastException
A more direct example can found in Effective Java: Item 25.
covariance: an array of type S[] is a subtype of T[] if S is a subtype of T
T vals[]; // OK
But, you cannot instantiate an array of T
// vals = new T[10]; // can't create an array of T
The reason you can’t create an array of T is that there is no way for the
compiler to know what type of array to actually create.
Try this:
List<?>[] arrayOfLists = new List<?>[4];

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