协变返回类型允许子类重写父类方法时将引用类型的返回值缩小为更具体的子类型,从jdk 5起由编译器自动校验;基本类型、void及泛型非继承关系不支持协变,且须遵守访问权限、@override和异常限制等重写规则。

Java 中子类重写父类方法时,可以安全地将返回值类型“缩小”为更具体的子类型,这叫协变返回(Covariant Return Type),从 JDK 5 开始原生支持。它不是靠配置实现的,而是编译器自动识别并校验的语法特性,关键在于满足继承关系和类型兼容性。
必须是引用类型才能协变
只有父类方法返回引用类型(如 Animal、List
- ✅ 父类返回
Animal,子类返回Dog extends Animal - ✅ 父类返回
List<string></string>,子类返回ArrayList<string></string>(因为ArrayList是List的实现类) - ❌ 父类返回
int、boolean或void,子类不能改成Integer或Boolean—— 基本类型和 void 不支持协变
泛型返回要特别谨慎
泛型本身不协变,List<dog></dog> 并不是 List<animal></animal> 的子类,所以不能直接替换。
- ❌ 父类返回
List<animal></animal>,子类返回List<dog></dog>→ 编译失败 - ✅ 父类返回
List<animal></animal>,子类返回ArrayList<dog></dog>→ 合法(前提是签名中父类返回的是接口List,且ArrayList<dog></dog>实现了它) - ? 更稳妥的做法:避免在返回值中嵌套泛型类型做协变;优先用具体类型(如返回
Dog而非List<dog></dog>),或统一用通配符(如List extends Animal>)提升灵活性
访问权限和 @Override 不可省略
缩小返回类型只是条件之一,其他重写规则同样必须遵守,否则编译不通过。
- 子类方法访问修饰符不能比父类更严格:父类是
protected,子类可用protected或public;父类是public,子类也必须是public - 务必加上
@Override注解:它能帮你在编译期发现拼写错误、参数不一致、或返回类型不构成合法协变等问题 - 不能抛出比父类更宽泛的检查异常(例如父类声明
IOException,子类只能抛FileNotFoundException这类子类异常,或不抛)
典型错误与验证方式
常见误操作会导致编译失败,而不是运行时异常,所以及时验证很重要。
- ❌ 把父类返回
String改成子类返回Object(这是“扩大”,违反协变方向) - ❌ 忘记加
@Override,结果变成重载(overload)而非重写(override),多态调用时不会执行子类逻辑 - ✅ 验证方法:用父类引用指向子类对象,调用该方法后尝试向下转型或使用子类特有方法,确认实际返回的是子类型实例
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











