• 【JAVA】06 封装、继承、多态 总结(初级)


    教程:B站韩顺平

    一、访问修饰符

    在这里插入图片描述

    二、封装

    1. 将属性进行私有化【不能直接修改属性】
    2. 提供一个公共的set方法,用于对属性判断并赋值
    3. 提供一个公共的fet方法,用于获取属性的值

    tips:将有防护功能的方法写在构造器中,也可以实现防护属性

    三、继承

    3.1 继承

    继承可以解决代码复用,当多个类存在相同属性(变量)和方法时,可以从种抽取父类,在父类中重新定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法,只需要通过extends继承即可

    3.1.1 super关键字

    1. super表示父类的引用,用于访问父类的属性,方法,构造器

    2. 基本语法

      • 访问父类的属性,不能访问父类的private属性
        super.属性名
        
        • 1
      • 访问父类的方法,不能访问父类的private方法
        super.方法名(参数列表);
        
        • 1
    3. 访问父类的构造器:super(参数列表只能放在构造器的第一句,只能出现一句!)
      student.java

      public class student {
      		    private String name;
      		    private int age;
      		    public student(){}
      		    public student(String name, int age){
      		        setName(name);
      		        setAge(age);
      		    }
      		
      		    public void setName(String name) {
      		        this.name = name;
      		    }
      		
      		    public void setAge(int age) {
      		        this.age = age;
      		    }
      		
      		    public String getName() {
      		        return name;
      		    }
      		
      		    public int getAge() {
      		        return age;
      		    }
      		}
      
      • 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

      pupil.java

      public class pupil extends student{
      				    private double grades;
      				
      				    public pupil(){}
      				
      				    public pupil(String name, int age,double grades){
      				        super(name,age);
      				        setGrades(grades);
      				    }
      				
      				    public void setGrades(double grades) {
      				        this.grades = grades;
      				    }
      				
      				    public double getGrades() {
      				        return grades;
      				    }
      				}
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18

      testing.java

      public class testing {
      	    public static void main(String[] args) {
      	        pupil p = new pupil("小明",18,100.00);
      	        System.out.printf("name:%s,\tage:%d,\tgrades:%.2f",p.getName(),p.getAge(),p.getGrades());
      	    }
      	}
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6

      在这里插入图片描述

    4. 调用方法的顺序:

      1. 先找本类,如果有,则调用

      2. 如果没有,则找父类,并可以调用,则调用

      3. 如果父类没有,则继续找父类的父类,整个规则相同,直到Object类

      4. tips:
        a. 如果查找方法的过程中,找到了,但是不能访问,则报错
        b. 如果查找方法的过程中,没有找到,则提示方法不存在
        c. super.cal()是直接查找父类,其他规则一样(从b步骤开始)
        d. 当子类中有和父类中的成员(属性和方法)重名是,为了访问父类的成员,必须通过super,如果没有重名,使用super、this、直接访问时一样的效果
        e. super的访问不限于直接父类,如果爷爷类和本类中有同名的成员,也可以使用super取访问爷爷类的成员,如果多个基类含有相同的属性名,则使用super访问遵循就近原则,A——>B——>C,同时也需要遵守访问权限的相关规则

      5. super和this的比较
        在这里插入图片描述

    3.2 继承

    3.2.1 概念

    1. 子类继承了所有类的属性和方法,非私有属性和方法可以在子类中直接访问,但是私有属性不能再子类直接访问,要通过公共的方法访问
    2. 子类必须调用父类的构造器,完成父类的初始化
    3. 当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会调用父类的无参构造器
    4. 如果父类没有提供无参构造器,则必须在子类的构造器中使用super去指定使用父类的哪个构造器完成对父类的初始化工作,否则编译不通过
    5. 如果希望指定去调用父类的某个构造器,则显式的调用一下
    6. super在使用时,需要放在构造器第一行
    7. super和this都只能放在构造器第一行,因为这两个方法不能共存在同一个构造器中
    8. java所有类都是Object类的子类,Object是所有类的基类
    9. 父类构造器的调用不限于直接父类,将一直往上追溯直到Object类(顶级父类)
    10. 子类最多只能继承一个父类(指直接继承),即java中是单继承方式
    11. 不能滥用继承,子类和父类之间必须满足is-a的逻辑关系

    3.2.2 继承的本质

    当子类对象创建好后,建立查找的关系

    public class ExtendsTheory{
        public static void main(Strings[] agrs]){
            Son son = new Son();    
        }
    }
    class GrandPa{
        String name = "爷爷";
        String hobby = "旅游";
    }
    class Father extends GrandPa{
        String name = "爸爸";
        int age = 39;
    }
    class Son extends Father{
        String name = "儿子";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在这里插入图片描述

    • 由于只创建一个Son对象,故堆中只划分了一块区域
    • 然后再在方法区创建按照 Object——>Son的顺序创建对象
    • 调用方法时按照 本类——>Object的顺序进行查找(继承的顺序)

    3.2.3 方法重写/覆盖

    1. 子类方法的形参列表,方法名要和父类的一样
    2. 子类方法的返回类型和父类方法返回类型一样,或者是父类返回类型的子类
      eg:父类:返回类型Object
      子类:返回类型String
    3. 子类方法不能缩小父类方法的访问权限:public>protected>默认>private
    3.2.3.1 方法重载和方法重写的比较

    在这里插入图片描述

    四、多态

    4.1 方法的多态

    重写+重载

    4.2 对象的多态

    1. 一个对象的编译类型和运行类型可以不一致

    2. 编译类型在定义对象时就确定了,不能改变

    3. 运行类型是可以变化的

    4. 编译时类型由声明该变量时使用的类型决定,编译时引用变量只能调用其编译类型所具有的方法。

    5. 运行时类型由实际赋给该变量的对象决定。

    6. 编译类型看定义时=的左边,运行类型看=的右边

      //Animal.java
      public class Animal {
          private String name;
          public Animal(){}
          public void cry(){
              System.out.println("cyr:animal");
          }
      }
      //Dog.java
      public class Dog extends Animal{
          public void cry() {
              System.out.println("cry dog");
          }
      }
      //Cat.java
      public class Cat extends Animal{
          public void cry(){
              System.out.println("cry: cat");
          }
      }
      //PolyObject.java
      public class PolyObject {
          public static void main(String[] args){
              Animal animal = new Dog(); //编译类型:Animal,运行类型Dog
              animal.cry();
              animal = new Cat();//编译类型:Animal,运行类型cat
              animal.cry();
          }
      }
      
      • 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

      运行结果:
      在这里插入图片描述

    7. 案例

      //Animal.java
      public class Animal {
          private String name;
          public Animal(String name){
              this.name=name;
          }
          public String getName(){
              return this.name;
          }
      }
      //Dog.java
      public class Dog extends Animal{
          public Dog(String name){
              super(name);
          }
          public void cry() {
              System.out.println("cry dog:"+this.getName());
          }
      }
      //Food.java
      public class Food {
          private String name;
          public Food(String name){this.name=name;}
          public String getName(){
              return this.name;
          }
      }
      //Rice.java
      public class Rice extends Food{
          public Rice(String name){
              super(name);
          }
      }
      //PolyObject.java
      public class PolyObject {
          public static void main(String[] args){
              Animal animal = new Dog("大黄");
              animal.cry();
              Food food = new Rice("黑米粥");
              Master master = new Master("杰西");
              master.feed(animal,food);
          }
      }
      
      • 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

    4.3 向上转型

    1. 前提:两个对象(类)存在继承关系

    2. 本质:父类的引用指向了子类的对象

    3. 语法:父类类型

      引用名=new 子类类型()
      Animal animal = new Dog();
      
      • 1
      • 2
    4. 特点:编译类型看左边,运行类型看右边

    5. 可以调用父类中的所有成员(需要遵循访问权限)

    6. 不能调用子类中特有成员

    7. 最终运行效果看子类的具体实现(即运行时,按照运行类型决定)
      在这里插入图片描述

    4.4 向下转型

    1. 语法:子类类型

      引用名 = (子类类型)父类引用;
      Cat cat = (Cat) animal; //但是要父类的引用必须是指向当前目标类型的引用
      
      • 1
      • 2
    2. 只能强转父类的引用,不能强转父类的对象

    3. 要求父类的引用必须指向的是当前目标类型的对象
      在这里插入图片描述

    4. 可以调用子类类型中的所有成员

    4.5 多态——属性

    属性没有重写之说,属性的值看编译类型

    4.6 多态——instanceOf

    instanceOf比较操作符,用于判断对象的运行类型 是否为xx类型 或者 xx类型的子类型

    4.7 动态绑定机制❤️

    • 当调用对象方法时,该方法会和该对象的 内存地址/运行类型 绑定
    • 当调用对象属性时,没有动态绑定机制,哪里声明,哪里使用
      在这里插入图片描述
      在这里插入图片描述

    4.8 应用

    4.8.1 多态数组

    例1:

    public class PolyArray {
        public static void main(String[] args){
            Person[] persons = new Person[5];
            persons[0] = new Student("小明",100);
            persons[1] = new Student("大明",400);
            persons[2] = new Teacher("大强",20000);
            persons[3] = new Teacher("小强",50000);
            persons[4] = new Teacher("中强",90000);
            for(int i=0;i<persons.length;i++){
                persons[i].say();
                if(persons[i] instanceof Student){
                    ((Student) persons[i]).study();
                }else if(persons[i] instanceof  Teacher){
                    ((Teacher) persons[i]).teach();
                }else{
                    System.out.println("类型错误");
                }
            }
        }
    }
    class Person {
        private String name;
        public Person(String name){
            this.name=name;
        }
        public String getName() {
            return this.name;
        }
        public void say(){
            System.out.println(this.name);
        }
    }
    class Student extends Person{
        private double grades;
        public Student(String name,double grades){
            super(name);
            this.grades = grades;
        }
    
        public double getGrades() {
            return grades;
        }
    
        public void say(){
            System.out.println("学生"+this.getName()+"成绩"+this.getGrades());
        }
    
        public void study(){
            System.out.println("学生"+this.getName()+"正在学习");
        }
    }
    class Teacher extends Person{
        private double salary;
        public Teacher(String name,double salary){
            super(name);
            this.salary = salary;
        }
    
        public double getSalary() {
            return salary;
        }
        public void say(){
            System.out.println("教师"+this.getName()+"薪酬"+this.getSalary());
        }
        public void teach(){
            System.out.println("教师"+this.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

    4.8.2 例题

    //Employee.java
    public class Employee {
        private String name;
        private double salary;
        public Employee(String name, double salary){
            this.name=name;
            this.salary=salary;
        }
        public String getName() {
            return name;
        }
        public double getSalary() {
            return salary;
        }
        public double getAnnual(){
            return this.salary*12;
        }
    }
    
    //CommenEmployee.java
    public class CommenEmployee extends Employee{
        public CommenEmployee(String name, double salary){
            super(name,salary);
        }
        public void work(){
            System.out.println("普通员工:"+super.getName()+"正在工作");
        }
    }
    
    //Manager.java
    public class Manager extends Employee{
        private double bonus;
        public Manager(String name,double salary,double bonus){
            super(name,salary);
            this.bonus = bonus;
        }
    
        public double getBonus() {
            return bonus;
        }
    
        public void manage(){
            System.out.println("经理:"+super.getName()+"正在管理");
        }
    }
    
    //PolyParametersTesting.java
    public class PolyParameterTesting {
        public void showEmpAnnual(Employee e){
            double salary = e.getSalary();
            if(e instanceof Manager){
                salary+=((Manager) e).getBonus();
            }
            System.out.println(salary);
        }
        public void testWork(Employee e){
            if(e instanceof CommenEmployee){
                ((CommenEmployee)e).work();
            }else if(e instanceof Manager){
                ((Manager)e).manage();
            }else {
                System.out.println("类型出错");
            }
        }
    }
    
    //PolyParameters.java
    public class PolyParameter {
        public static void main(String[] args){
            Employee[] es = new Employee[2];
            es[0] = new CommenEmployee("员工",1000);
            es[1] = new Manager("经理",2000,500);
            PolyParameterTesting ppt = new PolyParameterTesting();
            for(int i=0;i<es.length;i++){
                ppt.showEmpAnnual(es[i]);
                ppt.testWork(es[i]);
            }
        }
    }
    
    • 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

    五、Object类

    5.1 == 和 equal

    1. ==:
    • 既可以判断基本类型,又可以判断引用类型
    • 如果判断基本类型,判断的是值是否相等
    • 如果判断引用类型,判断的是地址是否相等,即判断是否是同一个对象
    1. equals:
    • 是Object类中的方法,只能判断引用类型

    • 默认判断的是地址是否相等,子类中往往重写该方法,用于判断内容是否相等

      public boolean equals(Object obj){
          return (this ==obj);
      }
      
      public boolean equals(Object obj){
          if(obj instanceOf Integer){
              return value=((Integer)obj).intValue();    
          }
          return false;
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10

    5.2 HashCode

    1. HashCode返回该对象的哈希码值,支持此方法是为了提高哈希表的性能
    2. 提高具有哈希结构的容器的效率
    3. 两个引用,如果指的是同一个对象,则哈希值肯定是一样的
    4. 两个引用,如果指向的不同对象,则哈希值是不一样的(但是也有可能一样:哈希碰撞)
    5. 哈希值主要是根据地址号来的!不能完全将哈希值等价于地址
    6. 在集合中,HashCode如果需要的话,也会重写

    5.3 toString()

    1. 默认返回:全类名+@+哈希值的十六进制【查看Object的toString方法】

    2. 子类往往重写toString 方法,用于返回对象的属性信息

      public String toString(){
          return getClass().getName()+'@'+Integer.toHexString(hashCode());
      }
      
      • 1
      • 2
      • 3
    3. 重写toString方法,打印对象或拼接对象时,都会自动调用该对象的toString形式

      public class Employee {
          private String name;
          private double salary;
          public Employee(String name, double salary){
              this.name=name;
              this.salary=salary;
          }
          public String toString(){
              return "Employee{" +
                      "name='"+name+'\'' +
                      "salary="+salary+'\''+
                      '}';
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
    4. 当直接输出一个对象时,toString方法会被默认的调用

    5.4 finalize

    1. 当对象被回收是,系统自动调用该对象的finalize方法。子类可以重写该方法,做一些释放资源的操作:例如断开数据库链接,关闭文件等
    2. 如果程序员补充些finalize,则调用Object类的finalize,默认处理
    3. 如果重写finalze,则可以实现自己的逻辑
    4. 一般开发的时候不会重写finalize
    5. 什么时候被回收:当某个对象没有任何引用时,则jvm就认为这个对象是一个垃圾对象,就会使6用垃圾回收机制来销毁该对象,在销毁该对象前,会调用finalize方法
    6. 垃圾回收机制的调用,是由系统决定的,也可以使用System.gc()主动触发垃圾回收机制
  • 相关阅读:
    C++ Qt开发:StringListModel字符串列表映射组件
    redis漏洞修复:(CNVD-2019-21763)
    【JS红宝书学习笔记】第6章 集合引用类型
    Web2.0架构与Web3.0架构
    APT和Javapoet的精彩联动
    【精品】vue3中setup语法糖下的组件之间的通信
    学会玩游戏,智能究竟从何而来?
    小米云原生文件存储平台化实践:支撑 AI 训练、大模型、容器平台多项业务
    【计算机网络】HTTPS 的加密流程
    C语言结构体的初始化方式
  • 原文地址:https://blog.csdn.net/qq_43681877/article/details/126657412