1

I have seen in many answers (e.g., this) that a way of creating an array using generics is the following:

T[] array = (T[]) new Object[SIZE];

I am trying to do something similar:

EntryRecipient<K,V>[] array = (EntryRecipient<K,V>[]) new Object[MAX_SIZE];

However, this does not work, casting the following error:

Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [LHashTable$EntryRecipient;

My code is:

HashTableEntry (included as private subclass of HashTable)

class HashTableEntry<K,V> {
    private K key;
    private V value;

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

    public V value() {
        return value;
    }

    public K key() {
        return key;
    }
}

EntryRecipient (included as private subclass of HashTable)

private class EntryRecipient<K,V> {
    private List<HashTableEntry<K,V>> entries;

    public EntryRecipient() {
        entries = new ArrayList<HashTableEntry<K,V>>();
    }

    // ... other methods
}

HashTable

class HashTable<K,V> {
    private EntryRecipient<K,V>[] map;
    private final int MAX_SIZE = 199; // Prime, to avoid collisions
    private int size;

    public HashTable() {
        map = (EntryRecipient<K,V>[]) new Object[MAX_SIZE];
        size = 0;
    }
    // ... other methods
}

Could you give me some hints to solve this?

Community
  • 1
  • 1
Eleanore
  • 1,628
  • 3
  • 16
  • 28
  • What is `EntryRecipient` is it a concrete class? Also why don't you use a `List` –  Jul 12 '15 at 12:24
  • I cannot use a `List` in my case. `EntryRecipient` is a concrete class, containing a `List` of HashTable (composed of a pair of values, `K key` and `V value`) – Eleanore Jul 12 '15 at 12:26
  • @RealSkeptic yes, typo in my question, but the code is correct. I edited the question. – Eleanore Jul 12 '15 at 12:28
  • @Eleanore Are you sure you don't have any other typos in your code? Please show the `EntryReceipt` class and any other relevant code. – CKing Jul 12 '15 at 12:31
  • Can you show us EntryRecipient? What is HashTable? Why not just use the provided collection classes? – pvg Jul 12 '15 at 12:33
  • 1
    The rule of thumb is - no external links to code. Include the essentials of your code (the relevant parts and things referenced from them) in your question itself, not outside of StackOverflow. – RealSkeptic Jul 12 '15 at 12:34
  • possible duplicate of [How to convert object array to string array in Java](http://stackoverflow.com/questions/1018750/how-to-convert-object-array-to-string-array-in-java) – emlai Jul 12 '15 at 12:35
  • That's not valid Java, @BugsHappen – pvg Jul 12 '15 at 12:42
  • @Eleanore In second comment you said "I cannot use a List". Any special reason for that? `List` can be (and in your case probably should be) used as `Type[]`. – Pshemo Jul 12 '15 at 12:46
  • @Pshemo yes, this is a coding interview question, and I am asked to implement a HashTable using an array, not a list. – Eleanore Jul 12 '15 at 12:47
  • @Eleanore zenith is right, your question is a dupe of the one linked. new instantiates an array not the instances in it. – pvg Jul 12 '15 at 12:53
  • Yes, it is. I posted an answer below for this. If you think my question is not helpful and duplicated, please feel free to mark it as dup. – Eleanore Jul 12 '15 at 12:56
  • @Eleanore Wait, are you trying to say that interviewer asked you to rewrite your code `entries = new ArrayList>();` to explicitly use Object array instead of type safe `List`? – Pshemo Jul 12 '15 at 12:56
  • @Pshemo well, in all honestly, `ArrayList` is just as safe as `[]`, due to type erasure. A properly built answer using `[]` as data and generics as protection is just as well as one using `ArrayList` as data - as long as the implementation is protected in a way forcing that no mixed elements are added, the class *will* be type-safe. –  Jul 12 '15 at 13:13
  • @vaxquis Yes, they have similar level of safety at run-time, but properly used generics provides type-safety in compilation time, preventing us from doing things like `List dogs = ...; dogs.add(new Cat());`. That is why generally it is better to use collections over arrays, unless we are absolutely sure what we are doing. Also if we want to ensure type-safety of collection at runtime we can use checked collections like `checkedList = Collections.checkedList(dogs, Dog.class)` which will wrap our list and will add mechanism checking if added element is of proper type. – Pshemo Jul 12 '15 at 13:27
  • @Pshemo you can't protect nobody from that. `List dogs = new ArrayList(); ((List)dogs).add(new Cat());` - your point would make sense if Java had type reification. Since it has erasure, the code provided by me is not only compiling, but actually *working*. Java doesn't provide any language-level facility to *prevent* that, since it has no reification. Compiler warnings? You've gotta be joking, you get the warnings regardless if the code is *not working* or *working but semantically wrong*. The only way you can protect somebody from that is by proper encapsulation. –  Jul 12 '15 at 14:01
  • @Pshemo I'm not arguing that generics are/aren't the way you usually should go - because they obviously are, for many reasons - but there *ain't nothing inherently unsafe in using arrays vs generics* - it takes both proper *encapsulation* (hiding unsafe memebers) and proper *implementation* (protecting from disrupting the valid state) to make a class type-safe, as you shown yourself. You can write type-safe code with arrays, and type-unsafe code with generics. It's just *usually* a lot easier with generics, that's all. This *ain't* the case for data classes - and `HashTable` is one of them. –  Jul 12 '15 at 14:09
  • as a side note: `checkedList` only proves my point - it requires a dedicated *class*, with both *encapsulation* and a proper type-safe *implementation* to provide run-time generic safety, since the language, by itself, *doesn't facilitate this*. `List` by itself is actually *less* type-safe than an array - you can't put an element into mismatched array, you *can* do that with unchecked `List`. Arrays are type-safe at run time *by default and automatically*, generics *ain't*. Also, bear in mind you can't use `checkedList` when the checked type has *generics* without invoking raw type. –  Jul 12 '15 at 14:24
  • 1
    @vaxquis Yes, that is true that arrays gives us more type safety at run-time than generics, which main purpose is provide additional type control while compilation, but it can't prevent problems when for instance rawtypes will be used. Also thanks for reminding about ugliness of `checkedList` caused by rawtypes. So yes I agree that array with proper type will be better when we would like to make sure that no incorrect object will be stored (like in case of ArrayList which internally works on `Object[]` which means it can accept any Object passed - including incorrect ones). – Pshemo Jul 12 '15 at 15:27

2 Answers2

5

I cannot find any reason for using an Object[] for EntryRecipient<K,V>[] in this code. The reference of the array is not a generic reference, so use the array of that class type. Converting an Object array to EntryRecipient array directly is not possible in Java. (EntryRecipient[] is not same as T[]). The solution for your problem is modifying your HashTable constructor as shown below:

public HashTable() {
    // Create an array of EntryRecipient
    map = new EntryRecipient[MAX_SIZE];
    size = 0;
    // Initialize the array
    // Otherwise you will get NullPointerException
    for (int i = 0; i < MAX_SIZE; i++) {
        map[i] = new EntryRecipient<K, V>();
    }
}
Gobinath
  • 862
  • 1
  • 14
  • 21
  • 1
    I was just about to post the very same answer. Using `Object[]` only makes sense for classes where the content's type is dynamic after the erasure; for this concrete example, using raw class is a lot better than copying to `Object[]`. –  Jul 12 '15 at 12:58
-3

Start by asking yourself: 'Do I really need an array? Could I just use ArrayList<EntryRecipient<K, V>>? An array list is a very skinny wrapper on an array; your code has to be awfully performance-sensitive to see any different in speed. Whereas, all this generic type stuff just works.

bmargulies
  • 91,317
  • 38
  • 166
  • 290