1

I have written my own 2-3-4 tree in java. Currently, my code looks like this:

public class tree234{  
    private class node{  
        Comparable data[]=new Comparable[3];  
        node next[]=new node[4];  
    }   
}

Instead, I'd like to have something like this:

public class tree234<T extends Comparable<? super T>>{  
    private class node{  
        T[] data=new T[3];//error here!  
        node[] next=new node[4];  
    }  
}

While I understand that I cannot create the array (and sort of understand why), I can't think of a reasonably simple way to implement the node class with generics. Any suggestions?

hugomg
  • 63,082
  • 19
  • 144
  • 230
Derek
  • 101
  • 1
  • 7

4 Answers4

2

You can always do an explicit cast...

The variable T[] will end up as a Comparable[] in the compiled class since T extends Comparable. So the array type must be Comparable[] - you can't assign an Object object to a Comparable variable, .

The other array type is Tree234.Node[].

public class Tree234<T extends Comparable<? super T>>{  
    private class Node{  
        T[] data=(T[]) new Comparable[3];  // need to be a comparable, as the superclass is known.
        Node[] next = (Node[]) new Tree234.Node[4];  

    }  
}
KarlP
  • 4,959
  • 2
  • 24
  • 40
  • I had tried that but got a warning, and wasn't sure if that method was safe. – Derek Jul 31 '11 at 16:29
  • Also, this happened when I ran a test program: `Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Comparable;` – Derek Jul 31 '11 at 16:30
  • OK, I fixed so that both array types uses the "naked" non-generic types, so no class cast exceptions will happen. I used eclipse to test, and I get no warnings. If you get 'unchecked' warnings , those can be ignored or supressed - @SuppressWarnings("unchecked") as this is safe. – KarlP Aug 01 '11 at 08:19
  • I believe that the runtime version is as fast as the non-generic version, but I haven't bothered to check the bytecode... – KarlP Aug 01 '11 at 15:41
  • You are welcome. (Feel free to tick the "accepted answer" checkbox...) – KarlP Aug 02 '11 at 07:45
1

Ah, Java-arrays-and-generics, how I loathe thee. While using Lists would certainly solve your typing problems, sometimes the speed of an array really is necessary.

Reflection is certainly one way out (search here for more), but I find that too code-smelly for my tastes. For the simpler cases, you can use something like the ArrayConstructor interface I have below. Were it not for the Node type we could solve your problem without any warnings at the cost of increased code verbosity and a leaky abstraction (users of your class will have to provide Node and T array constructors). Unfortunately, because the node type also takes a type parameter, there is no way we can generically handle that case without warnings.

interface ArrayConstructor<T> {
  T[] constructArray(int size);
}

class Node <T extends Comparable<? super T>>{  
    private T[] data;
    private Node[] next;

    Node(ArrayConstructor<T> dataConstructor,
         ArrayConstructor<Node<T>> nodeConstructor){
        this.data = dataConstructor.constructArray(3);
        this.next = nodeConstructor.constructArray(4);
    }
}  
nerdytenor
  • 431
  • 2
  • 7
1

Apart from the obvious "just use an object array and cast the returned values" you can also use Array.newInstance(class, size) and cast the returned value to T[]. You still have to suppress warnings as there's no way with the current generics implementation to avoid this, but this way you get type checking when inserting objects into the array and not when accessing them (and an earlier error is better imo).

Uses reflection in the background so not the most performant thing in the world probably.

Voo
  • 26,852
  • 9
  • 70
  • 145
0

You should create a new Comparable[4]. Since (I believe) this array is internal to your structure, nobody really cares what the real type of the array is.

You can then either 1) assign it to a T[] variable if you like (making sure not to have any outside code access it, or it will crash), or 2) just manually cast the elements to T when you get them out. Either way, you will get warnings.

newacct
  • 110,405
  • 27
  • 152
  • 217
  • 1
    I recommend using a `new Comparable[4]` instead, so you don't have to cast when comparing keys. – meriton Jul 31 '11 at 20:54