override, overload, covariance

本文深入探讨Java中继承和多态的概念,包括override与overload的区别,covariance的应用及其实现细节。通过实例说明如何正确理解和使用这些特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

java语法如此多娇,引无数英雄竞折腰。

java语法细抠起来,极其诡异,充满了陷阱。
尤其是java语法里面的继承问题。
论坛里面关于java语法里面的继承问题的讨论,
可以说是长篇累牍,罄竹难书。
长江后浪推前浪,江上代有才人出。
前仆后继,香火不绝。

我只是希望下面的内容,
a. 一劳永逸地阐述清楚关于java继承的相关问题。
能够帮助一些年轻朋友节省宝贵的时间. 并且
b. 不必把java语法当作OO语法宝典来理解。java语法也在不断地变化。其变化理由也非常理可以度之。

1. override vs overload
首先来看诡异度最低的 override, overload.

(1) override
class Parent{
Object func(Number n){
...
}
}

class Child extends Parent{
Object func(Number n){
...
}
}

这叫做override.
这时候,真是痛感c#里面引入override关键字的必要性。
java里面也真应该引入这个关键字。免得含糊不清,误导使用者。

override 的含义,就是俗称的多态。
Child.f 和 Parent.f 可以看作是占用了虚函数指针表里面的同一个Entry。
所以,实际上相当于Child.f 覆盖了Parent.f。
所以,override有时候翻译为 覆盖。

Parent vtable
Entry 1 : Parent.f

Child vtable
Entry 1 : Child.f


override 是 运行时动态决定调用哪个method. 所以叫做多态性。

(2) overload

class Child{
Object func(Number n){
...
}

Object func(String s){
...
}
}

这叫做overload。两个func完全是不同的函数。只是恰好函数名相同。这两个func在虚函数指针表占用了两个不同的Entry.
vtable
Entry 1: void func(Number)
Entry 2: void func(String)

一定要记住:
overload 是 编译期就决定了调用哪个函数。
编译器根据参数类型的不同,产生了不同的调用函数地址(不同的Entry)的jvm指令。

--

overload为啥翻译为重载。这可难住我了。重载在中文里面到底什么意思。我确实不清楚。我强烈怀疑重载完全是一个生造词。类似于 阿尔卑斯白 这类词汇。只可意会,不可言传。

--

class Parent{
Object func(Number n){
...
}
}

class Child extends Parent{
Object func(String s){
...
}
}

这还是叫做overload.
parent vtable
Entry 1: void func(Number) of parent

child vtable
Entry 1: void func(Number) of parent
Entry 2: void func(String) of child

--

class Parent{
Object func(Number n){
...
}
}

class Child extends Parent{
Object func(Number n){
...
}

Object func(String s){
...
}
}

这里面同时有override, 和 overload
parent vtable
Entry 1: void func(Number) of parent

child vtable
Entry 1: void func(Number) of child
Entry 2: void func(String) of child

--
强烈建议避免overload,
强烈建议不要自找麻烦
强烈建议采用不同的method name,写成

Object funcNumber(Number n){
...
}

Object funcString(String s){
...
}

2.
下面看诡异度较高的covariance.

Covariance means that the type of arguments, return values, or exceptions of overriding methods can be subtypes of the original types.
Java
Exception covariance has been supported since the introduction of the language. Return type covariance is implemented in the Java programming language version J2SE 5.0. Parameter types have to be exactly the same (invariant) for method overriding, otherwise the method is overloaded with a parallel definition instead.

上面的能理解就理解。不能理解看下面的例子,然后再回头理解。

(1) override -- covariance of return value and/or exception
class Parent{
Object func(Number n) throws Exception{
...
}
}

class Child extends Parent{
String func(Number n) throws SQLException {
...
}
}

这叫做override。因为child func method的返回值和Exception都parent funct method的返回值和Exception的子类。
SQLException extends Exception (since first version)
String extends Object, (since J2se 5.0)

所以,这是overrider.
parent vtable
Entry 1: Object func(Number n) throws Exception of Parent

child vtable
Entry 1: String func(Number n) throws SQLException of Child

(2)overload - no support covariance of parameter type
class Parent{
Object func(Number n){
...
}
}

class Child extends Parent{
Object func(Integer i) {
...
}
}

这是overload。因为java不支持method参数类型的covariance。

parent vtable
Entry 1: Object func(Number n) of Parent

child vtable
Entry 1: Object func(Number n) of Parent
Entry 2: Object func(Integer i) of Child

在这种极其变态诡异的overload情况下,年轻朋友们最着迷的游戏就是,你猜,你猜,你猜猜猜。

Number n = new Integer(0);
Integer i = new Integer(1);
Number nNull = null;
Integer iNull = null;

Child child = new Child();

child.func(n);
child.func(i);
child.func(nNull);
child.func(iNull);

child.func(null);

你猜,这几次都是调用哪个方法啊? 其乐无穷。

