首页 > 编程语言 >JAVA17/JAVA21接口和多态机制

JAVA17/JAVA21接口和多态机制

时间:2023-09-20 12:08:37浏览次数:57  
标签:JAVA21 JAVA17 void 多态 接口 class println Cat public

day08-JAVAOOP

课程目标

1. 【理解】什么是接口
2. 【掌握】接口的定义格式
3. 【掌握】接口的使用
4. 【理解】接口的成员特点
5. 【理解】类和接口 抽象类和接口之间的关系
6. 【掌握】单继承多实现 
7. 【理解】接口之间的多继承
8. 【掌握】接口的案例 
9. 【理解】什么是多态
10. 【理解】使用多态的前提
11. 【掌握】多态的格式
12. 【理解】多态中的成员访问特点
13. 【理解】多态中的好处和弊端
14. 【理解】多态中的转型
15. 【理解】转型的异常
16. 【掌握】综合案例

接口和多态.png

接口

接口基本概述及格式

接口概述

接口,是Java语言中一种引用类型,是方法的集合,如果说类的内部封装了成员变量、构造方法和成员方法,那么接口的内部主要就是封装了方法(功能),包含抽象方法 (JDK7及以前) , 默认方法和静态方法(JDK8)私有方法(JDK9)。

  • 总结

接口就是一种公共的规范标准,只要符合规范标准,大家都可以通用。

Java中的接口更多的体现在对行为的抽象!

接口定义格式

接口用关键字interface修饰

public interface 接口名 {} 

接口的使用

接口是不能创建对象,必须有实现类才能使用,类实现接口用implements表示

public class 类名 implements 接口名 {}

==注意: 接口的实现类必须重写接口中的所有的抽象方法,要么该类是一个抽象类==

接口成员的特点

成员变量

只能是常量,默认修饰符:public static final

成员方法

只能是抽象方法,默认修饰符:public abstract

构造方法

没有,因为接口主要是扩展功能的,而没有具体存在

代码演示

  • 接口
    public interface Inter {
        //接口只能是常量
        //默认修饰符:public static final
        public int num1 = 10;
        public final  int num2 = 20;
        public static final int num3 = 30;
        int num4 = 40;
    
        //接口没有构造方法
        // public Inter() {}
    
        //接口中不能有方法主体
        // public void show() {}
    
        //默认修饰符:public abstract 
        public abstract void method1();
    
        public void method2();
    
        void show();
    
    }
    
  • 实现类
    //子类可以是抽象类。但是意义不大
    public abstract class InterImpl extends Object implements  Inter {}
    
    /**
     *   字类是具体类,要实现接口中所有的抽象方法
     *   所有类都默认继承Object类,Object类是所有类的超类
     */
    public class InterImpl extends Object implements  Inter {
        public InterImpl(){
            super();//所有super走得是object类
        }
     
        @Override
        public void method1() {
            System.out.println("实现类中的method1");
    
        }
    
        @Override
        public void method2() {
            System.out.println("实现类中的method2");
    
        }
    
        @Override
        public void show() {
            System.out.println("实现类中的show");
        }
    }
    
  • 测试类
    public class Test {
        public static void main(String[] args) {
    
            //接口不能实例化
            // Inter i = new Inter();
    
            //通过多态的方法实
            Inter i = new InterImpl();
    
            //访问成员变量
            System.out.println(i.num1);
    
            //接口的常量是不能修改的
            // i.num1 = 100;
    
            i.method1();
            i.method2();
            i.show();
        }
    }
    

类与类的关系

类与类:
	继承关系,只能单继承,不能多继承,可以多层继承(Father son sun)。
	extends 	
接口与接口:
	继承关系,可以单继承也可以多继承。public interface Sister extends Father,Mother 
    
类与接口:
	实现关系,可以单实现,也可以多实现。 public class Son extends Object implements Father,Mother
	并且还可以在继承一个类的同时实现多个接口。

抽象类和接口的区别

