How is this generic array legal?

113 Views Asked by At

The problem of generic arrays (i.e., the impossibility of them) seems to be a recurring theme for me. Below is the relevant code of a HashMap data structure. Obviously, I cannot declare a Bucket[], since generic arrays are impossible. However, I can declare a MapThing.Bucket[]. Am I correct when I assert that this is good practice, since even though MapThing.Bucket[] is a raw type declaration, the actual MapThing.Bucket[] instance is type parameterized by its enclosing instance?

Thanks for any insight!!!

Chris

public class MapThing<K, V> {
  private Bucket buckets[];

  public static void main(String[] argv) {
    MapThing<String, Integer> thing = new MapThing<>();
    thing.put("got your number", 8675309);
  }

  @SuppressWarnings("unchecked")
  public MapThing() {
    buckets = new MapThing.Bucket[314159];
  }

  public void put(K key, V value) {
    Bucket bucket = new Bucket(key, value);

    // Prints typeof bucket key: String, value: Integer
    System.out.println("typeof bucket key: "
    + bucket.getKey().getClass().getSimpleName() + ", value: "
    + bucket.getValue().getClass().getSimpleName());

    buckets[Math.abs(key.hashCode() % buckets.length)] = bucket;
  }

  private class Bucket {
    private K key;
    private V value;

    Bucket(K key, V value) {
      this.key = key;
      this.value = value;
    }

    public K getKey() {
      return key;
    }

    public V getValue() {
      return value;
    }
  }
}
1

There are 1 best solutions below

0
newacct On

Obviously, I cannot declare a Bucket[], since generic arrays are impossible.

  1. You can ALWAYS declare a variable of any array type. Always. It is perfectly fine to declare variables of Bucket[] or ArrayList<String>[] or whatever.

  2. You cannot use the array creation expression (i.e. new X[...]) with a parameterized type (i.e. if X is Something<SomethingElse> where SomethingElse is anything except ?). You can use array creation expression with a raw type (i.e. new X[...] where X is a raw type), e.g. new ArrayList[10].

    Therefore, if Bucket were a raw type, then new Bucket[10] would be perfectly fine. The thing is, Bucket is not a raw type. Bucket is a non-static inner class inside a generic outer class. That means it is within the scope of the type parameters of its outer class. In other words, if you write the unqualified type Bucket inside MapThing, it implicitly means MapThing<K,V>.Bucket, which is a parameterized type.

    To get the raw type, you need to explicitly qualify it with the outer class, as in MapThing.Bucket. So new MapThing.Bucket[10] will work.

    Alternately, if you don't want to use raw types, you can parameterize it with all wildcards: new MapThing<?,?>.Bucket[10].