这个不用我猜。是编译器需要猜。
编译器根据参数类型进行猜测。猜得到,它就猜。猜不到,它就让你编译不过。
上面的,编译器能猜得到。
编译器才不管你运行的时候,真正的类型是什么。
它只按字面意思理解。你定义的参数,对应的变量是什么类型。它就选什么类型。如果两个类型都匹配,那么就猜更具体的类型。
如果都猜不到,那么就让你编译不过,说你是 含糊不清,二义性,ambiguous
编译器冷笑着:小样儿,跟我玩,你还嫩。

这种游戏,我不玩。
喜欢玩的朋友可以自己验证,根据下面的Proof里面给出,javap 得出jvm指令的方法。


3. Proof

最直接的验证方法,就是查看编译后的JVM指令。

javap -verbose yourClassName > someFile.txt

-------------------------

4. member variable visibility scope in the inheritance
like private, protected, public, package,...

Just data.
Nothing to say.

I refuse to give any comment on the notorious "member variable visibility scope in the inheritance" issue.
<think>嗯,用户问的是overrideoverload,这两个概念在编程里经常提到,尤其是面向对象的部分。先得确认自己理解正确,然后组织语言用中文解释清楚。 首先,override,也就是重写。记得这是子类覆盖父类的方法,方法名、参数列表和返回类型都得相同。目的是改变方法的行为,符合子类的需求。比如动物类的speak()方法,子类狗可能重写为“汪汪”。这时候应该用@Override注解,确保正确覆盖,避免错误。 然后是overload,重载。同一个类里,方法名相同但参数列表不同(类型、个数、顺序)。返回类型可以不同,但仅返回类型不同不算重载。比如一个add(int, int)和add(double, double),根据传入参数类型决定调用哪个。这提高了方法的灵活性。 用户可能需要区分两者的区别,或者在实际编程中应用时遇到的疑惑。比如为什么覆盖要有相同的参数,而重载要不同。要举例说明,让概念更清晰。还要注意语法上的区别,比如@Override注解的使用,以及重载不关心返回类型等。 可能用户是刚开始学Java或者类似的OOP语言,需要明确这两个概念的区别和应用场景。要确保解释准确,避免混淆。另外,是否需要提到多态?override是实现运行时多态,而overload是编译时多态?这样能更深入一点,帮助理解。 检查是否有遗漏,比如构造方法的重载,或者是否可以在不同访问权限下重写方法。不过可能用户只需要基础区别,暂时不需要深入细节。保持回答简洁明了,结构清晰,分点说明,再给出对比表格,帮助记忆。</think>在面向对象编程中,`override`(重写)和`overload`(重载)是两个重要概念,它们的区别和用法如下: --- ### 一、Override(重写) 1. **定义** 子类重新定义父类中**同名、同参数、同返回类型**的方法,用于修改或扩展父类方法的行为。 2. **特点** - **继承关系**:必须存在于父类与子类之间 - **方法签名严格一致**:方法名、参数列表、返回类型完全匹配 - **访问权限不能更严格**:子类方法的访问修饰符范围 ≥ 父类方法(例如父类是`protected`,子类可以是`public`,但不能是`private`) - **使用`@Override`注解**(Java等语言中):显式声明重写,编译器会检查是否符合规则 3. **示例** ```java class Animal { public void speak() { System.out.println("动物发声"); } } class Dog extends Animal { @Override // 明确标记为重写 public void speak() { System.out.println("汪汪"); } } ``` --- ### 二、Overload(重载) 1. **定义** 在同一个类中定义多个**同名但参数列表不同**的方法,根据传入参数类型或数量决定调用哪个方法。 2. **特点** - **参数差异**:通过参数类型、数量或顺序区分 - **返回类型可不同**:仅返回类型不同不足以构成重载 - **不依赖继承**:所有重载方法在同一类中 3. **示例** ```java class Calculator { // 重载方法1:两个整数相加 public int add(int a, int b) { return a + b; } // 重载方法2:两个浮点数相加 public double add(double a, double b) { return a + b; } // 重载方法3:三个整数相加 public int add(int a, int b, int c) { return a + b + c; } } ``` --- ### 三、对比表格 | **特性** | Override(重写) | Overload(重载) | |------------------|----------------------------------|-----------------------------------| | 作用范围 | 跨类(父类与子类) | 同一类内 | | 方法签名 | 必须完全相同 | 必须不同(参数类型、数量或顺序) | | 返回类型 | 必须相同 | 可以不同 | | 多态性 | 运行时多态(动态绑定) | 编译时多态(静态绑定) | | 访问权限 | 子类方法不能更严格 | 无限制 | | 抛出异常 | 子类方法异常范围 ≤ 父类方法 | 无限制 | --- ### 四、关键区别总结 1. **目的不同** - `Override`:实现多态,子类自定义父类方法的行为 - `Overload`:提供同一功能的多种调用方式 2. **绑定时机** - `Override`在运行时根据对象类型决定调用(动态绑定) - `Overload`在编译时根据参数类型决定调用(静态绑定) 3. **应用场景** - 重写常见于继承体系中对父类方法的扩展 - 重载用于简化API设计(例如不同参数类型的`println()`方法) 通过理解这两个概念,可以更灵活地设计类的层次结构和接口。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值