我正在使用Java 6.
我无法让我的内部类使用与其封闭类相同的泛型类。目前我有
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;
}
}
}
现在我收到警告
类型参数T隐藏类型T
如果我从内部类中删除type参数(即从<T>
行中删除protected class TSTNode<T>
),那么我会在行relatives = new TSTNode[4]
上收到编译错误。
我怎样才能把事情做好?
答案 0 :(得分:10)
你可以:
从<T>
中移除TSTNode
类型参数(即,使其成为非泛型) - 它仍然可以访问外部<T>
。
将班级<T>
中的TSTNode
类型参数重命名为(例如)U
。
<强> [UPDATE] 强>
以下是重写代码的四种不同方法。所有人都编译。我认为你应该考虑使用EnumMap
(参见下面的第4版)。
版本1 :在内部类中使用不同名称的类型参数。你需要使用List而不是数组。
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
}
}
版本2 :从封闭类继承T
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);
}
}
版本3 :使用地图(而不是列表)
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);
}
}
}
版本4 :将索引定义为枚举+使用EnunMap(而不是哈希映射)
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);
}
}
[更新2] 要记住一件事:Use EnumMap instead of ordinal indexing
答案 1 :(得分:4)
关于从内部类中删除T时的通用数组创建的编译错误:
因为它是一个非静态内部类,所以它在外部类的类型参数的范围内。这意味着它也被其外部类的类型参数
隐式地参数化所以当你写TSTNode
时,它基本上意味着TernarySearchTree<T>.TSTNode
(这里的T是外部T)。因此TSTNode
仍然是泛型类型(即使您没有明确看到任何括号),并且创建泛型类型的数组也会失败。
您可以通过手动限定名称来引用TSTNode
的原始类型:TernarySearchTree.TSTNode
。
所以new TernarySearchTree.TSTNode[4]
就是答案。
您将获得一个未经检查的警告,您可以忽略该警告(这是您必须使用的通用类型数组)
P.S。从内部类中删除类型参数几乎肯定是正确的选择,因为Java中的非静态内部类隐式地引用了外部类的实例。因此它已经使用外部T进行参数化。如果您只是想使用相同的T,请不要声明另一个。
答案 2 :(得分:2)
我不知道你想做什么,但是,有这个解决方案:
public class TernarySearchTree<T> {
protected class TSTNode<E extends T> {
protected static final int PARENT = 0, LOKID = 1, EQKID = 2, HIKID = 3;
protected char splitchar;
protected TSTNode<E>[] relatives;
private E data;
protected TSTNode(char splitchar, TSTNode<E> parent) {
this.splitchar = splitchar;
relatives = new TSTNode[4];
relatives[PARENT] = parent;
}
}
}
这样你就可以在同一行收到警告而不是错误。
使用列表可以更好解决方案(无警告)
public class TernarySearchTree<T> {
protected class TSTNode<E extends T> {
protected static final int PARENT = 0, LOKID = 1, EQKID = 2, HIKID = 3;
protected char splitchar;
protected List<TSTNode<E>> relatives;
private E data;
protected TSTNode(char splitchar, TSTNode<E> parent) {
this.splitchar = splitchar;
relatives = new ArrayList<TSTNode<E>>();
relatives.set(PARENT, parent);
}
}
}
答案 3 :(得分:0)
我怀疑你想要的是:
class Tree<T> {
Node<T> head;
static class Node<T> {
List<Node<T>> relatives = new ArrayList<Node<T>>();
T value;
}
}
这里,树的头节点与树本身具有相同的T
,并且每个相对节点与父节点具有相同的T
,因此树中的所有节点将具有相同的ArrayList
值类型为树本身。
我在这里使用{{1}}因为数组不能有通用类型。
答案 4 :(得分:0)
这是一个更广泛问题的答案,而不是OP提出的问题:如何在Java中创建一个仅在内部使用的泛型数组? (此解决方案不用于创建要返回给用户的通用数组 - 即unsafe as is well recognized。)
编辑:版本5 :将枚举与数组一起使用。 (我认为V4对于OP更好,但是如果你需要一个带有泛型的数组,这里是如何--Josiah Yoder)
public class TernarySearchTreeWithArray<T> {
protected static enum Index {
PARENT, LOKID, EQKID, HIKID, ARRAY_SIZE;
}
protected class TSTNode<U> {
protected char splitchar;
@SuppressWarnings("unchecked")
protected TSTNode<U>[] relatives = (TSTNode<U>[]) new TSTNode[Index.ARRAY_SIZE.ordinal()];
private U data;
protected TSTNode(char splitchar, TSTNode<U> parent) {
this.splitchar = splitchar;
relatives[Index.PARENT.ordinal()] = parent;
}
}
private TSTNode<T> root; // When you use it, pass T as U
public TernarySearchTreeWithArray() {
root = new TSTNode<>(',', null); // When you use it, pass T as U
}
}