A:成员区别
	抽象类:
		成员变量:可以变量,也可以常量
		构造方法:有
		抽象类不能实例化
		成员方法:可以抽象,也可以非抽象
	接口:
		成员变量:只可以静态常量  可以省略 static final
		构造方法:无
		接口不能实例化
		成员方法:默认是抽象的,可以省略abstract
B:关系区别
	类与类
		继承,单继承, 多层继承
	类与接口
		实现,单实现,多实现
	接口与接口
		继承,单继承,多继承

C:设计理念区别
	抽象类【共性功能】。一般父类抽象
	接口【扩展功能】。 方法集合

继承父类并实现多个接口

之前学过,在继承体系中,一个类只能继承一个父类。而对于接口而言,一个类是可以实现多个接口的,这叫做接口的多实现。并且,一个类能继承一个父类,同时实现多个接口。

多实现格式

class 类名 [extends 父类名] implements 接口名1,接口名2,接口名3... {    
    // 重写接口中抽象方法【必须】
    // 重写接口中默认方法【不重名时可选】
} 

代码演示

  • 定义接口
    interface A {
        public abstract void showA();   
        public abstract void show();
    }
    
    interface B {
        public abstract void showB();   
        public abstract void show();
    }
    
  • 定义父类
    public class Fu{}
    
  • 定义实现类
    public class C extends Fu implements A,B{
        @Override
        public void showA() {
            System.out.println("showA");    }
    
        @Override
        public void showB() {
            System.out.println("showB");    }
    
        @Override
        public void show() {
            System.out.println("show");    }
    }
    
  • ==注意事项==

    接口中,有多个抽象方法时,实现类必须重写所有抽象方法。如果抽象方法有重名的,只需要重写一次即可! 如果实现类继承了父类,这个父类是一个抽象类时,我们还需要再重写抽象类中的所有抽象方法。

接口默认方法

默认方法:使用 default 修饰,不可省略,供子类调用或者子类重写。

默认方法定义格式
public default 返回值类型  方法的名称(参数列表){
    方法体
}
默认方法的好处

接口的默认方法,实现类可以不用重写,默认方法可以用于接口升级

/**
 * @Auther: yanqi
 * @Desc   实现类没有没重写默认方法呢?
 *              接口中的抽象方法是必须要重写(实现)
 *              接口中的默认方法,不用重写,也可以手动重写,你默认方法存在的意义?
 *
 *              如果今后项目代码已以经写好,后期可能要扩展,接口中加新的方法(功能),如果你加抽象方法(功能)
 *              所有的实现类有影响,所以针对以上后期可能要扩展功能的话,代码的维护性比较差,出现了默认方法
 */
  • 定义接口

    public interface LiveAble {
        //接口的默认方法
        public default void fly(){ 
            System.out.println("天上飞"); 
        } 
    }
    
  • 定义实现类

    public class LiveAbleImpl implements LiveAble {    
        // default 可以选择是否重写,也可以根据实际需求进行重写
        /*
        	@Override
       		public void fly() {
            	System.out.println("自由自在的飞");   
            }
        */
    }
    
  • 定义测试类

    public class InterfaceDemo {
        public static void main(String[] args) {       
            // 创建子类对象 
            LiveAble a = new LiveAbleImpl();
            // 调用默认方法
            a.fly();
        }
    }
    

接口静态方法

静态方法:使用 static 修饰,供接口直接调用。

静态与.class文件相关,只能使用接口名调用,不可以通过实现类的类名或者实现类的对象调用

静态方法定义格式
public static 返回值类型 方法名称(参数列表){
    方法体
}
静态方法使用
  • 定义接口

    public interface LiveAble {
        //静态方法
        public static void show2(){
            System.out.println("静态方法-show2");
        }
    }
    
  • 定义实现类

    public class LiveAbleImpl implements LiveAble {    
      // 无法重写静态方法
    }
    
  • 定义测试类

    public class InterfaceDemo {
        public static void main(String[] args) {
            //无法调用
            // LiveAble l = new LiveAbleImpl();
            // l.show2();
            
            //接口名.静态方法(参数列表)
           LiveAble.show2();
        } 
    }
    

接口之间的多继承

