Type-safe array creation

M

Mike Schilling

Fooling around with generics, trying to create a type-safe list-like class,
and started with the following:

public class Glist<T>
{
private Class<T> etype;

private T[] elements;

public Glist(Class<T> cls, int size)
{
etype = cls;
// the next line gets an unchecked warning
elements = (T[]) java.lang.reflect.Array.newInstance(cls, size);
}

public T get(int i)
{
return elements;
}

public void set(T t, int i)
{
elements = t;
}
}

Which is fine, other than the redundancy in calls to the constructor, e.g.:

Glist<String> g = new Glist<String>(String.class, 10);

except for the unchecked warning. I looked at the Javadoc for both String
and Arrays, but couldn't find a type-safe way to create an array from a
Class instance. Am I missing something?
 
T

Thomas Hawtin

Mike said:
Which is fine, other than the redundancy in calls to the constructor, e.g.:

Glist<String> g = new Glist<String>(String.class, 10);

You can add a creation method:

public static <T> Glist create(Class<T> cls, size) {
return new Glist<T>(cls, size);
}

Which can be used as:

Glist<String> g = Glist.create(String.class, 10);

That even works if you don't pass the Class object.
except for the unchecked warning. I looked at the Javadoc for both String
and Arrays, but couldn't find a type-safe way to create an array from a
Class instance. Am I missing something?

The Array.newInstance was designed long before generics. You can pass
int.class to it and get an int[] back. There is no way you can express
that sort of thing in Java generics. Perhaps it would be tidier to have
Array.newReferenceArrayInstance, but no such method exists, yet.

Tom Hawtin
 
G

Googmeister

Mike said:
Fooling around with generics, trying to create a type-safe list-like class,
and started with the following:

public class Glist<T>
{
private Class<T> etype;

private T[] elements;

public Glist(Class<T> cls, int size)
{
etype = cls;
// the next line gets an unchecked warning
elements = (T[]) java.lang.reflect.Array.newInstance(cls, size);
}

public T get(int i)
{
return elements;
}

public void set(T t, int i)
{
elements = t;
}
}

Which is fine, other than the redundancy in calls to the constructor, e.g.:

Glist<String> g = new Glist<String>(String.class, 10);

except for the unchecked warning. I looked at the Javadoc for both String
and Arrays, but couldn't find a type-safe way to create an array from a
Class instance. Am I missing something?


There's no way to do it without a cast somewhere (as far as I know).
The underlying cause is that arrays in Jave are covariant, but
generics are not. In other words, String[] is a subtype of Object[],
but Glist<String> is not a subtype of Glist<Object>.

Note that the following version does essentially the same
thing, but avoids passing around the Class.

public class Glist<T>
{
private T[] elements;

public Glist(int size)
{
// the next line still gets an unchecked warning
elements = (T[]) new Object[size];
}

public T get(int i)
{
return elements;
}

public void set(T t, int i)
{
elements = t;
}

}
 
M

Mike Schilling

The Array.newInstance was designed long before generics. You can pass
int.class to it and get an int[] back. There is no way you can express
that sort of thing in Java generics. Perhaps it would be tidier to have
Array.newReferenceArrayInstance, but no such method exists, yet.

Or

T[] Class<T>.newArray(int size)

which I was (naively) expecting to find.
 
M

Mike Schilling

Googmeister said:
There's no way to do it without a cast somewhere (as far as I know).
The underlying cause is that arrays in Jave are covariant, but
generics are not. In other words, String[] is a subtype of Object[],
but Glist<String> is not a subtype of Glist<Object>.

This works because arrays know at runtime what their element type is (and
can throw an exception rather than add a bad element) where the JDK's
generic collection objects don't. That's really what I was fooling around
with, investigating generic collections that *do* know their element type.
 
M

Mike Schilling

Thomas Hawtin said:
You can add a creation method:

public static <T> Glist create(Class<T> cls, size) {
return new Glist<T>(cls, size);
}

A slight change seems to work better:

public static <T> Glist<T> create(Class<T> cls, size)

Now it returns the correct sort of Glist, which avoids an "unchecked" cast
for its callers.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top