• 【javase基础】第十四篇:深入浅出“多态与接口”



    在这里插入图片描述


    一.多态相关

    1.向上转型

    🌎向上转型的概念:父类调用子类对象

    class Animal{
        public String name;
        int age;
    
        public Animal(String name, int age) {
            this.name = name;
            this.age = age;
        }
    }
    class cat extends Animal{
    		public String color;
        public cat(String name,int age)
        {
            super(name,age);
        }
        public void eat()
        {
            System.out.println("吃");
        }
        
    }
    
    
    public class Review {
        public static void main(String[] args) {
            //父类调用子类对象
            Animal animal1=new cat("mimi",18);
            System.out.println(animal1.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
    • 26
    • 27
    • 28
    • 29
    • 30

    在这里插入图片描述

    2.向上转型发生的时机

    三种时机:1.直接赋值
    2.传参
    3.返回值

    public class Review {
            //父类接受
            public static void func(Animal animal1)
            {
                System.out.println(animal1.age);
            }
            public static Animal func1(){
                return new cat("david",16);
            }
            public static void main(String[] args) {
            //父类调用子类对象
            //1.直接赋值
            Animal animal1=new cat("mimi",18);
            //传参
            cat cat1=new cat("er",19);
            func(cat1);
            //返回值
            Animal animal=func1();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    3.运行时绑定

    🔥🔥上面的代码只有子类有eat方法,但是如果父类也有eat方法,则两个eat方法构成了重写。上面的图中提到向上转型是父类调用子类对象,但是父类只能调用父类本身被子类继承过去的成员(也就是父类本身自己的成员),那么按照推断。Animal animal=new cat(“mimi”,18);
    animal1.eat()应该调用自己本身的eat.打印“父类吃”。但结果却出人意料。请看下方截图

    class Animal{
        public String name;
        int age;
    
        public Animal(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        public void eat()
        {
            System.out.println("父类吃");
        }
    }
    class cat extends Animal{
        public String color;
        public cat(String name,int age)
        {
            super(name,age);
        }
        //重写父类方法
        public void eat()
        {
            System.out.println("吃");
        }
    
    }
    public class Review {
    
     public static void main(String[] args) {
             Animal animal1=new cat("mimi",18);
            animal1.eat();
            }
    
    • 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

    在这里插入图片描述

    总结:(1)发生运行时绑定的条件1.子类.父类具有同名的覆盖方法(重写)
    2.发生了向上转型
    (2)反编译角度在代码进行编译时确实是调用的父类自身的方法,但是在运行时却是实现的是子类的同名方法,这种现象叫做运行时绑定

    4.掌握“重写”用法

    1.重写的概念

    在子类中写一个和父类完全一样的方法就叫做重写

    class Animal{
        public String name;
        int age;
    
        public Animal(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        public void eat()
        {
            System.out.println("父类吃");
        }
    }
    class cat extends Animal{
        public String color;
        public cat(String name,int age)
        {
            super(name,age);
        }
        //重写
        public void eat()
        {
            System.out.println("吃");
        }
    
    }
    
    • 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

    2.重写的注意事项

    🌎1.需要重写的方法不能是被final修饰的,被final修饰的方法是密封的不能被修改
    2.被重写的方法,访问修饰限定符一定不能是private.(因为重写中子类的方法的访问权限不能低于父类的方法访问权限)
    3.被重写的方法,子类中的访问修饰限定要大于等于父类中的访问修饰限定
    4. 普通方法可以重写, static 修饰的静态方法不能重写.
    5.重写的方法返回值类型不一定和父类的方法相同(但是建议最好写成相同, 特殊情况除外).
    在这里插入图片描述

    //错误实例:
    public class Animal {
    public void eat(String food) {
    ...
    }
    }
    // Bird.java
    public class Bird extends Animal {
    // 将子类的 eat 改成 private
    private void eat(String food) {
    ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    5.重载与重写的区别

    在这里插入图片描述

    6.从代码层面理解“多态”

    1.基本理解:同一个实体同时具有多种形式,即同一个对象,在不同时刻,代表的对象不一样,指的是对象的多种形态。
    2.代码层面理解:什么时候发生多态:
    1.父类引用 引用子类对象
    2.父类和子类有同名的覆盖方法
    3.通过父类引用这个这个重写的方法

    class Shape{
        public void draw()
        {
            System.out.println("画一个图形");
        }
    }
    class Circle extends Shape{
        public void draw(){
            System.out.println("画一个圆");
        }
    }
    class React extends Shape{
        public void draw() {
            System.out.println("画一个方形");
        }
    }
    
    
    public class Review {
    		//向上转型的第二中的形式:传参
            public static void drawMap(Shape shape)
            {
                shape.draw();
            }
    
        public static void main(String[] args) {
        	//不同表现形式
            Shape shape1=new Circle();
            Shape shape2=new React();
            drawMap(shape1);
            drawMap(shape2);
        }
    
        }
    
    
    
    • 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

    七.opp三大特性归纳对比

    在这里插入图片描述

    二.抽象类及接口

    1.抽象类特点及使用方式

    1.含义:如果一个方法被abstract修饰则这个方法是抽象方法(抽象方法可以没有具体的实现)
    2.包含抽象方法的类叫做抽象类(抽象方法必须放在抽象类中)
    3.抽象类的主要作用就是用来继承的
    要点及注意事项如下:

    package bite;
    //抽象类一定不能被final修饰,因为final修饰的类是密封的,里面的方法不能被重写
    abstract class Shape{
        //当某个方法没有被实例化的必要。可以将他进行抽象化
        //抽象化的方法必须放在抽象类中
        //和其他类一样也可以添加成员变量,和普通类区分的唯一区别是类中有抽象方法
        //public String color;
    		int a=10;
        public abstract void draw();//并没有被具体应用
    
    }
    
    class circle extends Shape{
        //继承抽象类。必须先重写抽象类中的抽象方法
        //(除非子类也是抽象类,则第一次继承不用重写,第二次继承必须重写)
        @Override
        public void draw() {
            System.out.println("画一个⚪");
        }
    }
    class React extends Shape{
        @Override
        public void draw() {
            System.out.println("画一个正方形");
        }
    }
    class triangle extends Shape{
        @Override
        public void draw() {
        }
    }
    
    
    public class abstractFunc {
        //多态
        public static void drawMap(Shape shape)
        {
            shape.draw();
        }
        public static void main(String[] args) {
            //抽象类仍然可以发生向上转型
            //抽象类能不能被实例化,不能写成 Shape shape1=new Shape()
            Shape shape1=new circle();//不能实例化但可以向上转型
            drawMap(shape1);
            Shape shape2=new React();
            drawMap(shape2);
        }
    
    }
    
    
    • 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

    2.初识接口

    1.接口中的方法默认为,public abstract(接口中的方法必须是抽象方法)
    2.抽象方法不能被实例话,只能在子类继承中重写实现功能
    3.JDK1.8可以具体实现只需加上default
    4.接口中的变量默认为常量(public static final),必须赋初始值
    5.和抽象类一样,接口不能被实例化,但可以发生向上转型
    6.接口与类的关系(implentments(实现关系))
    7.接口的目的:解决java单根继承的问题(一个类虽然只能继承一个类,但却可以实现多个接口)
    8.类实现接口必须重写接口中方法(接口中方法都默认是抽象方法)
    8.只要类实现了接口,就可以利用接口向上转型,实现类的动作。

    package interfaceBite;
    //Shape 并没有包含别的非抽象方法, 也可以设计成一个接口
    //接口只有在继承后再能被间接使用
    interface Shape{
        //接口中的方法默认为,public abstract(接口中的方法必须是抽象方法)
        //抽象方法不能被实例话,只能在子类继承中重写实现功能
        //JDK1.8可以具体实现只需加上default
        //接口中的变量默认为常量(public static final)
        void draw();
         public static final int a=10;
    /*   default void color()
        {
            System.out.println("color");
        }
     */
    }
    //类实现接口必须重写当中的方法
    class Circle implements Shape{
        @Override
        public void draw() {
            System.out.println("画一个⚪");
        }
    }
    class React implements Shape{
        public void draw()
        {
            System.out.println("画一个正方形");
        }
    }
    
    public class interFace {
        public static void drawMap(Shape shape)
        {
            shape.draw();
        }
        public static void main(String[] args) {
            //Shape是接口不能出现Shape shape1=new Shape();这样的形式,因为它不能被实例化
            Shape shape1=new Circle();
            Shape shape2=new React();
            drawMap(shape1);
            drawMap(shape2);
        }
    }
    
    
    • 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

    3.理解接口

    接口一般是一个动作,类是一个发出动作的个体。类通过实现接口达到实现这个动作的目的

    package interfaceBite;
    //一个类
    class Animal{
        public  String name;
        public  Animal(String name)
        {
            this.name=name;
        }
    }
    //多个接口
    interface IFlying{
        void fly();
    }
    interface IRunning{
        void run();
    }
    interface ISwing{
        void swim();
    }
    //疑惑:我直接在子类中写一个run方法不行吗为什么用接口
    //答:比较方便:接口实现了以动作为主体,不管对象,
    // 只管是否可以完成这个动作
    class Cat extends Animal implements IRunning{
        public Cat(String name)
        {
            super(name);
        }
        public void run()
        {
            System.out.println("猫会跑");
        }
    }
    class Fish extends Animal implements ISwing{
        public Fish(String name) {
            super(name);
        }
    
        @Override
        public void swim() {
            System.out.println("乌龟会游");
        }
    }
    //extends和implements前后顺序不要变
    class Frog extends Animal implements IRunning,ISwing{
        public Frog(String name) {
            super(name);
        }
    
        @Override
        public void run() {
            System.out.println("青蛙会跑");
        }
    
        @Override
        public void swim() {
            System.out.println("青蛙会游");
        }
    }
    //上面的代码展示了 Java 面向对象编程中最常见的用法:
    // 一个类继承一个父类, 同时实现多种接口
    //不关心对象只关心谁可以完成这个动作
    public class understandInterface {
        public static void walk(IRunning running)
        {
            running.run();
        }
        //接口中方法的实例化不能由父类对象调用,必须由借口自己调用
        // (接口中的都为抽象方法)
        public static void main(String[] args) {
          IRunning running=new Cat("咪咪");
            IRunning running1=new Frog("青青");
            walk(running);
            walk(running1);
    
        }
    
    
    }
    
    
    • 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

    3.compare接口

    compare是java中自带的一种接口,里面有comareTo方法,我们通过改写compareTo方法决定判定标准。可能这么说还不够具体,请看下面的代码:

    import java.util.Arrays;
    
    class student implements Comparable<student>{
        String name;
        int age;
        int score;
        public student(String name,int age,int score)
        {
            this.name=name;
            this.age=age;
            this.score=score;
        }
    
        @Override
        public String toString() {
            return "student{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    ", score=" + score +
                    '}';
        }
    //一定要是可以比较的标准
        @Override
        public int compareTo(student o) {
            if (this.score>o.score)
            {
                return 1;
            }
            else if (this.score==o.score)
            {
                return 0;
            }
            else {
                return -1;
            }
        }
    }
    
    
    public class compares {
        public static void main(String[] args) {
            student stu1 = new student("里斯", 18, 90);
            student stu2 = new student("david", 19, 60);
            //if(stu1>stu2)此时不能比较,有多重标准。要用到compare
            //stu1调用compareTo所以他是主体,stu2 是o;
            if (stu1.compareTo(stu2) > 0) {
                System.out.println("student1的分数高");
            }
    
            student [] str={stu1,stu2};
            Arrays.sort(str);
            System.out.println(Arrays.toString(str));
        }
    }
    
    • 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

    如果直接比较if(stu1<stu2)是错误的,因为一个学生有姓名,年龄,分数。没有判定标准,我们需要重写compare中的方法,决定判定标准。
    看到如上代码要注意对应关系:stu1.compareTo(stu2),其中stu1,对应compareTo方法的this.score,stu2对应o.score.注意主客体关系
    在这里插入图片描述

  • 相关阅读:
    商业合作保密协议---技术开发
    26. 图论 - 树
    JavaScript-bind实现原理
    SpringBoot实现扫码登录
    DevComponents.DotNetBar2之SuperTabControl使用技巧
    数据导入与预处理-课程总结-01~03章
    Unity 之 安卓堆栈跟踪和日志工具 (Android Logcat | 符号表解析Bugly捕获)
    【无标题】
    sqlite3简单使用
    将树形结构的复杂数组转换为一维数组
  • 原文地址:https://blog.csdn.net/qq_61571098/article/details/125521532