一个接口能继承另一个或者多个接口,这和类之间的继承比较相似。接口的继承使用extends关键字,子接口继承父接口的方法。如果父接口中的默认方法有重名的,那么子接口需要重写一次。

  • 定义父接口
    interface A {
        public void method1();
    }
    
    interface B {
        public void method2();
    }
    
  • 定义子接口
    interface D extends A,B{
         public void method2();
    }
    
  • ==注意==
    接口多继承之后,如果想使用,我们还必须定义实现类,才能使用
    

接口小结

  • 接口中只有常量和抽象方法 、默认方法、静态方法、私有方法
  • 接口是没有静态代码块和构造方法的。
  • 一个类的直接父类是唯一的,但是一个类可以同时实现多个接口。 单继承多实现
    public class MyInterfaceImpl implements MyInterfaceA, MyInterfaceB {
        // 覆盖重写所有抽象方法
    }
    
  • 如果实现类所实现的多个接口当中,存在重复的抽象方法,那么只需要覆盖重写一次即可。
  • 如果实现类没有覆盖重写所有接口当中的所有抽象方法,那么实现类就必须是一个抽象类。
  • 如果实现类,同时继承父类,实现接口,父类和接口的方法名、访问权限、返回类型都一样,则“类优先”原则。

接口案例-TODO

  • 需求

    对猫和狗进行训练,他们就可以跳高了,这里加入跳高功能。

    请采用抽象类和接口来实现猫狗案例,并在测试类中进行测试。

  • 代码实现
    • Animal类
      public abstract class Animal {
          private String name;
          private int age;
      
          public Animal() {
          }
      
          public Animal(String name, int age) {
              this.name = name;
              this.age = age;
          }
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      
          public int getAge() {
              return age;
          }
      
          public void setAge(int age) {
              this.age = age;
          }
      
          public abstract void eat();
      }
      
    • 跳高接口Jumping
      public interface Jumpping {
          public abstract void jump();
      }
      
    • 猫类(Cat)
      //子类继承 抽象类,实现接口
      public class Cat extends Animal implements Jumpping {
      
          public Cat() {
          }
      
          public Cat(String name, int age) {
              super(name, age);
          }
      
          @Override
          public void eat() {
              System.out.println("猫吃鱼");
          }
      
          @Override
          public void jump() {
              System.out.println("猫可以跳高了");
          }
      }
      
    • 测试类
      public class AnimalDemo {
          public static void main(String[] args) {
              Cat c = new Cat();
              c.setName("加菲");
              c.setAge(5);
              System.out.println(c.getName()+","+c.getAge());
              c.eat();
              c.jump();
          }
      }
      

多态

什么是多态

多态是继封装、继承之后,面向对象的第三大特性。

生活中,比如跑的动作,小猫、小狗和大象,跑起来是不一样的。再比如飞的动作,昆虫、鸟类和飞机,飞起来也是不一样的。可见,同一行为,通过不同的事物,可以体现出来的不同的形态。多态,描述的就是这样的状态。

  • 定义:同一个对象,在不同时刻表现出来的形态是不同的

多态的前提

- 要有继承或实现关系
- 要有方法的重写
- 要有父类引用指向子类对象   fu  f = new zi();

多态格式

  • 普通类多态的格式

    父类 对象 = new 子类();

  • 抽象类多态的格式

    抽象类 对象名 = new 抽象类子类();

  • 接口多态的格式

    接口 对象名 = new 接口实现类();

多态中的成员访问特点

成员变量

编译看左边(父类),运行看左边(父类)

成员方法

编译看左边(父类),运行看右边(子类)

代码演示

  • 动物类(Animal)
    public class Animal {
        public int age = 40;
    
        public void eat() {
            System.out.println("动物吃东西");
        }
    }
    
  • 猫类(Cat)
    public class Cat extends Animal {
        public int age = 20;
        public int weight = 10;
    
        //子类要重写父类中的方法
        @Override
        public void eat() {
            System.out.println("猫吃鱼");
        }
    
        public void playGame() {
            System.out.println("猫捉迷藏");
        }
    }
    
  • 测试类
    public class AnimalDemo {
        public static void main(String[] args) {
            //有父类引用指向子类对象
            Animal a = new Cat();
    
          	//成员变量
            //编译看左边(父类),运行看左边(父类)
            System.out.println(a.age);
            // System.out.println(a.weight);
    
            //成员方法
            //编译看左边(父类),运行看右边(子类)
            a.eat();
            // a.playGame();
        }
    }
    

