Java基础——继承

来源:互联网 发布:淘宝便宜的布料店 编辑:程序博客网 时间:2024/05/16 19:14

继承是面向对象的三大特征之一,也是实现软件复用的重要手段。Java的继承具有单继承的特点,每个子类只有一个直接父类。

一、继承的特点
Java的继承通过extends关键字实现,实现继承的类被称为子类,被继承的类称为父类,有的也称为基类、超类。父类和子类的关系,是一种一般和特殊的关系。例如水果和苹果的关系。苹果继承了水果,苹果是水果的子类,则苹果是一种特殊的水果。

因为子类是一种特殊的父类,因此父类包含的范围总比子类包含的范围要大,所以可以认为父类是大类,而子类是小类。
Java里子类继承父类的语法格式如下:

修饰符  class SubClass extends SuperClass{    //类定义部分}

定义子类地方语法很简单,只需在原来类定义上增加extends SuperClass即可,即表明该子类继承了SuperClass类。

Java使用extends作为继承的关键字,extends关键字在英文中是扩展,而不是继承。这个关键字很好体现了父类与子类的关系:子类是对父类的扩展,子类是一种特殊的父类。 子类扩展了父类,将可以获得父类全部成员变量和方法,这与汉语中的继承很好的类似性。但是,Java的子类不能获得父类的构造器

下面程序示范了子类继承父类的特点。下面是Fruit类的代码。

public class Fruit{    public double weight;    public void info()    {        System.out.println("我是一个水果,重" + weight + "g");    }}

接下来定义该Fruit类的子类Apple,程序如下。

public class Apple extends Fruit{    public static void main(String[] args)    {        //创建Apple对象        Apple a = new Apple();        //Apple对象本身没有weight成员变量        //因为Apple的父类有weight成员变量        //也可以访问Apple对象的weight成员变量        a.weight = 56;        //调用Apple的info方法        a.info();    }}

上面的Apple类基本是一个空类,它只包含了一个main()方法,但程序中创建了Apple对象之后,可以访问该Apple对象的weight实例变量和info()方法,这表明Apple对象也具有了weight实例变量和iinfo()方法,这就是继承的作用。

Java摒弃了C++中难以理解的多继承特征,即每个类最多只有一个直接父类
例如,下面的代码将引起编译错误:

class SubClass extends Base1 , Base2 , Base3 {...}

有些书在介绍Java单继承时,可能会说,Java类只能有一个父类。严格来说,这种说法应该是:Java只能有一个直接父类,实际上Java类可以有无限多个间接父类
例如:

class Fruit extends Plant{...}class Apple extends Fruit{...}

上面类的工艺中Fruit是Apple类的父类,Plant类也是Apple类的父类。区别是Fruit是Apple类的间接父类。

如果定义一个Java类时并未显式指定这个类的直接父类,则这个类默认扩展java.lang.Object类。因此,java.lang.Object类是所有类的父类,要么是其直接父类,要么是其间接父类。因此所有java对象都可调用java.lang.Object类所定义的实例方法。

从子类的角度来看,子类扩展(extends)父类:但从父类角度来看,父类派生(derive)出了子类。也就是说,扩展和派生描述的是同一个动作,只是观察角度不同而已。

二、重写父类的方法
子类扩展了父类,子类是一个特殊的父类大部分时候,子类总是以父类为基础,额外增加新的成员变量和方法。但是有一种情况例外:子类需要重写父类的方法。
例如,鸟类都包含了飞翔方法,鸵鸟是一种特殊的鸟类,因此鸵鸟是鸟类的子类,因此它从鸟类获得飞翔的方法,但是这个飞翔的方法不适合鸵鸟,所以鸵鸟需要重写鸟类的方法。

下面程序先定义一个Bird类。

public class Bird{    //Bird类的fly()方法    public void fly()    {        System.out,println("我在天空中飞翔...");    }}

下面定义一个Ostrich类,这个类扩展了Bird类,重写了Bird的方法。

public class Ostrich extends Bird{    //重写Bird类fly()方法    public void fly()    {        System.out.println("我只能在地上奔跑...");    }    public static void main(String[] args)    {        //创建Ostrich对象        Ostrich os = new Ostrich();        //执行Ostrich对象的fly方法,将输出"我只能在地上奔跑..."        os.fly();    }}

这种子类包含与父类同名的方法的现象被称为方法重写(Override),也被称为方法覆盖。可以说子类重写了父类的方法,也可说是子类覆盖了父类的方法。

方法重写要遵守“两同两小一大”规则。
“两同”即方法名相同、形参列表相同
“两小”指的是子类方法返回值类型应比父类方法返回值类型更小或相等,子类方法声明抛出的异常应比父类方法抛出的异常类更小或相等
“一大”指的是子类方法的访问权限应比父类方法的访问权限更大或相等

需要指出的是,覆盖方法和被覆盖方法要么都是类方法,要么都是实例方法,不能一个是类方法,一个是实例方法。
例如,下面的代码将会编译错误。

class BaseClass{    public static void test(){...}}class SubClass extends BaseClass{    public void test(){...}}

当子类覆盖了父类的方法后,子类将无法访问父类中被覆盖的方法,但可以在子类方法中调用被覆盖的方法。如果需要在子类方法中调用父类被覆盖的方法,则可以使用super(被覆盖的实例方法)或者父类名(被覆盖的实例方法)作为调用者来调用父类中被覆盖的方法。

如果父类方法具有private访问权限,则该方法对其子类是隐藏的,因此子类无法访问,也就是无法重写该方法。如果子类中也定义了一个与父类private方法具有相同的方法名、相同的形参列表、相同的返回值类型的方法,只是在子类中定义了一个新方法。

class BaseClass{    //test()方法是private访问权限,子类不可访问该方法    private void test() {...}}class SubClass extends BaseClass{    //此处并不是方法重写,可以增加static关键字    public static void test(){...}}

方法重载和方法重写在英文中分别是overload和override。
重载和重写的区别在哪呢?

其实把重载和重写放在一起比较本身没太大的意义,因为重载主要发生在同一个类的多个同名方法之间,而重写发生在子类和父类同名方法之间。当然,父类和子类方法之间也可发生重载,因为子类可以获得父类的方法,如果子类定义了一个与父类方法有相同方法名,但参数列表不同的方法,就会形成父类方法和子类方法的重载。

0 0
原创粉丝点击