面向对象(JAVA)三大特性之------继承

时间:2022-10-03 21:06:02

一:继承的概念和优点。

1: 概念:总的来说基于已有的设计,去创造新的设计,就是面向对象程序设计中的继承。在继承之后子类获取父类的全部成员(包括成员变量和方法和各种访问属性的成员),来作为自己的一部分。(子类并不是只继承过来就完事了,他还要加入自己新定义的成员,包括变量和方法)。—–获取父类全部,并在此基础上进行了拓展。
:2:优点:继承是Java中实现软件重用的重要手段,避免重复,易于维护,易于理解。

二:实际操作和理解。

首先来看一段代码:

public class Animal {
    public String name;
    public int age;
    public void eat(){
    System.out.println("动物会吃");
}
}
public class Dog extends Animal{
    public void shout(){
    System.out.println("狗会叫");
}
}
public class Fish extends Animal{
    public void swim(){
    System.out.println("鱼会游泳");
}
}
public class Test{
    public static void main(String[] args){
    Dog dog = new Dog();
    dog.eat();//子类对象调用父类的方法。
    dog.shout;//子类对象调用自己的方法。

    Fish fish = new Fish();
    fish.eat();//子类对象调用父类的方法
    fish.swim();//子类对象调用自己的方法
    }

}

代码块中展示的,Dog类和Fish类共同继承自Animal类,Animal类中的所有的成员都被继承至两个子类中,对于子类来说,子类的对象可以毫无阻碍的调用父类非私有的成员(非private)。
注意:对于理解继承来说最重要的是要明白有哪些东西是可以继承下来的,即,除了构造方法以外的父类的所有的成员!!!!!

提到子类对于继承过来的属性的使用,就不得不去仔细的描述一下成员的访问修饰符。我们来分别讨论一下,父类成员的访问修饰符有四种:public,protected,缺省,private。我们分别来描述一下:
1:public。在父类和子类中都是公共的,都是可以*使用的。
2:protected。在父类和子类中只有包内的其他类,包括他的自身,还有他的子类都可以进行使用。
3:缺省。缺省是一件很操蛋的事,可千万别漏写了成员的访问修饰符,访问修饰符缺省的成员变量,在父类中只有包内的其他类,他自身可以*访问;继承到了子类之后,如果子类和父类是属于同一个包,那么可以*使用,如果不属于,那么他就相当于是private。
4:private。是一个相当常见的访问修饰符,在上一篇博客,封装中讲到了private,在这里我们来看看在继承中的作用和效果。无论是在父类还是在子类中,private只能在自己被定义的类中进行访问。同时,在子类中如果重新定义一个和父类中private的成员变量名称相同的属性,那么各自访问是毫不相干,互不干扰的。但是如果重新定义了一个非private的成员变量,那么就会提示错误,因为,从父类继承过来的非私有的成员变量都是可以直接使用的,就相当于是自己本身定义的一个成员变量,故,报错。
注意:被private定义的成员变量,也是被子类继承过来了,但是子类不能直接去使用从父类继承过来private成员变量,必须通过一些接口来使用,接下来详细说一下:

public class Book{
    private int pages = 300;

    public void setPages(int pages){
    this.pages=pages;
    }
    public int getPages(){
    return pages;
    }
}
public class Dictionary extends Book{
    private int definitions=5000;
    public double computeRatio(){
        return definitions/getPages();//注意此处除以的不是pages属性而是一个方法
    }

    public void setDefinitions(int definitions){
        this.definitions=definitions;
    }
    public int getDefinitions(){
        return definitions;
    }
}
public class Test{
    public static void main(String[] args){
        Dictionary xinhua = new Dictionary();
        System.out.println("页数:"+ xinhua.getPages());//输出300
        System.out.println("词条数: "+xinhua.getDefinitions());//输出5000
        System.out.println("每页词条数:"+xinhua.computeRatio());//输出16.0
    }
}

分析:从代码中我们看到父类Book的属性pages是private的,是私有的,所以虽然子类继承到了这个属性,但是他无法直接使用,只能通过从父类继承过来的public的方法去get到pages,这个很好理解,就是封装!
比如说,实体类Book有一个需要封装的属性,将它设置成private了,只有通过Book类中本来就有的公开的接口去访问到这个属性,如果你给Book设置一个子类Dictionary,他要是继承了就能直接使用这个在父类中私有的属性,那还有什么安全性可言,岂不是任何被封装的程序都可以通过被继承的方式破解私有的保密信息?? !!!!所以,在子类中无法直接访问从父类中继承过来的私有属性!!!

继续,我们来看初始化和传递参数这一段程序:

public class Game{
    Game(int i)  
    {System.out.println("构造Game"+ i) ; }
}
public class BoardGame extends Game { 
    BoardGame(int i){
            super(i);
            System.out.println("构造BoardGame"+ i );
    }
}
public class Chess extends BoardGame{
        Chess(){
            super(44);
            System.out.println("构造chess");
    }
    public static void main(String[] args){
        Chess x = new Chess();
    }
}
/* 程序的运行结果是: 构造Game44 构造BoardGame44 构造chess */

当创建了一个子类的对象的时候,父类的构造方法也会被调用,而且父类的构造方法调用顺序优先于子类的构造方法。可是为什么???
解释一下:因为子类继承自父类,并且有所扩展,所以父类是子类的补充,如果子类要创建一个对象,就要对子类进行初始化,可是如果只是初始化了子类那你觉得,子类初始化所有的东西了吗??所以父类要先进行初始化,再给子类初始化,这样,子类才能初始化完全了。
注意:构造方法有一个特性,那就是在创建对象的时候他会被自动的调用,而且无法制止。
所以当父类中没有构造函数的时候,他就会默认的调用无参的构造函数,如果有一个有参的构造函数,那么就必须在子类中通过super()调用父类的构造函数,并且传输进去相应的参数。不使用super会报错,父类中没有无参的构造函数了,除非是在父类中重新写一个无参的构造函数。
注:super。可以通过super关键字来实现对父类成员的访问,通过调用父类的构造方法把参数传递给父类的构造方法。也用来引用当前对象的父类。super点方法名:调用父类的方法,super点属性名:调用父类的属性。而且super必须放在方法的第一行,表示最先执行。
在程序块中super的执行过程是这样的:


    BoardGame(int i){
        Game(int i){
            System.out.println("构造Game"+ i );
        }
        System.out.println("构造BoardGame"+ i );
    }
    /*这一块代码相当于是 super(i) super放在构造方法的最前边,表示最先执行。 */

三:总结

1,四个访问修饰符的意义,限定范围;
2,继承和封装的联系;
3,初始化和传递参数中的super关键字,
4,了解好super关键字的作用,实际的运行流程。