在任何面向对象的编程语言中, "覆盖"是一项功能, 它允许子类或子类提供其超类或父类之一已经提供的方法的特定实现。当子类中的方法与其父类中的方法具有相同的名称, 参数或签名以及相同的返回类型(或子类型)时, 则将子类中的方法称为覆写超类中的方法。
方法重写是Java实现的方法之一运行时多态。执行的方法的版本将由用于调用该方法的对象确定。如果使用父类的对象来调用该方法, 则将执行父类中的版本, 但是如果使用子类的对象来调用该方法, 则将执行子类中的版本。换一种说法, 它是被引用对象的类型(不是引用变量的类型), 它确定将执行哪个版本的重写方法。
// A Simple Java program to demonstrate
// method overriding in java
// Base Class
class Parent {
void show()
{
System.out.println( "Parent's show()" );
}
}
// Inherited class
class Child extends Parent {
// This method overrides show() of Parent
@Override
void show()
{
System.out.println( "Child's show()" );
}
}
// Driver class
class Main {
public static void main(String[] args)
{
// If a Parent type reference refers
// to a Parent object, then Parent's
// show is called
Parent obj1 = new Parent();
obj1.show();
// If a Parent type reference refers
// to a Child object Child's show()
// is called. This is called RUN TIME
// POLYMORPHISM.
Parent obj2 = new Child();
obj2.show();
}
}
输出如下:
Parent's show()
Child's show()
方法覆盖的规则:
覆盖和访问修饰符:
的
访问修饰符
因为覆盖方法比覆盖方法可以允许更多但不能少于访问。例如, 超类中的受保护实例方法可以在子类中公开, 但不能私有。这样做会产生编译时错误。
// A Simple Java program to demonstrate
// Overriding and Access-Modifiers
class Parent {
// private methods are not overridden
private void m1()
{
System.out.println( "From parent m1()" );
}
protected void m2()
{
System.out.println( "From parent m2()" );
}
}
class Child extends Parent {
// new m1() method
// unique to Child class
private void m1()
{
System.out.println( "From child m1()" );
}
// overriding method
// with more accessibility
@Override
public void m2()
{
System.out.println( "From child m2()" );
}
}
// Driver class
class Main {
public static void main(String[] args)
{
Parent obj1 = new Parent();
obj1.m2();
Parent obj2 = new Child();
obj2.m2();
}
}
输出如下:
From parent m2()
From child m2()
最终方法不能被覆盖:
如果我们不希望某个方法被覆盖, 则将其声明为
MongoDB
。请参阅
在继承中使用final
.
// A Java program to demonstrate that
// final methods cannot be overridden
class Parent {
// Can't be overridden
final void show() {}
}
class Child extends Parent {
// This would produce error
void show() {}
}
输出如下:
13: error: show() in Child cannot override show() in Parent
void show() { }
^
overridden method is final
静态方法不能被覆盖(方法覆盖vs方法隐藏):
当你定义一个与基类中的静态方法具有相同签名的静态方法时, 它称为
方法隐藏
.
下表总结了在定义具有与超类中的方法相同的签名的方法时发生的情况。
超类实例方法 | 超类静态方法 | |
---|---|---|
子类实例方法 | 覆写 | 产生编译时错误 |
子类静态方法 | 产生编译时错误 | 皮 |
// Java program to show that
// if the static method is redefined by
// a derived class, then it is not
// overriding, it is hiding
class Parent {
// Static method in base class
// which will be hidden in subclass
static void m1()
{
System.out.println( "From parent "
+ "static m1()" );
}
// Non-static method which will
// be overridden in derived class
void m2()
{
System.out.println( "From parent "
+ "non-static(instance) m2()" );
}
}
class Child extends Parent {
// This method hides m1() in Parent
static void m1()
{
System.out.println( "From child static m1()" );
}
// This method overrides m2() in Parent
@Override
public void m2()
{
System.out.println( "From child "
+ "non-static(instance) m2()" );
}
}
// Driver class
class Main {
public static void main(String[] args)
{
Parent obj1 = new Child();
// As per overriding rules this
// should call to class Child static
// overridden method. Since static
// method can not be overridden, it
// calls Parent's m1()
obj1.m1();
// Here overriding works
// and Child's m2() is called
obj1.m2();
}
}
输出如下:
From parent static m1()
From child non-static(instance) m2()
私有方法不能被覆盖:私有方法不能被覆盖, 因为它们在编译期间是绑定的。因此, 我们甚至无法覆盖子类中的私有方法。(有关详细信息, 请参见此内容)。
覆盖方法必须具有相同的返回类型(或子类型):从Java 5.0开始, 子类中的覆盖方法可以具有不同的返回类型, 但是子对象的返回类型应该是父级返回类型的子类型。这种现象称为协变返回类型。
从子类调用重写的方法:
我们可以使用以下方法覆盖父类方法
超级关键字
.
// A Java program to demonstrate that overridden
// method can be called from sub-class
// Base Class
class Parent {
void show()
{
System.out.println( "Parent's show()" );
}
}
// Inherited class
class Child extends Parent {
// This method overrides show() of Parent
@Override
void show()
{
super .show();
System.out.println( "Child's show()" );
}
}
// Driver class
class Main {
public static void main(String[] args)
{
Parent obj = new Child();
obj.show();
}
}
输出如下:
Parent's show()
Child's show()
覆盖和构造函数:我们不能覆盖构造函数, 因为父类和子类永远不能具有相同名称的构造函数(构造函数名称必须始终与类名称相同)。
覆盖和异常处理:
当重写与异常处理相关的方法时, 以下两个规则要注意。
规则1 :
如果超类的重写方法没有引发异常, 则子类的重写方法只能引发
未经检查的异常
, 抛出检查异常将导致编译时错误。
/* Java program to demonstrate overriding when
superclass method does not declare an exception
*/
class Parent {
void m1()
{
System.out.println( "From parent m1()" );
}
void m2()
{
System.out.println( "From parent m2()" );
}
}
class Child extends Parent {
@Override
// no issue while throwing unchecked exception
void m1() throws ArithmeticException
{
System.out.println( "From child m1()" );
}
@Override
// compile-time error
// issue while throwin checked exception
void m2() throws Exception
{
System.out.println( "From child m2" );
}
}
输出如下:
error: m2() in Child cannot override m2() in Parent
void m2() throws Exception{ System.out.println("From child m2");}
^
overridden method does not throw Exception
规则2:
如果超类的重写方法确实引发异常, 则子类的重写方法只能引发相同的子类异常。在中抛出父异常
异常层次
会导致编译时错误。如果子类重写方法没有引发任何异常, 也没有问题。
// Java program to demonstrate overriding when
// superclass method does declare an exception
class Parent {
void m1() throws RuntimeException
{
System.out.println( "From parent m1()" );
}
}
class Child1 extends Parent {
@Override
// no issue while throwing same exception
void m1() throws RuntimeException
{
System.out.println( "From child1 m1()" );
}
}
class Child2 extends Parent {
@Override
// no issue while throwing subclass exception
void m1() throws ArithmeticException
{
System.out.println( "From child2 m1()" );
}
}
class Child3 extends Parent {
@Override
// no issue while not throwing any exception
void m1()
{
System.out.println( "From child3 m1()" );
}
}
class Child4 extends Parent {
@Override
// compile-time error
// issue while throwing parent exception
void m1() throws Exception
{
System.out.println( "From child4 m1()" );
}
}
输出如下:
error: m1() in Child4 cannot override m1() in Parent
void m1() throws Exception
^
overridden method does not throw Exception
覆盖和抽象方法:接口或抽象类中的抽象方法应在派生的具体类中被覆盖, 否则将引发编译时错误。
覆盖和同步/ strictfp方法:同步/ strictfp修饰符与方法一起使用对覆盖规则没有影响, 即, 同步/ strictfp方法有可能覆盖非同步/ strictfp方法, 反之亦然。
注意 :
在C ++中, 我们需要virtual关键字来实现覆盖或运行时多态。在Java中, 默认情况下方法是虚拟的。
我们可以进行多级方法覆盖。
// A Java program to demonstrate
// multi-level overriding
// Base Class
class Parent {
void show()
{
System.out.println( "Parent's show()" );
}
}
// Inherited class
class Child extends Parent {
// This method overrides show() of Parent
void show() { System.out.println( "Child's show()" ); }
}
// Inherited class
class GrandChild extends Child {
// This method overrides show() of Parent
void show()
{
System.out.println( "GrandChild's show()" );
}
}
// Driver class
class Main {
public static void main(String[] args)
{
Parent obj1 = new GrandChild();
obj1.show();
}
}
输出如下:
GrandChild's show()
覆盖vs
超载
:
重载大约是同一方法, 具有不同的签名。重写是关于相同的方法, 相同的签名, 但通过继承连接的不同类。
重载是编译器时多态的一个示例, 重载是运行时多态的一个示例。
为什么要覆盖方法?
如前所述, 重写的方法允许Java支持运行时多态。多态性对于面向对象的编程至关重要, 原因之一是:多态性允许通用类指定对其所有派生类通用的方法, 同时允许子类定义某些或所有这些方法的特定实现。重写方法是Java实现多态性的"一个接口, 多个方法"方面的另一种方式。
动态方法分派是面向对象设计带来的最强大的机制之一, 它关系到代码的重用性和健壮性。存在的代码库能够在维持干净的抽象接口的同时不重新编译的情况下调用新类实例上的方法的功能是一种强大的工具。
重写的方法使我们可以调用任何派生类的方法, 甚至不知道派生类对象的类型。
何时应用方法覆盖?(带有示例)
覆盖和遗产:成功应用多态性的部分关键是要理解, 超类和子类形成了一个层次结构, 该层次结构从较小的专业化过渡到较大的专业化。正确使用超类可提供子类可以直接使用的所有元素。它还定义了派生类必须自己实现的那些方法。这使子类可以灵活地定义其方法, 但仍然可以强制使用一致的接口。因此, 通过将继承与重写的方法组合在一起, 超类可以定义将由其所有子类使用的方法的一般形式。
让我们看一个使用方法重写的更实际的示例。考虑一个组织的雇员管理软件, 让代码具有一个简单的基类Employee, 该类具有诸如raiseSalary(), transfer(), promoise()等方法。不同类型的雇员, 如Manager, Engineer 、. .etc可能具有基类Employee中存在的方法的实现。在我们完整的软件中, 我们只需要在各处传递一个员工列表并调用适当的方法, 甚至不知道员工的类型。例如, 我们可以通过遍历员工列表轻松地提高所有员工的薪水。每种类型的员工都可能在其类中拥有自己的逻辑, 我们不必担心, 因为如果针对特定员工类型提供了raiseSalary(), 则仅会调用该方法。
// A Simple Java program to demonstrate application
// of overriding in Java
// Base Class
class Employee {
public static int base = 10000 ;
int salary()
{
return base;
}
}
// Inherited class
class Manager extends Employee {
// This method overrides salary() of Parent
int salary()
{
return base + 20000 ;
}
}
// Inherited class
class Clerk extends Employee {
// This method overrides salary() of Parent
int salary()
{
return base + 10000 ;
}
}
// Driver class
class Main {
// This method can be used to print the salary of
// any type of employee using base class reference
static void printSalary(Employee e)
{
System.out.println(e.salary());
}
public static void main(String[] args)
{
Employee obj1 = new Manager();
// We could also get type of employee using
// one more overridden method.loke getType()
System.out.print( "Manager's salary : " );
printSalary(obj1);
Employee obj2 = new Clerk();
System.out.print( "Clerk's salary : " );
printSalary(obj2);
}
}
输出如下:
Manager's salary : 30000
Clerk's salary : 20000
相关文章:
- Java中的动态方法调度或运行时多态
- 覆盖Object类的equals()方法
- 覆盖Object类的toString()方法
- Java重载
- Java程序的输出|设置18(覆盖)
如果发现任何不正确的地方, 或者想分享有关上述主题的更多信息, 请写评论。