Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I get an inner class to inherit enclosing class' generic type?

I'm using Java 6.

I'm having trouble getting my inner class to use the same generic class as its enclosing class. Currently I have

public class TernarySearchTree < T > {     ...     protected class TSTNode < T > {         // index values for accessing relatives array         protected static final int PARENT = 0, LOKID = 1, EQKID = 2, HIKID = 3;          protected char splitchar;         protected TSTNode < T > [] relatives;         private T data;          protected TSTNode(char splitchar, TSTNode < T > parent) {             this.splitchar = splitchar;             relatives = new TSTNode[4];             relatives[PARENT] = parent;         }     } } 

Right now I get the warning

The type parameter T is hiding the type T

If I remove the type parameter from the inner class (i.e. remove the <T> from teh protected class TSTNode<T> line), then I get a compile error on the line relatives = new TSTNode[4].

How can I make everything right?

like image 233
Dave Avatar asked Jan 06 '12 22:01

Dave


People also ask

Can generic class be inherited?

You cannot inherit a generic type. // class Derived20 : T {}// NO!

Can inner classes be inherited?

Inner classesA inner class declared in the same outer class (or in its descendant) can inherit another inner class.

Can an inner class method have access to the fields of the enclosing class?

Non-static nested classes (inner classes) have access to other members of the enclosing class, even if they are declared private. Static nested classes do not have access to other members of the enclosing class.

Can a non generic class inherit a generic class?

Yes you can do it.


1 Answers

You can either:

  • remove the <T> type parameter from TSTNode (i.e., make it non-generic) - it will still have access to the outer <T>.

  • rename the <T> type parameter in class TSTNode to (say) U.

[UPDATE]

Below are four different ways to rewrite your code. All of them compile. I think you should consider the use of an EnumMap (see Version 4, below).

Version 1: use a differenly named type parameter in the inner class. you need to use a List instead of an array.

  public class TernarySearchTree<T> {      protected class TSTNode<U> {       // index values for accessing relatives array:       protected static final int PARENT = 0, LOKID = 1, EQKID = 2, HIKID = 3;        protected char splitchar;       protected List<TSTNode<U>> relatives;       private U data;        protected TSTNode(char splitchar, TSTNode<U> parent) {         this.splitchar = splitchar;         relatives = new ArrayList<TSTNode<U>>();         for (int i = 0; i < HIKID; ++i) {  // Allocate 4 slots in relatives           relatives.add(null);         }         relatives.set(PARENT, parent);       }               }      private TSTNode<T> node; // When you use it, pass T as U      public TernarySearchTree() {       node = new TSTNode<T>(',', null);  // When you use it, pass T as U      }   } 

Version 2: inherit T from enclosing class

  public class TernarySearchTree<T> {      protected class TSTNode {       // index values for accessing relatives array:       protected static final int PARENT = 0, LOKID = 1, EQKID = 2, HIKID = 3;        protected char splitchar;       protected List<TSTNode> relatives;       private T data;        protected TSTNode(char splitchar, TSTNode parent) {         this.splitchar = splitchar;         relatives = new ArrayList<TSTNode>();         for (int i = 0; i < HIKID; ++i) {  // Allocate 4 slots in relatives           relatives.add(null);         }         relatives.set(PARENT, parent);       }     }      private TSTNode node;       public TernarySearchTree() {       node = new TSTNode(',', null);       }   } 

Version 3: use a Map (instead of a List)

  public class TernarySearchTree<T> {      protected class TSTNode {       // index values for accessing relatives array:       protected static final int PARENT = 0, LOKID = 1, EQKID = 2, HIKID = 3;        protected char splitchar;       protected Map<Integer, TSTNode> relatives;       private T data;        protected TSTNode(char splitchar, TSTNode parent) {         this.splitchar = splitchar;         // Create a hash map. No need to pre-allocate!         relatives = new HashMap<Integer, TSTNode>();          relatives.put(PARENT, parent); // set -> put       }     }      private TSTNode node;       public TernarySearchTree() {       node = new TSTNode(',', null);       }   } } 

Version 4: define the indices as an enum + use an EnunMap (instead of a hash map)

  public class TernarySearchTree<T> {      protected static enum Index {       PARENT, LOKID, EQKID, HIKID;     }      protected class TSTNode {           protected char splitchar;       protected EnumMap<Index, TSTNode> relatives;       private T data;        protected TSTNode(char splitchar, TSTNode parent) {         this.splitchar = splitchar;         // Create an EnumMap.          relatives = new EnumMap<Index, TSTNode>(Index.class);         relatives.put(Index.PARENT, parent);        }     }      private TSTNode node;       public TernarySearchTree() {       node = new TSTNode(',', null);       }   } 

[Update 2] One thing to keep in mind: Use EnumMap instead of ordinal indexing

like image 179
Itay Maman Avatar answered Sep 20 '22 10:09

Itay Maman