多态的好处和弊端

多态的好处

提高程序的扩展性。定义方法时候,使用父类型作为参数,在使用的时候,使用具体的子类型参与操作

多态的弊端

不能使用子类的特有成员

多态的好处代码演示

实际开发的过程中,父类类型作为方法形式参数,传递子类对象给方法,进行方法的调用,更能体现出多态的扩展性与便利

  • 定义父类
    public abstract class Animal {      
        public abstract void eat();
    }  
    
  • 定义子类
    class Cat extends Animal {  
        public void eat() {  
            System.out.println("吃鱼");  
        }  
    }  
    
    class Dog extends Animal {  
        public void eat() {  
            System.out.println("吃骨头");      }  
    }
    
  • 定义测试类
    public class Test {
        public static void main(String[] args) {        // 多态形式,创建对象
            Cat c = new Cat();  
            Dog d = new Dog(); 
    
            // 调用showCatEat 
            showCatEat(c);
            // 调用showDogEat 
            showDogEat(d); 
    
            /*
           	 多态的好处: 
           	 以上两个方法, 均可以被showAnimalEat(Animal a)方法所替代,而执行效果一致
            */
            showAnimalEat(c);
            showAnimalEat(d); 
        }
    
        public static void showCatEat (Cat c){
            c.eat(); 
        }
    
        public static void showDogEat (Dog d){
            d.eat();
        } 
    
        public static void showAnimalEat (Animal a){
            a.eat();
        }
    }
    

多态的好处小结

​ 由于多态特性的支持,showAnimalEat方法的Animal类型,是Cat和Dog的父类类型,父类类型接收子类对象,当然可以把Cat对象和Dog对象,传递给方法。当eat方法执行时,多态规定,执行的是子类重写的方法,那么效果自然与showCatEat、showDogEat方法一致,

​ 所以showAnimalEat完全可以替代以上两方法。

​ 不仅仅是替代,在扩展性方面,无论之后再多的子类出现,我们都不需要编写showXxxEat方法了,直接使用showAnimalEat都可以完成。

​ 所以,多态的好处,体现在,可以使程序编写的更简单,并有良好的扩展。

多态中的转型

为什么要用转型

当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误。也就是说,不能调用子类拥有,而父类没有的方法。编译都错误,更别说运行了。这也是多态给我们带来的一点"小麻烦"。所以,想要调用子类特有的方法,必须做向下转型。

向上转型

多态本身是子类类型向父类类型向上转换的过程,这个过程是默认的。

父类:Pet

^

|

子类:Pig Tiger Monkey

  • 使用格式
    向上转型
    父类类型  变量名 = new 子类类型();
    如:Animal a = new Cat();
    

向下转型

父类类型向子类类型向下转换的过程,这个过程是强制的。

一个已经向上转型的子类对象,将父类引用转为子类引用,可以使用强制类型转换的格式,便是向下转型。

  • 使用格式
    子类类型 变量名 = (子类类型) 父类变量名;
    如:Cat c =(Cat) a;  
    

代码演示

  • 定义类
    abstract class Animal {  
        abstract void eat();  
    }  
    
    class Cat extends Animal {  
        public void eat() {  
            System.out.println("吃鱼");  
        }  
        public void catchMouse() {  
            System.out.println("抓老鼠");      
        }  
    }  
    
    class Dog extends Animal {  
        public void eat() {  
            System.out.println("吃骨头");     
        }  
        public void watchHouse() {  
            System.out.println("看家");  
        }  
    }
    
  • 测试类
    public class Test {
        public static void main(String[] args) {
            // 向上转型     fu f = new zi()
            Animal a = new Cat();  
            a.eat();                // 调用的是 Cat 的 eat
    
            // 向下转型    猫c,抓老鼠;
            Cat c = (Cat)a;       
            c.catchMouse();         // 调用的是 Cat 的 catchMouse     
        }
    }  
    

