2.Java面向对象编程三大特性之继承

在《Think in Java》中有这样一句话:复用代码是java众多引人注目的功能之一。但要想成为极具革命性的语言,仅仅能够复用代码并对其加以改变是不够的,他还必须能够做更多的事情。复用代码是我们一直所追求的,而继承则是复用代码的一种方式。

继承的定义:继承是用已有的类(称之为父类或超类)作为基础类建立新类(子类),子类继承父类拥有父类的全部定义,并且子类可以定义新的功能或增加新的数据。使用继承我们可以很方便的复用已有的代码。继承所描述的是“is-a”的关系,有两个对象猫、动物,这两个对象可以描述为“猫是动物”,那么猫就可以继承动物。如果不存在“is-a”的关系则不能继承。

继承定义了类如何相互关联,共享特性,对于若干个相同或者相似的类,我们可以抽象出他们共有的属性和行为并将其定义成一个父类或超类,其他的子类则可以继承这个父类,如有需要子类可以再定义自己独有的属性或行为。

使用继承时需要注意的三点:

(1).子类拥有父类的非private的属性和方法;

(2).子类可以拥有自己的属性和方法,即子类可以对父类进行扩展;

(3).子类可以用自己的方式实现父类的方法。

使用继承有很多的优点,除了可以将几个子类共有的属性放入父类,实现代码共享,避免重复外,还可以使得在修改、扩展继承而来的实现时更加简单。

说到继承就一定要说另外三个东西:构造器(也叫构造函数或构造方法)、protected关键字、向上转型

(1).构造器:

在前面我们知道子类可以继承父类中除了用private修饰的属性和方法,但是除了用private修饰的不能被继承外父类的构造器也是不能被继承的,构造器只能被调用,使用super()方法即可调用。

public class Person {
    protected String name;
    protected int age;
    protected String sex;
    
    Person(){
        System.out.println("Person Constrctor...");
    }
}

public class Husband extends Person{
    private Wife wife;

    Husband(){
        System.out.println("Husband Constructor...");
    }
    
    public static void main(String[] args) {
        Husband husband  = new Husband();
    }
}

Output:
Person Constrctor...
Husband Constructor...

对子类而言,其构造器的正确初始化是非常重要的,而且只有一个方法可以保证这点:在子类的构造器中调用父类的构造器来完成初始化,因为父类构造器具有完成父类初始化所需要的所有知识和能力,所以他能正确的完成子类构造器的初始化。而且编译器会在子类构造器中默认调用父类构造器,不需要我们显示的调用。但是,默认调用父类的构造器是以父类有默认构造器为前提的,如果父类没有默认构造器我们就必须显示的使用super()方法来调用父类构造器,且必须写在子类构造器中的第一行,否则编译器会报错:无法找到符合父类形式的构造器。如下:

public class Person {
    protected String name;
    protected int age;
    protected String sex;
    
    Person(String name){
        System.out.println("Person Constrctor-----" + name);
    }
}

public class Husband extends Person{
    private Wife wife;

    Husband(){
        super("chenssy");
        System.out.println("Husband Constructor...");
    }
    
    public static void main(String[] args) {
        Husband husband  = new Husband();
    }
}

Output:
Person Constrctor-----chenssy
Husband Constructor...

 (2).protected关键字:

private(受保护的)访问修饰符,对于封装而言,是最好的选择。但有时候需要将某些事物尽可能地对这个世界隐藏,但是仍然允许子类的成员来访问它们,这个时候就需要使用到protected。

对protected而言,它指明所有继承此类的子类或者其他任何位于同一个包的类是可以访问的,但对其他类来说它是private的。 诚然尽管可以使用protected访问修饰符来限制父类属性和方法的访问权限,但是最好的方式还是将属性保持为private(我们应当一致保留更改底层实现),而通过protected方法来控制类的继承者的访问权限。

(3).向上转型:

 在上面的继承中我们谈到继承是is-a的相互关系,猫继承与动物,所以我们可以说猫是动物,或者说猫是动物的一种。这样将猫看做动物就是向上转型。如下:

public class Person {
    public void display(){
        System.out.println("Play Person...");
    }
    
    static void display(Person person){
        person.display();
    }
}

public class Husband extends Person{
    public static void main(String[] args) {
        Husband husband = new Husband();
        Person.display(husband);      //向上转型
    }
}

在这我们通过Person.display(husband)。这句话可以看出husband是person类型。

       将子类转换成父类,在继承关系上面是向上移动的,所以一般称之为向上转型。由于向上转型是从一个叫专用类型向较通用类型转换,所以它总是安全的,唯一发生变化的可能就是属性和方法的丢失。这就是为什么编译器在“未曾明确表示转型”活“未曾指定特殊标记”的情况下,仍然允许向上转型的原因。

(4).慎用继承:

继承存在如下缺陷:

A.父类变,子类就必须变;

B.继承破坏了封装,继承使父类的实现细节对于子类来说都是透明的;

C.继承是一种强耦合关系。

所以说当我们使用继承的时候,我们需要确信使用继承确实是有效可行的办法。那么到底要不要使用继承呢?《Think in java》中提供了解决办法:问一问自己是否需要从子类向父类进行向上转型。如果必须向上转型,则继承是必要的,但是如果不需要,则应当好好考虑自己是否需要继承。

 以上内容均来自http://www.cnblogs.com/chenssy/博客,此博客为本人学习笔记

http://www.cnblogs.com/haohaoge/
原文地址:https://www.cnblogs.com/haohaoge/p/6428271.html