Java 重写与重载
本文最后更新于:2024年3月18日 凌晨
Java 重写与重载
方法的重载
- 方法重载就是同一类中存在多个方法名相同但参数不同的方法,参数的差异包括形式参数的个数,类型等,在例6-2中,类A定义了3个
test()
方法,它们的参数类型不同。 - 方法调用的匹配处理原则是:首先按"精确匹配"原则去查找匹配方法,如果找不到,则按"自动类型转换匹配"原则去查找能匹配的方法。
- 所谓"精确匹配"就是实参和形参类型完全一致,所谓"自动类型转换匹配"是指虽然实参和形参类型不同,但能将实参的数据按自动转换原则赋值给形参。
[例6-2]:方法调用的匹配测试。
1 |
|
- 根据方法调用的匹配原则,不难发现运行程序时将得到如下结果:
1 |
|
- 如果将以上
test(int x)
方法注释掉,结果为:
1 |
|
- 说明:因为实参5默认为int型数据,因此,有
test(int x)
方法存在时将按"精确匹配"原则处理,但如果无该方法存在,将按"转换匹配"原则优先考虑匹配test(long x)
方法。
[例6-3]:从复数方法理解多态性。
1 |
|
- 以上有3个方法实现复数的相加运算,其中有两个为实例方法,一个时静态方法,它们的参数形式是不同的,调用方法时将根据参数形态决定匹配哪个方法,注意静态方法和实例方法的调用差异,实例方法一定要有一个对象作为前缀:静态方法则不依赖对象。
- 以上3个方法进行复数相加时将产生一个新的复数作为方法的返回值,并不改变参与运算的两个复数对象的值,如果要改变调用方法的复数的值,则方法设计为如下形式:
1 |
|
方法的覆盖与隐藏
- 子类将继承父类的非私有方法,在子类也可以对父类定义的方法重新定义,这时将产生方法覆盖,也就是通过子类对象访问的方法是子类自己重新定义的方法,需要注意的是,子类在重新定义父类已有的方法时,应保持与父类完全相同的方法头部声明,即应与父类具有完全相同的方法名,参数列表,返回类型一般也要相同。
- 例如,在以下类B中定义的方法,只有
test(int x)
存在对例6-2中类A的方法覆盖:
1 |
|
- 父类的实例方法被子类的同名实例方法覆盖,父类的静态方法被子类的同名静态方法隐藏,父类的实例变量和类变量可以被子类的实例变量和类变量隐藏
- 通过父类引用可以暴露隐藏的变量和方法。
- 方法覆盖不能改变方法的静态与非静态属性,子类中不能将父类的实例方法定义为静态方法,也不能将父类的静态方法定义为实例方法。
- 不允许子类中方法的访问修饰符比父类有更多的限制,例如,不能将父类定义中用public修饰的方法在子类中重定义为private方法,但可以将父类的private方法重定义为public方法,通常应将子类中方法访问修饰与父类中的保持一致。
父类引用指向子类对象
- 如果子类中定义了与父类同名的属性,在子类中将隐藏来自父类的同名属性变量,这里也是"最近优先原则",自己类中有就不会去找父类的。
1 |
|
说明
- 每个ExtendShow类型的对象将拥有4个属性,其中有两个y属性:一个是子类定义的,一个是父类定义的,在子类中,查找成员属性时将优先匹配本类定义的属性,在子类中没有找到的属性才会到父类中去查找,也就是在子类中将隐藏父类初始化过的同名属性。
- 将子类对象赋值给父类的引用变量后,通过该引用变量去访问对象的成员时,访问的行为方法是子类对象的覆盖方法,而属性值却是父类的,原因在于对象执行方法时由实际对象的类型决定,而不是引用变量类型,访问属性时则由引用变量的类型决定,因为编译程序在分析程序时是基于类型来访问哪个属性变量。
- 静态成员是依赖类的,静态成员的访问基于引用变量和的类型,而不是对象类型,尽管父类引用变量可指向子类对象,但通过父类引用变量访问的静态方法和静态方法均是父类的。
- 细心体会隐藏和覆盖在用词上的差异,当子类与父类有相同成员时,通过子类引用访问的成员均是子类定义的,问题在于通过父类引用操作一个子类对象时就有差异了,隐藏的父类成员再现,而覆盖的成员被子类"替代",只有实例方法会是子类定义的,对象属性,静态属性,静态方法均是指父类定义的。
对象引用转换
对象引用赋值匹配
- 允许将子类对象赋值给父类引用,这种赋值也经常发生在方法调用的参数传递时,如果一个方法的形式参数定义的是父类引用类型,那么调用这个方法时,可以使用子类对象作为实际参数,当然,任何方法调用将优先考虑参数精确匹配,然后才考虑转换匹配。
[例6-10]:方法的引用类型参数匹配处理。
1 |
|
- 如果将以上的
test(String str)
方法定义注释掉,则运行结果为:
1 |
|
- 注意:由于Object类是继承层次中最高层的类,所以任何对象均可匹配Object类型的形参,Java类库中有不少方法的参数未Object类型,方法定义考虑体现了通用性,在JDK1.5之后甚至基本类型的数据也可以赋值给Object类型或相应包装类型的引用变量,它是通过将基本类型自动包装成相应类型的对象来实现转换赋值的,例如,int类型数据包装成Integer类型的对象。
对象引用强制转换
- 以下代码,尽管先前将一个字符串对象赋给Object类型的引用变量m,但将m直接赋给字符串类型的变量y不允许,因为编译程序只知道m的类型为Object,将父类对象赋给子类引用变量是不允许的。
- 在将父类引用赋值给子类变量时要进行强制转换,这种强制转换在编译时总是认可的,但运行时的情况取决于对象的值,如果父类对象引用指向的就是该子类的一个对象,则转换是成功的,如果指向的是其他子类对象或父类自己的对象,则转换会抛出异常。
1 |
|
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!