转型的异常

问题描述

转型的过程中,一不小心就会遇到这样的问题,请看如下代码:

 public class Test {
    public static void main(String[] args) {
        // 向上转型  
        Animal a = new Cat();  
        a.eat();        // 调用的是 Cat 的 eat
        
        // 向下转型 
        Cat c = (Cat)a;
        c.catchMouse();//调用自己的方法
        System.out.println("================");
 
        // 向下转型  
        Dog d = (Dog)a;       //引用的父类,是多态cat类,并不是dog
        d.watchHouse();        // 调用的是 Dog 的 watchHouse 【运行报错】    
    }  
}

这段代码可以通过编译,但是运行时,却报出了ClassCastException类型转换异常!这是因为,明明创建了

Cat类型对象,运行时,当然不能转换成Dog对象的。这两个类型并没有任何继承关系,不符合类型转换的定义。

为了避免ClassCastException的发生,Java提供了instanceof关键字,给引用变量做类型的校验,格式如下:

instanceof使用格式

变量名 instanceof 数据类型 
    如果变量属于该数据类型,返回true。
    如果变量不属于该数据类型,返回false。

instanceof代码演示

public class Test {
    public static void main(String[] args) {
        // 向上转型  
        Animal a = new Cat();  
        a.eat();               // 调用的是 Cat 的 eat

        // 向下转型  
        if (a instanceof Cat){
            Cat c = (Cat)a;       
            c.catchMouse();        // 调用的是 Cat 的 catchMouse        
        } else if (a instanceof Dog){
            Dog d = (Dog)a;       
            d.watchHouse();       // 调用的是 Dog 的 watchHouse
        }
    }  
}

综合案例-TODO

案例需求

我们现在有乒乓球运动员和篮球运动员,乒乓球教练和篮球教练。

​ 为了出国交流,跟乒乓球相关的人员都需要学习英语。

​ 请用所学知识分析,这个案例中有哪些具体类,哪些抽象类,哪些接口,并用代码实现。

01

代码实现

  • Person类
    public abstract class Person {
        private String name;
        private int age;
    
        public Person() {
        }
    
        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public abstract void eat();
    }
    
  • 抽象运动员类(Player)
    public abstract class Player extends Person {
        public Player() {
        }
    
        public Player(String name, int age) {
            super(name, age);
        }
    
        public abstract void study();
    }
    
  • 抽象教练类(Coach)
    public abstract class Coach extends Person {
        public Coach() {
        }
    
        public Coach(String name, int age) {
            super(name, age);
        }
    
        public abstract void teach();
    }
    
  • 学英语接口(SpeakEnglish)
    public interface SpeakEnglish {
        public abstract void speak();
    }
    
  • 蓝球教练(BasketballCoach)
    public class BasketballCoach extends Coach {
        public BasketballCoach() {
        }
    
        public BasketballCoach(String name, int age) {
            super(name, age);
        }
    
        @Override
        public void teach() {
            System.out.println("篮球教练教如何运球和投篮");
        }
    
        @Override
        public void eat() {
            System.out.println("篮球教练吃羊肉,喝羊奶");
        }
    }
    
  • 乒乓球教练(PingPangCoach)
    public class PingPangCoach extends Coach implements SpeakEnglish {
    
        public PingPangCoach() {
        }
    
        public PingPangCoach(String name, int age) {
            super(name, age);
        }
    
        @Override
        public void teach() {
            System.out.println("乒乓球教练教如何发球和接球");
        }
    
        @Override
        public void eat() {
            System.out.println("乒乓球教练吃小白菜,喝大米粥");
        }
    
        @Override
        public void speak() {
            System.out.println("乒乓球教练说英语");
        }
    }
    
  • 乒乓球运动员(PingPangPlayer)
    public class PingPangPlayer extends Player implements SpeakEnglish {
        public PingPangPlayer() {
        }
    
        public PingPangPlayer(String name, int age) {
            super(name, age);
        }
    
        @Override
        public void study() {
            System.out.println("乒乓球运动员学习如何发球和接球");
        }
    
        @Override
        public void eat() {
            System.out.println("乒乓球运动员吃大白菜,喝小米粥");
        }
    
        @Override
        public void speak() {
            System.out.println("乒乓球运动员说英语");
        }
    }
    
  • 篮球运动员(BasketballPlayer)
    public class BasketballPlayer extends Player {
        public BasketballPlayer() {
        }
    
        public BasketballPlayer(String name, int age) {
            super(name, age);
        }
    
        @Override
        public void study() {
            System.out.println("篮球运动员学习如何运球和投篮");
        }
    
        @Override
        public void eat() {
            System.out.println("篮球运动员吃牛肉,喝牛奶");
        }
    }
    

