Java基础08 继承

作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明。谢谢!

继承(inheritance)是面向对象的重要概念。继承是除组合(composition)之外,提高代码重复可用性(reusibility)的另一种重要方式。我们在组合(composition)中看到,组合是重复调用对象的功能接口。我们将看到,继承可以重复利用已有的类的定义。

类的继承

我们之前定义类的时候,都是从头开始,详细的定义该类的每一个成员。比如下面的Human类:

class Human
{
   /**
     * accessor
     */
    public int getHeight()
    {
       return this.height;
    }

    /**
     * mutator
     */
    public void growHeight(int h)
    {
        this.height = this.height + h;
    }
    /**     * breath     */    public void breath()    {        System.out.println("hu...hu...");    }

    private int height;
}

从上面的类定义,我们可以了解该类的所有细节: 该类的数据成员,该类的方法,该类的接口。

现在要定义一个新的类,比如Woman类,并假设Woman与Human类相当类似:

Human & Woman

我们可以像以前一样,从头开始,完整的定义Woman类:

class Woman
{
    /**
     * accessor
     */
    public int getHeight()
    {
       return this.height;
    }

    /**
     * mutator
     */
    public void growHeight(int h)
    {
        this.height = this.height + h;
    }
    /**     * breath     */    public void breath()    {        System.out.println("hu...hu...");    }

    /**
     * new method
     */
    public Human giveBirth()
    {
        System.out.println("Give birth");
        return (new Human(20));
    }

    private int height;
}

一个程序员在写上面程序的时候,会有很大的烦恼。许多定义都曾在Human类中写过,但我们还要重新敲一遍。Woman类只新增了一个giveBirth()方法 (该方法创建并返回一个新的Human对象)。

利用继承,我们可以避免上面的重复。让Woman类继承自Human类,Woman类就自动拥有了Human类中所有public成员的功能。

我们用extends关键字表示继承:

class Woman extends Human
{    /**
     * new method
     */
    public Human giveBirth()
    {
        System.out.println("Give birth");
        return (new Human(20));
    }
}

这样,我们就省去了大量的输入。通过继承,我们创建了一个新类,叫做衍生类(derived class)。被继承的类(Human)称为基类(base class)。衍生类以基类作为自己定义的基础,并补充基类中没有定义的giveBirth()方法。继承关系可以表示为:

继承: 箭头指向基类

可以用以下Test类测试:

public class Test
{
    public static void main(String[] args)
    {
        Woman aWoman = new Woman();
        aWoman.growHeight(120);
        System.out.println(aWoman.getHeight());
    }
}

衍生层

通过继承,我们创建了Woman类。整个过程可以分为三个层次: 基类定义,衍生类定义,外部使用。

基类定义的层次就是正常的定义一个类,比如上面的Human类定义。

在外部使用者看来(比如Test类中创建Woman类对象),衍生类有一个统一的外部接口:

对于外部使用者来说,上述接口就已经足够了。仅从接口看,衍生类也没有什么特别之处。

然而,当程序员在衍生类定义的层次时,就必须要小心:

首先,接口是混合的: getHeight()方法和growHeight()方法来自基类,giveBirth()方法则是在衍生类内部定义的。

还有更加复杂的地方。我们之前在类的内部可以自由访问类的成员(利用this指代对象)。然而,当我们在Woman类的定义范围内,我们无法访问基类Human的private成员。我们记得private的含义: private的成员仅供该类内部使用。Woman类是一个不同于Human类的新类,所以位于Human类的外部。在衍生类中,不能访问基类的private成员。

但有趣的是,我们的growHeight()和getHeight()方法依然可以运行。这说明基类的private成员存在,我们只是不能直接访问。

为了清晰概念,我们需要了解衍生类对象的生成机制。当我们创建一个衍生类的对象时,Java实际上先创建了一个基类对象(subobject),并在基类对象的外部(注意,这里是基类对象的外部,衍生类对象的内部),增加衍生类定义的其他成员,构成一个衍生类对象。外部使用者能看到的,就是基类和衍生类的public成员。如下图:

基类对象与衍生类对象

图中黄色为基类对象。基层的成员之间可以互相访问 (利用Human类定义中的this指代基类对象)。

蓝色部分为衍生对象新增的内容,我将这部分称为衍生层。蓝色和黄色部分共同构成衍生对象。衍生层的成员可以相互访问(Woman定义中的this)。更进一步,我们还可以访问基层中public的成员。为此,我们用super关键字来指代基类对象,使用super.member的方式来表示基层的(public)成员。

当我们位于衍生层时(也就是在定义Woman类时),不能访问红色的基层private成员。当我们位于外部时,既不能访问紫色的衍生层private成员,也不能访问红色的基层private成员。

