45

I don't understand the error of Generic Array Creation.
First I tried the following:

  public PCB[] getAll() {
       PCB[] res = new PCB[list.size()];
           for (int i = 0; i < res.length; i++) {
               res[i] = list.get(i);
            }
       list.clear();
       return res;
}


Then I tried doing this:

PCB[] res = new PCB[100];


I must be missing something cause that seems right. I tried looking it up I really did. And nothing is clicking.


My question is: What can I do to fix this?


the error is :

.\Queue.java:26: generic array creation
PCB[] res = new PCB[200];
            ^
Note: U:\Senior Year\CS451- file      
uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
1 error

Tool completed with exit code 1

Luron
  • 1,057
  • 5
  • 17
  • 29
  • Can you post the Exception/Error – Chris J Oct 05 '10 at 17:08
  • 2
    I am assuming that `PCB` is a generic type parameter and thus, what you are doing is impossible in Java due to type-erasure. If that is all true, you should click on the link I marked this a dup of as it provides a workaround. – Kirk Woll Oct 05 '10 at 17:14
  • already tried reading that post. it doesn't help me – Luron Oct 05 '10 at 17:24
  • 3
    the sad truth is that Java made the conscious decision to explicitly prevent this syntax from working. Java implements type-erasure, which means that the type argument `PCB` actually has no meaning at runtime (or technically, it does, but it's probably just `Object` which wouldn't do you any good). There are two ways to circumvent this restriction. Both are explained in detail at the link I referenced. Let me know what specific part of that solution you are having trouble with. – Kirk Woll Oct 05 '10 at 17:35
  • I faced with the same problem. PCB is not likely a generic class (I think it's an internal class), but Java somehow think it is generic. Anybody know how to fix this? – Aniketos Aug 23 '12 at 09:48
  • 2
    PCB>[] res = new PCB>[100]; is possible – Christian Feb 11 '16 at 07:42

3 Answers3

48

You can't create arrays with a generic component type.

Create an array of an explicit type, like Object[], instead. You can then cast this to PCB[] if you want, but I don't recommend it in most cases.

PCB[] res = (PCB[]) new Object[list.size()]; /* Not type-safe. */

If you want type safety, use a collection like java.util.List<PCB> instead of an array.

By the way, if list is already a java.util.List, you should use one of its toArray() methods, instead of duplicating them in your code. This doesn't get your around the type-safety problem though.

erickson
  • 249,448
  • 50
  • 371
  • 469
  • 3
    yea but when you return it to the outside, and the caller assigns it to a variable of type PCB[]. boom you will get a class cast exception – newacct Oct 05 '10 at 17:56
  • @newacct - That won't necessarily happen. It depends on the calling context. But it can happen. That's what I meant by "Not type-safe," and why I recommended against it. – erickson Oct 05 '10 at 18:01
  • 2
    @erickson: It will eventually happen at some point as the recursion unfolds. Generics always become concrete at some point or else no work would ever get done. The only way this would reasonably work is if the result is never actually used as an array of the actual type of `PCB`. In which case it's much better to just declare yourself as returning an `Object[]`. – Mark Peters Oct 05 '10 at 18:12
  • @Mark Peters - No, there are many instances where you know that the resulting array will not "escape" to a context where it's used as anything but an `Object[]`. But, of course, it would be best not to try to shoe-horn generics into an array. – erickson Oct 05 '10 at 18:28
  • 2
    @erickson: Exactly, and since that's the case, then just return an `Object[]` since it's type-safe and doesn't limit usage **at all**. Any usage that uses the result as anything but an `Object[]` is basically guaranteed to throw a runtime error, so why the heck would you bother returning anything else? – Mark Peters Oct 05 '10 at 18:29
  • @Mark Peters - **I** wouldn't. That's why I recommend using a `List` instead. But I include it as a direct response to the OP's explicit question. – erickson Oct 05 '10 at 18:36
  • 2
    @erickson, actually, I found a usage example where it's not strictly stupid. If the generic array remains encapsulated in a collection (ArrayList, e.g.) then access to and from the array is performed through generics alone and it works. Wasn't thinking of keeping it around as an instance variable. – Mark Peters Oct 05 '10 at 18:38
  • This does not work for primitive types? I am looking for a generic solution handling int,long,double – StephenBoesch Mar 06 '21 at 19:16
5

The following will give you an array of the type you want while preserving type safety.

PCB[] getAll(Class<PCB[]> arrayType) {  
    PCB[] res = arrayType.cast(java.lang.reflect.Array.newInstance(arrayType.getComponentType(), list.size()));  
    for (int i = 0; i < res.length; i++)  {  
        res[i] = list.get(i);  
    }  
    list.clear();  
    return res;  
}

How this works is explained in depth in my answer to the question that Kirk Woll linked as a duplicate.

gdejohn
  • 6,648
  • 1
  • 30
  • 45
3

Besides the way suggested in the "possible duplicate", the other main way of getting around this problem is for the array itself (or at least a template of one) to be supplied by the caller, who will hopefully know the concrete type and can thus safely create the array.

This is the way methods like ArrayList.toArray(T[]) are implemented. I'd suggest you take a look at that method for inspiration. Better yet, you should probably be using that method anyway as others have noted.

Mark Peters
  • 76,122
  • 14
  • 153
  • 186