简体   繁体   中英

Java - non-generic class extends generic class

I would like to know how (if possible) can I create a class, that is a specific type of a generic class.

To be specific, I have an abstract class Stack<Type> with all necessary methods implemented and I would like to have a class StackInteger while an instance of StackInteger is also an instance of Stack<Integer> .

I see I can do something like this:

class StackInteger {
    Stack<Integer> s;

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

}

and then implement all Stack methods to contain s.method(); but I wonder if I can do it easily while extending from Stack .

Yes, in this case, inheritance is a better solution than composition as you have it, because a StackInteger is a Stack .

Just supply Integer as a type argument in the extends clause.

class StackInteger extends Stack<Integer>

However, if you don't supply any additional functionality beyond what Stack already has, then this class is useless and you might as well just use Stack<Integer> .

I would recommend against extending generic classes just to overcome generics verbosity. This is an antipattern, known as the pseudo-typedef antipattern .

From the article:

if a method parameter is of type StringList, you cannot pass an ordinary List to it. This means that you cannot use pseudotypes at all as method arguments without requiring that every use of that method use the pseudotype, which in practicality means that you cannot use pseudotypes at all in library APIs.

...

A further problem with the pseudo-typedef antipattern is that it tends to ignore the benefit of using interfaces to define the types of variables and method arguments. While it is possible to define StringList as an interface that extends List and a concrete type StringArrayList that extends ArrayList and implements StringList, most users of the pseudo-typedef antipattern generally do not go to this length, as the purpose of this technique is primarily to simplify and shorten type names. As a result, APIs will be less useful and more brittle because they use concrete types like ArrayList rather than abstract types like List.

So, why not sticking to Stack<Integer> ? I don't think it's so bad.

Yes you can do it.

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

As @Magnamag points out, this is often considered an antipattern. This is especially true if it is done just to avoid having to specify type parameters.

However, there can be legitimate ways to do this. For example, if the non-generic class is private , users of the class will be forced to program to the interface (or abstract class) anyway. In this example (admittedly rather contrived), there is a static method returning a non-generic anonymous class extending 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());
    } 
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM