Java支持引用类型返回值协变:子类重写方法可将返回类型替换为父类返回类型的子类,如Person→Student,但基本类型和void不支持;方法签名其余部分必须完全一致,配合多态可直接获得精确类型。

可以直接在子类重写方法时把返回类型换成更具体的子类,调用时无需强制转型,编译器自动识别并赋予精确类型。
明确父类方法返回引用类型
协变只对引用类型生效,基本类型(如int、boolean)和void不支持。父类方法必须返回类、接口或泛型擦除后的引用类型,例如Person、Shape、List<String>等。
- ✅ 正确:父类声明
Person getOwner() - ❌ 错误:父类声明
int getId()—— 子类不能改返回long或Integer来“协变”
子类返回类型必须是父类返回类型的子类
不是名字相似就行,必须存在真实的继承或实现关系。Java 编译器会严格检查类型层级,不满足则报错 return type is incompatible with xxx。
- ✅
Student extends Person→ 子类可写@Override Student getOwner() - ✅
Circle extends Shape→ 工厂子类可写@Override Circle create() - ❌
String和Integer都是Object子类,但互不为子类型 → 不能从Object协变为Integer再协变为String
保持方法签名其余部分完全一致
名称、参数列表、异常声明(包括throws子句)必须一字不差。哪怕多一个空格或改个异常顺序,都会变成重载而非重写,协变失效。
- 父类:
Document getDocument(String id) throws IOException - 子类必须也写:
@Override Document getDocument(String id) throws IOException,再把返回类型缩窄为SchoolDocument - 若子类写成
throws Exception或漏掉throws,编译失败
配合多态使用,享受类型精准红利
把子类实例赋给父类引用后调用,仍能获得协变后的具体类型——前提是变量声明类型足够宽,而实际对象是子类。
ShapeFactory factory = new CircleFactory();-
Circle circle = factory.create();—— 编译通过,直接拿到Circle,可立刻调用circle.draw() - 不需要
(Circle) factory.create(),也没有运行时转型开销或ClassCastException风险

















