Is co-variance safe here?

狂风中的少年 提交于 2019-12-24 02:20:53

问题


class Food{}

class Meat extends Food{}

class Animal{
    void feed(Food f){}
}

class Lion extends Animal{
    void feed(Meat m){}
}


void foo(Animal a){
   Food f = new Food();
   a.feed(f);
}

What will happen if we send to foo(new Lion()) ? I know that it will get error but I need the explanation please


回答1:


Your Lion can eat Meat, but it can also eat any kind of food (like Spinach).

If your Lion could not eat any kind of Food, then it could not be considered an implementation of Animal.

This is critical to understand when deciding to use sub-classing and class inheritance as a means of constructing programs: you don't make your subclasses more specific than your interface or super classes.

For sub-classing to work in ways that solve problems (instead of create problems), you need to abide by this guideline: All subclasses must be functionally equivalent to the super-class (Liskov Substitution Principle) This means that three classes which provide database access to three different databases is a good candidate for being subclasses from a common class (or perhaps sharing a common interface), because the "functionality" is "offer database access".

Where your Lion example falls short is that according to your definition of Animal a real world, Lions are not an Animals because real world Lions don't eat any kind of Food. Real world Lions are more specific in their food eating ability than the general definition of an unknown animal. And it is this functional difference which makes modeling real world Lions as subclasses of this specific definition of Animal a bad fit.

You could easily fix this by having the Animal "eat food" method throw an IncompatibleFoodException, which changes the definition of an Animal from something that "eats food" to something that "eats or rejects food".




回答2:


This violates the Liskov substitution principle, so it should likely be avoided (as Edwin says, it's really not an Animal if it can't eat Food).

Perhaps against first thought, this will actually not result in an error, but rather will call Animal::feed instead of Lion::feed as expected.

Just reread the title, and to answer the question specifically: No, covariance is not safe here (in terms of behaviour. In terms of syntax it is.).

Quick copy and paste of the question into an example:

class Food{}

class Meat extends Food{}

class Animal{
    void feed(Food f){
        System.out.println("om nom nom");
    }
}

class Lion extends Animal{
    void feed(Meat m)
    {
        System.out.println("OM NOM NOM");
    }
}

public class test
{

    public static void main(String[] args)
    {
        foo(new Lion());
    }

    static void foo(Animal a){
       Food f = new Food();
       a.feed(f);
    }

}

Outputs "om nom nom"



来源:https://stackoverflow.com/questions/9950501/is-co-variance-safe-here

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!