Can we create an Array of Generic class? [duplicate] - java

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Java how to: Generic Array creation
I want to create a Stack which contains 10 elements, I'm trying to do this with Generics.
I started by creating a Stack class of Type T, but I'm getting compilation error when I try to instantiate the array of generic type.
public class Stack<T>{
private T[] stk = new T[10];
}
What I'm doing wrong here?

You can't do this. Not without using some hacky round about code, and even then you have to do an unsafe cast in the end that completely ruins the entire reason for trying to be type safe in the first place.
This is because Java has something called type erasure, the compiler throws away all the generic information and the runtime doesn't know what T is.
Here is the preferred way of doing this:
#SuppressWarnings("unchecked")
static <T> T[] newArray(Class<T> type, int length)
{
return (T[]) java.lang.reflect.Array.newInstance(type, length);
}
This doesn't create the throw about list instance in the naive solution of calling toArray() on a List<T> implementation hack.
For more discussion on this see
Here is an answer to a similar question about creating a type safe array at runtime.

There reason you can't create a Array of a generic type is this:
When a generic type is instantiated, the compiler translates those types by a technique called type erasure — a process where the compiler removes all information related to type parameters and type arguments within a class or method. Type erasure enables Java applications that use generics to maintain binary compatibility with Java libraries and applications that were created before generics.
For instance, Box is translated to type Box, which is called the raw type — a raw type is a generic class or interface name without any type arguments. This means that you can't find out what type of Object a generic class is using at runtime. The following operations are not possible:
public class MyClass<E> {
public static void myMethod(Object item) {
if (item instanceof E) { //Compiler error
...
}
E item2 = new E(); //Compiler error
E[] iArray = new E[10]; //Compiler error
E obj = (E)new Object(); //Unchecked cast warning
}
}
http://download.oracle.com/javase/tutorial/java/generics/erasure.html
The reason to use generics is that you don't want to typecast.
That said, here are two solutions.
You can use a array of Objects and garantee you'll only push and pop T's by the methods you supply to access the array:
public class MyStack2<T> {
Object[] myStack2;
public MyStack2() {
myStack2 = new Object[10];
}
public void push(T t) {
// do whatever you wanna do to push t, like myStack2[x] = t;
}
public T pop() {
// do whatever you wanna do to pop t like return (T)myStack2[0];
// Here we typecasted, but we can be sure that myStack2 contains only T's
// because we garanteed it at the push method.
}
}
OR
You can use another thing other than array to store your stack.
public class MyStack<T> {
Stack<T> myStack;
public MyStack() {
myStack = new Stack<T>();
}
public void push(T t) {
myStack.push(t);
}
public T pop() {
return myStack.pop();
}
}
As you can see, java already provides a Stack class so you don't have to write one, but if you really want to do it, maybe to understand how it works, you can replace the Stack class in this example by a List. With a List you'll be able to play almost the same you'd do if you were using an array.

The reason that that doesn't work is that when you write a type like String[] in Java, that means that the object knows itself at runtime that its component type is String (or a subclass thereof). Generic type parameters are not available at runtime, hence you cannot do it. We wish there was something like Object[]<T>, i.e. "an array that does not know its component type at runtime, but which has generic type checks at compile time", but such a thing does not exist in the language.
However, it appears that from your code that you intend to use this array internally, and you don't really care if the array knows T at runtime; you just need an array, period. If you don't intend to pass the array out of the class, then there are two options:
Use a variable of type Object[], and create new Object[10]. This requires you to cast to T if you want to return an element from a method, which is an unchecked cast.
Use a variable of type T[], and assign to it using = (T[])new Object[10]. Now people will point out that the subtyping relationship is not technically true, but so long as it's inside the class (inside the scope of T), it doesn't matter, because T is erased. So with this method you have to be extra careful never to pass or return the array reference, because you won't be warned that it's unsafe.
Both methods are the same after type erasure, and both methods will cause unchecked cast warnings, so it's really your personal preference. The second one is more convenient (you can pretend it's a T[] and get things out of it without cast), while the first one is more formally correct and safer (the second requires you to be diligent not to pass it out).

Related

java generics classcastexception

