在任何面向对象的编程语言中,重写是一种功能,它允许子类或子类提供一个方法的特定实现,该方法已经由它的一个超类或父类提供。如果子类中的方法与其超类中的方法具有相同的名称、相同的参数或签名以及相同的返回类型(或子类型),则子类中的方法称为 推翻 超类中的方法。
方法重写是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()
- 无法覆盖最终方法: 如果我们不想重写一个方法,我们将其声明为 最终的 .请看 使用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
- 无法重写静态方法(方法重写与方法隐藏): 当您在基类中定义一个与静态方法具有相同签名的静态方法时,它被称为 方法隐藏 .
下表总结了当您定义一个与超类中的方法具有相同签名的方法时会发生什么。
超类实例方法 超类静态法 子类实例方法 覆盖 生成编译时错误 子类静态法 生成编译时错误 兽皮 // 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
- 规则#1: 如果超类重写方法没有抛出异常,子类重写方法只能抛出 未检查的异常 ,抛出选中的异常将导致编译时错误。
- 重写和抽象方法: 接口或抽象类中的抽象方法应在派生的具体类中重写,否则将引发编译时错误。
- 重写和同步/strictfp方法: synchronized/strictfp修饰符with method的存在对重写规则没有影响,即synchronized/strictfp方法可能会重写非synchronized/strictfp方法,反之亦然。
注:
- 在C++中,我们需要 虚拟关键字 达到压倒一切或 运行时多态性 .在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()
- 凌驾于 超载 :
- 重载是指具有不同签名的相同方法。重写是关于相同的方法、相同的签名,但通过继承连接不同的类。
- 重载是编译器时间多态性的一个例子,而重写是编译器时间多态性的一个例子 运行时多态性 .
为什么要重写方法?
如前所述,重写方法允许Java支持 运行时多态性 .多态性对面向对象编程至关重要,原因之一是:它允许一个通用类指定其所有派生的通用方法,同时允许子类定义某些或所有这些方法的特定实现。重写方法是Java实现多态性的“一个接口,多个方法”方面的另一种方式。
动态方法调度 是面向对象设计给代码重用和健壮性带来的最强大的机制之一。现有的代码库能够在不重新编译的情况下对新类的实例调用方法,同时维护干净的抽象接口,这是一个非常强大的工具。
重写方法允许我们调用任何派生类的方法,甚至不知道派生类对象的类型。
何时应用方法重写?(举个例子)
覆盖和 遗产 :成功应用多态性的部分关键是理解超类和子类形成了一个层次结构,从较小的专业化到更大的专业化。正确使用时,超类提供子类可以直接使用的所有元素。它还定义了派生类必须自己实现的方法。这允许子类灵活地定义其方法,但仍然强制执行一致的接口。 因此,通过将继承与重写方法相结合,超类可以定义其所有子类将使用的方法的一般形式。
让我们看一个使用方法重写的更实际的例子。考虑一个组织的雇员管理软件,让代码有一个简单的基类雇员,这个类有方法,比如RaSeSalayar()、Trand()、Apple(…)。不同类型的员工,比如经理、工程师。。etc可能会在基类Employee中提供方法的实现。在我们完整的软件中,我们只需要在不知道员工类型的情况下到处传递员工列表,并调用适当的方法。例如,我们可以通过遍历员工列表轻松提高所有员工的工资。每种类型的employee都可能在其类中有其逻辑,我们不必担心,因为如果针对特定的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
相关文章:
本文由 闪烁的泰吉和高拉夫·米格拉尼 .如果你喜欢GeekSforgek,并想贡献自己的力量,你也可以使用 写极客。组织 或者把你的文章寄去评论-team@geeksforgeeks.org.看到你的文章出现在Geeksforgeks主页上,并帮助其他极客。
如果您发现任何不正确的地方,或者您想分享有关上述主题的更多信息,请写下评论。