Reputation: 1452
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
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:
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>
.ParameterizedType
.ParameterizedType.getActualTypeArguments()
on that. You will get a Type
representing T
.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
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