Java - неуниверсальный класс расширяет универсальный класс

1

Я хотел бы знать, как (если возможно) я могу создать класс, который является определенным типом родового класса.

Чтобы быть конкретным, у меня есть abstract class Stack<Type> со всеми необходимыми методами, и я хотел бы иметь class StackInteger то время как экземпляр StackInteger также является экземпляром Stack<Integer>.

Я вижу, я могу сделать что-то вроде этого:

class StackInteger {
    Stack<Integer> s;

    public StackInteger(int size) {
        s = new Stack<Integer>(size);
    }

}

а затем реализовать все методы Stack, чтобы содержать s.method(); но я задаюсь вопросом, могу ли я сделать это легко, простираясь от Stack.

  • 3
    Есть ли конкретная причина, по которой вы хотите это сделать? Из приведенного вами примера все, что вы делаете, это маскируете Stack<Integer> с двумя меньшими символами ...
  • 0
    Тогда я могу иметь, например, StackInteger и StackString, которые оба реализуют свои собственные методы, но имеют общую функциональность Stack.
Показать ещё 1 комментарий
Теги:
class
generics
inheritance

3 ответа

3

Да, в этом случае наследование является лучшим решением, чем состав, как у вас, потому что StackInteger - это Stack.

Просто поставьте Integer как аргумент типа в предложении extends.

class StackInteger extends Stack<Integer>

Однако, если вы не предоставляете каких-либо дополнительных функций помимо того, что уже есть в Stack, этот класс бесполезен, и вы можете просто использовать Stack<Integer>.

  • 2
    Кроме того, если вам нужно использовать Stack<Integer> предпочтите эквивалентную реализацию Deque поскольку она обеспечивает более полный и согласованный набор операций стека LIFO.
  • 0
    Это анти-паттерн, см. Ibm.com/developerworks/library/j-jtp02216
Показать ещё 6 комментариев
2

Я бы рекомендовал не распространять общие классы, чтобы преодолеть многословность. Это антипаттерн, известный как антипаттер псевдотипа.

Из статьи:

если параметр метода имеет тип StringList, вы не можете передать ему обычный список. Это означает, что вы вообще не можете использовать псевдотипы как аргументы метода, не требуя, чтобы каждое использование этого метода использовало псевдотип, что в практическом смысле означает, что вы вообще не можете использовать псевдотипы в библиотечных API.

...

Еще одна проблема с antipattern псевдо-typedef заключается в том, что он имеет тенденцию игнорировать преимущество использования интерфейсов для определения типов переменных и аргументов метода. Хотя можно определить StringList как интерфейс, который расширяет List и конкретный тип StringArrayList, который расширяет ArrayList и реализует StringList, большинство пользователей антипаттера псевдоспециалистов обычно не идут на эту длину, так как цель этой техники заключается в том, чтобы упростить и сократить имена типов. В результате API будут менее полезными и более хрупкими, поскольку они используют конкретные типы, такие как ArrayList, а не абстрактные типы, такие как List.

Итак, почему бы не придерживаться Stack<Integer>? Я не думаю, что это так плохо.

1

Да, ты можешь сделать это.

class StackInteger extends Stack<Integer> {
    ....
}

Как указывает @Magnamag, это часто считается антипаттерном. Это особенно верно, если это делается только для того, чтобы не указывать параметры типа.

Однако для этого могут быть законные способы. Например, если не-общий класс является private, пользователи класса будут вынуждены программировать интерфейс (или абстрактный класс) в любом случае. В этом примере (по общему признанию, довольно надуманный) существует статический метод, возвращающий не общий универсальный класс, расширяющий AbstractList<String>.

public class Main  {

    public static List<String> helloWorld() {
        return new AbstractList<String>() {
            @Override
            public String get(int i) {
                switch (i) {
                    case 0: return "Hello";
                    case 1: return "World";
                    default: throw new ArrayIndexOutOfBoundsException();
                }
            }
            @Override
            public int size() {
                return 2;
            }
        };
    }

    public static void main(String[] args) {
        System.out.println(helloWorld());
    } 
}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню