zoukankan      html  css  js  c++  java
  • 06、面向对象特征之继承

    1、概述:

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

      多个类可以称为子类,单独这个类称为父类或超类。

      子类可以直接访问父类中的非私有的属性和行为。

      通过extends关键字让类与类之间产生继承关系。

      class SubDemo extends Demo{}

          图解:

     
     

    2、继承的好处和弊端:

      好处:

        (1)提高了代码的复用性

        (2)让类与类之间产生了关系,给第三个特征多态提供了前提。

      弊端:打破了封装性。

    3、java单继承

      *java中支持单继承。不直接支持多继承,但对C++的多继承机制进行改良。

          **一个类只能有一个父类,不可以有多个父类

      *单继承:一个子类只能有一个直接父类。

      *多继承:一个子类可以有多个直接父类(java中不允许,已改良);

                不直接支持,因为多个父类中有相同成员,会产生调用的不确定性。

              在java中是通过“多实现”的方式来体现。

     4、定义继承需要注意:

      (1)不要仅为了获取其他类中某个功能而去继承。

      (2)类与类之间要有所属(“is a”)关系,xx1是xx2的一种。

     

      *java支持多层(多重)继承

         C继承B,B继承A

         就会出现继承体系。

        **当要使用一个继承体系时:

          ***查看该体系中顶层类,了解该体系的基本功能

          ***创建体系中的最子类对象,完成功能的使用。

     

    5、什么时候定义继承呢?

        *当类与类之间存在着所属关系的时候,就定义继承。xxx是yyy中的一种。xxx extends yyy

     

    6、super关键字:

      this代表本类对象的引用

      super代表父类的内存空间的标识

      *在子父类中,成员的特点体现:

           成员变量、成员函数、构造函数

     

      成员变量:

          当本类的成员和局部变量同名用this区分。

            当子父类中的成员变量同名用super区分父类。

            子类要调用父类构造函数时,可以使用super语句。

     

      成员函数:

         当子父类中出现成员函数一模一样的情况,会运行子类的函数。

         这种现象,称为覆盖操作。这是函数在子父类中的特性:

           (1)重载。同一个类中。

           (2)覆盖。子类中,覆盖也称为重写,复写。

     

    7、函数覆盖:

      (1)定义:

        子类中出现与父类一模一样的方法时,会出现覆盖操作,也称为重写或复写。

        覆盖是函数的特性之一,只有函数才有覆盖

        父类中的私有方法不可以被覆盖

        在子类覆盖方法中,继续使用被覆盖的方法可以通过super.函数名获取

      (2)什么时候使用覆盖操作?

        *当对一个类进行子类的扩展时,子类需要保留父类的功能声明,但是要定义子类中该功能的特有内容时,就使用覆盖操作完成。

        *当子类需要父类的功能,而功能主体子类有自己特有内容时,可以复写父类中的方法,这样,即沿袭了父类的功能,又定义了子类特有的内容。

      (3)子父类中的构造函数的特点:

            *在子类构造对象时发现,访问子类构造函数时,父类也运行了,为什么?

              原因:在子类的构造函数中第一行有一个默认的隐式语句:super()

                    super();//调用的就是父类中空参数的构造函数。

      图解:

     
     

      (4)子类的实例化过程:子类中所有的构造函数默认都会访问父类中的空参数的构造函数。

        *为什么子类实例化时要访问父类中的构造函数呢?

          因为子类继承了父类,获取到了父类中的内容(属性),所以在使用父类内容之前,要先看父类如何对自己的内容进行初始化的。所以子类在构造对象时,必须访问父类的构造函数。为了完成这个必须的动作,就在子类的构造函数中加入了super()语句(在第一行)。

                子类会继承父类中的数据,所以要先明确父类是如何对这些数据初始化的。

            *如果父类中没有定义空参数构造函数,那么子类的构造函数必须用super明确要调用父类中的哪个构造函数。 同时,子类的构造函数中如果使用了this调用了本类的构造函数时,那么super就没有了,因为super和this都只能定义在第一行,所以只能有一个,但是可以保证的是,子类中肯定会有个其他的构造函数访问父类的构造函数。

           *注意:super语句必须要定义在子类构造函数的第一行。因为,父类初始化动作要先完成。

     (5)覆盖注意事项:

             *子类方法覆盖父类方法时,子类权限必须要不小于父类的权限

              *静态只能覆盖静态,或被静态覆盖。

    图解:

     
     

    8、设计模式:

      对问题行之有效的解决方式。其实它是一种思想。

      (1)单例设计模式:

        解决的问题:就是可以保证一个类在内存中的对象唯一性。

        比如对于多个程序使用同一个配置信息对象时,就需要保证该对象的唯一性。

        *如何保证对象唯一性?

          **不允许其他程序用new创建该类对象;

          **在该类中创建一个本类实例;

          **对外提供一个方法让其他程序可以获取该对象。

        *步骤:

          **私有化该类的构造函数

          **通过new在本类中创建一个本类对象

          **定义一个公有的方法,将创建的对象返回。

      代码体系:单例模式有饿汉式和懒汉式

    //饿汉式
    
    class Single{//类一加载,对象就已经存在了。
    
        private static Single s = new Single();
    
        private Single(){}
    
        public static Single getInstance(){
    
            return s;
    
        }
    
    }
    
     
    
    //懒汉式
    
    class Single2{//类加载进来,没有对象,只有调用了getInstance方法时,才会创建对象。//延迟加载形式。
    
        private static Single2 s = null;
    
        private Single2(){}
    
        public static Single2 getInstance(){
    
            if(s==null)
    
                s = new Single2();
    
            return s;
    
        }
    
    }

     

    图解:

     
     

    9、对象实例化过程

      例:Person p = new Person();

        *JVM会读取指定的路径下的Person.class文件,加载进内存,并会先加载Person的父类(如果有直接的父类的情况下)

        *在堆内存中开辟空间,分配地址;(如果有静态代码块的话,会先执行静态代码块,再开辟空间,因静态先于对象存在)

        *并在对象空间中,对对象中的属性进行默认初始化

        *调用对应的构造函数进行初始化(如果类中属性有赋值,则会先显示初始化,然后才是构造函数初始化)

        *在构造函数中,第一行会先调用父类中的构造函数进行初始化,

        *父类初始化完毕后,再对子类的属性进行显示初始化

        *再进行子类构造函数的特定初始化

        *初始化完毕后,将地址值赋值给引用变量

    图解:

     
     

    10、final关键字

      *final是一个修饰符,可以修饰类,方法,变量

      *final修饰的类不可被继承

      *final修饰的方法不可以被覆盖

      *final修饰的变量是一个常量,只能赋值一次。

      *内部类只能访问被final修饰的局部变量

          **final固定的是显示初始化,不固定默认初始化

      *为什么要用final修饰变量?

          其实在程序中如果一个数据是固定的,那么直接使用这个数据就可以了,但是这样阅读性差,所以该数据起个名字,而且这个变量名称的值不能变化,所以加上final固定。

       写法规范:常量所有字母都大写,多个单词,中间用下划线_连接

     

    11、抽象类

      (1)概述:java中的类没有足够的信息来描述一个具体的对象,这个类就是一个抽象类。

               抽象类就是对一系列看上去不同,但本质相同的具体概念的抽象。

          (2)抽象:笼统,模糊,看不懂,不具体。

              抽象定义:

                  *抽象就是从多个事物中将共性的,本质的内容抽取出来。

          (3)抽象类:

            java中可以定义没有方法体的方法,该方法的具体实现由子类完成,该方法称为抽象方法,包含抽象方法的类就是抽象类。

          (4)抽象方法的由来:

             *多个对象都具备相同的功能,但是功能具体内容有所不同,那么在抽取过程中,只抽取了功能定义,并未抽取功能主体,那么只有功能声明,没有功能主体的方法称为抽象方法。

             *例如:狼和狗都有吼叫的方法,可是吼叫的内容是不一样的,所以抽象出来的犬科虽然有吼叫功能,但是并不明确吼叫的细节。

          (5)抽象类特点:

           *抽象方法只有方法声明,没有方法体,定义在抽象类中。

             *格式:修饰符 abstract 返回值类型 函数名(参数列表);

           *方法只有声明没有实现时,该方法就是抽象方法,需要被关键字abstract修饰,抽象方法必须定义在抽象类中,该类必须也被abstract修饰。

             *抽象类不可以被实例化,也就是不可以用new创建对象。

             **为什么?因为调用抽象方法没意义。注:抽象方法只有声明没有实现,调用它无意义。

             **抽象类是具体事物抽取出来的,本身是不具体的,没有对应的实例。

             **例如:犬科是一个抽象的概念,真正存在的是狼和狗

             **而且抽象类即使创建了对象,调用抽象方法也没有意义。

          *抽象类必须有其子类覆盖了所有抽象方法后,该子类才可以实例化。(抽象类通过其子类实例化,而子类需要覆盖掉抽象类中所有的抽象方法后才可以创建对象,否则该子类也是抽象类)

       (6)问题:

          *抽象类中有构造函数吗?

              有,用于给子类对象进行初始化

          *抽象类可以不定义抽象方法吗?

              可以的。但是很少见,目的就是不让该类创建对象,AWT的适配器对象就是这种类。通常这个类中的方法有方法体,但是却没有内容。

          *抽象关键字不可以和那些关键字共存?

            private不行,子类必须覆盖父类方法后才能实例化,私有使父类方法隐藏不能被子类覆盖,矛盾。

            static 不行,该修饰符修饰后的方法可被类名直接调用,无需创建对象,但抽象方法没有方法体,直接调用该方法没有意义。

            final  不行,该修饰符修饰的方法不能被覆盖,使子类不能实例化。

           *抽象类和一般类的区别。

         **相同点:

                抽象类和一般类都是用来描述事物的,都在内部定义了成员;

               **不同点:

           ***一般类有足够的信息描述事物

                抽象类描述事物的信息有可能不足

           ***一般类中不能定义抽象方法只能定义非抽象方法

                而抽象类中可定义抽象方法,同时也可以定义非抽象方法

           ***一般类可以被实例化

                抽象类不可以被实例化。(只能由其子类覆盖实例化)

          **抽象类一定是个父类吗?

               是的。因为需要子类覆盖其方法后才可以对子类实例化。

      (7)雇员示例:

        需求:公司中程序员有姓名,工号,薪水,工作内容。

        项目经理除了有姓名,工号,薪水,还有奖金,工作内容。

        对给出需求进行数据建模。

        分析:

          在这个问题领域中,先找出涉及的对象。

          通过名词提炼法。

          程序员:

            属性:姓名,工号,薪水、

            行为:工作。

          经理:

            属性:姓名,工号,薪水,奖金。

            行为:工作。

          程序员和经理不存在着直接继承关系,

          但是程序员和经理却具有共性内容。

          可以进行抽取。因为他们都是公司的雇员 

          可以将程序员和经理进行抽取.建立体系.

    //描述雇员。
    
    abstract class Employee{
    
        private String name;
    
        private String id;
    
        private double pay;
    
        Employee(String name,String id,double pay){
    
            this.name = name;
    
            this.id = id;
    
            this.pay = pay;
    
        }
    
        public abstract void work();
    
    }
    
     
    
    //描述程序员。
    
    class Programmer extends Employee{
    
        Programmer(String name,String id,double pay){
    
            super(name,id,pay);
    
        }
    
        public void work(){
    
            System.out.println("code...");
    
        }
    
    }
    
     
    
    //描述经理。 
    
    class Manager extends Employee{
    
        private int bonus;
    
        Manager(String name,String id,double pay,int bonus){
    
            super(name,id,pay);
    
            this.bonus = bonus;
    
        }
    
        public void work(){
    
            System.out.println("manage");
    
        }
    
    }

     

     

    12、接口

      (1)定义:

        *当一个抽象类中的方法都是抽象的时候,这时可以将该抽象类用另一种形式定义和表示,就是接口 interface

        *定义接口使用的是interface,不是class。

          *格式:

            interface {}

     

      (2)接口中的成员修饰符是固定的。

         *全局常量:public static final

         *抽象方法:public abstract 

         *发现接口中的成员都是public的。

        由此得出结论,接口中的成员都是公共的权限。

     

      (3)接口的特点:

         *接口是对外暴露的规则。

         *接口是程序的功能扩展。

         *接口的出现降低耦合性。

         *接口可以用来多实现。

         *类与接口之间是实现关系,而且类可以继承一个类的同时实现多个接口。

         *接口与接口之间可以有继承关系,并且可以是多继承。

    如:

     

    interface CC{
    
        void show();
    
    }
    
    interface MM{
    
        void method();
    
    }
    
     
    
    interface QQ extends  CC,MM{//接口与接口之间是继承关系,而且接口可以多继承。
    
        void function();
    
    }
    
     
    
    class WW implements QQ{
    
        //覆盖3个方法。
    
        public void show(){}
    
        public void method(){}
    
        public void function(){}
    
    }

     

      

     

      (4)接口的出现,避免了单继承的局限性

        *接口不可以实例化。只能由实现了接口的子类并覆盖了接口中所有的抽象方法后,该子类才可用实例化,否则,这个子类就是一个抽象类。

        *在java中不直接支持多继承,因为会出现调用的不确定性。所以java将多继承机制进行改良,在java中变成多实现。

     

      (5)抽象类和接口的异同点:

        *相同点:都是不断向上抽取而来的。

        *不同点:

          **抽象类需要被继承,而且只能单继承

              接口需要被实现,而且可以多实现

          **抽象类中可以定义抽象方法和非抽象方法,子类继承后可以直接使用非抽象方法

              接口只能定义抽象方法,必须由子类去实现。

          **抽象类的继承是is a关系,在定义该体系的基本共性内容

              接口的实现是like a关系,在定义体系的额外功能。

     

      (6)接口举例:笔记本接口的例子:

    /*
    
    笔记本电脑使用。
    
    为了扩展笔记本的功能,但日后出现什么功能设备不知道。
    
    定义一个规则,只要日后出现的设备都符合这个规则就可以了。
    
    规则在java中就是接口。
    
    */
    
    interface USB{// 暴露的规则。
    
        public abstract void open();
    
        public abstract void close();
    
    }
    
     
    
    class BookPC{
    
        public static void main(String[] args){
    
            useUSB(new UPan());//功能扩展了。
    
            useUSB(new UsbMouse());
    
        }
    
        //使用规则。
    
        public static void useUSB(USB u){//接口类型的引用,用于接收(指向)接口的子类对象。USB u= new UPan();
    
            if(u!=null){
    
                u.open();
    
                u.close();
    
            }
    
        }
    
    }
    
    //一年后。------------------------------
    
    //实现规则。
    
    //这些设备和电脑的耦合性降低了。
    
    class UPan implements USB{
    
        public void open(){
    
            System.out.println("upan open");
    
        }
    
        public void close(){
    
            System.out.println("upan close");
    
        }
    
    }
    
    class UsbMouse implements USB{
    
        public void open(){
    
            System.out.println("UsbMouse open");
    
        }
    
        public void close(){
    
            System.out.println("UsbMouse close");
    
        }
    
    }

     

     

  • 相关阅读:
    ARC108解题报告
    整体dp小结
    SAM学习笔记&AC自动机复习
    Error creating bean with name 'bootstrapImportSelectorConfiguration':
    responseBody
    无力回天的CSP2020
    NOIP2020游记
    2020国家集训队作业选做
    flutter开发使用AnnotatedRegion修改状态栏字体颜色,导致导航栏也变黑了的解决方法
    flutter使用InkWell点击没有水波纹效果的解决方法
  • 原文地址:https://www.cnblogs.com/zyh-blog/p/3162510.html
Copyright © 2011-2022 走看看