Substituting types
When you override a method, you are replacing something of one type (in the old method) with something that might have a new type (in the new method). Similarly, when you pass an argument to a function, you are replacing something that has one type (a parameter with a declared type) with something that has another type (the actual argument). When can you replace something that has one type with something that has a subtype or a supertype?
When substituting types, it helps to think in terms of consumers and producers. A consumer absorbs a type and a producer generates a type.
You can replace a consumer’s type with a supertype and a producer’s type with a subtype.
Let’s look at examples of simple type assignment and assignment with generic types.
Simple type assignment
When assigning objects to objects, when can you replace a type with a different type? The answer depends on whether the object is a consumer or a producer. Consider the following type hierarchy:

Consider the following simple assignment where Cat c is a consumer and Cat() is a producer:
Cat c = Cat();
In a consuming position, it’s safe to replace something that consumes a specific type (Cat) with something that consumes anything (Animal), so replacing Cat c with Animal c is allowed, because Animal is a supertype of Cat.
Animal c = Cat();
But replacing Cat c with MaineCoon c breaks type safety, because the superclass may provide a type of Cat with different behaviors, such as Lion:
MaineCoon c = Cat();
In a producing position, it’s safe to replace something that produces a type (Cat) with a more specific type (MaineCoon). So, the following is allowed:
Cat c = MaineCoon();
Generic type assignment
Are the rules the same for generic types? Yes. Consider the hierarchy of lists of animals—a List of Cat is a subtype of a List of Animal, and a supertype of a List of MaineCoon:

In the following example, you can assign a MaineCoon list to myCats because List<MaineCoon> is a subtype of List<Cat>:
List<Cat> myCats = List<MaineCoon>();
What about going in the other direction? Can you assign an Animal list to a List<Cat>?
List<Cat> myCats = List<Animal>();
This assignment passes static analysis, but it creates an implicit cast. It is equivalent to:
List<Cat> myCats = List<Animal>() as List<Cat>;
The code may fail at runtime. You can disallow implicit casts by specifying implicit-casts: false in the analysis options file.
When overriding a method, the producer and consumer rules still apply. For example:

For a consumer (such as the chase(Animal) method), you can replace the parameter type with a supertype. For a producer (such as the parent getter method), you can replace the return type with a subtype.
Semantic portal