How to create a generic array in Java?
up vote
931
down vote
favorite
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.
java arrays generics reflection instantiation
add a comment |
up vote
931
down vote
favorite
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.
java arrays generics reflection instantiation
12
Do you really need to use an array here? What about using a Collection?
– matt b
Feb 9 '09 at 18:34
10
Yes I also think that collections are more elegant to for this problem. But this is for a class assignment and they are required :(
– tatsuhirosatou
Feb 9 '09 at 19:47
1
I do not understand why I need a reflect here.Java grammar is strange: like new java.util.HashMap<String,String>[10] is not valid. new java.util.HashMap<long,long>(10) is not valid. new long[10] is not valid, new long[10] is valid. That stuff make write a program that can write java program is more difficult then it looks like.
– bronze man
Jun 30 '17 at 2:46
add a comment |
up vote
931
down vote
favorite
up vote
931
down vote
favorite
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.
java arrays generics reflection instantiation
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.
java arrays generics reflection instantiation
java arrays generics reflection instantiation
edited Feb 19 '17 at 11:11
Cœur
17.3k9102142
17.3k9102142
asked Feb 9 '09 at 17:30
tatsuhirosatou
9,010113237
9,010113237
12
Do you really need to use an array here? What about using a Collection?
– matt b
Feb 9 '09 at 18:34
10
Yes I also think that collections are more elegant to for this problem. But this is for a class assignment and they are required :(
– tatsuhirosatou
Feb 9 '09 at 19:47
1
I do not understand why I need a reflect here.Java grammar is strange: like new java.util.HashMap<String,String>[10] is not valid. new java.util.HashMap<long,long>(10) is not valid. new long[10] is not valid, new long[10] is valid. That stuff make write a program that can write java program is more difficult then it looks like.
– bronze man
Jun 30 '17 at 2:46
add a comment |
12
Do you really need to use an array here? What about using a Collection?
– matt b
Feb 9 '09 at 18:34
10
Yes I also think that collections are more elegant to for this problem. But this is for a class assignment and they are required :(
– tatsuhirosatou
Feb 9 '09 at 19:47
1
I do not understand why I need a reflect here.Java grammar is strange: like new java.util.HashMap<String,String>[10] is not valid. new java.util.HashMap<long,long>(10) is not valid. new long[10] is not valid, new long[10] is valid. That stuff make write a program that can write java program is more difficult then it looks like.
– bronze man
Jun 30 '17 at 2:46
12
12
Do you really need to use an array here? What about using a Collection?
– matt b
Feb 9 '09 at 18:34
Do you really need to use an array here? What about using a Collection?
– matt b
Feb 9 '09 at 18:34
10
10
Yes I also think that collections are more elegant to for this problem. But this is for a class assignment and they are required :(
– tatsuhirosatou
Feb 9 '09 at 19:47
Yes I also think that collections are more elegant to for this problem. But this is for a class assignment and they are required :(
– tatsuhirosatou
Feb 9 '09 at 19:47
1
1
I do not understand why I need a reflect here.Java grammar is strange: like new java.util.HashMap<String,String>[10] is not valid. new java.util.HashMap<long,long>(10) is not valid. new long[10] is not valid, new long[10] is valid. That stuff make write a program that can write java program is more difficult then it looks like.
– bronze man
Jun 30 '17 at 2:46
I do not understand why I need a reflect here.Java grammar is strange: like new java.util.HashMap<String,String>[10] is not valid. new java.util.HashMap<long,long>(10) is not valid. new long[10] is not valid, new long[10] is valid. That stuff make write a program that can write java program is more difficult then it looks like.
– bronze man
Jun 30 '17 at 2:46
add a comment |
29 Answers
29
active
oldest
votes
up vote
609
down vote
accepted
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 aClass<E>
argument, and methods will throw an exception when they are passed arguments that are not of typeE
. SeeCollections.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.
4
What would performance-wise be the best option? I need to get elements from this array quite often (within a loop). So a collection is probably slower, but which of these two is fastest?
– user1111929
Sep 8 '12 at 3:52
3
And if the generic type is bounded, the backing array should be of the bounding type.
– Mordechai
Apr 8 '13 at 5:59
5
@AaronDigulla Just to clarify that's not assignment, but initialization of a local variable. You can't annotate an expression/statement.
– kennytm
Sep 26 '13 at 12:17
1
@Varkhan Is there a way to resize these arrays from within the class implementation. For example if I want to resize after overflow like ArrayList. I looked up the Implementation of ArrayList they haveObject EMPTY_ELEMENTDATA = {}
for storage. Can I use this mechanism to resize without knowing the type using generics?
– JourneyMan
Aug 28 '14 at 17:53
2
For those who want to make a method with a generic type (which was what I was looking for), use this:public void <T> T newArray(Class<T> type, int length) { ... }
– Daniel Kvist
Mar 13 '15 at 14:44
|
show 2 more comments
up vote
169
down vote
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 ClassCastException
s 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 List
s 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.
38
This will not work if the array is treated as a typed array of any kind, such asString s=b;
in the abovetest()
method. That's because the array of E isn't really, it's Object. This matters if you want, e.g. aList<String>
- you can't use anObject
for that, you must have aList
specifically. Which is why you need to use the reflected Class<?> array creation.
– Lawrence Dol
Oct 11 '10 at 16:09
6
The corner-case/problem is if you want to do, for example,public E toArray() { return (E)internalArray.clone(); }
wheninternalArray
is typed asE
, and is therefore actually anObject
. This fails at runtime with a type-cast exception because anObject
cannot be assigned to an array of whatever typeE
happens to be.
– Lawrence Dol
Aug 10 '11 at 20:04
15
Basically, this approach will work as long as you do not return the array or pass it or store it in some place outside of the class that requires an array of a certain type. As long as you're inside the class you're fine because E is erased. It's "dangerous" because if you try to return it or something, you get no warning that it's unsafe. But if you're careful then it works.
– newacct
Sep 23 '11 at 22:07
2
It is quite safe. InE b = (E)new Object[1];
you can clearly see that the only reference to the created array isb
and that the type ofb
isE
. Therefore there is no danger of you accidentally accessing the same array through a different variable of a different type. If instead, you hadObject a = new Object[1]; Eb = (E)a;
then you would need to be paranoid about how you usea
.
– Aaron McDaid
Jan 21 '12 at 19:53
4
At least in Java 1.6, this generates a warning: "Unchecked cast from Object to T"
– Quantum7
Mar 24 '12 at 0:42
|
show 13 more comments
up vote
58
down vote
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));
}
4
This is useless, it is only a complicated way to write new String[...]. But what is really needed is something like public static <T> T newArray(int size) { ... }, and this simply does not exist in java noir can it be simulated with reflection - the reason is that information about how a generic type is instantiated is not available at runtime.
– Ingo
Mar 21 '11 at 10:11
4
@Ingo What are you talking about? My code can be used to create an array of any type.
– gdejohn
Mar 23 '11 at 12:34
2
@Charlatan: Sure, but so can new . The question is: who knows the type and when. Therefore, if all you have is a generic type, you can't.
– Ingo
Mar 23 '11 at 12:48
@Ingo That's static. This is dynamic. I'm not sure what you don't understand.
– gdejohn
Mar 23 '11 at 12:54
1
I don't doubt that. The point is, you don't get a Class object at runtime for generic type X.
– Ingo
Mar 23 '11 at 12:58
|
show 9 more comments
up vote
36
down vote
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);
}
I had to look it up, but yes, the second "length" argument toArrays#copyOf()
is independent of the length of the array supplied as the first argument. That's clever, though it does pay the cost of calls toMath#min()
andSystem#arrayCopy()
, neither of which are strictly necessary to get this job done. docs.oracle.com/javase/7/docs/api/java/util/…
– seh
Oct 4 '12 at 19:53
5
This does not work ifE
is a type variable. The varargs creates an array of erasure ofE
whenE
is a type variable, making it not much different from(E)new Object[n]
. Please see http://ideone.com/T8xF91. It is by no means more type safe than any other answer.
– Radiodef
Apr 6 '15 at 4:13
1
@Radiodef - the solution is provably type-safe at compile time. note that erasure is not exactly part of the language spec; the spec is written carefully so that we could have full reification in future - and then this solution would work perfectly at runtime too, unlike other solutions.
– ZhongYu
May 18 '15 at 18:35
@Radiodef - It's debatable whether banning generic array creation is a good idea. regardless, the language does leave a backdoor - vararg requires generic array creation. It is as good as if the language have permittednew E
. The problem you showed in your example is a general erasure problem, not unique to this question and this answer.
– ZhongYu
May 18 '15 at 18:38
2
@Radiodef - There are some differences. The correctness of this solution is checked by the compiler; it does not rely on human reasoning of forced cast. The difference is not significant for this particular problem. Some people just like to be a little fancy, that's all. If anyone is misled by OP's wording, it's clarified by your comments and mine.
– ZhongYu
May 18 '15 at 19:19
|
show 4 more comments
up vote
28
down vote
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.
4
+1 There have been questions about multi-dimensional array creation that get closed as dupes of this post - but no answers had specifically addressed that.
– Paul Bellora
Aug 15 '13 at 13:52
Could this be an answer here?: stackoverflow.com/q/5670972
– JordanC
Nov 11 '14 at 19:48
1
@JordanC Maybe; although it is the same in spirit as stackoverflow.com/a/5671304/616460; I will think about best way to handle tomorrow. I am sleepy.
– Jason C
Nov 12 '14 at 5:19
add a comment |
up vote
11
down vote
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 don't really need a special interface likeArraySupplier
for this, you can declare the constructor asGenSet(Supplier<E> supplier) { ...
and call it with the same line as you have.
– Lii
Dec 27 '15 at 23:49
3
@Lii To be the same as my example, it would beIntFunction<E>
, but yes that's true.
– Radiodef
Dec 28 '15 at 16:16
add a comment |
up vote
10
down vote
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.
add a comment |
up vote
7
down vote
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.
add a comment |
up vote
6
down vote
Hi although the thread is dead, I would like to draw your attention to this:
Generics is used for type checking during compile time:
- Therefore the purpose is to check that what comes in is what you need.
- What you return is what the consumer needs.
- Check this:
Do don't worry about typecasting warnings when you are writing generic class. Worry when you are using it.
add a comment |
up vote
5
down vote
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?
2
Neat, but only works if you call it 'manually', i.e. pass the elements individually. If you can't create a new instance ofT
, then you can't programatically build up aT elems
to pass into the function. And if you could, you wouldn't need the function.
– orlade
Aug 29 '16 at 1:41
add a comment |
up vote
5
down vote
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.
add a comment |
up vote
4
down vote
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.
1
This of course fails if the array is empty.
– Kevin Cox
Feb 7 '14 at 14:05
by array you mean obj? if so, I didn't get your point
– MatheusJardimB
Feb 7 '14 at 14:40
Yes, you return null, which isn't the expected empty array. It is the best you can do, but not ideal.
– Kevin Cox
Feb 7 '14 at 14:49
Thanks, got it :)
– MatheusJardimB
Feb 7 '14 at 14:50
This can also fail if theList
has more than one type of object in it e.g.toArray(Arrays.asList("abc", new Object()))
will throwArrayStoreException
.
– Radiodef
Apr 6 '15 at 4:36
|
show 1 more comment
up vote
3
down vote
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.
12
The second example (using Array.newInstance()) is in fact typesafe. This is possible because the type T of the Class object needs to match the T of the array. It basically forces you to provide the information that the Java runtime discards for generics.
– Joachim Sauer
Feb 9 '09 at 22:41
add a comment |
up vote
3
down vote
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.
add a comment |
up vote
3
down vote
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
add a comment |
up vote
3
down vote
You do not need to pass the Class argument to the constructor.
Try this.
static class GenSet<T> {
private final T array;
@SuppressWarnings("unchecked")
public GenSet(int capacity, T... dummy) {
if (dummy.length > 0)
throw new IllegalArgumentException(
"Do not provide values for dummy argument.");
Class<?> c = dummy.getClass().getComponentType();
array = (T)Array.newInstance(c, 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]
add a comment |
up vote
2
down vote
Passing a list of values...
public <T> T array(T... values) {
return values;
}
add a comment |
up vote
1
down vote
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.
add a comment |
up vote
1
down vote
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.).
add a comment |
up vote
1
down vote
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.
add a comment |
up vote
0
down vote
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.
"We're looking for long answers that provide some explanation and context. Don't just give a one-line answer; explain why your answer is correct, ideally with citations. Answers without explanations may be removed."
– gparyani
Sep 16 '14 at 15:46
BUt that won`t work in some cases like if your generic class wants to implement Comparable interface.
– RamPrasadBismil
Apr 21 '16 at 8:55
Welcome to seven years ago, I suppose.
– Esko
Apr 26 '16 at 19:03
This will not work if you try to return the array from the generic code to a non-generic caller. There will be a head-scrating classcastexception.
– plugwash
Jul 12 '17 at 12:52
add a comment |
up vote
0
down vote
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>();
}
}
}
I can't get your code running, where does yourElement
class comes from?
– Xetra
Feb 21 at 0:15
add a comment |
up vote
0
down vote
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]
}
3
This doesn't actually work.new Holder<Thing>[10]
is a generic array creation.
– Radiodef
Mar 10 '14 at 19:43
add a comment |
up vote
0
down vote
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];
Yeah, this is not quite related, but rooted in the same issues (erasure, array covariance). Here's an example of a post about creating arrays of parameterized types: stackoverflow.com/questions/9542076/…
– Paul Bellora
Aug 21 '13 at 16:23
add a comment |
up vote
0
down vote
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.
No, this does not work. The varargs creates erasure ofT
whenT
is a type variable, i.e.zeroArray
returns anObject
. See http://ideone.com/T8xF91.
– Radiodef
Apr 6 '15 at 4:03
add a comment |
up vote
0
down vote
You could use a cast:
public class GenSet<Item> {
private Item a;
public GenSet(int s) {
a = (Item) new Object[s];
}
}
If you are going to suggest this, you really need to explain its limitations. Never exposea
to outside the class!
– Radiodef
Apr 6 '15 at 4:00
add a comment |
up vote
0
down vote
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++;
}
1
The question was about creating an array of the type of the generic type parameterT
, not an array of some parameterized type.
– Sotirios Delimanolis
Jun 29 '17 at 15:14
It completes the same task though and doesn't require you pushing in a class making your custom collection easier to use.
– Crab Nebula
Jun 29 '17 at 23:50
What task? It's literally a different task: an array of a paramaterized type vs an array of a generic type parameter.
– Sotirios Delimanolis
Jun 30 '17 at 0:16
It allows you to create an array from a generic type? The original problem was initializing an array using a generic type which using my method allows you to do without having to have the user push in a class or give an unchecked error such as trying to cast an Object to a String. Like chill, I'm not the best at what I do, and I haven't gone to school for programming but I think I still deserve a little input rather than being told off by some other kid on the internet.
– Crab Nebula
Jun 30 '17 at 23:53
I agree with Sotiros. There are two ways to think of the answer. Either it is an answer to a different question, or it is an attempt to generalize the question. Both are wrong / not helpful. People who are looking for guidance on how to implement a "generic array" class would / stop reading when they read the question title. And when they find an Q with 30 answers, they are highly unlikely to scroll to the end and read a zero vote answer from a SO newcomer.
– Stephen C
Jul 11 '17 at 23:00
|
show 1 more comment
up vote
-1
down vote
private E a;
private int size;
public GenSet(int elem)
{
size = elem;
a = (E) new E[size];
}
You should always add an explanation to your code, and explain why it solves the original posted question.
– mjuarez
Jun 3 '15 at 6:11
add a comment |
up vote
-1
down vote
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];
}
}
add a comment |
protected by Aniket Thakur Oct 2 '15 at 19:02
Thank you for your interest in this question.
Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).
Would you like to answer one of these unanswered questions instead?
29 Answers
29
active
oldest
votes
29 Answers
29
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
609
down vote
accepted
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 aClass<E>
argument, and methods will throw an exception when they are passed arguments that are not of typeE
. SeeCollections.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.
4
What would performance-wise be the best option? I need to get elements from this array quite often (within a loop). So a collection is probably slower, but which of these two is fastest?
– user1111929
Sep 8 '12 at 3:52
3
And if the generic type is bounded, the backing array should be of the bounding type.
– Mordechai
Apr 8 '13 at 5:59
5
@AaronDigulla Just to clarify that's not assignment, but initialization of a local variable. You can't annotate an expression/statement.
– kennytm
Sep 26 '13 at 12:17
1
@Varkhan Is there a way to resize these arrays from within the class implementation. For example if I want to resize after overflow like ArrayList. I looked up the Implementation of ArrayList they haveObject EMPTY_ELEMENTDATA = {}
for storage. Can I use this mechanism to resize without knowing the type using generics?
– JourneyMan
Aug 28 '14 at 17:53
2
For those who want to make a method with a generic type (which was what I was looking for), use this:public void <T> T newArray(Class<T> type, int length) { ... }
– Daniel Kvist
Mar 13 '15 at 14:44
|
show 2 more comments
up vote
609
down vote
accepted
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 aClass<E>
argument, and methods will throw an exception when they are passed arguments that are not of typeE
. SeeCollections.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.
4
What would performance-wise be the best option? I need to get elements from this array quite often (within a loop). So a collection is probably slower, but which of these two is fastest?
– user1111929
Sep 8 '12 at 3:52
3
And if the generic type is bounded, the backing array should be of the bounding type.
– Mordechai
Apr 8 '13 at 5:59
5
@AaronDigulla Just to clarify that's not assignment, but initialization of a local variable. You can't annotate an expression/statement.
– kennytm
Sep 26 '13 at 12:17
1
@Varkhan Is there a way to resize these arrays from within the class implementation. For example if I want to resize after overflow like ArrayList. I looked up the Implementation of ArrayList they haveObject EMPTY_ELEMENTDATA = {}
for storage. Can I use this mechanism to resize without knowing the type using generics?
– JourneyMan
Aug 28 '14 at 17:53
2
For those who want to make a method with a generic type (which was what I was looking for), use this:public void <T> T newArray(Class<T> type, int length) { ... }
– Daniel Kvist
Mar 13 '15 at 14:44
|
show 2 more comments
up vote
609
down vote
accepted
up vote
609
down vote
accepted
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 aClass<E>
argument, and methods will throw an exception when they are passed arguments that are not of typeE
. SeeCollections.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.
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 aClass<E>
argument, and methods will throw an exception when they are passed arguments that are not of typeE
. SeeCollections.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.
edited Apr 6 '15 at 4:19
Radiodef
31.4k126595
31.4k126595
answered Feb 9 '09 at 22:19
Varkhan
13.7k42523
13.7k42523
4
What would performance-wise be the best option? I need to get elements from this array quite often (within a loop). So a collection is probably slower, but which of these two is fastest?
– user1111929
Sep 8 '12 at 3:52
3
And if the generic type is bounded, the backing array should be of the bounding type.
– Mordechai
Apr 8 '13 at 5:59
5
@AaronDigulla Just to clarify that's not assignment, but initialization of a local variable. You can't annotate an expression/statement.
– kennytm
Sep 26 '13 at 12:17
1
@Varkhan Is there a way to resize these arrays from within the class implementation. For example if I want to resize after overflow like ArrayList. I looked up the Implementation of ArrayList they haveObject EMPTY_ELEMENTDATA = {}
for storage. Can I use this mechanism to resize without knowing the type using generics?
– JourneyMan
Aug 28 '14 at 17:53
2
For those who want to make a method with a generic type (which was what I was looking for), use this:public void <T> T newArray(Class<T> type, int length) { ... }
– Daniel Kvist
Mar 13 '15 at 14:44
|
show 2 more comments
4
What would performance-wise be the best option? I need to get elements from this array quite often (within a loop). So a collection is probably slower, but which of these two is fastest?
– user1111929
Sep 8 '12 at 3:52
3
And if the generic type is bounded, the backing array should be of the bounding type.
– Mordechai
Apr 8 '13 at 5:59
5
@AaronDigulla Just to clarify that's not assignment, but initialization of a local variable. You can't annotate an expression/statement.
– kennytm
Sep 26 '13 at 12:17
1
@Varkhan Is there a way to resize these arrays from within the class implementation. For example if I want to resize after overflow like ArrayList. I looked up the Implementation of ArrayList they haveObject EMPTY_ELEMENTDATA = {}
for storage. Can I use this mechanism to resize without knowing the type using generics?
– JourneyMan
Aug 28 '14 at 17:53
2
For those who want to make a method with a generic type (which was what I was looking for), use this:public void <T> T newArray(Class<T> type, int length) { ... }
– Daniel Kvist
Mar 13 '15 at 14:44
4
4
What would performance-wise be the best option? I need to get elements from this array quite often (within a loop). So a collection is probably slower, but which of these two is fastest?
– user1111929
Sep 8 '12 at 3:52
What would performance-wise be the best option? I need to get elements from this array quite often (within a loop). So a collection is probably slower, but which of these two is fastest?
– user1111929
Sep 8 '12 at 3:52
3
3
And if the generic type is bounded, the backing array should be of the bounding type.
– Mordechai
Apr 8 '13 at 5:59
And if the generic type is bounded, the backing array should be of the bounding type.
– Mordechai
Apr 8 '13 at 5:59
5
5
@AaronDigulla Just to clarify that's not assignment, but initialization of a local variable. You can't annotate an expression/statement.
– kennytm
Sep 26 '13 at 12:17
@AaronDigulla Just to clarify that's not assignment, but initialization of a local variable. You can't annotate an expression/statement.
– kennytm
Sep 26 '13 at 12:17
1
1
@Varkhan Is there a way to resize these arrays from within the class implementation. For example if I want to resize after overflow like ArrayList. I looked up the Implementation of ArrayList they have
Object EMPTY_ELEMENTDATA = {}
for storage. Can I use this mechanism to resize without knowing the type using generics?– JourneyMan
Aug 28 '14 at 17:53
@Varkhan Is there a way to resize these arrays from within the class implementation. For example if I want to resize after overflow like ArrayList. I looked up the Implementation of ArrayList they have
Object EMPTY_ELEMENTDATA = {}
for storage. Can I use this mechanism to resize without knowing the type using generics?– JourneyMan
Aug 28 '14 at 17:53
2
2
For those who want to make a method with a generic type (which was what I was looking for), use this:
public void <T> T newArray(Class<T> type, int length) { ... }
– Daniel Kvist
Mar 13 '15 at 14:44
For those who want to make a method with a generic type (which was what I was looking for), use this:
public void <T> T newArray(Class<T> type, int length) { ... }
– Daniel Kvist
Mar 13 '15 at 14:44
|
show 2 more comments
up vote
169
down vote
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 ClassCastException
s 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 List
s 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.
38
This will not work if the array is treated as a typed array of any kind, such asString s=b;
in the abovetest()
method. That's because the array of E isn't really, it's Object. This matters if you want, e.g. aList<String>
- you can't use anObject
for that, you must have aList
specifically. Which is why you need to use the reflected Class<?> array creation.
– Lawrence Dol
Oct 11 '10 at 16:09
6
The corner-case/problem is if you want to do, for example,public E toArray() { return (E)internalArray.clone(); }
wheninternalArray
is typed asE
, and is therefore actually anObject
. This fails at runtime with a type-cast exception because anObject
cannot be assigned to an array of whatever typeE
happens to be.
– Lawrence Dol
Aug 10 '11 at 20:04
15
Basically, this approach will work as long as you do not return the array or pass it or store it in some place outside of the class that requires an array of a certain type. As long as you're inside the class you're fine because E is erased. It's "dangerous" because if you try to return it or something, you get no warning that it's unsafe. But if you're careful then it works.
– newacct
Sep 23 '11 at 22:07
2
It is quite safe. InE b = (E)new Object[1];
you can clearly see that the only reference to the created array isb
and that the type ofb
isE
. Therefore there is no danger of you accidentally accessing the same array through a different variable of a different type. If instead, you hadObject a = new Object[1]; Eb = (E)a;
then you would need to be paranoid about how you usea
.
– Aaron McDaid
Jan 21 '12 at 19:53
4
At least in Java 1.6, this generates a warning: "Unchecked cast from Object to T"
– Quantum7
Mar 24 '12 at 0:42
|
show 13 more comments
up vote
169
down vote
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 ClassCastException
s 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 List
s 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.
38
This will not work if the array is treated as a typed array of any kind, such asString s=b;
in the abovetest()
method. That's because the array of E isn't really, it's Object. This matters if you want, e.g. aList<String>
- you can't use anObject
for that, you must have aList
specifically. Which is why you need to use the reflected Class<?> array creation.
– Lawrence Dol
Oct 11 '10 at 16:09
6
The corner-case/problem is if you want to do, for example,public E toArray() { return (E)internalArray.clone(); }
wheninternalArray
is typed asE
, and is therefore actually anObject
. This fails at runtime with a type-cast exception because anObject
cannot be assigned to an array of whatever typeE
happens to be.
– Lawrence Dol
Aug 10 '11 at 20:04
15
Basically, this approach will work as long as you do not return the array or pass it or store it in some place outside of the class that requires an array of a certain type. As long as you're inside the class you're fine because E is erased. It's "dangerous" because if you try to return it or something, you get no warning that it's unsafe. But if you're careful then it works.
– newacct
Sep 23 '11 at 22:07
2
It is quite safe. InE b = (E)new Object[1];
you can clearly see that the only reference to the created array isb
and that the type ofb
isE
. Therefore there is no danger of you accidentally accessing the same array through a different variable of a different type. If instead, you hadObject a = new Object[1]; Eb = (E)a;
then you would need to be paranoid about how you usea
.
– Aaron McDaid
Jan 21 '12 at 19:53
4
At least in Java 1.6, this generates a warning: "Unchecked cast from Object to T"
– Quantum7
Mar 24 '12 at 0:42
|
show 13 more comments
up vote
169
down vote
up vote
169
down vote
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 ClassCastException
s 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 List
s 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.
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 ClassCastException
s 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 List
s 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.
edited Nov 29 at 23:24
answered May 27 '10 at 20:00
dimo414
31k12101168
31k12101168
38
This will not work if the array is treated as a typed array of any kind, such asString s=b;
in the abovetest()
method. That's because the array of E isn't really, it's Object. This matters if you want, e.g. aList<String>
- you can't use anObject
for that, you must have aList
specifically. Which is why you need to use the reflected Class<?> array creation.
– Lawrence Dol
Oct 11 '10 at 16:09
6
The corner-case/problem is if you want to do, for example,public E toArray() { return (E)internalArray.clone(); }
wheninternalArray
is typed asE
, and is therefore actually anObject
. This fails at runtime with a type-cast exception because anObject
cannot be assigned to an array of whatever typeE
happens to be.
– Lawrence Dol
Aug 10 '11 at 20:04
15
Basically, this approach will work as long as you do not return the array or pass it or store it in some place outside of the class that requires an array of a certain type. As long as you're inside the class you're fine because E is erased. It's "dangerous" because if you try to return it or something, you get no warning that it's unsafe. But if you're careful then it works.
– newacct
Sep 23 '11 at 22:07
2
It is quite safe. InE b = (E)new Object[1];
you can clearly see that the only reference to the created array isb
and that the type ofb
isE
. Therefore there is no danger of you accidentally accessing the same array through a different variable of a different type. If instead, you hadObject a = new Object[1]; Eb = (E)a;
then you would need to be paranoid about how you usea
.
– Aaron McDaid
Jan 21 '12 at 19:53
4
At least in Java 1.6, this generates a warning: "Unchecked cast from Object to T"
– Quantum7
Mar 24 '12 at 0:42
|
show 13 more comments
38
This will not work if the array is treated as a typed array of any kind, such asString s=b;
in the abovetest()
method. That's because the array of E isn't really, it's Object. This matters if you want, e.g. aList<String>
- you can't use anObject
for that, you must have aList
specifically. Which is why you need to use the reflected Class<?> array creation.
– Lawrence Dol
Oct 11 '10 at 16:09
6
The corner-case/problem is if you want to do, for example,public E toArray() { return (E)internalArray.clone(); }
wheninternalArray
is typed asE
, and is therefore actually anObject
. This fails at runtime with a type-cast exception because anObject
cannot be assigned to an array of whatever typeE
happens to be.
– Lawrence Dol
Aug 10 '11 at 20:04
15
Basically, this approach will work as long as you do not return the array or pass it or store it in some place outside of the class that requires an array of a certain type. As long as you're inside the class you're fine because E is erased. It's "dangerous" because if you try to return it or something, you get no warning that it's unsafe. But if you're careful then it works.
– newacct
Sep 23 '11 at 22:07
2
It is quite safe. InE b = (E)new Object[1];
you can clearly see that the only reference to the created array isb
and that the type ofb
isE
. Therefore there is no danger of you accidentally accessing the same array through a different variable of a different type. If instead, you hadObject a = new Object[1]; Eb = (E)a;
then you would need to be paranoid about how you usea
.
– Aaron McDaid
Jan 21 '12 at 19:53
4
At least in Java 1.6, this generates a warning: "Unchecked cast from Object to T"
– Quantum7
Mar 24 '12 at 0:42
38
38
This will not work if the array is treated as a typed array of any kind, such as
String s=b;
in the above test()
method. That's because the array of E isn't really, it's Object. This matters if you want, e.g. a List<String>
- you can't use an Object
for that, you must have a List
specifically. Which is why you need to use the reflected Class<?> array creation.– Lawrence Dol
Oct 11 '10 at 16:09
This will not work if the array is treated as a typed array of any kind, such as
String s=b;
in the above test()
method. That's because the array of E isn't really, it's Object. This matters if you want, e.g. a List<String>
- you can't use an Object
for that, you must have a List
specifically. Which is why you need to use the reflected Class<?> array creation.– Lawrence Dol
Oct 11 '10 at 16:09
6
6
The corner-case/problem is if you want to do, for example,
public E toArray() { return (E)internalArray.clone(); }
when internalArray
is typed as E
, and is therefore actually an Object
. This fails at runtime with a type-cast exception because an Object
cannot be assigned to an array of whatever type E
happens to be.– Lawrence Dol
Aug 10 '11 at 20:04
The corner-case/problem is if you want to do, for example,
public E toArray() { return (E)internalArray.clone(); }
when internalArray
is typed as E
, and is therefore actually an Object
. This fails at runtime with a type-cast exception because an Object
cannot be assigned to an array of whatever type E
happens to be.– Lawrence Dol
Aug 10 '11 at 20:04
15
15
Basically, this approach will work as long as you do not return the array or pass it or store it in some place outside of the class that requires an array of a certain type. As long as you're inside the class you're fine because E is erased. It's "dangerous" because if you try to return it or something, you get no warning that it's unsafe. But if you're careful then it works.
– newacct
Sep 23 '11 at 22:07
Basically, this approach will work as long as you do not return the array or pass it or store it in some place outside of the class that requires an array of a certain type. As long as you're inside the class you're fine because E is erased. It's "dangerous" because if you try to return it or something, you get no warning that it's unsafe. But if you're careful then it works.
– newacct
Sep 23 '11 at 22:07
2
2
It is quite safe. In
E b = (E)new Object[1];
you can clearly see that the only reference to the created array is b
and that the type of b
is E
. Therefore there is no danger of you accidentally accessing the same array through a different variable of a different type. If instead, you had Object a = new Object[1]; Eb = (E)a;
then you would need to be paranoid about how you use a
.– Aaron McDaid
Jan 21 '12 at 19:53
It is quite safe. In
E b = (E)new Object[1];
you can clearly see that the only reference to the created array is b
and that the type of b
is E
. Therefore there is no danger of you accidentally accessing the same array through a different variable of a different type. If instead, you had Object a = new Object[1]; Eb = (E)a;
then you would need to be paranoid about how you use a
.– Aaron McDaid
Jan 21 '12 at 19:53
4
4
At least in Java 1.6, this generates a warning: "Unchecked cast from Object to T"
– Quantum7
Mar 24 '12 at 0:42
At least in Java 1.6, this generates a warning: "Unchecked cast from Object to T"
– Quantum7
Mar 24 '12 at 0:42
|
show 13 more comments
up vote
58
down vote
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));
}
4
This is useless, it is only a complicated way to write new String[...]. But what is really needed is something like public static <T> T newArray(int size) { ... }, and this simply does not exist in java noir can it be simulated with reflection - the reason is that information about how a generic type is instantiated is not available at runtime.
– Ingo
Mar 21 '11 at 10:11
4
@Ingo What are you talking about? My code can be used to create an array of any type.
– gdejohn
Mar 23 '11 at 12:34
2
@Charlatan: Sure, but so can new . The question is: who knows the type and when. Therefore, if all you have is a generic type, you can't.
– Ingo
Mar 23 '11 at 12:48
@Ingo That's static. This is dynamic. I'm not sure what you don't understand.
– gdejohn
Mar 23 '11 at 12:54
1
I don't doubt that. The point is, you don't get a Class object at runtime for generic type X.
– Ingo
Mar 23 '11 at 12:58
|
show 9 more comments
up vote
58
down vote
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));
}
4
This is useless, it is only a complicated way to write new String[...]. But what is really needed is something like public static <T> T newArray(int size) { ... }, and this simply does not exist in java noir can it be simulated with reflection - the reason is that information about how a generic type is instantiated is not available at runtime.
– Ingo
Mar 21 '11 at 10:11
4
@Ingo What are you talking about? My code can be used to create an array of any type.
– gdejohn
Mar 23 '11 at 12:34
2
@Charlatan: Sure, but so can new . The question is: who knows the type and when. Therefore, if all you have is a generic type, you can't.
– Ingo
Mar 23 '11 at 12:48
@Ingo That's static. This is dynamic. I'm not sure what you don't understand.
– gdejohn
Mar 23 '11 at 12:54
1
I don't doubt that. The point is, you don't get a Class object at runtime for generic type X.
– Ingo
Mar 23 '11 at 12:58
|
show 9 more comments
up vote
58
down vote
up vote
58
down vote
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));
}
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));
}
edited May 23 '17 at 12:34
Community♦
11
11
answered Nov 19 '10 at 3:30
gdejohn
5,2372441
5,2372441
4
This is useless, it is only a complicated way to write new String[...]. But what is really needed is something like public static <T> T newArray(int size) { ... }, and this simply does not exist in java noir can it be simulated with reflection - the reason is that information about how a generic type is instantiated is not available at runtime.
– Ingo
Mar 21 '11 at 10:11
4
@Ingo What are you talking about? My code can be used to create an array of any type.
– gdejohn
Mar 23 '11 at 12:34
2
@Charlatan: Sure, but so can new . The question is: who knows the type and when. Therefore, if all you have is a generic type, you can't.
– Ingo
Mar 23 '11 at 12:48
@Ingo That's static. This is dynamic. I'm not sure what you don't understand.
– gdejohn
Mar 23 '11 at 12:54
1
I don't doubt that. The point is, you don't get a Class object at runtime for generic type X.
– Ingo
Mar 23 '11 at 12:58
|
show 9 more comments
4
This is useless, it is only a complicated way to write new String[...]. But what is really needed is something like public static <T> T newArray(int size) { ... }, and this simply does not exist in java noir can it be simulated with reflection - the reason is that information about how a generic type is instantiated is not available at runtime.
– Ingo
Mar 21 '11 at 10:11
4
@Ingo What are you talking about? My code can be used to create an array of any type.
– gdejohn
Mar 23 '11 at 12:34
2
@Charlatan: Sure, but so can new . The question is: who knows the type and when. Therefore, if all you have is a generic type, you can't.
– Ingo
Mar 23 '11 at 12:48
@Ingo That's static. This is dynamic. I'm not sure what you don't understand.
– gdejohn
Mar 23 '11 at 12:54
1
I don't doubt that. The point is, you don't get a Class object at runtime for generic type X.
– Ingo
Mar 23 '11 at 12:58
4
4
This is useless, it is only a complicated way to write new String[...]. But what is really needed is something like public static <T> T newArray(int size) { ... }, and this simply does not exist in java noir can it be simulated with reflection - the reason is that information about how a generic type is instantiated is not available at runtime.
– Ingo
Mar 21 '11 at 10:11
This is useless, it is only a complicated way to write new String[...]. But what is really needed is something like public static <T> T newArray(int size) { ... }, and this simply does not exist in java noir can it be simulated with reflection - the reason is that information about how a generic type is instantiated is not available at runtime.
– Ingo
Mar 21 '11 at 10:11
4
4
@Ingo What are you talking about? My code can be used to create an array of any type.
– gdejohn
Mar 23 '11 at 12:34
@Ingo What are you talking about? My code can be used to create an array of any type.
– gdejohn
Mar 23 '11 at 12:34
2
2
@Charlatan: Sure, but so can new . The question is: who knows the type and when. Therefore, if all you have is a generic type, you can't.
– Ingo
Mar 23 '11 at 12:48
@Charlatan: Sure, but so can new . The question is: who knows the type and when. Therefore, if all you have is a generic type, you can't.
– Ingo
Mar 23 '11 at 12:48
@Ingo That's static. This is dynamic. I'm not sure what you don't understand.
– gdejohn
Mar 23 '11 at 12:54
@Ingo That's static. This is dynamic. I'm not sure what you don't understand.
– gdejohn
Mar 23 '11 at 12:54
1
1
I don't doubt that. The point is, you don't get a Class object at runtime for generic type X.
– Ingo
Mar 23 '11 at 12:58
I don't doubt that. The point is, you don't get a Class object at runtime for generic type X.
– Ingo
Mar 23 '11 at 12:58
|
show 9 more comments
up vote
36
down vote
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);
}
I had to look it up, but yes, the second "length" argument toArrays#copyOf()
is independent of the length of the array supplied as the first argument. That's clever, though it does pay the cost of calls toMath#min()
andSystem#arrayCopy()
, neither of which are strictly necessary to get this job done. docs.oracle.com/javase/7/docs/api/java/util/…
– seh
Oct 4 '12 at 19:53
5
This does not work ifE
is a type variable. The varargs creates an array of erasure ofE
whenE
is a type variable, making it not much different from(E)new Object[n]
. Please see http://ideone.com/T8xF91. It is by no means more type safe than any other answer.
– Radiodef
Apr 6 '15 at 4:13
1
@Radiodef - the solution is provably type-safe at compile time. note that erasure is not exactly part of the language spec; the spec is written carefully so that we could have full reification in future - and then this solution would work perfectly at runtime too, unlike other solutions.
– ZhongYu
May 18 '15 at 18:35
@Radiodef - It's debatable whether banning generic array creation is a good idea. regardless, the language does leave a backdoor - vararg requires generic array creation. It is as good as if the language have permittednew E
. The problem you showed in your example is a general erasure problem, not unique to this question and this answer.
– ZhongYu
May 18 '15 at 18:38
2
@Radiodef - There are some differences. The correctness of this solution is checked by the compiler; it does not rely on human reasoning of forced cast. The difference is not significant for this particular problem. Some people just like to be a little fancy, that's all. If anyone is misled by OP's wording, it's clarified by your comments and mine.
– ZhongYu
May 18 '15 at 19:19
|
show 4 more comments
up vote
36
down vote
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);
}
I had to look it up, but yes, the second "length" argument toArrays#copyOf()
is independent of the length of the array supplied as the first argument. That's clever, though it does pay the cost of calls toMath#min()
andSystem#arrayCopy()
, neither of which are strictly necessary to get this job done. docs.oracle.com/javase/7/docs/api/java/util/…
– seh
Oct 4 '12 at 19:53
5
This does not work ifE
is a type variable. The varargs creates an array of erasure ofE
whenE
is a type variable, making it not much different from(E)new Object[n]
. Please see http://ideone.com/T8xF91. It is by no means more type safe than any other answer.
– Radiodef
Apr 6 '15 at 4:13
1
@Radiodef - the solution is provably type-safe at compile time. note that erasure is not exactly part of the language spec; the spec is written carefully so that we could have full reification in future - and then this solution would work perfectly at runtime too, unlike other solutions.
– ZhongYu
May 18 '15 at 18:35
@Radiodef - It's debatable whether banning generic array creation is a good idea. regardless, the language does leave a backdoor - vararg requires generic array creation. It is as good as if the language have permittednew E
. The problem you showed in your example is a general erasure problem, not unique to this question and this answer.
– ZhongYu
May 18 '15 at 18:38
2
@Radiodef - There are some differences. The correctness of this solution is checked by the compiler; it does not rely on human reasoning of forced cast. The difference is not significant for this particular problem. Some people just like to be a little fancy, that's all. If anyone is misled by OP's wording, it's clarified by your comments and mine.
– ZhongYu
May 18 '15 at 19:19
|
show 4 more comments
up vote
36
down vote
up vote
36
down vote
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);
}
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);
}
edited Apr 6 '15 at 4:11
Radiodef
31.4k126595
31.4k126595
answered Nov 8 '11 at 15:28
irreputable
38.8k75483
38.8k75483
I had to look it up, but yes, the second "length" argument toArrays#copyOf()
is independent of the length of the array supplied as the first argument. That's clever, though it does pay the cost of calls toMath#min()
andSystem#arrayCopy()
, neither of which are strictly necessary to get this job done. docs.oracle.com/javase/7/docs/api/java/util/…
– seh
Oct 4 '12 at 19:53
5
This does not work ifE
is a type variable. The varargs creates an array of erasure ofE
whenE
is a type variable, making it not much different from(E)new Object[n]
. Please see http://ideone.com/T8xF91. It is by no means more type safe than any other answer.
– Radiodef
Apr 6 '15 at 4:13
1
@Radiodef - the solution is provably type-safe at compile time. note that erasure is not exactly part of the language spec; the spec is written carefully so that we could have full reification in future - and then this solution would work perfectly at runtime too, unlike other solutions.
– ZhongYu
May 18 '15 at 18:35
@Radiodef - It's debatable whether banning generic array creation is a good idea. regardless, the language does leave a backdoor - vararg requires generic array creation. It is as good as if the language have permittednew E
. The problem you showed in your example is a general erasure problem, not unique to this question and this answer.
– ZhongYu
May 18 '15 at 18:38
2
@Radiodef - There are some differences. The correctness of this solution is checked by the compiler; it does not rely on human reasoning of forced cast. The difference is not significant for this particular problem. Some people just like to be a little fancy, that's all. If anyone is misled by OP's wording, it's clarified by your comments and mine.
– ZhongYu
May 18 '15 at 19:19
|
show 4 more comments
I had to look it up, but yes, the second "length" argument toArrays#copyOf()
is independent of the length of the array supplied as the first argument. That's clever, though it does pay the cost of calls toMath#min()
andSystem#arrayCopy()
, neither of which are strictly necessary to get this job done. docs.oracle.com/javase/7/docs/api/java/util/…
– seh
Oct 4 '12 at 19:53
5
This does not work ifE
is a type variable. The varargs creates an array of erasure ofE
whenE
is a type variable, making it not much different from(E)new Object[n]
. Please see http://ideone.com/T8xF91. It is by no means more type safe than any other answer.
– Radiodef
Apr 6 '15 at 4:13
1
@Radiodef - the solution is provably type-safe at compile time. note that erasure is not exactly part of the language spec; the spec is written carefully so that we could have full reification in future - and then this solution would work perfectly at runtime too, unlike other solutions.
– ZhongYu
May 18 '15 at 18:35
@Radiodef - It's debatable whether banning generic array creation is a good idea. regardless, the language does leave a backdoor - vararg requires generic array creation. It is as good as if the language have permittednew E
. The problem you showed in your example is a general erasure problem, not unique to this question and this answer.
– ZhongYu
May 18 '15 at 18:38
2
@Radiodef - There are some differences. The correctness of this solution is checked by the compiler; it does not rely on human reasoning of forced cast. The difference is not significant for this particular problem. Some people just like to be a little fancy, that's all. If anyone is misled by OP's wording, it's clarified by your comments and mine.
– ZhongYu
May 18 '15 at 19:19
I had to look it up, but yes, the second "length" argument to
Arrays#copyOf()
is independent of the length of the array supplied as the first argument. That's clever, though it does pay the cost of calls to Math#min()
and System#arrayCopy()
, neither of which are strictly necessary to get this job done. docs.oracle.com/javase/7/docs/api/java/util/…– seh
Oct 4 '12 at 19:53
I had to look it up, but yes, the second "length" argument to
Arrays#copyOf()
is independent of the length of the array supplied as the first argument. That's clever, though it does pay the cost of calls to Math#min()
and System#arrayCopy()
, neither of which are strictly necessary to get this job done. docs.oracle.com/javase/7/docs/api/java/util/…– seh
Oct 4 '12 at 19:53
5
5
This does not work if
E
is a type variable. The varargs creates an array of erasure of E
when E
is a type variable, making it not much different from (E)new Object[n]
. Please see http://ideone.com/T8xF91. It is by no means more type safe than any other answer.– Radiodef
Apr 6 '15 at 4:13
This does not work if
E
is a type variable. The varargs creates an array of erasure of E
when E
is a type variable, making it not much different from (E)new Object[n]
. Please see http://ideone.com/T8xF91. It is by no means more type safe than any other answer.– Radiodef
Apr 6 '15 at 4:13
1
1
@Radiodef - the solution is provably type-safe at compile time. note that erasure is not exactly part of the language spec; the spec is written carefully so that we could have full reification in future - and then this solution would work perfectly at runtime too, unlike other solutions.
– ZhongYu
May 18 '15 at 18:35
@Radiodef - the solution is provably type-safe at compile time. note that erasure is not exactly part of the language spec; the spec is written carefully so that we could have full reification in future - and then this solution would work perfectly at runtime too, unlike other solutions.
– ZhongYu
May 18 '15 at 18:35
@Radiodef - It's debatable whether banning generic array creation is a good idea. regardless, the language does leave a backdoor - vararg requires generic array creation. It is as good as if the language have permitted
new E
. The problem you showed in your example is a general erasure problem, not unique to this question and this answer.– ZhongYu
May 18 '15 at 18:38
@Radiodef - It's debatable whether banning generic array creation is a good idea. regardless, the language does leave a backdoor - vararg requires generic array creation. It is as good as if the language have permitted
new E
. The problem you showed in your example is a general erasure problem, not unique to this question and this answer.– ZhongYu
May 18 '15 at 18:38
2
2
@Radiodef - There are some differences. The correctness of this solution is checked by the compiler; it does not rely on human reasoning of forced cast. The difference is not significant for this particular problem. Some people just like to be a little fancy, that's all. If anyone is misled by OP's wording, it's clarified by your comments and mine.
– ZhongYu
May 18 '15 at 19:19
@Radiodef - There are some differences. The correctness of this solution is checked by the compiler; it does not rely on human reasoning of forced cast. The difference is not significant for this particular problem. Some people just like to be a little fancy, that's all. If anyone is misled by OP's wording, it's clarified by your comments and mine.
– ZhongYu
May 18 '15 at 19:19
|
show 4 more comments
up vote
28
down vote
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.
4
+1 There have been questions about multi-dimensional array creation that get closed as dupes of this post - but no answers had specifically addressed that.
– Paul Bellora
Aug 15 '13 at 13:52
Could this be an answer here?: stackoverflow.com/q/5670972
– JordanC
Nov 11 '14 at 19:48
1
@JordanC Maybe; although it is the same in spirit as stackoverflow.com/a/5671304/616460; I will think about best way to handle tomorrow. I am sleepy.
– Jason C
Nov 12 '14 at 5:19
add a comment |
up vote
28
down vote
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.
4
+1 There have been questions about multi-dimensional array creation that get closed as dupes of this post - but no answers had specifically addressed that.
– Paul Bellora
Aug 15 '13 at 13:52
Could this be an answer here?: stackoverflow.com/q/5670972
– JordanC
Nov 11 '14 at 19:48
1
@JordanC Maybe; although it is the same in spirit as stackoverflow.com/a/5671304/616460; I will think about best way to handle tomorrow. I am sleepy.
– Jason C
Nov 12 '14 at 5:19
add a comment |
up vote
28
down vote
up vote
28
down vote
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.
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.
edited Jan 12 '14 at 18:55
naXa
13k885132
13k885132
answered Aug 15 '13 at 13:47
Jason C
28.3k969121
28.3k969121
4
+1 There have been questions about multi-dimensional array creation that get closed as dupes of this post - but no answers had specifically addressed that.
– Paul Bellora
Aug 15 '13 at 13:52
Could this be an answer here?: stackoverflow.com/q/5670972
– JordanC
Nov 11 '14 at 19:48
1
@JordanC Maybe; although it is the same in spirit as stackoverflow.com/a/5671304/616460; I will think about best way to handle tomorrow. I am sleepy.
– Jason C
Nov 12 '14 at 5:19
add a comment |
4
+1 There have been questions about multi-dimensional array creation that get closed as dupes of this post - but no answers had specifically addressed that.
– Paul Bellora
Aug 15 '13 at 13:52
Could this be an answer here?: stackoverflow.com/q/5670972
– JordanC
Nov 11 '14 at 19:48
1
@JordanC Maybe; although it is the same in spirit as stackoverflow.com/a/5671304/616460; I will think about best way to handle tomorrow. I am sleepy.
– Jason C
Nov 12 '14 at 5:19
4
4
+1 There have been questions about multi-dimensional array creation that get closed as dupes of this post - but no answers had specifically addressed that.
– Paul Bellora
Aug 15 '13 at 13:52
+1 There have been questions about multi-dimensional array creation that get closed as dupes of this post - but no answers had specifically addressed that.
– Paul Bellora
Aug 15 '13 at 13:52
Could this be an answer here?: stackoverflow.com/q/5670972
– JordanC
Nov 11 '14 at 19:48
Could this be an answer here?: stackoverflow.com/q/5670972
– JordanC
Nov 11 '14 at 19:48
1
1
@JordanC Maybe; although it is the same in spirit as stackoverflow.com/a/5671304/616460; I will think about best way to handle tomorrow. I am sleepy.
– Jason C
Nov 12 '14 at 5:19
@JordanC Maybe; although it is the same in spirit as stackoverflow.com/a/5671304/616460; I will think about best way to handle tomorrow. I am sleepy.
– Jason C
Nov 12 '14 at 5:19
add a comment |
up vote
11
down vote
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 don't really need a special interface likeArraySupplier
for this, you can declare the constructor asGenSet(Supplier<E> supplier) { ...
and call it with the same line as you have.
– Lii
Dec 27 '15 at 23:49
3
@Lii To be the same as my example, it would beIntFunction<E>
, but yes that's true.
– Radiodef
Dec 28 '15 at 16:16
add a comment |
up vote
11
down vote
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 don't really need a special interface likeArraySupplier
for this, you can declare the constructor asGenSet(Supplier<E> supplier) { ...
and call it with the same line as you have.
– Lii
Dec 27 '15 at 23:49
3
@Lii To be the same as my example, it would beIntFunction<E>
, but yes that's true.
– Radiodef
Dec 28 '15 at 16:16
add a comment |
up vote
11
down vote
up vote
11
down vote
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.
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.
edited Jul 5 '17 at 1:17
answered Mar 5 '14 at 14:14
Radiodef
31.4k126595
31.4k126595
You don't really need a special interface likeArraySupplier
for this, you can declare the constructor asGenSet(Supplier<E> supplier) { ...
and call it with the same line as you have.
– Lii
Dec 27 '15 at 23:49
3
@Lii To be the same as my example, it would beIntFunction<E>
, but yes that's true.
– Radiodef
Dec 28 '15 at 16:16
add a comment |
You don't really need a special interface likeArraySupplier
for this, you can declare the constructor asGenSet(Supplier<E> supplier) { ...
and call it with the same line as you have.
– Lii
Dec 27 '15 at 23:49
3
@Lii To be the same as my example, it would beIntFunction<E>
, but yes that's true.
– Radiodef
Dec 28 '15 at 16:16
You don't really need a special interface like
ArraySupplier
for this, you can declare the constructor as GenSet(Supplier<E> supplier) { ...
and call it with the same line as you have.– Lii
Dec 27 '15 at 23:49
You don't really need a special interface like
ArraySupplier
for this, you can declare the constructor as GenSet(Supplier<E> supplier) { ...
and call it with the same line as you have.– Lii
Dec 27 '15 at 23:49
3
3
@Lii To be the same as my example, it would be
IntFunction<E>
, but yes that's true.– Radiodef
Dec 28 '15 at 16:16
@Lii To be the same as my example, it would be
IntFunction<E>
, but yes that's true.– Radiodef
Dec 28 '15 at 16:16
add a comment |
up vote
10
down vote
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.
add a comment |
up vote
10
down vote
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.
add a comment |
up vote
10
down vote
up vote
10
down vote
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.
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.
edited Aug 29 '16 at 16:56
answered Feb 9 '09 at 18:50
Jeff Olson
4,89721626
4,89721626
add a comment |
add a comment |
up vote
7
down vote
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.
add a comment |
up vote
7
down vote
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.
add a comment |
up vote
7
down vote
up vote
7
down vote
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.
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.
answered Feb 11 '09 at 10:07
Bill Michell
7,19932431
7,19932431
add a comment |
add a comment |
up vote
6
down vote
Hi although the thread is dead, I would like to draw your attention to this:
Generics is used for type checking during compile time:
- Therefore the purpose is to check that what comes in is what you need.
- What you return is what the consumer needs.
- Check this:
Do don't worry about typecasting warnings when you are writing generic class. Worry when you are using it.
add a comment |
up vote
6
down vote
Hi although the thread is dead, I would like to draw your attention to this:
Generics is used for type checking during compile time:
- Therefore the purpose is to check that what comes in is what you need.
- What you return is what the consumer needs.
- Check this:
Do don't worry about typecasting warnings when you are writing generic class. Worry when you are using it.
add a comment |
up vote
6
down vote
up vote
6
down vote
Hi although the thread is dead, I would like to draw your attention to this:
Generics is used for type checking during compile time:
- Therefore the purpose is to check that what comes in is what you need.
- What you return is what the consumer needs.
- Check this:
Do don't worry about typecasting warnings when you are writing generic class. Worry when you are using it.
Hi although the thread is dead, I would like to draw your attention to this:
Generics is used for type checking during compile time:
- Therefore the purpose is to check that what comes in is what you need.
- What you return is what the consumer needs.
- Check this:
Do don't worry about typecasting warnings when you are writing generic class. Worry when you are using it.
edited Dec 8 '12 at 10:56
assylias
243k49506647
243k49506647
answered Jun 14 '11 at 19:26
puneeth
6111
6111
add a comment |
add a comment |
up vote
5
down vote
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?
2
Neat, but only works if you call it 'manually', i.e. pass the elements individually. If you can't create a new instance ofT
, then you can't programatically build up aT elems
to pass into the function. And if you could, you wouldn't need the function.
– orlade
Aug 29 '16 at 1:41
add a comment |
up vote
5
down vote
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?
2
Neat, but only works if you call it 'manually', i.e. pass the elements individually. If you can't create a new instance ofT
, then you can't programatically build up aT elems
to pass into the function. And if you could, you wouldn't need the function.
– orlade
Aug 29 '16 at 1:41
add a comment |
up vote
5
down vote
up vote
5
down vote
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?
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?
answered Feb 21 '16 at 1:28
Benjamin M
8,8491573145
8,8491573145
2
Neat, but only works if you call it 'manually', i.e. pass the elements individually. If you can't create a new instance ofT
, then you can't programatically build up aT elems
to pass into the function. And if you could, you wouldn't need the function.
– orlade
Aug 29 '16 at 1:41
add a comment |
2
Neat, but only works if you call it 'manually', i.e. pass the elements individually. If you can't create a new instance ofT
, then you can't programatically build up aT elems
to pass into the function. And if you could, you wouldn't need the function.
– orlade
Aug 29 '16 at 1:41
2
2
Neat, but only works if you call it 'manually', i.e. pass the elements individually. If you can't create a new instance of
T
, then you can't programatically build up a T elems
to pass into the function. And if you could, you wouldn't need the function.– orlade
Aug 29 '16 at 1:41
Neat, but only works if you call it 'manually', i.e. pass the elements individually. If you can't create a new instance of
T
, then you can't programatically build up a T elems
to pass into the function. And if you could, you wouldn't need the function.– orlade
Aug 29 '16 at 1:41
add a comment |
up vote
5
down vote
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.
add a comment |
up vote
5
down vote
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.
add a comment |
up vote
5
down vote
up vote
5
down vote
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.
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.
answered Nov 9 '16 at 20:43
Nik-Lz
1,22031629
1,22031629
add a comment |
add a comment |
up vote
4
down vote
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.
1
This of course fails if the array is empty.
– Kevin Cox
Feb 7 '14 at 14:05
by array you mean obj? if so, I didn't get your point
– MatheusJardimB
Feb 7 '14 at 14:40
Yes, you return null, which isn't the expected empty array. It is the best you can do, but not ideal.
– Kevin Cox
Feb 7 '14 at 14:49
Thanks, got it :)
– MatheusJardimB
Feb 7 '14 at 14:50
This can also fail if theList
has more than one type of object in it e.g.toArray(Arrays.asList("abc", new Object()))
will throwArrayStoreException
.
– Radiodef
Apr 6 '15 at 4:36
|
show 1 more comment
up vote
4
down vote
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.
1
This of course fails if the array is empty.
– Kevin Cox
Feb 7 '14 at 14:05
by array you mean obj? if so, I didn't get your point
– MatheusJardimB
Feb 7 '14 at 14:40
Yes, you return null, which isn't the expected empty array. It is the best you can do, but not ideal.
– Kevin Cox
Feb 7 '14 at 14:49
Thanks, got it :)
– MatheusJardimB
Feb 7 '14 at 14:50
This can also fail if theList
has more than one type of object in it e.g.toArray(Arrays.asList("abc", new Object()))
will throwArrayStoreException
.
– Radiodef
Apr 6 '15 at 4:36
|
show 1 more comment
up vote
4
down vote
up vote
4
down vote
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.
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.
answered Aug 8 '13 at 23:32
MatheusJardimB
1,88942759
1,88942759
1
This of course fails if the array is empty.
– Kevin Cox
Feb 7 '14 at 14:05
by array you mean obj? if so, I didn't get your point
– MatheusJardimB
Feb 7 '14 at 14:40
Yes, you return null, which isn't the expected empty array. It is the best you can do, but not ideal.
– Kevin Cox
Feb 7 '14 at 14:49
Thanks, got it :)
– MatheusJardimB
Feb 7 '14 at 14:50
This can also fail if theList
has more than one type of object in it e.g.toArray(Arrays.asList("abc", new Object()))
will throwArrayStoreException
.
– Radiodef
Apr 6 '15 at 4:36
|
show 1 more comment
1
This of course fails if the array is empty.
– Kevin Cox
Feb 7 '14 at 14:05
by array you mean obj? if so, I didn't get your point
– MatheusJardimB
Feb 7 '14 at 14:40
Yes, you return null, which isn't the expected empty array. It is the best you can do, but not ideal.
– Kevin Cox
Feb 7 '14 at 14:49
Thanks, got it :)
– MatheusJardimB
Feb 7 '14 at 14:50
This can also fail if theList
has more than one type of object in it e.g.toArray(Arrays.asList("abc", new Object()))
will throwArrayStoreException
.
– Radiodef
Apr 6 '15 at 4:36
1
1
This of course fails if the array is empty.
– Kevin Cox
Feb 7 '14 at 14:05
This of course fails if the array is empty.
– Kevin Cox
Feb 7 '14 at 14:05
by array you mean obj? if so, I didn't get your point
– MatheusJardimB
Feb 7 '14 at 14:40
by array you mean obj? if so, I didn't get your point
– MatheusJardimB
Feb 7 '14 at 14:40
Yes, you return null, which isn't the expected empty array. It is the best you can do, but not ideal.
– Kevin Cox
Feb 7 '14 at 14:49
Yes, you return null, which isn't the expected empty array. It is the best you can do, but not ideal.
– Kevin Cox
Feb 7 '14 at 14:49
Thanks, got it :)
– MatheusJardimB
Feb 7 '14 at 14:50
Thanks, got it :)
– MatheusJardimB
Feb 7 '14 at 14:50
This can also fail if the
List
has more than one type of object in it e.g. toArray(Arrays.asList("abc", new Object()))
will throw ArrayStoreException
.– Radiodef
Apr 6 '15 at 4:36
This can also fail if the
List
has more than one type of object in it e.g. toArray(Arrays.asList("abc", new Object()))
will throw ArrayStoreException
.– Radiodef
Apr 6 '15 at 4:36
|
show 1 more comment
up vote
3
down vote
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.
12
The second example (using Array.newInstance()) is in fact typesafe. This is possible because the type T of the Class object needs to match the T of the array. It basically forces you to provide the information that the Java runtime discards for generics.
– Joachim Sauer
Feb 9 '09 at 22:41
add a comment |
up vote
3
down vote
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.
12
The second example (using Array.newInstance()) is in fact typesafe. This is possible because the type T of the Class object needs to match the T of the array. It basically forces you to provide the information that the Java runtime discards for generics.
– Joachim Sauer
Feb 9 '09 at 22:41
add a comment |
up vote
3
down vote
up vote
3
down vote
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.
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.
answered Feb 9 '09 at 17:33
Ola Bini
67466
67466
12
The second example (using Array.newInstance()) is in fact typesafe. This is possible because the type T of the Class object needs to match the T of the array. It basically forces you to provide the information that the Java runtime discards for generics.
– Joachim Sauer
Feb 9 '09 at 22:41
add a comment |
12
The second example (using Array.newInstance()) is in fact typesafe. This is possible because the type T of the Class object needs to match the T of the array. It basically forces you to provide the information that the Java runtime discards for generics.
– Joachim Sauer
Feb 9 '09 at 22:41
12
12
The second example (using Array.newInstance()) is in fact typesafe. This is possible because the type T of the Class object needs to match the T of the array. It basically forces you to provide the information that the Java runtime discards for generics.
– Joachim Sauer
Feb 9 '09 at 22:41
The second example (using Array.newInstance()) is in fact typesafe. This is possible because the type T of the Class object needs to match the T of the array. It basically forces you to provide the information that the Java runtime discards for generics.
– Joachim Sauer
Feb 9 '09 at 22:41
add a comment |
up vote
3
down vote
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.
add a comment |
up vote
3
down vote
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.
add a comment |
up vote
3
down vote
up vote
3
down vote
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.
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.
answered Aug 31 '12 at 10:39
Bobster
311
311
add a comment |
add a comment |
up vote
3
down vote
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
add a comment |
up vote
3
down vote
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
add a comment |
up vote
3
down vote
up vote
3
down vote
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
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
edited Jun 12 '15 at 9:53
shruti1810
2,87611126
2,87611126
answered Jun 12 '15 at 9:40
Pedram Esmaeeli
9118
9118
add a comment |
add a comment |
up vote
3
down vote
You do not need to pass the Class argument to the constructor.
Try this.
static class GenSet<T> {
private final T array;
@SuppressWarnings("unchecked")
public GenSet(int capacity, T... dummy) {
if (dummy.length > 0)
throw new IllegalArgumentException(
"Do not provide values for dummy argument.");
Class<?> c = dummy.getClass().getComponentType();
array = (T)Array.newInstance(c, 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]
add a comment |
up vote
3
down vote
You do not need to pass the Class argument to the constructor.
Try this.
static class GenSet<T> {
private final T array;
@SuppressWarnings("unchecked")
public GenSet(int capacity, T... dummy) {
if (dummy.length > 0)
throw new IllegalArgumentException(
"Do not provide values for dummy argument.");
Class<?> c = dummy.getClass().getComponentType();
array = (T)Array.newInstance(c, 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]
add a comment |
up vote
3
down vote
up vote
3
down vote
You do not need to pass the Class argument to the constructor.
Try this.
static class GenSet<T> {
private final T array;
@SuppressWarnings("unchecked")
public GenSet(int capacity, T... dummy) {
if (dummy.length > 0)
throw new IllegalArgumentException(
"Do not provide values for dummy argument.");
Class<?> c = dummy.getClass().getComponentType();
array = (T)Array.newInstance(c, 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]
You do not need to pass the Class argument to the constructor.
Try this.
static class GenSet<T> {
private final T array;
@SuppressWarnings("unchecked")
public GenSet(int capacity, T... dummy) {
if (dummy.length > 0)
throw new IllegalArgumentException(
"Do not provide values for dummy argument.");
Class<?> c = dummy.getClass().getComponentType();
array = (T)Array.newInstance(c, 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]
edited Feb 21 at 5:31
answered Jul 11 '17 at 21:53
saka1029
8,8442726
8,8442726
add a comment |
add a comment |
up vote
2
down vote
Passing a list of values...
public <T> T array(T... values) {
return values;
}
add a comment |
up vote
2
down vote
Passing a list of values...
public <T> T array(T... values) {
return values;
}
add a comment |
up vote
2
down vote
up vote
2
down vote
Passing a list of values...
public <T> T array(T... values) {
return values;
}
Passing a list of values...
public <T> T array(T... values) {
return values;
}
answered Sep 15 '17 at 10:19
Rodrigo Asensio
1,60131923
1,60131923
add a comment |
add a comment |
up vote
1
down vote
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.
add a comment |
up vote
1
down vote
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.
add a comment |
up vote
1
down vote
up vote
1
down vote
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.
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.
answered Sep 14 '13 at 21:26
vnportnoy
2,4621911
2,4621911
add a comment |
add a comment |
up vote
1
down vote
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.).
add a comment |
up vote
1
down vote
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.).
add a comment |
up vote
1
down vote
up vote
1
down vote
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.).
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.).
edited Oct 18 '15 at 14:54
seh
13.1k3853
13.1k3853
answered Oct 17 '15 at 5:49
plugwash
4,1981124
4,1981124
add a comment |
add a comment |
up vote
1
down vote
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.
add a comment |
up vote
1
down vote
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.
add a comment |
up vote
1
down vote
up vote
1
down vote
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.
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.
edited Oct 19 '16 at 12:57
answered Oct 19 '16 at 1:04
developer747
5,5771962120
5,5771962120
add a comment |
add a comment |
up vote
0
down vote
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.
"We're looking for long answers that provide some explanation and context. Don't just give a one-line answer; explain why your answer is correct, ideally with citations. Answers without explanations may be removed."
– gparyani
Sep 16 '14 at 15:46
BUt that won`t work in some cases like if your generic class wants to implement Comparable interface.
– RamPrasadBismil
Apr 21 '16 at 8:55
Welcome to seven years ago, I suppose.
– Esko
Apr 26 '16 at 19:03
This will not work if you try to return the array from the generic code to a non-generic caller. There will be a head-scrating classcastexception.
– plugwash
Jul 12 '17 at 12:52
add a comment |
up vote
0
down vote
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.
"We're looking for long answers that provide some explanation and context. Don't just give a one-line answer; explain why your answer is correct, ideally with citations. Answers without explanations may be removed."
– gparyani
Sep 16 '14 at 15:46
BUt that won`t work in some cases like if your generic class wants to implement Comparable interface.
– RamPrasadBismil
Apr 21 '16 at 8:55
Welcome to seven years ago, I suppose.
– Esko
Apr 26 '16 at 19:03
This will not work if you try to return the array from the generic code to a non-generic caller. There will be a head-scrating classcastexception.
– plugwash
Jul 12 '17 at 12:52
add a comment |
up vote
0
down vote
up vote
0
down vote
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.
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.
answered Feb 9 '09 at 17:46
Esko
23.3k104776
23.3k104776
"We're looking for long answers that provide some explanation and context. Don't just give a one-line answer; explain why your answer is correct, ideally with citations. Answers without explanations may be removed."
– gparyani
Sep 16 '14 at 15:46
BUt that won`t work in some cases like if your generic class wants to implement Comparable interface.
– RamPrasadBismil
Apr 21 '16 at 8:55
Welcome to seven years ago, I suppose.
– Esko
Apr 26 '16 at 19:03
This will not work if you try to return the array from the generic code to a non-generic caller. There will be a head-scrating classcastexception.
– plugwash
Jul 12 '17 at 12:52
add a comment |
"We're looking for long answers that provide some explanation and context. Don't just give a one-line answer; explain why your answer is correct, ideally with citations. Answers without explanations may be removed."
– gparyani
Sep 16 '14 at 15:46
BUt that won`t work in some cases like if your generic class wants to implement Comparable interface.
– RamPrasadBismil
Apr 21 '16 at 8:55
Welcome to seven years ago, I suppose.
– Esko
Apr 26 '16 at 19:03
This will not work if you try to return the array from the generic code to a non-generic caller. There will be a head-scrating classcastexception.
– plugwash
Jul 12 '17 at 12:52
"We're looking for long answers that provide some explanation and context. Don't just give a one-line answer; explain why your answer is correct, ideally with citations. Answers without explanations may be removed."
– gparyani
Sep 16 '14 at 15:46
"We're looking for long answers that provide some explanation and context. Don't just give a one-line answer; explain why your answer is correct, ideally with citations. Answers without explanations may be removed."
– gparyani
Sep 16 '14 at 15:46
BUt that won`t work in some cases like if your generic class wants to implement Comparable interface.
– RamPrasadBismil
Apr 21 '16 at 8:55
BUt that won`t work in some cases like if your generic class wants to implement Comparable interface.
– RamPrasadBismil
Apr 21 '16 at 8:55
Welcome to seven years ago, I suppose.
– Esko
Apr 26 '16 at 19:03
Welcome to seven years ago, I suppose.
– Esko
Apr 26 '16 at 19:03
This will not work if you try to return the array from the generic code to a non-generic caller. There will be a head-scrating classcastexception.
– plugwash
Jul 12 '17 at 12:52
This will not work if you try to return the array from the generic code to a non-generic caller. There will be a head-scrating classcastexception.
– plugwash
Jul 12 '17 at 12:52
add a comment |
up vote
0
down vote
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>();
}
}
}
I can't get your code running, where does yourElement
class comes from?
– Xetra
Feb 21 at 0:15
add a comment |
up vote
0
down vote
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>();
}
}
}
I can't get your code running, where does yourElement
class comes from?
– Xetra
Feb 21 at 0:15
add a comment |
up vote
0
down vote
up vote
0
down vote
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>();
}
}
}
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>();
}
}
}
answered Feb 13 '11 at 20:37
David Bernard
91
91
I can't get your code running, where does yourElement
class comes from?
– Xetra
Feb 21 at 0:15
add a comment |
I can't get your code running, where does yourElement
class comes from?
– Xetra
Feb 21 at 0:15
I can't get your code running, where does your
Element
class comes from?– Xetra
Feb 21 at 0:15
I can't get your code running, where does your
Element
class comes from?– Xetra
Feb 21 at 0:15
add a comment |
up vote
0
down vote
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]
}
3
This doesn't actually work.new Holder<Thing>[10]
is a generic array creation.
– Radiodef
Mar 10 '14 at 19:43
add a comment |
up vote
0
down vote
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]
}
3
This doesn't actually work.new Holder<Thing>[10]
is a generic array creation.
– Radiodef
Mar 10 '14 at 19:43
add a comment |
up vote
0
down vote
up vote
0
down vote
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]
}
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]
}
answered Apr 5 '12 at 0:10
StarMonkey
91
91
3
This doesn't actually work.new Holder<Thing>[10]
is a generic array creation.
– Radiodef
Mar 10 '14 at 19:43
add a comment |
3
This doesn't actually work.new Holder<Thing>[10]
is a generic array creation.
– Radiodef
Mar 10 '14 at 19:43
3
3
This doesn't actually work.
new Holder<Thing>[10]
is a generic array creation.– Radiodef
Mar 10 '14 at 19:43
This doesn't actually work.
new Holder<Thing>[10]
is a generic array creation.– Radiodef
Mar 10 '14 at 19:43
add a comment |
up vote
0
down vote
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];
Yeah, this is not quite related, but rooted in the same issues (erasure, array covariance). Here's an example of a post about creating arrays of parameterized types: stackoverflow.com/questions/9542076/…
– Paul Bellora
Aug 21 '13 at 16:23
add a comment |
up vote
0
down vote
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];
Yeah, this is not quite related, but rooted in the same issues (erasure, array covariance). Here's an example of a post about creating arrays of parameterized types: stackoverflow.com/questions/9542076/…
– Paul Bellora
Aug 21 '13 at 16:23
add a comment |
up vote
0
down vote
up vote
0
down vote
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];
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];
answered Aug 21 '13 at 16:11
Mohsen Afshin
9,91585175
9,91585175
Yeah, this is not quite related, but rooted in the same issues (erasure, array covariance). Here's an example of a post about creating arrays of parameterized types: stackoverflow.com/questions/9542076/…
– Paul Bellora
Aug 21 '13 at 16:23
add a comment |
Yeah, this is not quite related, but rooted in the same issues (erasure, array covariance). Here's an example of a post about creating arrays of parameterized types: stackoverflow.com/questions/9542076/…
– Paul Bellora
Aug 21 '13 at 16:23
Yeah, this is not quite related, but rooted in the same issues (erasure, array covariance). Here's an example of a post about creating arrays of parameterized types: stackoverflow.com/questions/9542076/…
– Paul Bellora
Aug 21 '13 at 16:23
Yeah, this is not quite related, but rooted in the same issues (erasure, array covariance). Here's an example of a post about creating arrays of parameterized types: stackoverflow.com/questions/9542076/…
– Paul Bellora
Aug 21 '13 at 16:23
add a comment |
up vote
0
down vote
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.
No, this does not work. The varargs creates erasure ofT
whenT
is a type variable, i.e.zeroArray
returns anObject
. See http://ideone.com/T8xF91.
– Radiodef
Apr 6 '15 at 4:03
add a comment |
up vote
0
down vote
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.
No, this does not work. The varargs creates erasure ofT
whenT
is a type variable, i.e.zeroArray
returns anObject
. See http://ideone.com/T8xF91.
– Radiodef
Apr 6 '15 at 4:03
add a comment |
up vote
0
down vote
up vote
0
down vote
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.
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.
answered Jul 9 '14 at 13:36
Cambot
77113
77113
No, this does not work. The varargs creates erasure ofT
whenT
is a type variable, i.e.zeroArray
returns anObject
. See http://ideone.com/T8xF91.
– Radiodef
Apr 6 '15 at 4:03
add a comment |
No, this does not work. The varargs creates erasure ofT
whenT
is a type variable, i.e.zeroArray
returns anObject
. See http://ideone.com/T8xF91.
– Radiodef
Apr 6 '15 at 4:03
No, this does not work. The varargs creates erasure of
T
when T
is a type variable, i.e. zeroArray
returns an Object
. See http://ideone.com/T8xF91.– Radiodef
Apr 6 '15 at 4:03
No, this does not work. The varargs creates erasure of
T
when T
is a type variable, i.e. zeroArray
returns an Object
. See http://ideone.com/T8xF91.– Radiodef
Apr 6 '15 at 4:03
add a comment |
up vote
0
down vote
You could use a cast:
public class GenSet<Item> {
private Item a;
public GenSet(int s) {
a = (Item) new Object[s];
}
}
If you are going to suggest this, you really need to explain its limitations. Never exposea
to outside the class!
– Radiodef
Apr 6 '15 at 4:00
add a comment |
up vote
0
down vote
You could use a cast:
public class GenSet<Item> {
private Item a;
public GenSet(int s) {
a = (Item) new Object[s];
}
}
If you are going to suggest this, you really need to explain its limitations. Never exposea
to outside the class!
– Radiodef
Apr 6 '15 at 4:00
add a comment |
up vote
0
down vote
up vote
0
down vote
You could use a cast:
public class GenSet<Item> {
private Item a;
public GenSet(int s) {
a = (Item) new Object[s];
}
}
You could use a cast:
public class GenSet<Item> {
private Item a;
public GenSet(int s) {
a = (Item) new Object[s];
}
}
answered Sep 15 '14 at 17:23
samir benzenine
42848
42848
If you are going to suggest this, you really need to explain its limitations. Never exposea
to outside the class!
– Radiodef
Apr 6 '15 at 4:00
add a comment |
If you are going to suggest this, you really need to explain its limitations. Never exposea
to outside the class!
– Radiodef
Apr 6 '15 at 4:00
If you are going to suggest this, you really need to explain its limitations. Never expose
a
to outside the class!– Radiodef
Apr 6 '15 at 4:00
If you are going to suggest this, you really need to explain its limitations. Never expose
a
to outside the class!– Radiodef
Apr 6 '15 at 4:00
add a comment |
up vote
0
down vote
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++;
}
1
The question was about creating an array of the type of the generic type parameterT
, not an array of some parameterized type.
– Sotirios Delimanolis
Jun 29 '17 at 15:14
It completes the same task though and doesn't require you pushing in a class making your custom collection easier to use.
– Crab Nebula
Jun 29 '17 at 23:50
What task? It's literally a different task: an array of a paramaterized type vs an array of a generic type parameter.
– Sotirios Delimanolis
Jun 30 '17 at 0:16
It allows you to create an array from a generic type? The original problem was initializing an array using a generic type which using my method allows you to do without having to have the user push in a class or give an unchecked error such as trying to cast an Object to a String. Like chill, I'm not the best at what I do, and I haven't gone to school for programming but I think I still deserve a little input rather than being told off by some other kid on the internet.
– Crab Nebula
Jun 30 '17 at 23:53
I agree with Sotiros. There are two ways to think of the answer. Either it is an answer to a different question, or it is an attempt to generalize the question. Both are wrong / not helpful. People who are looking for guidance on how to implement a "generic array" class would / stop reading when they read the question title. And when they find an Q with 30 answers, they are highly unlikely to scroll to the end and read a zero vote answer from a SO newcomer.
– Stephen C
Jul 11 '17 at 23:00
|
show 1 more comment
up vote
0
down vote
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++;
}
1
The question was about creating an array of the type of the generic type parameterT
, not an array of some parameterized type.
– Sotirios Delimanolis
Jun 29 '17 at 15:14
It completes the same task though and doesn't require you pushing in a class making your custom collection easier to use.
– Crab Nebula
Jun 29 '17 at 23:50
What task? It's literally a different task: an array of a paramaterized type vs an array of a generic type parameter.
– Sotirios Delimanolis
Jun 30 '17 at 0:16
It allows you to create an array from a generic type? The original problem was initializing an array using a generic type which using my method allows you to do without having to have the user push in a class or give an unchecked error such as trying to cast an Object to a String. Like chill, I'm not the best at what I do, and I haven't gone to school for programming but I think I still deserve a little input rather than being told off by some other kid on the internet.
– Crab Nebula
Jun 30 '17 at 23:53
I agree with Sotiros. There are two ways to think of the answer. Either it is an answer to a different question, or it is an attempt to generalize the question. Both are wrong / not helpful. People who are looking for guidance on how to implement a "generic array" class would / stop reading when they read the question title. And when they find an Q with 30 answers, they are highly unlikely to scroll to the end and read a zero vote answer from a SO newcomer.
– Stephen C
Jul 11 '17 at 23:00
|
show 1 more comment
up vote
0
down vote
up vote
0
down vote
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++;
}
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++;
}
answered Jun 28 '17 at 19:59
Crab Nebula
274
274
1
The question was about creating an array of the type of the generic type parameterT
, not an array of some parameterized type.
– Sotirios Delimanolis
Jun 29 '17 at 15:14
It completes the same task though and doesn't require you pushing in a class making your custom collection easier to use.
– Crab Nebula
Jun 29 '17 at 23:50
What task? It's literally a different task: an array of a paramaterized type vs an array of a generic type parameter.
– Sotirios Delimanolis
Jun 30 '17 at 0:16
It allows you to create an array from a generic type? The original problem was initializing an array using a generic type which using my method allows you to do without having to have the user push in a class or give an unchecked error such as trying to cast an Object to a String. Like chill, I'm not the best at what I do, and I haven't gone to school for programming but I think I still deserve a little input rather than being told off by some other kid on the internet.
– Crab Nebula
Jun 30 '17 at 23:53
I agree with Sotiros. There are two ways to think of the answer. Either it is an answer to a different question, or it is an attempt to generalize the question. Both are wrong / not helpful. People who are looking for guidance on how to implement a "generic array" class would / stop reading when they read the question title. And when they find an Q with 30 answers, they are highly unlikely to scroll to the end and read a zero vote answer from a SO newcomer.
– Stephen C
Jul 11 '17 at 23:00
|
show 1 more comment
1
The question was about creating an array of the type of the generic type parameterT
, not an array of some parameterized type.
– Sotirios Delimanolis
Jun 29 '17 at 15:14
It completes the same task though and doesn't require you pushing in a class making your custom collection easier to use.
– Crab Nebula
Jun 29 '17 at 23:50
What task? It's literally a different task: an array of a paramaterized type vs an array of a generic type parameter.
– Sotirios Delimanolis
Jun 30 '17 at 0:16
It allows you to create an array from a generic type? The original problem was initializing an array using a generic type which using my method allows you to do without having to have the user push in a class or give an unchecked error such as trying to cast an Object to a String. Like chill, I'm not the best at what I do, and I haven't gone to school for programming but I think I still deserve a little input rather than being told off by some other kid on the internet.
– Crab Nebula
Jun 30 '17 at 23:53
I agree with Sotiros. There are two ways to think of the answer. Either it is an answer to a different question, or it is an attempt to generalize the question. Both are wrong / not helpful. People who are looking for guidance on how to implement a "generic array" class would / stop reading when they read the question title. And when they find an Q with 30 answers, they are highly unlikely to scroll to the end and read a zero vote answer from a SO newcomer.
– Stephen C
Jul 11 '17 at 23:00
1
1
The question was about creating an array of the type of the generic type parameter
T
, not an array of some parameterized type.– Sotirios Delimanolis
Jun 29 '17 at 15:14
The question was about creating an array of the type of the generic type parameter
T
, not an array of some parameterized type.– Sotirios Delimanolis
Jun 29 '17 at 15:14
It completes the same task though and doesn't require you pushing in a class making your custom collection easier to use.
– Crab Nebula
Jun 29 '17 at 23:50
It completes the same task though and doesn't require you pushing in a class making your custom collection easier to use.
– Crab Nebula
Jun 29 '17 at 23:50
What task? It's literally a different task: an array of a paramaterized type vs an array of a generic type parameter.
– Sotirios Delimanolis
Jun 30 '17 at 0:16
What task? It's literally a different task: an array of a paramaterized type vs an array of a generic type parameter.
– Sotirios Delimanolis
Jun 30 '17 at 0:16
It allows you to create an array from a generic type? The original problem was initializing an array using a generic type which using my method allows you to do without having to have the user push in a class or give an unchecked error such as trying to cast an Object to a String. Like chill, I'm not the best at what I do, and I haven't gone to school for programming but I think I still deserve a little input rather than being told off by some other kid on the internet.
– Crab Nebula
Jun 30 '17 at 23:53
It allows you to create an array from a generic type? The original problem was initializing an array using a generic type which using my method allows you to do without having to have the user push in a class or give an unchecked error such as trying to cast an Object to a String. Like chill, I'm not the best at what I do, and I haven't gone to school for programming but I think I still deserve a little input rather than being told off by some other kid on the internet.
– Crab Nebula
Jun 30 '17 at 23:53
I agree with Sotiros. There are two ways to think of the answer. Either it is an answer to a different question, or it is an attempt to generalize the question. Both are wrong / not helpful. People who are looking for guidance on how to implement a "generic array" class would / stop reading when they read the question title. And when they find an Q with 30 answers, they are highly unlikely to scroll to the end and read a zero vote answer from a SO newcomer.
– Stephen C
Jul 11 '17 at 23:00
I agree with Sotiros. There are two ways to think of the answer. Either it is an answer to a different question, or it is an attempt to generalize the question. Both are wrong / not helpful. People who are looking for guidance on how to implement a "generic array" class would / stop reading when they read the question title. And when they find an Q with 30 answers, they are highly unlikely to scroll to the end and read a zero vote answer from a SO newcomer.
– Stephen C
Jul 11 '17 at 23:00
|
show 1 more comment
up vote
-1
down vote
private E a;
private int size;
public GenSet(int elem)
{
size = elem;
a = (E) new E[size];
}
You should always add an explanation to your code, and explain why it solves the original posted question.
– mjuarez
Jun 3 '15 at 6:11
add a comment |
up vote
-1
down vote
private E a;
private int size;
public GenSet(int elem)
{
size = elem;
a = (E) new E[size];
}
You should always add an explanation to your code, and explain why it solves the original posted question.
– mjuarez
Jun 3 '15 at 6:11
add a comment |
up vote
-1
down vote
up vote
-1
down vote
private E a;
private int size;
public GenSet(int elem)
{
size = elem;
a = (E) new E[size];
}
private E a;
private int size;
public GenSet(int elem)
{
size = elem;
a = (E) new E[size];
}
edited Jun 3 '15 at 6:16
Ilija Dimov
4,10062635
4,10062635
answered Jun 3 '15 at 5:52
Zubair Ibrhaim
11
11
You should always add an explanation to your code, and explain why it solves the original posted question.
– mjuarez
Jun 3 '15 at 6:11
add a comment |
You should always add an explanation to your code, and explain why it solves the original posted question.
– mjuarez
Jun 3 '15 at 6:11
You should always add an explanation to your code, and explain why it solves the original posted question.
– mjuarez
Jun 3 '15 at 6:11
You should always add an explanation to your code, and explain why it solves the original posted question.
– mjuarez
Jun 3 '15 at 6:11
add a comment |
up vote
-1
down vote
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];
}
}
add a comment |
up vote
-1
down vote
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];
}
}
add a comment |
up vote
-1
down vote
up vote
-1
down vote
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];
}
}
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];
}
}
answered Apr 19 at 13:45
Irfan Ul Haq
2741412
2741412
add a comment |
add a comment |
protected by Aniket Thakur Oct 2 '15 at 19:02
Thank you for your interest in this question.
Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).
Would you like to answer one of these unanswered questions instead?
12
Do you really need to use an array here? What about using a Collection?
– matt b
Feb 9 '09 at 18:34
10
Yes I also think that collections are more elegant to for this problem. But this is for a class assignment and they are required :(
– tatsuhirosatou
Feb 9 '09 at 19:47
1
I do not understand why I need a reflect here.Java grammar is strange: like new java.util.HashMap<String,String>[10] is not valid. new java.util.HashMap<long,long>(10) is not valid. new long[10] is not valid, new long[10] is valid. That stuff make write a program that can write java program is more difficult then it looks like.
– bronze man
Jun 30 '17 at 2:46