1

I'm getting the error "Cannot create a generic array" for the following code:

public class MapImpl<K, V> {
 private static int DEFAULT_CAPACITY = 16;
 private int size;
 // array holding the entries of the map
 private Entry[] entries;
 public MapImpl() {
 entries = new Entry[DEFAULT_CAPACITY]; // error at this line: Cannot create a generic array of MapImpl<K,V>.Entry
 }
 // represents an entry in the map
 private class Entry {
 private K key;
 private V value;
 public Entry(K key, V value) {
 this.key = key;
 this.value = value;
 }
 }

Surprisingly, this works fine:

public class MapImpl<K, V> {
 private static int DEFAULT_CAPACITY = 16;
 private int size;
 // array holding the entries of the map
 private Entry<K, V>[] entries;
 public MapImpl() {
 entries = new Entry[DEFAULT_CAPACITY];
 }
 // represents an entry in the map
 private class Entry<K, V> {
 private K key;
 private V value;
//but here K and V are being hidden.
 public Entry(K key, V value) {
 this.key = key;
 this.value = value;
 }
 }
 }

I do understand that we can't create an array of generic type or a type that takes type parameters. But, here in my code the Entry class is not of a generic type. Am i overlooking something ?

asked May 4, 2015 at 11:31
4
  • possible duplicate of stackoverflow.com/questions/529085/… Commented May 4, 2015 at 11:33
  • @Parth I don't think so. I already know that question. My context is different. Commented May 4, 2015 at 12:01
  • Is there a reason you've made Entry an inner class? See stackoverflow.com/questions/70324/…. Commented May 4, 2015 at 12:42
  • @Radiodef There is no specific reason; it's just some trivial code. Commented May 4, 2015 at 12:50

5 Answers 5

4

Problem here is that non-static nested class has access to all members of its outer classes, which includes information about generic types used in outer class, like

class Outer<T>{
 private T t;
 class Inner{
 void method(T tt){//we can use same type T as used in outer class
 t = tt;
 }
 }
}

So in reality Inner class type is more like Outer<T>.Inner which makes form of it generic type and arrays can't be created from generic types because of type erasure which would prevent arrays from being able to test if added elements are valid.

Most common solution in that cases is to use collections instead of arrays like List<OurType>.

But if you really want to have only arrays then other possible solution (but you should try to avoid it) is to use raw type, so instead of

new Entry[DEFAULT_CAPACITY];

which is equivalent of

new MapImpl<K, V>.Entry[DEFAULT_CAPACITY];

you could use

new MapImpl.Entry[DEFAULT_CAPACITY];
// ^no generic type -> it is raw type

Solution with

private class Entry<K, V> {
 private K key;
 private V value;
//but here K and V are being hidden.
 public Entry(K key, V value) {
 this.key = key;
 this.value = value;
 }
}

works probably (I can't find any relevant JLS describing this) because as you said, you have shadowed original K and V from outer class, which means you can't access them and now

 void method(T tt){
 t = tt;
 }

method will not compile because T from inner class is not the same as T from outer class. Because of that, Entry is no longer MapImpl<K,V>.Entry but MapImpl.Entry<K,V> and when you write it as

new Entry[...]

you are explicitly making it raw type which will work (with compilation warning about rawtypes when you declare private Entry[] entries)

answered May 4, 2015 at 11:36
1
  • 1
    Thanks for reading my question carefully and giving the perfect explanation. Commented May 4, 2015 at 12:59
2

Declare Entry class as static. Currently it's not static, so it's implicitly linked to the MapImpl instance and to its generic arguments.

Edit: I mean

 private static class Entry<K, V>
answered May 4, 2015 at 11:32
4
  • 1
    It does not help. In this case OP will have to make it generic implicitly. Commented May 4, 2015 at 11:33
  • @Tagir Valeev, not really. In that case I can't make a reference of K and V in Entry class. Commented May 4, 2015 at 11:34
  • Added an explanation. Commented May 4, 2015 at 11:39
  • In that case , the type parameters K&V of Entry class hides that of MapImpls's K&V, which probably is not correct. Commented May 5, 2015 at 4:27
2

Since Entry is an inner class of a generic class MapImpl, it is also parametrized by K and V. To make an array, you will have to create it with raw type:

entries = new MapImpl.Entry[DEFAULT_CAPACITY];
answered May 4, 2015 at 11:40
2
  • thanks for the answer. May I know the difference between new Entry[DEFAULT_CAPACITY] and new MapImpl.Entry[DEFAULT_CAPACITY] ? Commented May 4, 2015 at 11:59
  • As I wrote in the answer, by declaring Entry as an inner class of MapImpl, you are tying Entry to an instance of MapImpl. That makes Entry generic by MapImpl's parametric types. The full name of class Entry is MapImpl<K,V>.Entry. By creating array of MapImpl.Entry, you make the type raw rather then generic. Commented May 4, 2015 at 12:25
0

It's because Java's arrays (unlike generics) contain, at runtime, information about its component type. So you must know the component type when you create the array. Since you don't know what K and V are at runtime, you can't create the array.

answered May 4, 2015 at 11:36
0

Try below code instead

package com.vibhs.stack.overflow.generics;
public class MapImpl<K, V> {
private static int DEFAULT_CAPACITY = 16;
private int size;
// array holding the entries of the map
private Entry[] entries;
public MapImpl() {
 entries = new Entry[DEFAULT_CAPACITY]; // error at this line: Cannot
 // create a generic array of
 // MapImpl<K,V>.Entry
}
// represents an entry in the map
private class Entry<K,V> {
 private K key;
 private V value;
 public Entry(K key, V value) {
 this.key = key;
 this.value = value;
 }
}
}
answered May 4, 2015 at 11:38
1
  • Yes, I know that it works.I just edited my post. But i want to know the reason behind it. Commented May 4, 2015 at 11:40

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.