`

010 方法重载与重写

 
阅读更多

重载与重写

 

 

在Java编程语言中,有两个概念非常相近,很容易混淆。它们就是重写与重载。

 

这里先在类继承的话题上,继续来说说重写,也叫覆盖。

 

没有继承,就不可能有重写。这是子类对父类的一种特殊操作。这里先提一下,重载主要发生在同一个类中的操作,也可以发生在父类与子类之间。

 

当一个子类继承了一个父类时,它也同时继承了父类的属性和方法。我们可以直接使用父类的属性和方法,或者,如果父类的方法不能满足子类的需求,则可以在子类中对父类的方法进行“改造”,这个“改造”的过程在Java中称为“覆盖(override)”。


比如,假设我们在Person 类中定义了一个方法用于显示姓名,如下:
public String showName(){
 return name;
}


那么,在子类Teacher中,就会继承这个父类的showName()方法,此时,即使Teacher类中没有定义showName()方法,也可以在它的实例(instance)中使用这个方法。

 

比如,我们实例化了一个Teacher的实例,这是就可以直接调用从Teacher的父类Person中继承的这个showName()方法。如下:
Teacher teacher = new Teacher();
teacher.showName();


但是,我们在Teacher类中,我们或许需要在姓名后面加上“老师”,比如,“张三”就显示为“张三老师”,那么,这个时候就需要在子类“Teacher”中对从父类中继承的showName()方法进行“改造”,也就是在子类Teacher中覆盖父类Person的方法showName():
public class Teacher extends Person{
 … …
 public String showName(){
  return name+”老师”;
 }
}


在子类Teacher中,覆盖了父类的showName方法,在覆盖的过程中,需要提供和父类中的被覆盖方法相同的方法名称、输入参数(此处为空)以及返回类型。


另外,在子类对父类的方法进行覆盖的过程中,不能使用比父类中的被覆盖方法更严格的访问权限。

 

比如,父类Person中的方法showName()的修饰符是public,那么,在子类Teacher中的覆盖方法showName()就不能用protected、默认(Default)或者private等来限制。


从前面的讨论可以看出,类的继承主要可以从两方面来看:


对父类的扩充。如,在子类中加入新的属性、新的方法。
对父类的改造。比如,对方法的覆盖。

首先定义一个父类:Person,它有三个属性,分别由各自的存取方法来存取。

public class Person {
 private String name;

 private int age;

 private String sex;

 public String showName() {
  return name;
 }

 public void setName(String theName) {
  name = theName;
 }

 public int getAge() {
  return age;
 }

 public void setAge(int theAge) {
  age = theAge;
 }

 public String getSex() {
  return sex;
 }

 public void setSex(String theSex) {
  sex = theSex;
 }
}


在这边,我们将它的属性的访问控制定义为Default,是因为在子类中我们需要访问这些属性。


接着,我们定义一个类“Teacher”,它继承“Person”类。

public class Teacher extends Person {
 // 扩充父类属性
 private String department;

 // 扩充父类方法
 public void setDepartment(String theDept) {
  department = theDept;
 }

 public String getDepartment() {
  return department;
 }

 // 方法覆盖
 public String showName() {
  return name + "老师";
 }

 // 测试
 public static void main(String[] args) {
  Teacher t = new Teacher();
  t.setName("Alex");
  System.out.println(t.showName());
 }
}


在这个子类中,继承了父类,新增了一个“部门”的属性:department,并新增了相应的存取方法。改写(覆盖)了父类中的showName()方法,在姓名后面加上“老师”后返回。

 

因为在同一个包中的子类中用到了父类的属性name,所以,父类Person中的name属性不能定义为private的。最后定义了一个main()方法用于测试。

 

执行这个程序,在控制台上将会输出如下信息:
Alex老师


在程序中加入一个main()方法用于测试一个类是不错的主意,无论这个类是否是一个Java应用程序(Java Application)。

 

你可以通过类的main()方法测试这个类的各个方法是否与你的设计相一致。

 

 

1 重载

 

 

在Java程序中,如果同一个类(或者父类子类之间)中如果有两个相同的方法(方法名相同、返回值相同、参数列表相同)是不行的,因为这样编译器无法将方法调用和特定的方法联系起来。但是,在一个类中,如果有多个方法具有相同的名称,而有不同的参数,这种情况是允许的,我们就称这种行为为方法的重载(overload)。

 

我们经常使用println来向控制台输出各种类型的数据,这些println方法就是实现了方法的重载。


在进行方法的重载时方法的参数列表必须不同(参数个数或者参数数据类型,或者两者皆不同)。而方法的返回值可以相同,也可以不同。


我们来看一个例子。还是以上面的“Person”类,我们需要取得“Person”对象的“name(姓名)”属性,可能会有两种情况:一种是直接得到对象的“name”属性,还有一种情况是在获取的对象属性“name”的方法上输入一个参数,将这个参数当作头衔和“name”结合起来,比如:输入的头衔是“先生”,则通过方法返回的是:“XXX先生”。

 

我们可以为这两个需求定义两个方法,但是,为了显示这两个方法的相似点,我们更倾向于使用方法重载来完成:
public class Person{
 … …
 public String getName() {
  return name;
 }
 public String getName(String title) {
  return name+title;
 }
 … …
}


这样,如果只需要得到“Person”对象的“name”属性,调用不带参数的getName()方法就可以了;如果需要得到“Person”对象的“name”属性并且需要指明它的头衔,则可以调用带一个参数的getName()方法。


在进行方法的重载时,有四条基本原则需要遵守:


方法名相同;
参数列表必须不同;
返回值可以不同;
可以相互调用。


注意:方法的返回值不是方法的签名(signature)的一部分,所以,进行方法的重载的时候,不能将返回值类型的不同当成两个方法的区别。也就是说,在同一个类中,不能有这样的两个方法,它们的方法名相同、参数相同,只是方法的返回值类型不同。


构造器重载

 

在前面我们说过,构造器在某种程度上可以看成是一个特殊的方法:它没有返回值,它的方法名称必需和类的名称一致。因此,构造器也常常被称为“构造方法”。

 

作为Java类的组成成分之一,构造器也可以进行重载,下例中的类Person就定义了4个重载的构造器以满足不同的需要。


public class Person {
 private String name;

 private int age;

 private String sex;

 public Person() {
  System.out.println("构造器Person()被调用");
  name = "";
 }

 public Person(String theName) {
  System.out.println("构造器Person(String theName)被调用");
  name = theName;
 }

 public Person(String theName, int theAge) {
  System.out.println("构造器Person(String theName,int theAge)被调用");
  name = theName;
  age = theAge;
 }

 public Person(String theName, int theAge, String theSex) {
  System.out.println("构造器Person(String theName,"
    + "int theAge,String theSex)被调用");
  name = theName;
  age = theAge;
  sex = theSex;
 }
 // 其他代码
 // …. …
}


在这个类中,定义了四个构造器,这四个构造器中,各自的参数个数都不一样。在创建对象的时候,编译器会根据参数类型和参数个数来确定到底调用哪一个构造器。


我们来看下面这个创建“Person”对象的例子:

public class NewPerson {
 public static void main(String[] args) {
  Person person = new Person("Tom", 18, "male");
 }
}


编译并运行上面这个程序,它将会向控制台打印出如下信息:
构造器Person(String theName,int theAge,String theSex)被调用


这说明,它的带三个参数的构造器被调用来创建Person对象了。

 

 

1)方法重载(Overload)。表示两个或多个方法名字相同,但方法参数不同。方法参数不同有两层含义:1)参数个数不同。2)参数类型不同。 注意:方法的返回值对重载没有任何影响。

 

普通的方法在重载的情况下,可以互相调用。

2)构造方法重载:只需看参数即可。如果想在一个构造方法中调用另外一个构造方法,那么可以使用this()的方式调用,this()括号中的参数表示目标构造方法的参数。this()必须要作为构造方法的第一条语句,换句话说,this()之前不能有任何可执行的代码。

 

13. 方法重写(Override):又叫做覆写,子类与父类的方法返回类型一样、方法名称一样,参数一样,这样我们说

子类与父类的方法构成了重写关系。

14. 方法重写与方法重载之间的关系:重载发生在同一个类内部的两个或多个方法。重写发生在父类与子类之间。重载是一种平行关系,几个方法参数不同。重写是一种层次关系。

15. 当两个方法形成重写关系时,可以在子类方法中通过super.run()形式调用父类的run()方法,其中super.run()

不必放在第一行语句,因此此时父类对象已经构造完毕,先调用父类的run()方法还是先调用子类的run()方法是根据

程序的逻辑决定的。

 

 

Java中虚方法调用

 

 

我们前面已经知道了,在多态的情况下,声明为父类类型的引用变量只能访问父类中定义过的方法,但如果此变量实际引用的是子类的对象,而子类中又进行了方法覆盖时,实际调用的是子类中覆盖后的方法,这种机制称为虚方法调用


在使用多态的情况下,有可能出现编译时类型和运行时的类型不一致的问题,如上面的例子中:
public class CalClass{
 .. …
 public int calPersonBirthYear(Person p) {
  // 根据参数p的年龄来计算出生年代
 }
}


在编译的时候,方法calPersonBirthYear 的参数类型是Person的,而在运行的时候,可能就是Student 或Teacher或Person或其他的Person子类类型了。

分享到:
评论

相关推荐

    方法重载和方法重写

    在编程语言中,方法重载(Overloading)和方法重写(Overriding)是两个非常重要的概念,它们都是实现多态性(Polymorphism)的关键机制。本文将深入探讨这两个概念,以及它们在实际编程中的应用。 ### 方法重载...

    C#重写重载与多态

    在C#编程语言中,重写、重载和多态是面向对象...重写允许子类定制继承自基类的方法,重载让我们可以创建多个同名但参数不同的方法,而多态则让我们可以通过父类引用调用子类的特定方法,实现更高效、更灵活的代码设计。

    重载与覆写/重写的区别

    重载与覆写/重写的区别 区别 重载 覆写 1 单词 OverLoading Override 2 概念 方法名称相同,参数的类型或个数不同 方法名称相同,参数的类型或个数相 同,返回值类型相同 3 范围 发生在一个类之中...

    Java中方法重载与重写的区别

     方法的重载是同一个类中多态性的一种表现。  方法重载须遵循如下两条规则  (1)方法名相同。  (2)参数列表不同。  注意:方法的返回值类型不能用来区分重载的方法。这是因为当调用一个方法时,返回值...

    JAVA中的方法重写与方法重载区别

    JAVA中的方法重写与方法重载区别 JAVA 中的方法重写和方法重载是两个重要的概念,在面向对象程序设计语言中尤为重要。方法重写和方法重载都是多态性的体现,但它们之间有着本质的区别。 方法重写(Override)是指...

    Java方法的艺术:重载与重写的深度解析

    ### Java 方法的艺术:重载与重写的深度解析 在 Java 编程语言中,方法的重载(Overloading)和重写(Overriding)是面向对象编程的重要概念。这两种技术使得方法能够在不同的上下文中表现出不同的行为,从而增强了...

    java中的重载和重写的区别

    重写发生在父类和子类之间,当子类继承父类时,如果子类定义了一个与父类中已存在的方法同名、同参数列表的方法,那么子类中的这个方法就是对父类方法的重写。重写的主要目的是为了在子类中改变或扩展父类的功能。在...

    java中重载与重写

    在Java编程语言中,方法的重载(Overloading)与重写(Overriding)是两个非常重要的概念。它们虽然只有一字之差,但其实质却大相径庭。理解这两者的不同对于深入掌握Java语言至关重要。 ### 一、重载(Overloading...

    C++中重载与重写函数区别及虚函数

    ### C++中重载与重写函数的区别及虚函数详解 #### 一、虚函数概述 **1.1 虚函数定义与作用** 在C++中,虚函数是一种特殊的成员函数,它允许子类覆盖父类的行为。虚函数的核心在于实现多态性,即在运行时动态决定...

    java 重载,重写以及继承,多态的区别

    重写的方法必须与父类的方法同名,同返回值,同形参个数和类型。重写的目的是为了提供更加具体的实现。 例如,在上面的例子中,`Triangle` 类中的 `getSides()` 方法是对 `Shape` 类中的 `getSides()` 方法的重写。...

    java中重载与重写的区别.pdf

    Java 中重载与重写的区别 Java 中的重载(Overloading)和重写(Overriding)是两个不同的概念,它们都是 Java 语言中实现多态性的手段。 方法重载(Overloading) 方法重载是让类以统一的方式处理不同类型数据的...

    Java中重载和重写总结

    Java 中重载和重写总结 Java 中的重载(Overloading)和重写(Overriding)是两个非常...方法重载是让类以统一的方式处理不同类型数据的一种手段,而方法重写是父类与子类之间的多态性,对父类的函数进行重新定义。

    Java重写与重载(区别与用途)

    我根据我的理解来谈谈Java中重写方法与重载方法的区别。  重写  Java 中重写又叫覆盖,主要是指继承(extends)父类或者实现(implements)接口时将父类或者接口中已经存在的方法进行重新定义。重写的方法在父类...

    方法的重载和重写1

    在编程语言中,方法的重载(Overloading)和重写(Overriding)是两种不同的多态性表现,它们在类的继承体系中扮演着重要角色。本文将深入探讨这两种概念,以及它们在实际编程中的应用和规则。 首先,我们来看方法...

    Java的重载和重写

    重写的方法必须与被重写的方法有完全相同的名称、返回类型和参数列表。重写的方法在子类中可以更改其行为,但不能更改其签名,也不能降低其访问权限。例如,父类有一个打印消息的方法,子类可以重写这个方法,使其...

    重载,重写,覆盖,多态

    ### 重载、重写、覆盖与多态的深刻剖析 在面向对象编程语言中,如Java、C#等,重载(Overloading)、重写(Overriding)、覆盖(也称为重写)以及多态(Polymorphism)是几个非常重要的概念。它们之间既有关联又有...

    重载、重写、重构.md

    - **增强代码的可维护性**:当需要增加与现有方法类似的新功能时,可以通过重载来实现,而不需要为新功能创建全新的方法名。 ### 重构(Refactoring) 重构是指在不改变程序外部行为的前提下,对内部结构进行修改,...

    继承与多态,重载和重写

    重写(Overriding)是指子类可以提供与父类相同签名的方法,但提供不同的实现。重写只发生在继承关系中,子类方法必须声明为`@Override`(在Java中),以确保该方法确实覆盖了父类的相应方法。在运行时,如果对象是...

    Java方法重载和方法重写的区别.docx

    Java编程语言中,方法的两种重要特性是方法重载(Overloading)和方法重写(Overriding)。这两种机制都是为了实现多态性,但它们在实际应用中有着明显的区别。 **方法重载(Overloading)**: 方法重载发生在同一...

Global site tag (gtag.js) - Google Analytics