简体   繁体   中英

Is it possible to override an inherited method with type parameter List<Animal> with List<Dog>?

I'm having trouble changing the type parameter of an inherited method.

abstract class Animal {
    abstract List<Animal> animalList();
}

public class Dog extends Animal {
    @Override
    public List<Dog> animalList() {
        ...
        ...
    }
}

public class Cat extends Animal {
    @Override
    public List<Cat> animalList() {
        ...
        ...
    }
}

All animal subclasses need to implement a method animalList . What's the best practice of doing this if i want the best possible code regarding readability and maintainability? Please note that this is extremely simplified i comparison to the actual project.

I don't know what the best solution is, but I would do the following:

import java.util.List;
abstract class Animal {
    abstract <T extends Animal> List<T> animalList();
}

...

import java.util.List;
public class Dog extends Animal {
    @Override
    List<Dog> animalList() {
        return null;
    }
}

...

import java.util.List;
public class Cat extends Animal{
    @Override
    List<Cat> animalList() {
        return null;
    }
}

It feels a little bit weird, but this might work.

abstract class Animal<T extends Animal<T>> {
    abstract List<T> animalList();
}

class Dog extends Animal<Dog> {
    @Override
    List<Dog> animalList() {
    }
}

class Cat extends Animal<Cat> {
    @Override
    List<Cat> animalList() {
    }
}

Though the working solutions are already provided, I'll put some useful references that might be helpful.

The reason why you cannot "return dogs or cats as animals" is that they are wrapped in a collection ( java.util.List in this case).

Fe you CAN write this way:

    abstract class Animal {
        abstract Animal[] animalArray();
    }

    public class Dog extends Animal {
        @Override
        public Dog[] animalArray() {
            //
        }
    }

    public class Cat extends Animal {
        @Override
        public Cat[] animalArray() {
            //
        }
    }

Why can't you do the same for List s?

Because in Java arrays are covariant, but generics ( Collection<E> ) are invariant.

There is a great explanation on this topic in the best Java book, I've read - "Effective Java" (now there is a 3rd edition ) by J. Bloch ( Item 28: Prefer Lists to Arrays ).

The good working solution is provided by @Zymus, using the trick so-called " recursive type bound ", which is also described in the book ( Item 30: Favor Generic Methods ).

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