如何让内部类inheritance封闭类的generics类型?

我正在使用Java 6。

我无法让我的内部类使用与其封闭类相同的generics类。 目前我有

public class TernarySearchTree  { ... 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 TSTNode  [] relatives; private T data; protected TSTNode(char splitchar, TSTNode  parent) { this.splitchar = splitchar; relatives = new TSTNode[4]; relatives[PARENT] = parent; } } } 

现在我收到了警告

类型参数T隐藏类型T.

如果我从内部类中删除type参数(即从protected class TSTNode行中protected class TSTNode ),那么我在行relatives = new TSTNode[4]上得到一个编译错误。

我怎样才能把一切都搞定?

你可以:

  • TSTNode删除类型参数(即,使其成为非generics) – 它仍然可以访问外部

  • 将类TSTNode类型参数重命名为(例如) U

[UPDATE]

以下是重写代码的四种不同方法。 所有人都编译。 我认为你应该考虑使用EnumMap (参见下面的第4版)。

版本1 :在内部类中使用不同名称的类型参数。 你需要使用List而不是数组。

  public class TernarySearchTree { 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> relatives; private U data; protected TSTNode(char splitchar, TSTNode parent) { this.splitchar = splitchar; relatives = new ArrayList>(); for (int i = 0; i < HIKID; ++i) { // Allocate 4 slots in relatives relatives.add(null); } relatives.set(PARENT, parent); } } private TSTNode node; // When you use it, pass T as U public TernarySearchTree() { node = new TSTNode(',', null); // When you use it, pass T as U } } 

版本2 :从封闭类inheritanceT.

  public class TernarySearchTree { 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 relatives; private T data; protected TSTNode(char splitchar, TSTNode parent) { this.splitchar = splitchar; relatives = new ArrayList(); 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); } } 

版本3 :使用Map(而不是List)

  public class TernarySearchTree { 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 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(); relatives.put(PARENT, parent); // set -> put } } private TSTNode node; public TernarySearchTree() { node = new TSTNode(',', null); } } } 

版本4 :将索引定义为枚举+使用EnunMap(而不是哈希映射)

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

[更新2]要记住一件事: 使用EnumMap而不是序数索引

至于从内部类中删除T时通用数组创建的编译错误:

因为它是一个非静态内部类,所以它在外部类的类型参数的范围内。 这意味着它也通过其外部类的类型参数隐式地进行参数化

因此,当您编写TSTNode它基本上意味着TernarySearchTree.TSTNode (这里的T是外部T)。 因此TSTNode仍然是generics类型(即使您没有明确看到任何括号),并且创建generics类型的数组失败。

您可以通过手动限定名称来引用TSTNode的原始类型: TernarySearchTree.TSTNode

所以new TernarySearchTree.TSTNode[4]就是答案。

您将获得一个未经检查的警告,您可以忽略它(这是您必须使用generics类型的数组)

PS从内部类中删除类型参数几乎肯定是正确的选择,因为Java中的非静态内部类隐式地引用了外部类的实例。 因此它已经使用外部T进行了参数化。如果您只是想使用相同的T,请不要声明另一个。

我不知道你想做什么,但是,有这个解决方案:

 public class TernarySearchTree { protected class TSTNode { protected static final int PARENT = 0, LOKID = 1, EQKID = 2, HIKID = 3; protected char splitchar; protected TSTNode[] relatives; private E data; protected TSTNode(char splitchar, TSTNode parent) { this.splitchar = splitchar; relatives = new TSTNode[4]; relatives[PARENT] = parent; } } } 

通过这种方式,您可以在同一行收到警告而不是错误。

使用List可能是更好的解决方案(没有警告)

 public class TernarySearchTree { protected class TSTNode { protected static final int PARENT = 0, LOKID = 1, EQKID = 2, HIKID = 3; protected char splitchar; protected List> relatives; private E data; protected TSTNode(char splitchar, TSTNode parent) { this.splitchar = splitchar; relatives = new ArrayList>(); relatives.set(PARENT, parent); } } } 

我怀疑你想要的是:

 class Tree { Node head; static class Node { List> relatives = new ArrayList>(); T value; } } 

这里,树的头节点与树本身具有相同的T ,并且每个相对节点具有与父节点相同的T ,因此树中的所有节点将具有与树本身相同的值类型。

我在这里使用了一个ArrayList ,因为数组不能有generics类型。

Itay Maman解决方案的变种。

这是一个比OP要求更广泛的问题的答案:如何创建一个在Java 内部使用的generics数组? (此解决方案不是用于创建要返回给用户的通用数组 – 这是不安全的,因为已经很好地识别 。)

编辑:版本5 :将枚举与数组一起使用。 (我认为V4对于OP来说更好,但是如果你需要一个带有generics的数组,这里是如何 – Josiah Yoder)

 public class TernarySearchTreeWithArray { protected static enum Index { PARENT, LOKID, EQKID, HIKID, ARRAY_SIZE; } protected class TSTNode { protected char splitchar; @SuppressWarnings("unchecked") protected TSTNode[] relatives = (TSTNode[]) new TSTNode[Index.ARRAY_SIZE.ordinal()]; private U data; protected TSTNode(char splitchar, TSTNode parent) { this.splitchar = splitchar; relatives[Index.PARENT.ordinal()] = parent; } } private TSTNode root; // When you use it, pass T as U public TernarySearchTreeWithArray() { root = new TSTNode<>(',', null); // When you use it, pass T as U } }