Java学习笔记三:继承和多态


5.1 类,父类与子类

5.1.1 子类定义与方法覆盖

1.子类可以继承父类成员变量与方法,通过extends 关键字。

class subClass extends parentClass{...}

2.子类可以通过定义相同签名的方法来覆盖父类方法(无需关键字)。
3.子类不可访问父类私有方法及成员变量,可通过super.XXX来访问父类非私有成员变量与方法。
4.父类被覆盖的方法也可用super.XXX在子类中调用。
5.子类中可以增加成员变量,方法和覆盖方法,但不可以删除父类的任何变量与方法。
6.子类覆盖父类方法时,可见性不能低于父类方法。如父类是public,子类必须为public
7.每个类只可有一个父类,但一个类可以用无限多个子类。

5.1.2 子类构造器

子类构造器的第一条语句必须使用super(….)调用父类构造器。
例:

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

如果子类构造器没有调用父类的构造器,则将自动调用父类的无参构造器。若父类无无参构造器,则会报错。

5.1.3 多态

多态:一个对象,两种形态(或多种形态)。
对象的多态:每一个子类对象首先也是一个父类对象(is-a规则)。
因为子类是从父类派生而来,它保留了父类的所有特征,并加以丰富和修改。如每一个dog也是一个animal,它首先是一个动物,然后才是狗。
可以将一个子类对象赋给父类变量,但该变量不可以使用子类中特有的方法,只能调用父类原有的方法,如果子类覆盖了父类的方法,那么该变量会调用子类覆盖后的方法
例:

class Employee{
    private String name;
    private double salary;
    protected int age;
    private LocalDate hireDay;

    public Employee(String n,double s,int year,int month,int day){//父类构造器
        name = n;
        salary = s;
        hireDay = LocalDate.of(year,month,day);
    }

    public String getName(){
        return this.name;
    }

    public double getSalary(){
        return this.salary;
    }

    public LocalDate getHireDay(){
        return this.hireDay;
    }

    public void raiseSalary(double byPercent){//按比例加薪
        double raise = this.salary*byPercent/100;
        this.salary += raise;
    }
}

class Manager extends Employee
{
    private double bonus;
    public Manager(String n, double s, int year, int month, int day,int bonus) {
        super(n, s, year, month, day);//调用父类构造器
        this.bonus = bonus;
    }
    public double getSalary()//覆盖父类方法
    {
        return this.bonus+super.getSalary();//调用父类方法
    }
    public double getBonus(){//子类特有方法
       return this.bonus;
    }
    public void setBonus(double b)
    {
        this.bonus = b;
    }
}
Employee e = new Manager(“Bob”,1000,2002,9,1,500);//将子类对象赋给父类变量
e.getBounus();//error,父类变量无法调用子类特有方法。
double s = e.getSalary();//e = 1500.调用子类覆盖了的getSalary方法

5.1.4 方法调用

java编译器确定调用的是哪个方法的步骤:
(1)先将类中同名的,声明类型符合的方法罗列出来。
(2)查看这些方法中有没有参数类型匹配上的。

注意:子类覆盖父类方法时,可改变其返回值。因为返回值不属于方法签名。但是不可以改变父类方法的参数,因为参数属于方法签名,如果改变了参数,就相当于定义了一个子类特有的新方法,不再是覆盖了。

动态绑定:只有运行时才知道是哪类对象调用了方法。
例:

Employee e = new Manager(“Bob”,1000,2002,9,1,500);//将子类对象赋给父类变量
e.getSalary();//动态绑定,只有运行时才知道e调用的是子类的覆盖方法

静态绑定:调用private、static、final方法或者类构造器,这类方法能在编译时就确定是哪类对象调用的。

5.1.5 阻止继承:final类和方法

不可以被继承的类为final类。
例:

public final class XXX{...}

非final类中的特定方法也可被声明为 final,这样子类就不能覆盖该方法(final类中所有方法自动成为final方法)。
成员变量也可以为final,被赋值后不可修改(成员变量的final和方法的final意义截然不同)。
将类声明为final,只有其中的方法自动变为final,而不包括成员变量。

5.1.6 强制类型转换

将某个类的对象转换成另一个类的引用。
进行类型转换的唯一原因:在暂时忽略对象的实际类型之后,使用对象的全部功能。
比如将子类对象赋值给父类变量时,该变量无法调用子类的特有方法,所以要将其强制转换为子类变量。
只有父类变量转换为子类变量时,才需要强制类型转换,将转换类型用括号括起来。

在进行类型转换之前,需要用instanof判断能否成功转换。
如:

Employee e = new Employee(......);
if(e instanceof Manager)
{
    Manaer boss = (Manager e);//这种情况是不能成功转换的,如果不用instanceof检测会抛出异常
}

综上:
1.只能在继承层次进行类型转换(从父转子需强制转换)
2.将父类转换为子类之前,应该用instanceof进行检查。
3.尽量少使用强制转换和instanceof

5.1.7 抽象类

当一个方法不需要在当前类中实现,只需要在子类中实现时,可用abstract关键字。
如定义一个Person类,该类用来描述一个人的基本信息。现在要在该类中加入一个getDescription方法用来输出对一个人的一段描述。
那么在Person类中,该方法不容易实现,因为只是对一个人的描述不可能做到非常具体,但是在其子类Student和Emoloyee中,该方法很好具体实现。

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

public abstract class Person
{
    ...
    public abstact String getDescription();
    ...
}

除抽象方法外,抽象类还可包含具体数据和具体方法。
如果子类不定义父类抽象方法或只定义了部分抽象方法,那必须将子类也标记为抽象类。
如果子类定义了全部抽象方法,那子类也就不是抽象类了。除非又定义了新的抽象方法。
类即使不含抽象方法,也可以将类声明为抽象类。
抽象类不可被实例化。
可定义一个抽象类对象变量,它只能引用非抽象的子类的对象。但是和之前在多态中说过的一样,不能调用子类的特有方法。

5.1.8 控制可见性的4个访问修饰符

(1)仅对本类可见—–private.
(2)对所有类可见—–public.
(3)对本包和所有子类可见—–protected.
(4)对本包可见——–默认,无需修饰符.


文章作者: Extreme Ways
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Extreme Ways !
评论
 上一篇
“最初的欧亚大陆文明 “最初的欧亚大陆文明
最初的欧亚大陆文明 (BC 3500——BC 1000)综述最早的文明中心:苏美尔(美索不达米亚)伊拉克南部,南临波斯湾。 文明与新石器时代部落文化区别:城市中心,制度确立的政治权利,纳贡或税收,文字,阶级等。 技术革新: 灌溉术,冶金术(
下一篇 
全球通史——史前人类 全球通史——史前人类
史前人类人类——食物采集者地球形成于50亿年之前,40亿年前出现最早的生命:原生单细胞生物。 进化的过程:微生物——原始生物(海藻)——无脊椎动物(水母)——脊椎动物。 3亿年前,进入陆地。 人类: 最早猿人:南方古猿——400多万年前,非
  目录