• Java——面向对象进阶(封装、继承、多态)


    一、封装

    1.封装基本概念

    封装(encapsulation,有时称为信息隐藏)是处理对象的一个重要概念。
    从形式上看,封装就是将数据和行为组合在一个包中,并对对象的使用者
    隐藏具体的实现细节。对象中的数据称为实例字段(instance field),
    操作数据的过程称为方法(method)。作为一个类的实例,一个特定对象
    就有一组特定的实例字段值。这些值的集合就是这个对象当前的状态(state)
    只要在对象上调用一个方法,它的状态就有可能发生改变。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    封装的关键:
    绝对不能让其他类中的方法直接访问这个类的实例字段。程序只能通过对象的方法与对象的数据进行交互。

    2.访问修饰符

    下面是小编整理的访问限定符,这是一定要掌握的哦😊

    No范围privatedefaultprotectedpublic
    1同一包中的同一类
    2同一包中的不一类
    3不同包中的子类
    4不同包中的非子类

    3.Java中封装的理解

    我们在设计程序的时候追求高内聚、低耦合
    高内聚——类的内部数据的操作和细节自己完成,不允许外部干涉;
    低耦合——对外提供少量的公共方法使用

    我们在实现的一个类的时候隐藏类内部的复杂性、之对外提供简单的公开的接口。便于外界调用从而提高系统的可拓展性、可维护性,这里就要讲到Java中权限访问修饰符(private、默认(什么都不加)、protected、public)进行封装。

    下面我们用封装的思想来编写一个员工类
    属性——姓名、年龄、工资
    行为——上班摸鱼

    public class Employee {
        /**
         * 将特有的属性进行封装,并且不希望外界随意
         * 的对他进行修稿,这里我们就要用到私有的访
         * 问修饰符——private
         */
        private String name;
        private int age;
        private double salary;
    
        //构造方法,供外界实例一个类对象来操作数据
        public Employee(String name,int age,double salary) {
            this.name = name;
            this.age = age;
            this.salary = salary;
        }
    
        /**
         * 对外提供少量的公共方法供实例对象来操作数据
         * 主要是get、set方法,就比如说有一天我的员工修
         * 改了姓名或者调薪
         */
        //set设置器
        public void setName(String name) {
            this.name = name;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        //get访问器
        public String getName() {
            return name;
        }
    
        public int getAge() {
            return age;
        }
    
        public double getSalary() {
            return salary;
        }
    
        //特有的行为
        public void work() {
            System.out.println("名字为" + name + "的员工正在上班摸鱼");
        }
    
        public void raiseSalary(double byPercent) {
            double raise = salary * byPercent / 100;
            salary += raise;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    4.封装的优点

    最后我们再仔细看一下非常简单getName、getSalary方法

    public String getName() {
    	return name;
    }
    
    public double getSalary() {
    	return salary;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    这些都是典型的访问器。由于他们只返回实例字段的值,因此又称为字段访问器(field accessor)。

    如果将name、salary字段标记为公共,而不是编写单独的访问器方法,不是更容易一些吗?

    不过name只是一个只读字段,一旦再构造器(构造方法)中设置,就没有办法能够修改这个字段。这样我们就可以确保name字段不会受到外界的破坏。

    虽然salary不是只读字段,但是它只能用raiseSalary方法修改。具体的,如果这个值发生错误,那么只需要调试这个raiseSalary方法就可以了。如果salary字段是公共的,破坏这个字段的罪魁祸首就可以出现再任何地方(那就很难调试了)。

    二、继承

    1.为什么需要继承

    让我们回忆一下上面讨论的employee类。假设你在某个公司工作,这个公司里经理的待遇与普通员工的待遇存在着一些差异。不过,当然他们当中也存在很多相同的地方,例如,他们都领取薪水。只是普通员工在完成本职任务后仅领取薪水,而经理在完成了预期的业绩之后还能得到奖金。这种情形就需要使用继承。
    为什么呢?因为需要为经理定义一个新类Manager,并增加一些新功能,但可以重用Employee类中已经编写好的部分代码,并保留Employee类中的所有字段。

    **继承机制:**是面向对象程序设计使代码可以复用的重要手段,它允许程序员在保持原有类特性的基础上进行拓展,这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。继承主要解决的问题是:共性的抽取,实现代码复用。

    2.继承层次结构

    继承并不仅限于一个层次。例如,可以由Animal类派生出狗类、猫类、鸟类,再由猫类派生出中华田园猫、英国短毛猫、布偶猫等。由一个公共超类派生出来的所有类的集合称为继承层次结构(inheritance hierarchy),如下图所示。再继承层次结构中,从某个特定的类到其祖先的路径称为该类的继承链(inheritance chain)。

    补充:
    在C++中,一个类可以有多个超类。Java不支持多重继承,但支持多层继承。

    在这里插入图片描述

    3.super和this关键字

    由于设计不好,或者因场景需要,子类和父类中可能会存在相同名称的成员,如果要在子类方法中访问父类同名成员时,该如何操作?直接访问是无法做到的,Java提供了super关键字,该关键字主要作用:在子类方法中访问父类的成员。
    this关键字主要在本类访问本类成员成员变量,**该关键字的主要作用:**在本类方法中访问本类的成员
    super和this都可以在成员方法中用来访问:成员变量和调用其他的成员函数,都可以作为构造方法的第一条语句,他们之间有什么区别呢/?
    【相同点】
    1.都是Java中的关键字
    2。只能在类的非静态方法中使用,用来访问非静态的成员方法和字段
    3.在构造方法中调用时,必须时构造方法中的第一条语句,并且不能不能同时存在
    【不同点】
    1.this是当前对象的引用,当前对象即为调用实例方法的对象,super相当于是子类对象中从父类继承下来部分成员的引用
    2. 在非静态成员方法中,this用来访问本类的方法和属性,super用来访问父类继承下来的方法和属性
    3. 在构造方法中:this(…)用于调用本类构造方法,super(…)用于调用父类构造方法,两种调用不能同时在构造
    方法中出现
    4. 构造方法中一定会存在super(…)的调用,用户没有写编译器也会增加,但是this(…)用户不写则没有

    4.继承语法与设计一个继承体系

    4.1 继承语法:
    Java中如果要表示类之间的继承关系,需借助extends关键字,具体如下:

    修饰符 class 子类名 extends 父类名 {
    	//...
    }
    
    • 1
    • 2
    • 3

    4.2 设计一个继承体系
    父类Employee类:
    属性——姓名、年龄、工资
    行为——上班摸鱼、调薪
    子类Manager类:
    属性——姓名、年龄、工资、奖金(特有的)
    行为——看看谁摸鱼、调薪

    class Employee {
        //属性
        private String name;
        private int age;
        private double salary;
    
        //构造方法
        public Employee(String name,int age,double salary) {
            /**this关键字的用法解释
             * 由于方法形参与成员变量同名,不适用this关键字就造成变量
             * 同名,不使用this关键字就遵循就近原则,影响不到成员变量
             * 故this.name指定了成员变量的name,而非形参的name
             */
            this.name = name;
            this.age = age;
            this.salary = salary;
        }
        //set更改器
        public void setName(String name) {
            this.name = name;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        //get访问器
        public String getName() {
            return name;
        }
    
        public int getAge() {
            return age;
        }
    
        public double getSalary() {
            return salary;
        }
    
        //行为
        public void work() {
            System.out.println("名字为" + name + "的员工正在上班摸鱼!");
        }
    
        public void raiseSalary(double byPercent) {
            double raise = salary * byPercent / 100;
            salary += raise;
        }
    }
    
    class Manager extends Employee {
        //属性,与父类相同的属性就不必写了,这就是继承的好处
        private double bonus;
    
        public Manager(String name, int age, double salary) {
            /**super关键字用法的解释
             * 因为这个类继承了Employee类,必须帮助父类构造
             * 这里的super是调用了父类的构造方法
             */
            super(name, age, salary);
            //这里的奖金并不是构造对象时马上给出的,根据业绩的给定的
            this.bonus = 0;
        }
    
        /*由于父类的访问器已经不能满足子类的需求了,故需要重写
        父类的getSalary()方法,这里不加拓展重写,有关内容期待博主更新
        或者网上查阅资料哦!!!*/
        public double getSalary() {
            //这里super关键字的用法时调用父类的成员方法
            double baseSalary = super.getSalary();
            return baseSalary + bonus;
        }
    
        public void setBonus(double bonus) {
            this.bonus = bonus;
        }
    
        public void superviseWork() {
            System.out.println("名为" + super.getName() + "正在看看谁上班摸鱼!");
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82

    三、多态

    1.多态的概念

    在Java程序设计语言中,对象变量时多态的(polymorphic)。一个Employee类型的变量既可以引用一个Employee类型的对象,也可以引用Employee类的任何一个子类的对象(例如:Manager)。
    那就意味着我们可以这样用,接上面的继承篇

    Manager boss = new Manager("张三",24,12000);
    Employee[] staff = new Employee[3];
    staff[0] = boss;
    boss.setBonus(5000)//OK
    staff[0].setBonus(5000)//ERROR
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    为什么会发生错误呢?这是因为staff声明是Employee类型,Employee类中并没有setBonus()方法,boss则是声明为Manager类型,类中有setBonus()方法,所以调用时正确的。

    **多态的概念:**通俗来说,就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生不同的状态。

    2.多态的实现条件

    在Java中要想完成多态,必须要满足如下几个条件,缺一不可:

    • 必须在继承体系下
    • 子类必须要对父类中的方法进行重写
    • 通过父类的引用调用重写的方法

    **多态体现:**在代码运行时,当传递不同类对象时,会调用对应类中的方法。

    Employee boss = new Manager("张三",24,12000);
    /**
    *此时父类和子类中都有setSalary()方法,编译器在编译代码时并不知道
    *要调用Employee中的方法还是Manager中的方法,等程序运行起来后,变量
    *boss引用的具体对象确定后,才知道要调用那个方法。明显这里boss引用
    *Manager,所以回调用Manager类中的getSalary方法。
    */
    boss.getSalary();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    3.多态的优缺点

    1.多态的优点

    • 能够降低代码的复杂度,避免大量使用if-else
    • 拓展能力更强

    2.多态的缺陷

    • 属性没有多态性
    当父类和子类都有同名属性的时候,通过父类引用,只能引用父类自己
    的成员属性
    
    • 1
    • 2
    • 构造方法没有多态性

    结语:每个人的成长和进步都离不开点点滴滴的积累,如果小编的内容对您有所帮助,希望友友们三连加关注哦,你的支持是小编创作的最大动力。

  • 相关阅读:
    【数据集制作】用于语义分割,labelme4.5.13版本,实现按照指定颜色生成分割颜色批量转换json文件
    每天几道Java面试题(第一天)
    random生成随机数的灵活运用
    OP-TEE的内存和缓存管理(五):OP-TEE的共享内存和cache
    uniapp小程序因使用 uni.switchTab传不了值使用vuex(简单明了)
    给根目录扩容
    JTS: 15 Angle 角度计算
    安装docker
    python如何批量创建文件与文件夹
    idea右边找不到maven窗口(Idea_最右侧常用栏中没有Maven选项)
  • 原文地址:https://blog.csdn.net/qq_59599094/article/details/127866179