java提升篇(二)-----理解java的三大特性之继承

      在《Think in java》中有这样一句话:复用代码是Java众多引人注目的功能之一。但要想成为极具革命性的语言,仅仅可以复制代码并对加以改变是不够的,它还必须可以作更多的事情。在这句话中最引人注目的是“复用代码”,尽量的复用代码使咱们程序员一直在追求的,如今我来介绍一种复用代码的方式,也是java三大特性之一---继承。html

继承

      在讲解以前咱们先看一个例子,该例子是前篇博文(java提升篇-----理解java的三大特性之封装)的。java

继承—01

      从这里咱们能够看出,Wife、Husband两个类除了各自的husband、wife外其他部分所有相同,做为一个想最大限度实现复用代码的咱们是不可以忍受这样的重复代码,若是再来一个小3、小4、小五……(扯远了大笑)咱们是否是也要这样写呢?那么咱们如何来实现这些类的可复用呢?利用继承!!程序员

      首先咱们先离开软件编程的世界,从常识中咱们知道丈夫、妻子、小3、小四…,他们都是人,并且都有一些共性,有名字、年龄、性别、头等等,并且他们都可以吃东西、走路、说话等等共同的行为,因此从这里咱们能够发现他们都拥有人的属性和行为,同时也是从人那里继承来的这些属性和行为的。编程

      从上面咱们就能够基本了解了继承的概念了,继承是使用已存在的类的定义做为基础创建新类的技术,新类的定义能够增长新的数据或新的功能,也能够用父类的功能,但不能选择性地继承父类。经过使用继承咱们可以很是方便地复用之前的代码,可以大大的提升开发的效率。继承—02安全

      对于Wife、Husband使用继承后,除了代码量的减小咱们还可以很是明显的看到他们的关系。this

      继承所描述的是“is-a”的关系,若是有两个对象A和B,若能够描述为“A是B”,则能够表示A继承B,其中B是被继承者称之为父类或者超类,A是继承者称之为子类或者派生类。spa

      实际上继承者是被继承者的特殊化,它除了拥有被继承者的特性外,还拥有本身独有得特性。例如猫有抓老鼠、爬树等其余动物没有的特性。同时在继承关系中,继承者彻底能够替换被继承者,反之则不能够,例如咱们能够说猫是动物,但不能说动物是猫就是这个道理,其实对于这个咱们将其称之为“向上转型”,下面介绍3d

      诚然,继承定义了类如何相互关联,共享特性。对于若干个相同或者相识的类,咱们能够抽象出他们共有的行为或者属相并将其定义成一个父类或者超类,而后用这些类继承该父类,他们不只能够拥有父类的属性、方法还能够定义本身独有的属性或者方法。code

      同时在使用继承时须要记住三句话:htm

         一、子类拥有父类非private的属性和方法。

         二、子类能够拥有本身属性和方法,即子类能够对父类进行扩展。

        三、子类能够用本身的方式实现父类的方法。之后介绍)。

      综上所述,使用继承确实有许多的优势,除了将全部子类的共同属性放入父类,实现代码共享,避免重复外,还可使得修改扩展继承而来的实现比较简单。

      诚然,讲到继承必定少不了这三个东西:构造器、protected关键字、向上转型。

构造器

      经过前面咱们知道子类能够继承父类的属性和方法,除了那些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...

      经过这个示例能够看出,构建过程是从父类“向外”扩散的,也就是从父类开始向子类一级一级地完成构建。并且咱们并无显示的引用父类的构造器,这就是java的聪明之处:编译器会默认给子类调用父类的构造器。

      可是,这个默认调用父类的构造器是有前提的:父类有默认构造器。若是父类没有默认构造器,咱们就要必须显示的使用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...

     因此综上所述:对于继承而已,子类会默认调用父类的构造器,可是若是没有默认的父类构造器,子类必需要显示的指定父类的构造器,并且必须是在子类构造器中作的第一件事(第一行代码)。

protected关键字

      private访问修饰符,对于封装而言,是最好的选择,但这个只是基于理想的世界,有时候咱们须要这样的需求:咱们须要将某些事物尽量地对这个世界隐藏,可是仍然容许子类的成员来访问它们。这个时候就须要使用到protected。

      对于protected而言,它指明就类用户而言,他是private,可是对于任何继承与此类的子类而言或者其余任何位于同一个包的类而言,他倒是能够访问的

public class Person {
    private String name;
    private int age;
    private String sex;

    protected String getName() {
        return name;
    }

    protected void setName(String name) {
        this.name = name;
    }

    public String toString(){
        return "this name is " + name;
    }
    
    /** 省略其余setter、getter方法 **/
}

public class Husband extends Person{
    private Wife wife;

    public  String toString(){
        setName("chenssy");    //调用父类的setName();
        return  super.toString();    //调用父类的toString()方法
    }

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

Output:
this name is chenssy

      从上面示例能够看书子类Husband能够明显地调用父类Person的setName()。

      诚然尽管可使用protected访问修饰符来限制父类属性和方法的访问权限,可是最好的方式仍是将属性保持为private(咱们应当一致保留更改底层实现),经过protected方法来控制类的继承者的访问权限

向上转型

      在上面的继承中咱们谈到继承是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类型。

       将子类转换成父类,在继承关系上面是向上移动的,因此通常称之为向上转型。因为向上转型是从一个叫专用类型向较通用类型转换,因此它老是安全的,惟一发生变化的可能就是属性和方法的丢失。这就是为何编译器在“不曾明确表示转型”活“不曾指定特殊标记”的状况下,仍然容许向上转型的缘由。

谨慎继承

      上面讲了继承所带来的诸多好处,那咱们是否是就能够大肆地使用继承呢?送你一句话:慎用继承

      首先咱们须要明确,继承存在以下缺陷:

         一、父类变,子类就必须变

         二、继承破坏了封装,对于父类而言,它的实现细节对与子类来讲都是透明的

         三、继承是一种强耦合关系     

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

      慎用继承!!!!!!!!!!!!!!!!!!!!!!!!!!!

相关文章
相关标签/搜索