(衍生层的private成员有访问禁忌,所以标为斜线。基层的private成员访问禁忌最多,所以标为交叉斜线)

super和this类似,也是隐式参数。我们在类定义的不同层次时,this会有不同的含义。要小心的使用this和super关键字。

(Java并不强制使用this和super。Java在许多情况下可以自动识别成员的归属。但我觉得这是个好习惯。)

protected

我们之前介绍了两个访问权限相关的关键字,private和public,它们控制了成员的外部可见性。现在,我们介绍一个新的访问权限关键字:protected。

标为protected的成员在该类及其衍生类中可见。这个概念很容易理解,就是说,基类的protected成员可以被衍生层访问,但不能被外部访问,如下图:

方法覆盖

衍生类对象的外部接口最终由基类对象的public成员和衍生层的public成员共同构成。如果基类public成员和衍生层的public成员同名,Java接口中呈现的究竟是哪一个呢?

我们在构造方法与方法重载中已经提到,Java是同时通过方法名和参数列表来判断所要调用的方法的。方法是由方法名和参数列表共同决定的。上述问题中,如果只是方法名相同,而参数列表不同,那么两个方法会同时呈现到接口,不会给我们造成困扰。外部调用时,Java会根据提供的参数,来决定使用哪个方法 (方法重载)。

如果方法名和参数列表都相同呢? 在衍生层时,我们还可以通过super和this来确定是哪一个方法。而在外部时,我们呈现的只是统一接口,所以无法同时提供两个方法。这种情况下,Java会呈现衍生层的方法,而不是基层的方法。

这种机制叫做方法覆盖(method overriding)。方法覆盖可以被很好的利用,用于修改基类成员的方法。比如,在衍生层,也就是定义Woman时,可以修改基类提供的breath()方法:

class Woman extends Human
{/**
     * new method
     */
    public Human giveBirth()
    {
        System.out.println("Give birth");
        return (new Human(20));
    }

    /**
     * override Human.breath()
     */
    public void breath()
    {
        super.breath();
        System.out.println("su...");
    }
}

注意,此时我们位于衍生层,依然可以通过super来调用基类对象的breath()方法。当我们外部调用Woman类时,由于方法覆盖,就无法再调用基类对象的该方法了。

方法覆盖保持了基类对象的接口,而采用了衍生层的实现。

构造方法

在了解了基类对象和衍生层的概念之后,衍生类的构造方法也比较容易理解。

我们要在衍生类的定义中定义与类同名的构造方法。在该构造方法中:

  • 由于在创建衍生对象的时候,基类对象先被创建和初始化,所以,基类的构造方法应该先被调用。我们可以使用super(argument list)的语句,来调用基类的构造方法。
  • 基类对象创建之后,开始构建衍生层 (初始化衍生层成员)。这和一般的构建方法相同,参考构造方法与方法重载

比如下面的程序中,Human类有一个构造方法:

class Human
{   
    /**
     * constructor
     */    public Human(int h)    {        this.height = h;    }
    /**
     * accessor
     */
    public int getHeight()
    {
       return this.height;
    }

    /**
     * mutator
     */
    public void growHeight(int h)
    {
        this.height = this.height + h;
    }
    /**     * breath     */    public void breath()    {        System.out.println("hu...hu...");    }

    private int height;
}

衍生类Woman类的定义及其构造方法:

class Woman extends Human
{
    /**
     * constructor
     */
    public Woman(int h)
    {
        super(h); // base class constructor
        System.out.println("Hello, Pandora!");
    }

    /**
     * new method
     */
    public Human giveBirth()
    {
        System.out.println("Give birth");
        return (new Human(20));
    }

    /**
     * override Human.breath()
     */
    public void breath()
    {
        super.breath();
        System.out.println("su...");
    }
}

总结

extends

method overriding

protected

super.member, super()

欢迎继续阅读“Java快速教程”系列文章

时间: 2024-10-25 18:35:54

Java基础08 继承的相关文章

Java基础08 继承(转载)

继承(inheritance)是面向对象的重要概念.继承是除组合(composition)之外,提高代码重复可用性(reusibility)的另一种重要方式.组合是重复调用对象的功能接口.继承可以重复利用已有的类的定义. 类的继承 我们之前定义类的时候,都是从头开始,详细的定义该类的每一个成员.比如下面的Human类: 从上面的类定义,我们可以了解该类的所有细节: 该类的数据成员,该类的方法,该类的接口. 现在要定义一个新的类,比如Woman类,并假设Woman与Human类相当类似: 可以像以

黑马程序员——java基础--面向对象--继承

