用子类与父类声明对象的差异:Cat cat1=new Cat() vs Animal cat2=new Cat()
针对你提到的Cat cat1 = new Cat();和Animal cat2 = new Cat();两种声明方式,除了你已经知道的集合、方法参数限制外,还有这些关键差异:
可调用成员的范围不同
用Cat声明的cat1,能直接调用Cat类独有的方法或属性,比如假设Cat有Meow()方法,直接写cat1.Meow()就行,不用额外转换。而Animal声明的cat2,默认只能调用Animal类里定义的成员,要调用Cat独有的内容,必须先把它强制转换成Cat类型,比如((Cat)cat2).Meow(),转换前最好用is或as做类型检查,避免报错。隐藏成员的调用逻辑不同
如果Cat用new关键字隐藏了父类Animal的某个方法(比如new void MakeSound()),那么cat1.MakeSound()会执行Cat的版本,而cat2.MakeSound()会执行Animal的版本——这是因为编译时会根据变量的声明类型来决定调用哪个隐藏成员,而重写(override)的方法不受这个影响,两者都会执行Cat的重写实现。类型转换的规则不同
cat1转成Animal是隐式转换,直接写Animal a = cat1;就可以。但cat2转成Cat必须显式转换,而且如果cat2实际指向的不是Cat实例(比如不小心赋值成Dog),会直接抛出异常。安全的做法是用is模式匹配:if (cat2 is Cat c) { c.Meow(); }或者用
as关键字,转换失败会返回null:Cat c = cat2 as Cat;编译时类型检查的差异
编译器会严格按照变量的声明类型做检查,比如有个只接受Cat参数的方法Feed(Cat cat),传cat1能直接通过编译,但传cat2会报错,必须先转换成Cat类型才能传递——这就是你说的方法参数限制的底层原因。typeof与GetType的返回结果不同
虽然两者的GetType()都会返回Cat(因为实际运行时实例是Cat),但typeof(cat1)返回的是Cat类型,typeof(cat2)返回的是Animal类型——typeof取的是变量声明时的静态类型,GetType取的是实例的实际运行时类型。
内容的提问来源于stack exchange,提问作者MrV

