Java - 非泛型类继承泛型类

4
我想知道如何创建一个特定类型的泛型类,如果可能的话。
具体来说,我有一个抽象类 Stack 并且所有必要的方法已经实现,我想拥有一个 StackInteger 类,而 StackInteger 的一个实例也是 Stack 的一个实例。
我看到我可以这样做:
class StackInteger {
    Stack<Integer> s;

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

}

然后实现所有的Stack方法,以包含s.method();,但我想知道我是否可以在扩展Stack时轻松地完成它。


3
你想这样做有特别的原因吗?从你给出的示例来看,你只是用两个字符少来掩盖“Stack<Integer>”… - Jon Egeland
然后我可以有例如StackInteger和StackString,它们都实现自己的方法,但具有共同的Stack功能。 - dannymo
1
@dannymo 问题在于,如果您只需要处理一个堆栈,即对StackString和StackInteger的常规处理,则无法这样做,因为StackString不是StackInteger。 - fps
3个回答

6

是的,在这种情况下,继承比组合更好,因为一个 StackInteger 是一个 Stack

只需在 extends 子句中提供 Integer 作为类型参数即可。

class StackInteger extends Stack<Integer>

然而,如果您没有提供任何超出Stack已有功能的附加功能,则此类是无用的,您可以直接使用Stack<Integer>


2
此外,如果您确实需要使用 Stack<Integer>,则最好选择等效的 Deque 实现,因为它提供了更完整和一致的 LIFO 栈操作集。 - user3248346
这是一种反模式,请参见http://www.ibm.com/developerworks/library/j-jtp02216/。 - fps
当我执行 StackInteger st = new StackInteger(3); 时,它按预期工作。但是,当我执行 Stack st = new StackInteger(3); 时,我可以轻松地将任何类型的元素推入堆栈中。为什么这是可能的呢?因为 st 是 StackInteger 的实例,所以它是 Stack<Integer> 的实例,即使指针只是一个 Stack。 - dannymo
2
这是因为你正在使用Stack类的原始形式。类型擦除会发生,T变成Object(上界)。相反,使用Stack<Integer> st = new StackInteger(3); - rgettman
@rgettman 是的,是我。抱歉。只是我认为这不是一个好答案。正如我在我的回答中所说,并且Brian Goetz在我提供链接的文章中解释的那样,从通用类型扩展到掩码类型信息是一种反模式。实际上,是一种相当糟糕的反模式。 - fps
显示剩余3条评论

3
我建议不要扩展泛型类,仅仅是为了克服泛型的冗长。这是一种反模式,被称为伪类型定义反模式
从文章中可以看到:
如果一个方法参数的类型是StringList,你不能将普通的List传递给它。这意味着你无法在方法参数中使用伪类型,除非每次使用该方法时都使用伪类型,而在实际应用中这意味着你无法在库API中使用伪类型。

...

伪类型定义反模式的另一个问题是它往往忽略使用接口来定义变量和方法参数类型的好处。虽然可以将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());
    } 
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接