------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 继承: 1.当一个类中包含了另一个类的所有变量个方法时,但另一个类中不包含另一个类的所有变量和方法时,表示范围比较小的就可以作为另一个的父类. 集合表示:A属于B,B不属于A,A就可以作为B的父类,B继承A 2.当只是为了获取其他类的功能的时候,不能为了简化代码而继承. 3.必须是类与类之间的所属关系才可以继承,所属关系看前面集合 继承的特点: 1.不支持多继承,只支持单继承: 多继承的话容易

黑马程序员——Java基础——面向对象——继承、抽象类、接口、多态、包、内部类、异常等

第一讲 继承 1.继承: 当多个类拥有相同的功能时,那么这些类不需要每个都写这些相同的功能,只需要把相同功能抽到 一个单独的类中,继承这个类就能获得这些相同的功能: (1)继承的体系结构:就是对要描述的事物进行不断的向上抽取,就出现了体系结构. 要了解这个体系结构中最共性的内容,就看最顶层的类. 要使用这个体系的功能,就用最底层的类创建对象 (2)好处: A.提高代码复用性: B.继承的出现,让类与类之间产生关系,为多态的前提 (3)特点: A.只能单继承(准确的说是java对多继承进行优化,避

黑马程序员-Java基础-面向对象—继承、构造函数、重写、final、抽象类、接口

第一讲  继承 1.  继承的作用 1) 提高代码复用性: 2) 让类与类之间产生了关系: 2.  java继承特点 1) java只支持单继承,不支持多继承 因为多继承容易带来安全隐患:当多个父类中定义了相同功能,但功能内容不同时,子类对象不确定要运行哪一个. 2) java支持多层继承:可以形成一个继承体系 利用一个继承体系的方法:阅读体系父类,了解共性功能(该体系的基本功能),具体要调用这些基本功能时,需要创建最子类的对象,为什是最子类: 一是:父类有可能不能创建兑现(如,静态类或接口):

java基础知识--继承

继承 1.继承的概念 继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类. 继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为. 1.类的继承格式 在 Java 中通过 extends 关键字可以申明一个类是从另外一个类继承而来的,一般形式如下: class 父类 { } class 子类 extends 父类 { } 2.继承的特性 子类拥有父类非private的属性,方法. 子类可以拥有自己的属性

Java基础笔记-继承、抽象类、接口、多态、内部类、异常

继承:多个类具有相同的属性和行为时,将这些内容单独抽取到一个单独的类中,那么多个类无需再定义这些属性和行为,直接继承那个类即可 1)  多个类称为子类,单独的类称为父类或者超类 2)  子类可以继承父类中非私有的属性和方法 3)  通过extends关键字让类与类之间建立继承关系 4)  继承的出现提高了代码的复用性,让类与类之间产生了关系,为多态的出现提供了前提 5)  不能为了实现某类的功能,简化代码而继承,必须是类与类之间具有所属关系才可以继承,所属关系:is a 6)  特点:java只

【Java基础】继承的一些总结

什么是继承 把一些类的具有共性的东西剥离出来形成一个新的类,然后各个其他类保留自己独有的特性,并用关键字extends继承这个剥离出来的新的类,可以最终达到各类原始相同效果,但是在每个类中,单用一个“extends 新类” 就可以减少新类里差不多相同量级的代码量. 继承的格式 class 类1 extends 新类{} 其中新类就是剥离出的有共同特性的类. 继承的适用场景 存在“is a”的关系时,例如猫is a 动物,狗is a 动物. 继承的特点 Java中类只支持单继承 Java中可以多层

11. Java基础之继承

在<Think in java>中有这样一句话:复用代码是Java众多引人注目的功能之一.但要想成为极具革命性的语言,仅仅能够复制代码并对加以改变是不够的,它还必须能够做更多的事情.在这句话中最引人注目的是"复用代码",尽可能的复用代码使我们程序员一直在追求的,现在我来介绍一种复用代码的方式,也是java三大特性之一---继承. 继承 在讲解之前我们先看一个例子,该例子是前篇博文(java提高篇-----理解java的三大特性之封装)的. 从这里我们可以看出,Wife.Hu

【Java基础08】内部类、枚举类、日期和时间、Math、Random

1 内部类 1.1 概念 大部分时候,类被定义成一个独立的程序单元,在某些情况下,也会把一个类放到另一个类的内部定义,这个定义在其他类内部的类就被称为内部类,包含内部类的类被称为外部类. 1.2 作用 1.提供更好的封装,可以把内部类隐藏在外部类之内,不允许同一个包中的其他类访问该类. 2.内部类成员可以直接访问外部类的私有数据,因为内部类被当成其外部类成员,同一个类的成员之间可以互相访问.但外部类不能访问内部类的实现细节,例如内部类的成员变量. 3.匿名内部类适合用于创建那些仅需要一次使用的类