标签:JAVA21,JAVA17,void,多态,接口,class,println,Cat,public
From: https://blog.51cto.com/teayear/7535757

相关文章

  • 类,封装,继承,多态
    Student.java学生类:importjava.util.Objects;importjava.util.Scanner;publicclassStudent{staticintage;staticStringid,subject;staticStringname="张晗";//name="张晗"//非法,因为在class类中,赋值操作语句只允许在成员函数中才可......
  • JAVA17/JAVA21继承和抽象类
    day07-JAVAOOP课程目标1.【理解】什么是继承2.【掌握】继承的使用3.【理解】继承中的成员的特点4.【理解】super和this的作用5.【理解】什么是抽象类6.【掌握】抽象的使用继承继承概述​ 多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,这个类就是......
  • 封装,继承,多态(下)
    8.5多态一个对象可以有多种形态。一个对象现在可以是学生类的对象,也可是老师类的对象。要形成多态必须是父类对象中存放子类的实例,用父类对象去调用子类重写的方法。语法:父类对象名=new子类();例如:QianFengstu=newStudent();QianFengtea=newTeacher();类图,可以反映出一......
  • 封装,继承,多态(上)
    8.1封装将一系列零碎的代码用方法的形式把它组装在一起形成一个完整的功能就是封装(这是广义的封装)。狭义的封装,就是将以前对类的成员变量的赋值取值操作把它们放到方法中去,用方法的方式来实现赋值和取值。Peoplezhangpeng=newPeople();zhangpeng.name="张鹏";......
  • 多态
                ......
  • JAVA17/JAVA21方法精讲
    day05_java基础课程目标1.【理解】什么是方法2.【掌握】方法的格式3.【理解】方法的执行流程4.【掌握】方法的案例5.【理解】方法的重载6.【理解】方法参数的传递方法概述什么是方法方法(method)完成某一个特定功能的代码块方法基本使用将资料中给大家提供的打......
  • Go语言实现多态
    1.什么是多态多态是指根据类型的具体实现采取不同行为的能力。如果某个类型实现了某个接口,那么所有使用这个接口的地方,都可以支持这种类型的值。即不同的数据类型的实体实现提供统一的接口。Go中没有类的概念,它的多态是靠接口来实现的。2.在Go中的实现先定义一个抽象的接口,这个......
  • Java 继承与多态
    1.子类与父类子类:由其他类派生出来的类,父类:包含一些共同特征。子类继承父亲的所有非私有成员。子类只能继承一个父亲子类可以直接调用父类的非私有方法。2.继承语法extendpublicclassMargicionextendsRole{@Overridepublicvoidshowfight(){Sys......
  • Java21虚拟线程的注意点
    Java21虚拟线程的注意点ThreadLocal能继续用么?Java开发组设计虚拟线程的时候,原本想去掉对ThreadLocal的支持。但由于使用它的库太多,并且很多为了传参才用,并不是缓存,所以就保持了支持。像隐式传参的这种场景,继续用也没事儿,就是性能有所损耗。(不会影响GC,生命周期随着虚拟线程......
  • 多态
     在面向对象的程序设计中,使用多态能够增强程序的可扩充性,即程序需要修改或增加功能时,只需改动或增加较少的代码。此外,使用多态也能起到精简代码的作用。多态优点代码组织结构清晰可读性强利于前期和后期的扩展以及维护  初识多态1#include<iostream>2using......