Access a value in a generic array inside a generic class

206 views Asked by At

I am making a program that creates a generic hashtable that has both generic keys and generic data. When I cast the data array as the type Person, a class I created, and I try to access the data stored inside an individual Person from my Driver class using a getter method, I get an Object-type returned. My question is how do I access a non-generic class's information through a generic class, since it is stored in a generic array.

This is how I constructed the hashtable:

//region Instance Variables
    private int count;
    private K[] keys;
    private E[] data;
    private boolean[] hasBeenUsed;
    //endregion


    //region Constructor
    public Table(int capacity)
    {
        if (capacity <= 0)
            throw new IllegalArgumentException("Capacity is negative.");

        keys = (K[]) new Object[capacity];
        data = (E[]) new Object[capacity];
        hasBeenUsed = new boolean[capacity];
    }

My data getters(part of the Table class):

public E[] getData()
    {
        return data;
    }

    public E getDataAt(int index)
    {
        return data[index];
    }

This is where I am trying to access the information from my Driver class:

public void print(Table hash)
    {
        Person[] people = toArray(hash);
        for (int i = 0; i < hash.getData().length; i++)
        {
            if (null == hash.getKeyAt(i))
                System.out.println("NULL AT " + i);
            else
                System.out.println("Key: " + hash.getKeyAt(i) + " Data: " + hash.getDataAt(i));
        }
    }


    private Person[] toArray(Table hash)
    {
        Person[] people = new Person[hash.getData().length];

        for (int i = 0; i < hash.getData().length; i++)
        {
            people[i] = hash.getDataAt(i);
        }
    }

This is my entire Hashtable Class if it's needed:

public class Table<K,E>
{
    //region Instance Variables
    private int count;
    private K[] keys;
    private E[] data;
    private boolean[] hasBeenUsed;
    //endregion


    //region Constructors

    /**
     * Constructor
     * Instantiates the keys, data, and hasBeenUsed variables with a passed value of capacity
     * @param capacity the size to give the three instance arrays
     */
    @SuppressWarnings("unchecked")
    public Table(int capacity)
    {
        if (capacity <= 0)
            throw new IllegalArgumentException("Capacity is negative.");

        keys = (K[]) new Object[capacity];
        data = (E[]) new Object[capacity];
        hasBeenUsed = new boolean[capacity];
    }


    /**
     * Constructor
     * Default-Sets arrays to size 10
     */
    @SuppressWarnings("unchecked")
    public Table()
    {
        keys = (K[]) new Object[10];
        data = (E[]) new Object[10];
        hasBeenUsed = new boolean[10];
    }
    //endregion


    //region Public Methods

    /**
     * Put
     * Adds a new set to the table
     * @param key The new Key value
     * @param data the new Data value
     * @return null if this is a new set, the old data value if the key already exists
     */
    public E put(K key, E data)
    {
        int index = findIndex(key);
        E answer;

        if (index != -1)
        {
            answer = (E) this.data[index];
            this.data[index] = data;
            return answer;
        } else if (count < this.data.length)
        {
            index = hash(key);
            while (keys[index] != null)
            {
                System.out.println("Collision!");
                index = nextIndex(index, key);
            }
            keys[index] = key;
            this.data[index] = data;
            hasBeenUsed[index] = true;
            count++;
            return null;
        } else
            System.out.println("ERROR IN PUT");
        return null;
    }


    /**
     * Remove
     * Removes a key-data set from the table
     * @return the value removed
     */
    @SuppressWarnings("unchecked")
    public E remove(K key)
    {
        int index = findIndex(key);
        E answer = null;

        if (index != -1)
        {
            answer = (E) data[index];
            keys[index] = null;
            data[index] = null;
            count--;
        }
        return answer;
    }


    /**
     * Contains Key
     * Checks if the passed key exists
     * @param key generic type key to check for
     * @return true if the key exists
     */
    public boolean containsKey(K key)
    {
        for (int i = 0; i < data.length; i++)
        {
            if (hasBeenUsed[i])
            {
                if (keys[i].equals(key))
                {
                    return true;
                }
            }
        }
        return false;
    }


    /**
     * Get
     * Retrieves the data held stored with key
     * @param key the key to access
     * @return the data at key, null if key does not exist
     */
    @SuppressWarnings("unchecked")
    public E get(K key)
    {
        int index = findIndex(key);

        if (index == -1)
            return null;
        else
            return (E) data[index];
    }
    //endregion


    //region Private Methods

    //Locates the index value of key
    private int findIndex(K key)
    {
        int count = 0;
        int i = hash(key);

        while ((count < data.length) && (hasBeenUsed[i]))
        {
            if (key.equals(keys[i]))
                return i;
            count++;
            i = nextIndex(i, key);
        }

        return -1;
    }


    //Hashes the key
    private int hash(K key)
    {
        return Math.abs(key.hashCode()) % data.length;
    }


    private int hash2(K key)
    {
        return 1 + (Math.abs(key.hashCode()) % (data.length-2));
    }


    //Determines if the next index is valid
    private int nextIndex(int i, K key)
    {
        return (i + hash2(key)) % data.length;
    }
    //endregion


    //region Getters and Setters
    public int getCount()
    {
        return count;
    }

    public void setCount(int count)
    {
        this.count = count;
    }

    public K[] getKeys()
    {
        return keys;
    }

    public K getKeyAt(int index)
    {
        return keys[index];
    }

    public void setKeys(K[] keys)
    {
        this.keys = keys;
    }

    public E[] getData()
    {
        return data;
    }

    public E getDataAt(int index)
    {
        return data[index];
    }

    public void setData(E[] data)
    {
        this.data = data;
    }
    //endregion
}

EDIT I edited the print method, and now I am getting a ClassCastException

Here is my new print method:

public void print(Table<Integer, Person> hash)
    {
        for (int i = 0; i < hash.getKeys().length; i++)
        {
            if (null == hash.getKeyAt(i))
                System.out.println("NULL AT " + hash.getKeyAt(i));
            else
            {
                System.out.println("Data at key " + hash.getKeyAt(i) + ": \n");
                hash.getDataAt(i).printInfo();
            }
        }
    }
1

There are 1 answers

0
Praba On

You Table is actually generic. So when you want a new Table instance, you can say new Table<KEY_TYPE, VALUE_TYPE>() which will not need you to cast anywhere.

If you're not sure how to create an instance of generic class, please check https://docs.oracle.com/javase/tutorial/java/generics/types.html.