如何让内部类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
(这里的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 } }