Java继承

以公司雇员与经理为例

继承概念

  继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。允许创建分等级层次的类。

  例子:公司雇员与经理的待遇有一些差异,但也存在很多相同的地方,例如雇员仅领取薪水,而经理可以领取薪水和奖金,这种情形就需要使用继承,这是因为需要为经理定义一个新类Manager,增加一些新功能,可以重用Employee类中的部分代码,Employee和Manager存在“is-a ”的关系。

为什么需要继承

  不使用继承具有相同特性的话,需要写多份相同的代码,代码存在重复了,导致后果就是代码量大且臃肿,而且维护性不高(维护性主要是后期需要修改的时候,就需要修改很多的代码,容易出错),所以要从根本上解决这两段代码的问题,就需要继承。

定义子类

  关键字extends表示继承,关键字extends表明正在构造的新类派生于一个已存在的类已存在的类称为超类(superclass)新类称为子类(subclass),子类比超类拥有的功能更加丰富。在Manager类中,增加了一个用于存储奖金信息的域,以及一个用于设置这个域的新方法:

public class Manager extends Employee {
    private double bonus;

    public void setBonus(double bonus) {
        this.bonus = bonus;
    }
}

超类代码:

package demo;

import java.time.LocalDate;

public class Employee{
    private String name;
    private double salary;
    private LocalDate hireDay;
    public Employee(String name, double salary, int year,int month,int day) {
        super();
        this.name = name;
        this.salary = salary;
        this.hireDay = LocalDate.of(year,month,day);
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public double getSalary() {
        return salary;
    }
    public void setSalary(double salary) {
        this.salary = salary;
    }
    public LocalDate getHireDay() {
        return hireDay;
    }
    public void setHireDay(LocalDate hireDay) {
        this.hireDay = hireDay;
    }
    public void raiseSalary(double byPercent) {
        double raise = salary * byPercent / 100;
        salary +=raise;
    }
}

 

尽管在Manager类中没有显式地定义Employee类中的getNamegetHireDay等方法但属于Manager类的对象却可以使用它们这是因为Manager类自动地继承了超类Employee中的这些方法同样从超类中还继承了namesalaryhireDay3个域这样一来每个Manager类对象就包含了4个域namesalaryhireDaybonus

通用的方法放在超类,具有特殊用途的方法放在子类中。

覆盖方法

  超类中的有些方法对子类Manager并不一定适用,Manager类中的getSalary方法应该返回薪水和奖金的总和为此需要提供一个新的方法来覆盖override)超类中的这个方法。

public class Manager extends Employee {
    private double bonus;

    public void setBonus(double bonus) {
        this.bonus = bonus;
    }
    public double getSalary() {
        double baseSalary = super.getSalary();
        return baseSalary + bonus;
    }
}

如果 double baseSalary = super.getSalary();改为 double baseSalary =salary;或者 double baseSalary = getSalary();都不能运行,前者是因为因为Manager类的getSalary方法不能够直接地访问超类的私有域,如果一定要访问私有域,必须借助共有的接口getSalary;后者是因为Manager类也有一个getSalary方法,如果这样写会导致无限次调用自己,直到整个程序崩溃,为此可以用关键字super解决这个问题:super.getSalary(),调用的是Employee类中的getSalary方法。

super 与 this 关键字

super关键字:我们可以通过super关键字来实现对父类成员的访问,用来引用当前对象的父类。

this关键字:指向自己的引用。

子类构造器

public class Manager extends Employee {
    private double bonus;

    public void setBonus(double bonus) {
        this.bonus = bonus;
    }
    public double getSalary() {
        double baseSalary = super.getSalary();
        return baseSalary + bonus;
    }
    public Manager(String name,double salary,int year,int month,int day) {
        super(name,salary,year,month,day);
        bonus = 0;
    }
}

最后提供了一个构造器,这里的super具有不同的含义。 super(name,salary,year,month,day);是调用超类Employee中含有name,salary,year,month,day参数的构造器的简写形式。使用super调用构造器的语句必须是子类构造器的第一条语句如果子类的构造器没有显式地调用超类的构造器则将自动地调用超类默认没有参数)的构造器

Test代码:

  

package demo;

public class ManagerTest {

    public static void main(String[] args) {
        Manager boss = new Manager("Car Cracker", 80000, 1987, 12, 15);
        boss.setBonus(5000);
        Employee[] staff = new Employee[3];
        staff[0] = boss;
        staff[1] = new Employee("Harry Hacker", 50000, 1989, 10, 1);
        staff[2] = new Employee("Tommy Tester", 40000, 1990, 3, 15);
        
        for(Employee e : staff) {
            System.out.println("name="+e.getName()+",salary="+e.getSalary());
            
        }
    }

}

创建一个经理两个雇员,这里需要提到的是e.getSalary()调用能够确定应该执行哪个getSalary方法请注意尽管这里将e声明为Employee类型但实际上e既可以引用Employee类型的对象也可以引用Manager类型的对象

  一个对象变量例如变量e)可以指示多种实际类型的现象被称为多态polymorphism)在运行时能够自动地选择调用哪个方法的现象称为动态绑定dynamicbinding)。

继承层次

  继承并不仅限于一个层次由一个公共超类派生出来的所有类的集合被称为继承层次inheritancehierarchy),在继承层次中从某个特定的类到其祖先的路径被称为该类的继承链(inheritancechain)通常一个祖先类可以拥有多个子孙继承链例如可以由Employee类派生出子类ProgrammerSecretary它们与Manager类没有任何关系有可能它们彼此之间也没有任何关系

 

 

 需要注意的是 Java 不支持多继承,但支持多重继承

 

 

 

 

 

继承的特性

  • 子类拥有父类非 private 的属性、方法。

  • 子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。

  • 子类可以用自己的方式实现父类的方法。

  • Java 的继承是单继承,但是可以多重继承,单继承就是一个子类只能继承一个父类,多重继承就是,例如 A 类继承 B 类,B 类继承 C 类,所以按照关系就是 C 类是 B 类的父类,B 类是 A 类的父类,这是 Java 继承区别于 C++ 继承的一个特性。

  • 提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系越紧密,代码独立性越差)。

多态

  一个用来判断是否应该设计为继承关系的简单规则这就是is-a规则表明子类的每个对象也是超类的对象is-a规则的另一种表述法是置换法则它表明程序中出现超类对象的任何地方都可以用子类对象置换

  例如可以将一个子类的对象赋给超类变量

  Employee e;
  e = new Employee(...);
  e = new Manager(...);

Java程序设计语言中对象变量是多态的一个Employee变量既可以引用一个Employee类对象也可以引用一个Employee类的任何一个子类的对象例如ManagerExecutiveSecretary)。然而不能将一个超类的引用赋给子类变量

阻止继承final类和方法

  有时候可能希望阻止人们利用某个类定义子类不允许扩展的类被称为final例如假设希望阻止人们定义Executive类的子类就可以在定义这个类的时候使用final修饰符声明声明格式如下所示

    public final calss Executive extends Manager{
          ...
      }

类中的特定方法也可以被声明为final如果这样做子类就不能覆盖这个方法

  public class Employee{

  ...

  public final String getName()
}

}

方法或类声明为final主要目的是确保它们不会在子类中改变语义

 

posted @ 2020-05-12 16:31  我们村里的小花儿  阅读(214)  评论(0编辑  收藏  举报