Java基础三 继承

1 类,超类和子类

1 Java与C++定义继承类的方式十分相似。Java用关键字extends代替了C++中的冒号(:)。在Java中,所有的继承都是公有继承,而没有C++中的私有继承和保护继承。

2 子类方法并不能直接访问超类的私有域,而且应该用super.超类方法的方式获取私有域的值。super和this不一样,因为super不是一个对象的引用,不能将super赋给另一个对象变量,它只是一个指示编译器调用超类方法的特殊关键字。在子类中可以增加域,增加方法或覆盖超类的方法,而不能删除继承的任何域和方法。在Java中使用关键字super调用超类的方法,而在C++中则采用超类名加上::操作符的形式。

3 由于子类的构造器不能访问超类的私有域,所以必须利用超类的构造器对这部分私有域进行初始化,我们可以通过super实现对超类构造器的调用。使用super调用构造器的语句必须是子类构造器的第一条语句。如果子类的构造器没有显式的调用超类的构造器,则自动地调用超类默认(没有参数)的构造器。如果超类没有不带参数的构造器,并且在子类的构造器中又没有显式地调用超类的其他构造器,则Java编译器将报告错误。

4 一个对象变量可以指示多种实际类型的现象被称为多态(polymorphism)。在运行时能够自动地选择调用哪个方法的现象称为动态绑定。在Java中,不需要将方法声明为虚拟方法。动态绑定是默认的处理方式。如果不希望让一个方法具有虚拟特征,可以将它标记为final。

5 由一个公共超类派生出来的所有类的集合被称为继承层次(inheritance hierarchy),在继承层次中,从某个特定的类到其祖先的路径被称为该类的继承链。通常,一个祖先类可以拥有多个子孙继承链,例如,可以由Employee类派生出子类Programmer或Secretary,它们与Manager类没有任何关系。

2 多态

1 有一个用来判断是否应该设计为继承关系的简单规则,这就是is-a规则,它表明子类的每个对象也是超类的对象。例如,每个经理都是雇员,因此,将Manager类设计为Employee类的子类是显而易见的,反之不然,并不是每个雇员都是经理。。

2 在Java中,对象变量是多态的。一个Employee变量既可以引用一个Employee类对象,也可以引用一个Employee类的任何一个子类对象(例如,Manager,Executive,Secretary等)。

Manager boss = new Manager();

Employee[] staff=new Employee[3];

staff[0] = boss;

在这个例子中,staff[0]与boss引用同一个对象。但编译器将staff[0]看成Employee对象。这意味着,可以这样调用 

boss.setBonus(5000);//OK

但不能这样调用 staff[0].setBonus(5000);// Error

这是因为staff[0]声明的类型是Employee,而setBonus不是Employee类的方法。

不能将一个超类的引用赋给子类变量因为不是所有的雇员都是经理。  Manager m = staff[i]  //Error

3 在Java中,子类数组的引用可以转换为超类数组的引用,而不需要采用强制类型转换例如:

Manager[] managers = new Manager[10];

Employee[] staff = managers;//OK

staff[0]=new Employee("Harrry Hacker",,,);//OK

编译器允许这个复制操作,此时staff[0]和managers[0]引用的是同一个对象。似乎我们把一个普通雇员擅自归入经理行列之中了。这是一种很忌讳发生的事,当调用managers[0].setBonus(1000)的时候,将会导致调用一个不存在的实例域,进而搅乱相邻存储空间的内容。为了不发生这类错误,所有的数组都要牢记创建它们的元素类型,并负责监督仅将类型兼容的引用存储到数组中。

4 当程序运行,并且采用动态绑定调用方法时,,虚拟机一定调用与x类型所引用对象的实际类型最适合的那个类的方法。假设x的实际类型是D,它是C类的子类。如果D类定义类方法f(String),就直接调用它;否则,将在D类的超类中寻找f(String),以此类推。

5 在覆盖一个方法的时候,子类的方法不能低于超类方法的可见性。特别是,如果超类方法是public,子类方法一定要声明为public。经常会发生这类错误:在声明子类方法的时候,遗漏了public修饰符。此时,编译器会把它解释为试图提供更严格的访问权限。

6 不允许扩展的类被称为final类,如果在定义类的时候使用final修饰符就表明这个类是final类。例如,假设希望阻止人们定义Executive类的子类,就可以在定义这个类的时候,使用final修饰符声明。声明格式为:

public final class Executive extends Manager{

}

类中的特定方法也可以被声明为final。如果这样做,子类就不能覆盖这个方法(final类中的所有方法自动地成为final方法)。

域也可以被声明为final。对于final域来说,构造对象之后就不允许改变它们的值了。不过如果将一个类声明为final,只有其中的方法自动地成为final而不包括域。将方法或类声明为final主要目的是:确保它们不会在子类中改变语义。

7 有时需要将某个类的对象引用转换为另外一个类的对象引用。 譬如Manager boss = (Manager) staff[0];进行转换的唯一原因是:在暂时忽视对象的实际类型之后,使用对象的全部功能。例如,在managerTest类中,由于某些项是普通雇员,所以staff数组必须是Employee对象的数组。我们需要将数组中引用经理的元素恢复成Manager类,以便能够访问新增加的所有变量。将一个子类引用赋给一个超类变量,编译器是允许的,但是将一个超类的引用赋 给一个子类变量,必须进行类型转换,这样才能通过运行时检查。如果在继承链上进行向下的类型转换,需要先检查:

if(staff[1] instanceof Manager)

{

   boss= (Manager)staff[1];

}

所以在进行类型转换前,要记住只能在层次内进行类型转换。在将超类转换为子类之前,应该使用instanceof进行检查。不过在一般情况下,应该尽量少用类型转换和instanceof运算符。

Employee.java
package inheritance;

import java.time.*;

public class Employee {
    private String name;
    private double salary;
    private LocalDate hireDay;

    public Employee(){
        name="";
        salary=0;
        hireDay=LocalDate.now();
    }


    public Employee(String name,double salary,int year,int month,int day){
        this.name=name;
        this.salary=salary;
        hireDay = LocalDate.of(year,month,day);
    }

    public String getName(){
        return name;
    }
    public double getSalary(){
        return salary;
    }
    public LocalDate getHireDay(){
        return hireDay;
    }
    public void raiseSalary(double byPercent){
        double raise = salary*byPercent/100;
        salary+=raise;
    }
}

 

Manager.java

package inheritance;

public class Manager extends Employee {
    private double bonus;

    public Manager(){
        super();
        bonus=0;
    }
    public Manager(String name,double salary,int year,int month,int day){
        super(name, salary, year, month, day);
        bonus=0;
    }

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

 

 

ManagerTest.java

package inheritance;

public class ManagerTest {
    public static void main(String[] args){
        Manager boss= new Manager("Carl Cracker",80000,1987,12,15);



        Employee[] staff =new Employee[3];

        staff[0] = boss;
        boss.setBonus(5000);
        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());
        }

    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值