Exceptions are thrown because the type "E" is read as the class Object and not the parameter that was specified. Is that how it should be?
#Override
public E[] getAllEntities() {
String jpdlQuery = String.format("select e from %s e", entityShortName);
Query query = entityManager.createQuery(jpdlQuery, entityClass);
return (E[]) query.getResultList().toArray();
}
You need to "genericize" the method,
public <E> E[] getAllEntities() or else in the class definition somewhere.
HOWEVER, mixing generics and arrays is a Really Bad Idea, since arrays have their base type at runtime and generics do not. You will get a compile warning from the cast (E[]).
Also, you left out the generic result on createQuery(), which in the form you used returns a TypedQuery<E>. If you used the more specific return value you wouldn't need the cast. Furthermore, you wouldn't be returning a raw List. Don't use raw types.
https://docs.oracle.com/javaee/7/api/javax/persistence/EntityManager.html
https://docs.oracle.com/javaee/7/api/javax/persistence/EntityManager.html#createQuery-javax.persistence.criteria.CriteriaQuery-
https://docs.oracle.com/javaee/7/api/javax/persistence/TypedQuery.html
Arrays know their component type at runtime, so when you create an array, you must provide the component type at runtime, and arrays created with different component types are instances of different runtime classes. On the other hand, instances of generic classes don't know their generic type arguments at runtime.
Collection has two .toArray() methods:
Object[] toArray(): this method takes no parameters, and it returns an array whose runtime class is always Object[]. This is because the collection doesn't have any idea what its component type is at runtime, and without any arguments, it has no information about what component type of array to create at runtime.
<T> T[] toArray(T[] a): this method takes in an array parameter, and it returns an array with the same runtime class as the one passed in. It does this by either returning the same array object, or (if the array passed in is not big enough) extracting the component type of the runtime class of the array passed in, and using that to create a new array object of the same runtime class.
You have used the .toArray() method without arguments; thus it will always return an array object whose runtime class is Object[], as if created by new Object[...]. If you want your getAllEntities() method to return an array of the right runtime type E[], it would need to somehow know at runtime what E is; to do that, you would need to make the caller pass in an argument of type E[] or Class<E>. For example,
public E[] getAllEntities(E[] array) {
//...
return query.getResultList().toArray(array);
}
The alternative would be to return a List, which does not need to know it component type at runtime, so you can create a List<E> without knowing what E is at runtime:
public List<E> getAllEntities() {
//...
return query.getResultList();
}

Why should I have to specify <?> when using a generic in Java?

