In Java, List<Cat> may or may not be the subclass of List<Animal>, but it is up to the List implementor. This way Scala/Kotlin/another JVM language is free to define their own variance model independent of the host language. C# did limit their language ecosystem with it quite a bit. (Afaik Scala for CLR stopped in part due to this).
https://docs.microsoft.com/en-us/dotnet/csharp/language-refe... https://docs.microsoft.com/en-us/dotnet/csharp/language-refe...
You probably know this, but I'm replying in the hope it clarifies things to other readers. The way it's expressed in Java is List<? extends Animal>
Also, unfortunately arrays are covariant so Cat[] is a subclass of Animal[] (both in Java and C# actually), where your mentioned example indeed introduces a “poisoned” value, waiting for a classcastexception.