2

I have this code:

import java.util.*;
import java.lang.*;
import java.io.*;

class Main{
    public static void main (String[] args){
        Foo<String> foo = new Foo<String>(1000);
    }
}

class Foo<Key extends Comparable<Key>>{
    private Entry[] a;
    private class Entry{
        Key key;
    }
    public Foo(int size){
        a = (Entry[])new Object[size]; // <- this is the problem
    }
}

when I compile it, I get an error, saying:

Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [LFoo$Entry;
at Foo.<init>(Main.java:17)
at Main.main(Main.java:7)

I tried:

import java.util.*;
import java.lang.*;
import java.io.*;

class Main{
    public static void main (String[] args){
        Foo<String> foo = new Foo<String>(1000);
    }
}

class Foo<Key extends Comparable<Key>>{
    private Entry[] a;
    private class Entry{
        Key key;
    }
    public Foo(int size){
        a = new Entry[size];
    }
}

But then I got an error saying:

Main.java:17: error: generic array creation
        a = new Entry[size];
            ^

Is it possible to create that array at all?

Pavel
  • 1
  • 2
  • 14
  • 43

4 Answers4

1

It because Generics don't cope very well with arrays (at compile-time).

You should rather use some Collection, instead:

class Foo<Key extends Comparable<Key>> {
    private List<Entry> a;

    private class Entry {
        Key key;
    }

    public Foo(int size) {
        a = new ArrayList<Entry>(size);
    }
}
Community
  • 1
  • 1
Konstantin Yovkov
  • 59,030
  • 8
  • 92
  • 140
1

Well, actually you can via reflection:

public class Main {
    public static void main(String[] args) {
        Foo<String> foo = new Foo<String>(1000);
        foo.a[0] = foo.new Entry();
        foo.a[0].key = "ss";
    }
}

class Foo<Key extends Comparable<Key>> {
    public Entry[] a;

    public class Entry {
        Key key;
    }

    public Foo(int size) {
        a = (Entry[]) java.lang.reflect.Array.newInstance(Entry.class, size);
    }
}
Andremoniy
  • 31,241
  • 14
  • 110
  • 218
  • Why can't java do this by default? Sounds like a pain to have to cast and write this long winded method call. – Pavel Jul 29 '15 at 14:48
  • you can always do `import java.lang.reflect;` and write simple `...Array.newInstance(...` – Andremoniy Jul 30 '15 at 12:28
1

I agree with kocko that you should use some Collection instead of arrays. But specifically to your point, this compiles and runs for me. This just pushes off the responsibility for creating the array to the Array.newInstance method. The downside is it forces the cast

 class Foo<Key extends Comparable<Key>>{
     private Entry[] a;
     private class Entry{
       Key key;
     }
     public Foo(int size){
       a = (Entry[])Array.newInstance(Entry.class,size);
     }
}
MadConan
  • 3,589
  • 1
  • 13
  • 25
0

Being an inner class, the Entry type is within the scope of the type parameter Key declared in the enclosing class. In other words, Entry is also generic.

You can use

a = (Entry[]) new Foo<?>.Entry[size];

or the raw equivalent (which I don't recommend)

a = (Entry[]) new Foo.Entry[size];

This type of array creation is explained in the JLS

ArrayCreationExpression:
    new ClassOrInterfaceType DimExprs [Dims]

stating

It is a compile-time error if the ClassOrInterfaceType does not denote a reifiable type (§4.7).

where a reifiable type is

A type is reifiable if and only if one of the following holds:

  • It refers to a non-generic class or interface type declaration.
  • It is a parameterized type in which all type arguments are unbounded wildcards (§4.5.1).
  • It is a raw type (§4.8).
  • It is a primitive type (§4.2).
  • It is an array type (§10.1) whose element type is reifiable.
  • It is a nested type where, for each type T separated by a ".", T itself is reifiable.

By using the parameterization with a wildcard or the raw type, we can get the array creation expression presented above.

Sotirios Delimanolis
  • 252,278
  • 54
  • 635
  • 683