OK, rozszerzyliśmy:
enum Answer {
YES,
NO
}
enum NuancedAnswer extends Answer {
MAYBE
}
Teraz co tu ma się stać?
void doSomething(Answer answer) {
Answer copy = answer;
}
doSomething(NuancedAnswer.MAYBE);
Jakiego typu jest copy
? Ono nie może już być zadeklarowanego typu Answer
, bo Answer
nie zawiera wartości MAYBE
. Polimorfizm się tu załamuje.
Animal animal = new Dog()
to jest co innego, ponieważ Dog
może zawierać dodatkową metodę np. bark
, ale nie przeszkadza to w patrzeniu na niego jako na Animal
. Nic, co ma Dog
, nie wyklucza go z tego, by mieścić się w przestrzeni możliwych wartości Animal
. Po prostu części charakterystyk obiektu Dog
nie będziemy widzieć, póki nie nałożymy specjalnych okularów rzutujących.
Dog
nie może jednak wykluczyć niczego z zakresu Animal
- "wyprzeć się" rodzica. Np. rozszerzając klasę Animal
nie możesz "skasować" żadnej metody rodzica. Nie ma w Javie czegoś takiego:
public class Dog extends Animal {
public void bark() {
// arff!
}
// a tu USUWAMY metodę, którą posiadał rodzic - w Javie to niemożliwe, i też popsułoby polimorfizm, jak i zaburzyło działanie psa
delete void takeShit();
}
MAYBE
to co całkiem innego. MAYBE
to nie jest ani YES
, ani NO
. Ani trochę, w żadnym stopniu. Nie ma z nimi wspólnego mianownika. To są wartości które - inaczej niż Dog
i Animal
- wykluczają się. Wynika to z faktu, że enum nie jest tak naprawdę (w sensie koncepcyjnym) klasą, tylko multitonem.
Gdybyśmy mieli go "zasymulować" (np. w języku, w którym nie ma takich enumów jak w Javie - jak C#), wyglądałoby to tak:
public class EmulatedEnum {
static final Value YES = new Yes();
static final Value NO = new No();
static class Value {
}
static final class Yes extends Value {
}
static final class No extends Value {
}
}
Inaczej mówiąc, YES
nie jest (znowu, w sensie koncepcyjnym) wartością typu EmulatedEnum
. EmulatedEnum
to tylko nazwa wiadra na wartości. Dlatego idee dziedziczenia nie do końca się tu moim zdaniem sprawdzają.