Как получить внутренний класс для наследования типа универсального класса?
Я использую 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
Если я удалю параметр типа из внутреннего класса (т.е. удаляю строку <T>
из строки protected class TSTNode<T>
), я получаю ошибку компиляции в строке relatives = new TSTNode[4]
.
Как я могу сделать все правильно?
Ответы
Ответ 1
Вы можете:
[ОБНОВЛЕНИЕ]
Ниже перечислены четыре способа переписать код. Все они компилируются. Я думаю, вы должны рассмотреть возможность использования 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]
Одна вещь, которую нужно иметь в виду: Использовать EnumMap вместо порядкового индексации
Ответ 2
Что касается ошибки компиляции для создания общего массива при удалении T из внутреннего класса:
Поскольку это нестатический внутренний класс, он входит в объем внешнего параметра класса. Это означает, что он неявно также параметризуется параметром внешнего класса
Поэтому, когда вы пишете TSTNode
, это в основном означает TernarySearchTree<T>.TSTNode
(здесь T - внешний T). Таким образом, TSTNode
по-прежнему является общим типом (даже если вы явно не видите никаких скобок), и создание массива родового типа не выполняется.
Вы можете обратиться к необработанному типу TSTNode
, вручную присвоив имя: TernarySearchTree.TSTNode
.
Так что new TernarySearchTree.TSTNode[4]
- это ответ.
Вы получите непроверенное предупреждение, которое вы можете игнорировать (вам нужно жить с массивами общих типов)
P.S. удаление параметра типа из внутреннего класса почти наверняка является правильным выбором, поскольку нестатические внутренние классы в Java неявно имеют ссылку на экземпляр внешнего класса. Таким образом, он уже параметризуется внешним T. Если вы просто хотите использовать тот же T, не объявляйте еще один.
Ответ 3
Я не знаю, что вы пытаетесь сделать, но вот это решение:
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);
}
}
}
Ответ 4
Я подозреваю, что вы хотите что-то вроде:
class Tree<T> {
Node<T> head;
static class Node<T> {
List<Node<T>> relatives = new ArrayList<Node<T>>();
T value;
}
}
Здесь дерево node имеет тот же самый T
как само дерево, и каждый относительный node имеет тот же T
, что и родительский node, поэтому все узлы в дереве будут иметь тот же тип значения, что и дерево.
Я использовал ArrayList
здесь, потому что массивы не могут иметь общие типы.
Ответ 5
Вариант Решение Itay Maman.
Это ответ на вопрос более широкий, чем спрашивает OP: Как создать массив генерических элементов, которые будут использоваться только внутри в Java? (Это решение НЕ предназначено для создания универсального массива, который будет возвращен пользователю - это будет небезопасно как хорошо известна.)
Изменить: Версия 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
}
}