关于JAVA核心技术(卷一)读后的思考(继承中的类、子类和超类)

前面说过类之间的关系有一种便是继承,其中“is-a”关系是继承的一个明显特征。举个例子有一个类是Employee,还有一个类是Manager类,Employee表示的是员工,而Manager表示的是老板,即管理层,而作为管理层也是员工,所以可以说这两者之间具有"is-a"这种关系。也就是说Manager是Employee的子类。

定义子类:

这里要用到一个关键字extends来表示继承。

用上面的Employee例子就是:

public class Manager extends Employee{

……

}

extends表明正在构造的新类派生于一个已存在的类。已存在的类成为超类;新类称为子类。

在Manager类中有一个奖金信息的方法,具体为:

public class Manager extends Employee {
    private double bonous;

public void setBonous(double b) {
        bonous =b;
    }
    

}
即这个方法,在超类中并不存在,而在子类中存在,而在子类中并未显式地定义部分超类的方法,但仍然可以使用,因为Manager自动继承了超类Employee的方法。

而对于构造函数有这样一个要求:

当子类继承时,必须在自己的构造函数显式调用父类的构造函数,自己才能确保子类在初始化前父类会被实例化
如果你父类中有无参的构造函数,子类就不会强制要求调用,即你写的那个就可以通过,
编译器会默认帮你调用父类的构造函数。
如果不按这个要求编译器会报错

 

因为考虑到这些实例域都是private定义的,所以后面又把重新定义一边仍然报错,所以从侧面证明了这个原理

方法覆盖

超类的有些方法子类并不适用,所以这个时候就会进行提供一个新的方法来覆盖。

子类的方法是不允许直接放为超类的私有域的,也就是说,尽管Manager对象都拥有一个名叫salary的域,但在Manager类的getSalary方法并不能直接访问salary域,必须调用超类中的公有的接口,才能使用通过。使用时,要加上super.getSalary,否则会无限调用自己,造成出错。

子类可以增加域、增加方法或者覆盖超类的方法,却不能删除继承的任何域和方法

子类构造器

代码分析:

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

其中的   super(name,salary,year,month,day);是调用超类的含对应参数的构造器。

对该部分私有域进行初始化。我们用super实现对超类构造器的调用

super调用构造器的语句必须是子类构造器的第一句

如果子类的构造器没有显示地调用超类的构造器,则将自动地调用超类默认的构造器,若超类无无参数构造器,则会报错。

package com.java.inheritance;

public class ManagerTest {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Manager boss =new Manager("Carl Cracker",80000,1987,12,15);
        boss.setBonous(5000);
        Employee[] staff = new Employee[3];
        
        
        staff[0]=boss;
        staff[1]=new Employee("Harry Hacker",50000,1989,10,1);
        staff[2]=new Employee("Tommy Teter",40000,1990,3,15);
        
        for(Employee e:staff)
            System.out.println("name="+e.getName()+",salary="+e.getSalary());
        

    }

}

package com.java.inheritance;

import java.time.*;

public class Employee {
    private String name;
    private double salary;
    private LocalDate hireDay;
    
    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 Employee() {
        
    }*/


    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;
    }

}

package com.java.inheritance;

import java.time.LocalDate;

public class Manager extends Employee {
    private double bonous;
    
    public Manager(String name,double salary,int year,int month,int day) {
    
        super(name,salary,year,month,day);
        bonous=0;
        
    }
    public  double getSalary() {
        double baseSalary=super.getSalary();
        return baseSalary+bonous;
        
    }
    public void setBonous(double b) {
        bonous =b;
    }
    

}

其中循环中有e.gatSalary()

调用能够确定应该执行那个getSalary方法。尽管e声明为Employee类型,但实际是e技能引用Employee类型的对象,也可以引用Manager类型的对象。引用的是什么对象就是调用的是什么方法。

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

继承层次

继承并非限于一个层次。eg:Manager类派生Executive类。由一个公共超类派生出来的的所有类的集合称为继承层次,其中不管派生了几次都称为该类的继承层次

在继承层次中,由某个特定的类到祖先的路径称为该类的继承链

多态

"is-a"规则是判定是否应该设计为继承关系的简单规则,即每个子类对象都是超类的对象。

"is-a"规则是另一种表述法是置换法则,即两个对象进行置换观察是否任然满足条件。

对象变量是多态的,一个Employee变量既可以引用Employee对象,也可以引用一个Employee的任何一个子类的对象。

Employee[] staff = new Employee[3];
        
        
        staff[0]=boss;

这是允许的,但编译器将staff[0]堪称Employee对象,

意味着可以这样调用:

boss.setBonous(5000);

但不能

staff[0].setBonus(5000);

因为staff[0]声明类型是Employee,故不能调用子类方法。

同时不允许将超类的引用赋值给子类变量。

阻止继承:final类和方法

不允许扩展的类称为final类。

子类不允许覆盖的方法在前加final

强制类型转换

基本数据类型转换:

低——>高:直接转换

高——>低:强制类型转换

方式:(类型名)变量名

类:子类类型 变量名=(超类类型) 变量名

超累类型 变量名=子类变量名       即:直接转换

抽象类

关键字:abstract

即在超类中增加一个方法加上abstract,即可以不用实现这个方法

而包含一个或多个抽象方法的类必须被声明为抽象的

抽象方法充当着占位的角色,它的具体实现在子类中,扩展抽象类可以有两种选择,一种是在抽象类中定义部分抽象类方法或不定义抽象类方法,这样必须将子类也标记为抽象类。

另一种是定义全部的抽象类方法

类即使不含抽象类方法,也可以将类声明为抽象类。

抽象类不能实例化,即不能创建对象,但可以创建子类变量

受保护访问

关键字:protect

使用这个关键字声明的实例域和方法,可以被该类的子类直接调用。

不提倡使用

访问修饰符总结总结

(1)仅本类可以见——private

(2)对所有类可见——public

(3)对本包和所有子类可见——protect

(4)对本包可见——默认(无修饰符)

如果有写的不对的地方,欢迎指正,希望能够共同进步,谢谢!
原文地址:https://www.cnblogs.com/zzuzhouxiang/p/10329775.html