I'm quite new in Java, although I have much experience in C++ and other languages. So templates/generics are not something I don't know.
There's something that bothers me though, it is this <?> that I was told I should use everytime I use a generic instance of something when I don't know in advance of which specific type it will be:
Like:
List< MyGeneric > foo; // bad
List< MyGeneric<?> > bar; // good
IntelliJ doesn't barf on me when using the first expression, and I don't understand why it should. My coworkers have expressed that the 2nd expression was much better, but couldn't tell me exactly why.
I mean, what exactly is the difference between these two, apart from the second being explicit about the fact that it is a generic that we manipulate ?
The compiler certainly knows that it is a generic at compile time, so my guess is that the second expression is only better because it tells the programmer that he is manipulating a generic.
Am I right?
Edit: for clarification, I ovbiously use the most restrictive type, like List<MyGeneric<Double>>, whenever I know in advance what I am going to store in there. My question is for when I store unknown types of generics.
Every time? It's not applicable always, and it doesn't always make sense.
Let's describe what that actually is: <?> is an unbound wildcard, which immediately implies two things:
MyGeneric is a generic class, but
You do not know what type it's holding (and it likely doesn't matter).
It is preferable to the first expression in that the first expression always guarantees that you'll be working with a raw type, and you really don't want to use raw types. However, it is a gross overgeneralization to assume that using an unbound wildcard every time would be ideal.
If you actually know or care the type, or know or care about its bounds, use that instead.
Let's give an example of why it's bad to use the first. Assuming MyGeneric is defined like this:
class MyGeneric<T> {
private final T instance;
MyGeneric(T instance) { this.instance = instance; }
T get() { return instance; }
}
The following code would compile and run, but fail at runtime with a ClassCastException:
List<MyGeneric> list = new ArrayList<>();
list.add(new MyGeneric<>("Hello"));
for (MyGeneric instance : list) {
Integer value = (Integer) instance.get(); // Compiles, but fails at runtime.
}
This compiles because you're using raw types: the compiler doesn't know that instance.get() can't return an Integer; it would merely warn you that it might be unsafe.
On the other hand, the following code would not even compile:
List<MyGeneric<String>> list = new ArrayList<>();
list.add(new MyGeneric<>("Hello"));
for (MyGeneric<String> instance : list) {
Integer value = (Integer) instance.get(); // Won't compile, incompatible types.
}
The difference is that a raw type ignores the fact that the class is a generic, while the wildcard <?> specifies that the class is a generic but the type argument is unknown.
Raw means that you lose all compiler type-checking. Wildcard keeps type-checking intact.
Example:
public class MyGeneric<T> {
private T val;
public T get() {
return this.val;
}
public void set(T val) {
this.val = val;
}
}
MyGeneric a = new MyGeneric<Integer>();
a.set("Foo"); // accepted
Setting the value for a to a String when it was declared to be an Integer is accepted by the compiler, because a was defined raw, which means that the compiler is ignoring the fact that the class is a generic. When val is later used as an Integer, the program will crash. It's a bomb waiting to go off.
MyGeneric<?> b = new MyGeneric<Integer>();
b.set("Bar"); // compile error
Trying to set the value for b will not compile:
The method set(capture#1-of ?) in the type MyGeneric<capture#1-of ?> is not applicable for the arguments (String)
Here the compiler knows that the class is a generic and will not allow setting the value to anything (even an Integer), because it doesn't know what type would be allowed (wildcard = unknown, remember?). The compiler safeguards here, as it should.
List<?> means a list typed to an unknown type. This could be a List<A>, a List<B>, a List<String> etc.
Since the you do not know what type the List is typed to, you can only read from the collection, and you can only treat the objects read as being Object instances. Here is an example:
public void processElements(List<?> elements) {
for(Object o : elements){
System.out.println(o);
}
}
The processElements() method can now be called with any generic List as parameter. For instance a List<A>, a List<B>, List<C>, a List<String> etc. Here is a valid example:
List<A> listA = new ArrayList<A>();
processElements(listA);
Following tutorials will further help you to understand it:
https://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html
http://tutorials.jenkov.com/java-generics/wildcards.html

Why Java Cannot Create Instances of Type Parameters

I know Java does not allow not Create Instances of Type Parameters. Many articles simply said "Type Erase" as the reason. But does type parameters initialization not occur before type erase? Is Type Erase the only reason? Here is a example:
public class GenObj {
public static <E> void append(List<E> list) {
E elem = new E(); // compile-time error
list.add(elem);
}
public static main(){
List<String> list= new ArrayList<String>();
GenOjb.append<String>(list);
}
}
When we call the generic method using GenOjb.append(list), I think the compiler will replace E in the method with String first and then do "Type Erase", is that correct? If so, as long as we have a way to ensure E does indeed have a default constructor, we should be able to create instance of type parameters. Can someone explain in more detail why Java does not allow creating instance of parameter type? Thanks.
It is instructive to ask: How would you do it without Generics?
Every program with Generics can be converted into an equivalent program without Generics by simply removing generic parameters and inserting casts in appropriate places. This is called type erasure. So, if you want to know if you can do it with Generics, you need to first ask if you can do it without Generics.
Without Generics, your program looks like this:
public class GenObj {
public static void append(List list) {
Object elem = // what goes here?
list.add(elem);
}
public static main(){
List list= new ArrayList();
GenOjb.append(list);
}
}
Due to runtime type erasure, the type is not available to do anything with.
You can however pass a type token:
public static <E> void append(List<E> list, Class<E> c) {
E elem = c.newInstance();
list.add(elem);
}
This presupposes that the class has a no-args constructor.
Remember that Generics are for compile time checking and that when you compile a class within .java file, Java produces a single .class file for that class.
When we call the generic method using GenOjb.append(list); I think
compiler will replace E in the method with String first and then do
"Type Erase", is that correct?
No, nothing is replaced in the method. Once the .class file is generated, that's what you get. When compiling, the compiler simply verifies that the String type is an acceptable type argument for the append() method. Since you've specified no bounds on E, the compiler judges that String is an acceptable type argument.
Can someone explain in more details why java not allow creating
instance of parameter type?
That's just not how the java language works. Class instantiation happens at run time. At run time, there is no longer any notion of type variables because of type erasure and therefore we cannot know what E is.
There are a few alternatives for getting an instance of whatever type T ends up being. See here:
Instantiating a generic class in Java
Instantiating generics type in java
Create instance of generic type in Java?
Because under the covers, a List<E> is just a List. The actual type that has been substituted for E is not passed on the stack. Therefore, when the JVM is running this code, there is no way to tell what type E is, so it has no way of knowing what class to instantiate.

Java Error: New Generic TreeNode Array

I have generic class of TreeNode:
public class TreeNode<E> {
public E key;
public int num_of_children;
public TreeNode<E> [] children;
public TreeNode(int num_of_children)
{
this.num_of_children = num_of_children;
children = new TreeNode[num_of_children];// Why not: new TreeNode<E>[num_of_children]?
}
public TreeNode<E> clone()
{
TreeNode<E> node = new TreeNode<E>(num_of_children);
return node;
}
}
When I try to do:children = new TreeNode<E> [num_of_children];
I get error. But "new TreeNode[num_of_children]" works.
I read about type erasure, and I don't understand why TreeNode<E>[] doesn't work.
Why is that? Please enlighten me!
Things like new TreeNode<String>[] and new TreeNode<E>[] are disallowed by Java. The only things you can do are new TreeNode[] and new TreeNode<?>[] (unbounded wildcard parameter).
The reason for this is a little complicated, but instructive. Arrays in Java know their component type at runtime, and every time you put something in, it checks to see if it's an instance of the component type, and if not, throws an exception (this is related to how array types are covariant and therefore inherently unsafe at compile time).
Object[] foo = new Integer[5];
foo[2] = "bar"; // compiles fine, but throws ArrayStoreException at runtime
Now add generics. The problem with a generic component type is that, there is no way for you to check if an object is an instance of say, TreeNode<Integer> at runtime (as opposed to TreeNode<String>), since generics are erased from runtime types. It can only check TreeNode, but not the component type. But programmers might have expected this checking and exception throwing behavior from arrays, since it normally works. So to avoid this surprise failure, Java disallows it. (In most code, you won't run into this problem anyway because you won't be mixing objects of the same type but different type parameters. But it is theoretically possible to come up.)
Of course, you can simply work around the problem by creating an array of raw or wildcard parameter type, and then casting to the proper type, e.g. (TreeNode<Integer>)new TreeNode[5]. What's the difference? Well, that's an unchecked cast, which generates a warning, and you, the programmer, takes responsibility for all the unsafe things that might happen later. If it does something unexpected, the compiler can say, "we told ya so!".
Because the Java Language Specification writes:
An array creation expression creates an object that is a new array whose elements are of the type specified by the PrimitiveType or ClassOrInterfaceType.
It is a compile-time error if the ClassOrInterfaceType does not denote a reifiable type (§4.7). Otherwise, the ClassOrInterfaceType may name any named reference type, even an abstract class type (§8.1.1.1) or an interface type (§9).
The rules above imply that the element type in an array creation expression cannot be a parameterized type, other than an unbounded wildcard.
It is not clear to me why they require this. Certainly, the component type of the array must be available at runtime, and it would be misleading for the programmer if it were different from the type specified in the source code. Consider:
E[] a = new E[10];
Here, it would be bad if the compiler used the erasure of E as the array component type, as the programmer might well depend upon the array to check that nothing but instances of E is stored in it.
It's less clear what harm would come from allowing:
List<E>[] lists = new List<E>[10];
The only thing that comes to mind is that assigning an array element would amount to an unchecked cast, because the array would check the element is a List, but not that it is a List<E>, and thus fail to throw an ArrayStoreException.
In practice, you can safely suppress this warning as long as you remain aware that the array will not check the type parameters of its component type.

Java Generics: Instantiating arrays with parameterized types: illegal?

I must be confused here.
I read everywhere that in generics arrays of parametrized types are illegal.
Example from AngelikaLanger:
static void test() {
Pair<Integer,Integer>[] intPairArr = new Pair<Integer,Integer>[10] ; // error
addElements(intPairArr);
Pair<Integer,Integer> pair = intPairArr[1];
Integer i = pair.getFirst();
pair.setSecond(i);
}
Quote from Langer (but everywhere else I read it says the same thing):
The compiler prohibits creation of arrays whose component type is a
concrete parameterized type, like Pair in our
example. We discussed in the preceding entry why is it reasonable
that the compiler qualifies a Pair[] as illegal.
So far ok.
But in my code here:
private MyEntry<E> [] elements = (MyEntry<E>[])new Object[capacity];
I do exactly that, it compiles fine (I use eclipse) but get a class cast exception error (Object can not be cast to MyEntry):
My question is, why does this line compiles in the first place?
I thought that this instantiation is disallowed by the compiler.
What I am doing wrong/differerent here?
UPDATE:
On the same page, why am I able to succesfully do:
List<E> elements[] = (List<E>[])new LinkedList[capacity];
and have no runtime exceptions?
UPDATE:
Everywhere I have read (mentioned Langer since she's quoted often) it says that this declaration (arrays of parametrized types) is disallowed by compiler.
I can understand what happens after that.
I can't understand why the compiler doesn't report an error.
I am not judging, I am saying everywhere I read, it says this does not compile.
Am I missreading something?
UPDATE:
I saw some comments related to the missing parameter in the new part.
This also has no issue:
List<Entry<KeyType, ValueType>> table[] = (List<Entry<KeyType, ValueType>>[])new LinkedList[capacity];
In your first example, there's no problem with the instantiation - here's exactly what you're creating:
new Object[capacity]
Perfectly legal. You do however get a runtime exception when you attempt to cast, because an array of Object is not an array of MyEntry<E>. You might have a point that the cast or declaration could be rejected by the compiler, if these generically-parameterised arrays can't exist, though this depends what order erasure kicks in. In any case, the instantiation itself is fine.
In the second example, you're creating a non-generic array of LinkedList. You then assign it to a genericised reference, which at runtime will have been erased to just a List[]. This works fine (because rightly or wrongly, arrays are covariant).
I'm not sure why you were expecting a runtime exception; it's not much different to calling, say
List<E> = new LinkedList();
You would get some unchecked warnings, but nothing that would stop the code compiling or running.
You have completely misunderstood whatever you have read. There is absolutely nothing wrong with having the type that is an array of a parameterized type: MyEntry<E>[] or HashMap<String,Integer>[][] or whatever. You can have variables of such types all you want, and use them anywhere a type can be used.
However, with array creation, you cannot do something like new MyEntry<E>[...]. It is not allowed by the language (for type safety reasons we will not go into here), so it is a compile error.
The best solution is either new MyEntry[] (array of raw type) or new MyEntry<?>[] (array of wildcard type); either one is allowed by the language. Both of them will require you to do an explicit cast back to MyEntry<E>[].
Since you ask about your code examples, your first example is syntactically correct (there is nothing wrong with new Object[...], and it is syntactically okay to cast to MyEntry<E>[]), so there is no compile error. However, the runtime check of the cast fails at runtime, because the object's actual type Object[] is not a subtype of MyEntry[].
The second code example is also syntactically correct, and plus the runtime check of the cast succeeds (LinkedList[] is a subtype of List[]).
Because LinkedList is an instance of List.
But Object is NOT an instance of MyEntry.
Also compiler don't check can one object be cast to another or not. Because it is runtime operation.
You should use:
private MyEntry<E> [] elements = new MyEntry [capacity];
Or:
class SomeOtherEntry extends MyEntry {}
private MyEntry<E> [] elements = new SomeOtherEntry [capacity];
But not:
class SomeOtherEntry extends MyEntry {}
private SomeOtherEntry <E> [] elements = new MyEntry [capacity];
UPDATE:
List<Entry<KeyType, ValueType>> [] table = (List<Entry<KeyType,ValueType>> []) new Linked[capacity];
Built-in Java List classes actually use a work-around whenever you use the
<T> T[] toArray(T[] a) method. If we take a closer look at the code, if you supply an array that's smaller than required, the method actually creates a new array of the type parameter.
Let's see the code: https://github.com/openjdk-mirror/jdk7u-jdk/blob/f4d80957e89a19a29bb9f9807d2a28351ed7f7df/src/share/classes/java/util/LinkedList.java#L1085
public <T> T[] toArray(T[] a) {
if (a.length < size)
a = (T[])java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), size);
...
}

Categories