s3rius
s3rius

Reputation: 1452

Creating/Copying arrays of a generic type

I've to solve a problem regarding generics which gives me quite the stomache ache.

Basically it's supposed to be an implementation for an array-based max-heap and I have to follow the given conditions. The code to start from looks like this:

//Interface with methods such as insert(), remove(), etc
public interface IMaxHeap<T extends Comparable<T>> {
   ...
}

public class MaxHeap<T extends Comparable<T>> implements IMaxHeap<T>{
    T[] m_array;

    ...

    public MaxHeap(int size){
        //TODO:
        //m_array = new T[size];
    }
    public MaxHeap(T[] array){
        //TODO:
        //Deep copy of array into m_array
    }
}

The code for the two constructors is what I'm strugling with. I am not supposed to modify the signature of the methods so I can't do things like this:

public MaxHeap(Class<T> clazz, int size){
    m_array = (T[]) Array.newInstance(clazz, size);
}

Additionally, doing the "unsafe" type-casting of an Object[] array like this gives me a runtime excetion (InvocationTargetException)

public MaxHeap(Class<T> clazz, int size){
    m_array = (T[]) new Object[size];
}

I've found a generic way to make a copy of my array, however it's not a deep copy:

public MaxHeap(T[] array){
    m_array = Arrays.copyOf(array, array.length);
}

So that this point m_array[0] == array[0] which isn't what I'm looking for.

I'm also not supposed to add other constraints to the class (so no T exdends Cloneable either). Given these problems I haven't actually found a way to instantiate my arrays.

I'm somewhat new to generics (I've only been working with C++ templates) so those quirks with T are pretty annoying. Can you guys point me to a solution that works?

Upvotes: 1

Views: 3223

Answers (2)

gpeche
gpeche

Reputation: 22514

Even with Java generics and type erasure, as your class implements IMaxHeap<T>, you can get T.class at runtime using reflection, and at that point everything becomes easier. The following should work:

  1. Call Class.getGenericInterfaces() to get the interfaces implemented by your class, with generic type information. The first result should be a Type instance representing IMaxHeap<T>.
  2. Cast that to a ParameterizedType.
  3. Call ParameterizedType.getActualTypeArguments() on that. You will get a Type representing T.
  4. Cast that to Class<T>.

Basically, in Java you cannot get the actual type arguments for a given generic class, but you can get the actual type arguments for its superclass and interfaces. The thing is that for those cases the runtime needs to know those actual types so it can make the appropiate runtime checks / casts.

Upvotes: -1

Nayuki
Nayuki

Reputation: 18552

From my experience, the standard thing to do is to make the backing array be of type Object[], then cast to type T when reading its elements.

Generally speaking, working with generic-typed arrays in Java is really dangerous and confusing. It's best to avoid it as much as possible.

But as you insist on doing things this way, this seems to be the solution:

    public MaxHeap(int size){
        m_array = (T[])new Comparable[size];
    }
    public MaxHeap(T[] array){
        this(array.length);
        System.arraycopy(array, 0, m_array, 0, array.length);
    }

Upvotes: 2

Related Questions