zoukankan      html  css  js  c++  java
  • 大数据第十天

    继承extends(也叫扩展)

    引入

    首先写两个类:

        //定义学生类

        class Student {

           //成员变量

           private String name;

           private int age;

           //空构造

           public Student(){}

          

           //getXxx()/setXxx()

       

           public void eat() {

               System.out.println("吃饭");

           }

        }

       

        //定义教师类

        class Teacher {

           //成员变量

           private String name;

           private int age;

           //空构造

           public Teacher(){}

          

           //getXxx()/setXxx()

          

           public void eat() {

               System.out.println("吃饭");

           }

        }

    我们观察上面两个类代码:

    发现name,age成员变量,以及getXxx()/setXxx(),还有eat()等都是相同的。如果我们后来继续定义类,比如,工人类,运动员类。他们肯定也具备这些内容。那么,我们每一次定义这样的类的时候,都要把这些重复的内容都重新定义一遍。

    太麻烦,重复的代码太多,所以,要考虑改进

    如何改进呢?

    能不能把这些相同的内容给定义到一个独立的类中。然后,让这多个类和这个独立的类产生一个关系,有了这个关系后,这多个类就可以具备这个独立的类的功能。

    为了实现这个效果,Java提供了一个技术:继承(也叫“扩展”)

    举例:

    父亲:4个儿子

    继承怎么表示呢?继承的格式是什么样子的呢?

    class Father {...}              //定义一个Father类,被继承的类

    class Son extends Father {  //定义一个Son类继承(或叫扩展)Father类

    }

    修改我们的代码:

    将Student,Teacher类共同的东西抽取出来,单独放到一个类中,叫Person

        class Person {

           String name;

           int age;

           public Person(){}

          

           //getXxx()/setXxx()

       

           public void eat() {

               System.out.println("吃饭");

           }

        }

        //自定义类继承自抽象出来的Person类,这样,Person中定义的方法就不用再次定义了

        class Student extends Person {

           //空参构造方法,构造方法不能被继承,所以子类的构造还是需要定义

           public Student(){}

           //子类在继承的基础上,再增加自己特有的方法

           public void study(){}

        }

       

        class Teacher extends Person {

           public Teacher(){}

           public void teach(){}

        }

    继承概述

    多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可。

    通过extends关键字可以实现类与类的继承,继承的格式如下:

        class 子类名 extends 父类名 {} 

    单独的这个类,也就是被继承的类,称为父类,基类或者超类;这多个类称为子类或者派生类。

    有了继承以后,我们定义一个类的时候,可以在一个已经存在的类的基础上,还可以定义自己的新成员。

    继承的案例和继承的好处

    通过一个具体案例来演示代码

    案例1:学生类和教师,定义两个功能(吃饭,睡觉)

    案例2:加入人类后改进

    /*

        继承概述:

           把多个类中相同的内容给提取出来定义到一个类中。

        格式:

           class 子类名 extends 父类名 {}

        好处:

           A:提高了代码的复用性

           B:提高了代码的维护性

           C:让类与类之间产生了关系,是多态的前提

    */

    //使用继承前

    /*

    class Student {

        public void eat() {

           System.out.println("吃饭");

        }

        public void sleep() {

           System.out.println("睡觉");

        }

    }

     

    class Teacher {

        public void eat() {

           System.out.println("吃饭");

        }

        public void sleep() {

           System.out.println("睡觉");

        }

    }

    */

    //使用继承后

    class Person {

        public void eat() {

           System.out.println("吃饭");

        }

       

        public void sleep() {

           System.out.println("睡觉");

        }

    }

     

    class Student extends Person {}

     

    class Teacher extends Person {}

     

    class ExtendsDemo {

        public static void main(String[] args) {

           Student s = new Student();

           s.eat();

           s.sleep();

           System.out.println("-------------");

           Teacher t = new Teacher();

           t.eat();

           t.sleep();

        }

    }

    继承的好处

    提高了代码的复用性

       多个类相同的成员可以放到同一个类中

    提高了代码的维护性

       如果功能的代码需要修改,修改一处即可,继承的类中自动都被修改了

    让类与类之间产生了关系,是多态的前提(后面讲)

    Java中继承的特点

    • Java只支持单继承,不支持多继承。

        即:一个类只能有一个直接父类,不可以有多个直接父类。

        class SubDemo extends Demo{}           //ok

        class SubDemo extends Demo1,Demo2...//error不能继承多个类

     

    • Java支持多层继承(继承体系)

        class A{}

        class B extends A{}

        class C extends B{}

    /*

    class Father {}

    class Mother {}

    class Son exnteds Father {} //正确的

    class Son extends Father,Mother {} // 错误的,不能多继承

    */

    class GrandFather {

        public void show() {

           System.out.println("GrandFather");

        }

    }

     

    class Father extends GrandFather {

        public void method(){

           System.out.println("Father");

        }

    }

     

    class Son extends Father {}

     

    class ExtendsDemo2 {

        public static void main(String[] args) {

           Son s = new Son();

           s.method(); //使用从Father继承的方法

           s.show(); //使用从Father继承的方法

        }

    }

    Java中继承的注意事项

    子类只能继承父类所有非私有的成员(成员方法和成员变量)

    子类不能继承父类的构造方法,但是可以通过super(后面讲)关键字去访问父类构造方法。

    不要为了部分功能而去继承

    我们到底在什么时候使用继承呢?

    继承中类之间体现的是:"is a"的关系。

    /*

        继承的注意事项:

           A:子类只能继承父类所有非私有的成员(成员方法和成员变量)

           B:子类不能继承父类的构造方法,但是可以通过super(马上讲)关键字去访问父类构造方法。

           C:不要为了部分功能而去继承

               class A {

                  public void show1(){}

                  public void show2(){}

               }

               class B {

                  public void show2(){}

                  public void show3(){}

               }

               //我们发现B类中出现了和A类一样的show2()方法,所以,我们就用继承来体现

               class B extends A {

                  public void show3(){}

               }

               这样其实不好,因为这样你不但有了show2(),还多了show1()。

               有可能show1()不是你想要的。

        那么,我们什么时候考虑使用继承呢?

           继承其实体现的是一种关系:"is a"。

               Person

                  Student

                  Teacher

               水果

                  苹果

                  香蕉

                  橘子

           采用假设法。

           如果有两个类A,B。只有他们符合A是B的一种,或者B是A的一种,就可以考虑使用继承。

    */

    class Father {

        private int num = 10;

        public int num2 = 20;

        //私有方法,子类不能继承

        private void method() {

           System.out.println(num);

           System.out.println(num2);

        }

        public void show() {

           System.out.println(num);

           System.out.println(num2);

        }

    }

     

    class Son extends Father {

        public void function() {

           //num可以在Father中访问private

           //System.out.println(num); //子类不能继承父类的私有成员变量

           System.out.println(num2);

        }

    }

     

    class ExtendsDemo3 {

        public static void main(String[] args) {

           // 创建对象

           Son s = new Son();

           //s.method(); //子类不能继承父类的私有成员方法

           s.show();

           s.function();

        }

    }

    继承中成员变量的关系

    案例演示

    子父类中同名和不同名的成员变量

    子类方法中寻找变量的顺序

    /*

        类的组成:

           成员变量:

           构造方法:

           成员方法:

        而现在我们又讲解了继承,所以,我们就应该来考虑一下,类的组成部分的各自关系。

        继承中成员变量的关系:

           A:子类中的成员变量和父类中的成员变量名称不一样,这个太简单。

           B:子类中的成员变量和父类中的成员变量名称一样,这会出现什么情况呢?

               在子类方法中访问一个变量的查找顺序:

               a:在子类方法的局部范围找,有就使用

               b:在子类的成员范围找,有就使用

               c:在父类的成员范围找,有就使用

               d:如果还找不到,就报错。

    */

    class Father {

        public int num = 10;

        public void method() {

           int num = 50;

        }

    }

     

    class Son extends Father {

        public int num2 = 20;

        public int num = 30;

       

        public void show() {

           int num = 40;

           System.out.println(num);

           System.out.println(num2);

           // 找不到符号

           System.out.println(num3);

        }

    }

     

    class ExtendsDemo4 {

        public static void main(String[] args) {

           //创建对象

           Son s = new Son();

           s.show();

        }

    }

    结论

    在子类方法中访问一个变量

    首先在子类局部范围找,也就是方法内部

    然后在子类成员范围找,也就是子类的成员变量

    最后在父类成员变量范围找(肯定不能访问到父类局部范围)

    如果还是没有就报错。

    super关键字

    super的用法和this很像

    this   代表本类对象的引用

    super  代表父类存储空间的标识(可以理解为父类对象的引用)

     

    用法(this和super均可如下使用)

    • 访问成员变量

        this.成员变量

        super.成员变量(访问父类的成员变量,不能访问父类的private变量)

        访问静态成员时,也可以用:父类名.静态成员

    • 访问构造方法(子父类的构造方法问题再讲)

    this(…)       super(…)          //

    • 访问成员方法(子父类的成员方法问题再讲)

       this.成员方法()      super.成员方法()

       

    /*

        问题是:

           我不仅仅要输出局部范围的num,还要输出本类成员范围的num。怎么办呢?

           我还想要输出父类成员范围的num。怎么办呢?

               如果有一个东西和this相似,但是可以直接访问父类的数据就好了。

               恭喜你,这个关键字是存在的:super。

        this和super的区别?

               this代表本类对应的引用。

               super代表父类存储空间的标识(可以理解为父类引用,可以操作父类的成员)

               A:调用成员变量

                  this.成员变量 调用本类的成员变量

                  super.成员变量 调用父类的成员变量

               B:调用构造方法

                  this(...)  调用本类的构造方法

                  super(...) 调用父类的构造方法

               C:调用成员方法

                  this.成员方法 调用本类的成员方法

                  super.成员方法 调用父类的成员方法

    */

    class Father {

        public int num = 10;

    }

     

    class Son extends Father {

        public int num = 20;

        public void show() {

           int num = 30;

           System.out.println(num);    //30

           System.out.println(this.num);   //20

           System.out.println(super.num);  //10

        }

    }

     

    class ExtendsDemo5 {

        public static void main(String[] args) {

           Son s = new Son();

           s.show();

        }

    }

    继承中构造方法的关系

    1.子类中所有的构造方法默认都会访问父类中空参数的构造方法,除非显式使用super/this调用了父类或者是本类的其他构造方法。

    2.在类中对本类或者是父类构造方法的调用,只能是在构造方法中,不能在实例方法中调用构造方法(更不能在类方法中调用构造方法),原因:

    • 实例方法被调用时,说明实例对象已经被创建完了,此时不能再使用this/super去初始化本实例或者是父类实例
    • 类方法是在本类加载的时候就已经加载的,这时实例对象还没有被创建出来,是不能使用this或者super的

    class A {

        public A(int i){

           this(1 ,2);//

        }

        public A(int a ,int b){

           System.out.println("hello");//默认在这行之上,调用super();父类的空参构造

        }

    }

    因为子类会继承父类中的数据(成员变量),可能还会使用父类的数据。

    所以,子类初始化之前,一定要先完成父类数据的初始化。

    换句话说,一个对象的创建意味着它的所有的父类都会被创建出来。

    子类构造方法的第一条语句:

    如果是this(...)表明调用的是本类的另一个构造方法,在另一个构造方法中还可以继续使用this(...)调用本类其他的构造方法,如果有多个构造方法的话,可以继续调用下去,但是不能递归调用,最终总会有一个构造方法,第一条语句不是this()了。

    这时,可以显式的调用父类的构造方法super(...);或者什么都不写,这时系统默认调用父类的空参构造方法。

    总之,当子类对象被创建的时候,总是会先调用父类的构造方法,直到Object这个最上层的对象被创建出来之后,其下的子类对象才会被创建出来。

    构造方法不能递归调用

    class A {

        public A(int i){

           this(1 ,2);

        }

        public A(int a ,int b){

           this(2);

        }

    }

    /*

        继承中构造方法的关系

           子类中所有的构造方法默认都会访问父类中空参数的构造方法

           注意:子类每一个构造方法的第一条语句默认都是:super();除非显式this/super

    */

    class Father {

        int age;

        public Father() {

           System.out.println("Father的无参构造方法");

        }

       

        public Father(String name) {

           System.out.println("Father的带参构造方法");

        }

    }

     

    class Son extends Father {

        public Son() {

           //super();

           System.out.println("Son的无参构造方法");

        }

       

        public Son(String name) {

           //super();

           System.out.println("Son的带参构造方法");

        }

    }  

     

    class ExtendsDemo6 {

        public static void main(String[] args) {

           //创建对象

           Son s = new Son();

           System.out.println("------------");

           Son s2 = new Son("tom");

        }

    }

    考察父类,子类代码块的执行顺序

    从这个案例中能看到有继承关系的类的实例初始化的过程,以及为什么在类方法中不能使用this或者是super关键字

    class Father{

        static{

           System.out.println("Father类的静态代码块");

        }

        {

           System.out.println("Father类的构造代码块1");

        }

        public Father(){

           System.out.println("Father的无参构造方法");

        }

        public Father(int x){

           System.out.println("Father的有参构造方法");

        }

        {

           System.out.println("Father类的构造代码块2");

        }

    }

    class Son extends Father{

        static{

           System.out.println("Son类的静态代码块");

        }

        {

           System.out.println("Son类的构造代码块1");

        }

        public Son(){

           System.out.println("Son的无参构造方法");

        }

        public Son(int x){

           System.out.println("Son的有参构造方法");

        }

        {

           System.out.println("Son类的构造代码块2");

        }

    }

    class TestBlock{

        public static void main(String[] args){

           Son s = new Son();

        }

    }

    如果父类中没有空参构造方法,怎么办?

    1.子类可以通过super去显式调用父类其他的带参的构造方法

    2.子类可以通过this去调用本类的其他构造方法,但是本类其他构造也必须首先用super(...)访问了父类的带参构造(因为父类没有空参构造)

    总结

    如果父类没有空参构造,子类的构造方法中就必须显式调用父类带参构造super(...);

    一定要注意:

    super(…)或者this(…)必须出现在构造方法第一条语句上

    否则,就会有父类数据的多次初始化

    /*

        如果父类没有无参构造方法,那么子类的构造方法会出现什么现象呢?

           报错。

        如何解决呢?

           A:在父类中加一个无参构造方法

           B:通过使用super关键字去显示的调用父类的其他带参构造方法

           C:子类通过this去调用本类的其他构造方法

           子类中一定要有一个去访问了父类的构造方法,否则父类数据就没有初始化。

        注意事项:

           this(...)或者super(...)必须出现在第一条语句上。

           如果不是放在第一条语句上,就可能对父类的数据进行了多次初始化,所以必须放在第一条语句上。

    */

    class Father {

        /*

        public Father() {

           System.out.println("Father的无参构造方法");

        }

        */

        public Father(String name) {

           System.out.println("Father的带参构造方法");

        }

    }

     

    class Son extends Father {

        public Son() {

           super("随便给");

           System.out.println("Son的无参构造方法");

           //super("随便给");

        }

       

        public Son(String name) {

           //super("随便给");

           this();

           System.out.println("Son的带参构造方法");

        }

    }

     

    class ExtendsDemo7 {

        public static void main(String[] args) {

           Son s = new Son();

           System.out.println("----------------");

           Son ss = new Son("tom");

        }

    }

  • 相关阅读:
    Unity 3(一):简介与示例
    MongoDB以Windows Service运行
    动态SQL中变量赋值
    网站发布IIS后堆栈追踪无法获取出错的行号
    GridView Postback后出错Operation is not valid due to the current state of the object.
    Visual Studio 2010 SP1 在线安装后,找到缓存在本地的临时文件以便下次离线安装
    SQL Server 问题之 排序规则(collation)冲突
    IIS 问题集锦
    linux下安装mysql(ubuntu0.16.04.1)
    apt-get update 系列作用
  • 原文地址:https://www.cnblogs.com/zhaoyongcx/p/6618794.html
Copyright © 2011-2022 走看看