【接口、多态】

【接口、多态】

接口

接口概述和生活举例

生活中的接口举例:电源插座当中的电源接口。

接口就是一种公共的规范标准。

只要符合规范标准,就可以大家通用。

在计算机中,有USB接口。只要符合USB接口规范,那么各种设备都可以使用。

U盘、打印机、夜读灯、USB小风扇…

接口的定义基本格式

接口就是多个类的公共规范,是一种引用数据类型,最重要的内容就是其中的:抽象方法。

接口的格式:

public Interface 接口名称{

​ //接口内容

}

备注:换成了关键字interface之后,编译生成的字节码文件仍然是:.java --> .class。

如果是Java 7,那么接口中可以包括的内容有:常量、抽象方法。

如果是Java 8,还可以额外包含有:默认方法、静态方法。

如果是Java 9,还可以额外包含有:私有方法。

接口的抽象方法

接口的抽象方法定义

在任何版本的Java中,接口都能定义抽象方法。

格式:

public abstract 返回值类型 方法名称(参数列表);

注意事项:

  • 1.接口当中的抽象方法,修饰符必须是两个固定的关键字:public abstract。
  • 2.这两个关键字修饰符,可以选择性地省略。
  • 3.方法的三要素,可以随意定义。
public interface MyInterfaceAbstract {
    //这是一个抽象方法
    public abstract void methodAbstract1();
    //这也是一个抽象方法
    public String methodAbstract2();
    //这也是一个抽象方法
    abstract  int methodAbstract3(int num);
    //这也是一个抽象方法
    boolean methodAbstract3(String str);
}
接口的抽象方法使用

接口使用的步骤:

  • 1.接口不能直接使用,必须有一个“实现类”来“实现”该接口。

    • 格式:

    public class 实现类名称 implements 接口名称{

    ​ //…

    }

  • 2.接口的实现类必须覆盖重写(实现)接口中的所有抽象方法。

    • 实现:去掉abstract关键字,加上方法体大括号及内容
  • 3.创造实现类的对象,进行使用。

注意事项:

如果实现类中没有对接口中的所有抽象方法进行实现,那么这个实现类必须是抽象类,否则会报错。

public interface MyInterfaceAbstract {
    //这是一个抽象方法
    public abstract void methodAbstract1();
}
public class MyInterfaceAbstractImpl implements MyInterfaceAbstract {
    @Override
    public void methodAbstract1(){
        System.out.println("抽象方法1实现");
    }
}
public class Interface01 {
    public static void main(String[] args) {
        MyInterfaceAbstractImpl impl = new MyInterfaceAbstractImpl();
        impl.methodAbstract1();//抽象方法1实现
    }

}

接口的默认方法

接口的默认方法定义

从Java 8开始,接口里允许定义默认方法。

格式:

public default 返回值类型 方法名称(参数列表){

​ 方法体

}

备注:接口当中的默认方法,可以解决接口升级的问题。

接口的默认方法的使用
  • 1.接口的默认方法,可以通过接口实现类对象,直接调用
  • 2.接口的默认方法,也可以被接口实现类进行覆盖重写

接口的静态方法

接口的静态方法定义

从Java 8开始,接口里允许定义静态方法。

格式:

public static 返回值类型 方法名称(参数列表){

​ 方法体

}

提示:就是将abstract或者default换成static即可,带上方法体。

接口的静态方法使用

**注意事项:**不能通过接口实现类的对象来调用接口当中的静态方法。

**正确用法:**通过接口名称,直接调用其中的静态方法。

格式:

接口名称.静态方法();

public interface MyInterfaceStatic {
    public static void methodStatic(){
        System.out.println("这是接口的静态方法!");
    }
}
public class Interface02 {
    public static void main(String[] args) {
        MyInterfaceStatic.methodStatic();
    }
}

接口的私有方法定义及内部使用

问题描述:

我们需要抽取一个公有方法,用来解决两个默认方法之间重复代码问题。

但是这个共有方法不应该让实现类使用,应该是私有化的。

解决方案:

从Java 9开始,接口当中允许定义私有方法。

1.**普通私有方法:**解决多个默认方法之间重复代码的问题

格式:

private 返回值类型 方法名称(参数类型){

​ 方法体

}

2.**静态私有方法:**解决多个静态方法之间代码重复的问题

格式:

private static 返回值类型 方法名称(参数类型){

​ 方法体

}

public interface MyInterfacePrivate {
    private void methodPrivateForDefault() {
        System.out.println("默认方法的私有方法");
    }
    
    public default void methodDefault1() {
        System.out.println("默认方法1");
        methodPrivateForDefault();
    }

    public default void methodDefault2() {
        System.out.println("默认方法2");
        methodPrivateForDefault();
    }
    
    private static void methodPrivateForStatic(){
        System.out.println("静态方法的默认方法");
    }
    
    public static void methodStatic1(){
        System.out.println("静态方法1");
        methodPrivateForStatic();
    }
    
    public static void methodStatic2(){
        System.out.println("静态方法2");
        methodPrivateForStatic();
    }
}

接口的常量定义和使用

接口当中也可以定义"成员变量",但是必须使用public static final三个关键字进行修饰。

从效果上看,这其实就是接口的【常量】。

格式:

public static final 数据类型 常量名称 = 数据值;

备注:一旦使用final关键字修饰,说明不可改变。

注意事项:

  • 1.接口当中的常量,可以忽略public static final,注意:不写也照样是这样。
  • 2.接口当中的常量,必须进行赋值,不能不赋值。
public interface MyInterfaceConst {
    public static int NUM = 12;
}
public class Interface03 {
    public static void main(String[] args) {
        System.out.println(MyInterfaceConst.NUM);//12
    }
}

接口内容小结

在Java 9+版本中,接口的内容可以有:

  • 1.成员变量其实是常量,格式:
    • public static final 数据类型 常量名称 = 数据值;
    • 注意:
      • 常量必须进行赋值,而且一旦赋值不能改变;
      • 变量名称完全大写,用下划线将每个单词进行分隔。
  • 2.接口中最重要的就是抽象方法,格式:
    • public abstract 返回值类型 方法名称(参数列表);
    • 注意:实现类必须覆盖重写接口所有的抽象方法,除非实现类是抽象类。
  • 3.接口里允许定义默认方法,格式:
    • public default 返回值类型 方法名称(参数列表){方法体}
    • 注意:默认方法也可以被覆盖重写。
  • 4.接口里允许定义静态方法,格式:
    • public static 返回值类型 方法名称(参数列表){方法体}
    • 注意:应该通过接口名称进行赋值,不能通过实现类对象调用接口静态方法。
  • 5.接口里允许定义私有方法,格式:
    • 普通私有方法:private 返回值类型 方法名称(参数列表){方法体}
    • 静态私有方法:private static 返回值类型 方法名称(参数列表){方法体}
    • 注意:private的方法只有接口自己才能使用,不能被实现类或别人调用。

接口注意事项

  • 1.接口是没有静态代码块或者构造方法的。

  • 2.一个类的直接父类是唯一的,但是一个类可以同时实现多个接口。

    • 格式:

      public class 实现类名称 implements 接口名称1,接口名称2…{

      ​ //覆盖重写所有抽象方法

      }

  • 3.如果实现类所实现的多个接口当中,存在你重复的抽象方法,那么只需要覆盖重写一次即可。

  • 4.如果实现类没有覆盖重写所有接口当中的所有抽象方法,那么实现类必须是抽象类。

  • 5.如果实现类所实现的多个接口当中,存在重复的默认方法,那么实现类一定要对冲突的默认方法进行覆盖重写。

  • 6.一个类如果直接父类当中的方法,与接口当中的默认方法产生了冲突,优先用父类当中的方法。

接口之间的多继承

  • 1.类与类之间是单继承的,直接父类只有一个。
  • 2.类与接口之间是多实现的。一个类可以实现多个接口。
  • 3.接口与接口之间是多继承的。
    • 注意事项:
      • 1.多个父接口当中的抽象方法如果重复,没有关系。
      • 2.多个父接口当中的默认方法如果重复,继承的子接口必须对默认方法覆盖重写。
public interface InterfaceFu1 {
    public abstract void methodA();
    public abstract void method();

    public default void methodDefault(){
        
    }

}
public interface InterfaceFu2 {
    public abstract void methodB();
    public abstract void method();

    public default void methodDefault(){

    }

}
public interface InterfaceZi extends InterfaceFu1,InterfaceFu2 {
//    现在,InterfaceZi接口中,有三个继承下来的抽象方法:methodA、methodB、method;
//    有一个自己创建的抽象方法:methodC;
//    对父接口中继承的重名的默认方法进行了覆盖重写。
    public abstract void methodC();
    @Override
    default void methodDefault() {

    }
}

多态

面向对象的三大特征:封装性、继承性、多态性。

extends继承或者implements实现,是多态性的前提。

(类与类之间的继承,接口与接口之间的继承,类与接口之间的实现等。)

小明是一个学生,但同时也是一个人。

小明是一个对象,这个对象既有学生形态,也有人类形态。

一个对象拥有多种形态,这就是:对象的多态性。

多态的格式和使用

代码当中体现多态性,其实就是一句话,父类引用指向子类对象。

格式:

父类名称 对象名 = new 子类名称();

或者:

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

public class Fu {
    public void mtehod(){
        System.out.println("父类成员方法");
    }
    public void methodFu(){
        System.out.println("父类成员方法");
    }
}
public class Zi extends Fu {
    @Override
    public void mtehod() {
        System.out.println("子类成员方法");
    }
}
public class Polymorphism {
    public static void main(String[] args) {
        Fu obj = new Zi();//体现了多态性
        obj.mtehod();//子类成员方法
        obj.methodFu();//父类成员方法
    }
}

多态中成员变量的使用特点

  • 直接通过子类对象访问成员变量
    • 创建时等号左边是谁,就优先用谁,没有则向上(向父类)找
  • 间接通过成员方法访问成员变量
    • 方法属于谁,就优先用谁,没有则向上找

多态中成员方法的使用特点

在多态的代码当中,访问成员方法的规则:

  • 创建的对象是谁,就优先用谁的方法,没有就向上找

使用多态的好处

假设有员工类(Employee),其中有一个名叫work的抽象方法。

创建员工类的两个子类,一个子类叫讲师类(Teacher),对work抽象方法进行实现,方法体为:讲课。

另一个子类叫做助教类(Assistant),对work抽象方法进行实现,方法体为:辅导。

如果不用多态,只用子类,那么写法为:

Teacher teacher = new Teacher();

teacher.work();//讲课

Assistant assistant = new Assistant();

assistant.work();//辅导

我现在唯一想要做的事,就是调用work方法,其他的功能不关心。

如果使用多态的写法,对比一下:

Employee teacher = new Teacher();

teacher.work();//讲课

Employee assistant = new Assistant();

assistant.work();//辅导

好处,无论右边new的时候换成哪个子类对象,等号左边调用方法都不会改变。

对象的向上转型

对象的向上转型,其实就是多态写法:

格式:父类名称 对象名称 = new 子类名称(); 例如:Animal animal = new Cat();

含义:右侧创建了一个子类的对象,把它当做父类来看待使用 创建了一只猫,当做动物看待

注意事项:**向上转型一定是安全的。**从小范围转向了大范围,从小范围的猫,向上转换成为更大范围的动物。

对象的向下转型

对象的向上转型一定是安全的,没有问题的,正确的。但是也有一个弊端:

对象一旦向上转型为父类,那么就无法调用子类原本特有的内容。

解决方案:用对象的向下转型【还原】。

对象的向下转型,其实是一个【还原】的动作。

格式:子类名称 对象名称 = (子类名称)父类对象;

含义:将父类对象,【还原】成为本来的子类对象。

public abstract class Animal {
    abstract void eat();
}
public class Cat extends Animal {
    @Override
    public void eat(){
        System.out.println("猫吃鱼!");
    }
    public void catchMouse(){
        System.out.println("猫抓老鼠!");
    }
}
public class Main01 {
    public static void main(String[] args) {
        Animal animalCat = new Cat();//本来是猫,向上转型成为动物。
        animalCat.eat();//猫吃鱼!
        Cat cat = (Cat)animalCat;//本来是猫,已经被当做动物了,还原回来成为本来的猫。
        cat.catchMouse();//猫抓老鼠!
    }
}

注意事项:

  • 1.必须保证对象本来创建的时候,就是猫,才能向下转型成为猫;
  • 2.如果对象创建的时候本来不是猫,现在非要向下转型为猫,就会报错。

关键字instanceof

如何才能知道 一个父类引用的对象,本来是什么子类?

格式:

对象 instanceof 类名称

这将会得到一个boolean值结果,也就是判断前面的对象能不能当做后面类型的实例。

public class Instanceof01 {
    public static void main(String[] args) {
        Animal animalCat = new Cat();//本来是一只猫
        animalCat.eat();//猫吃鱼

        //判断一下父类引用animalCat本来是不是Cat
        if(animalCat instanceof Cat){
            Cat cat = (Cat)animalCat;
            cat.catchMouse();//猫抓老鼠
        }
    }
}

笔记本USB接口案例

//创建USB接口
public interface USB {
    public abstract void openDevice();
    public abstract void closeDevice();

}
//创建USB接口的键盘实现类
public class Keyboard implements USB {

    @Override
    public void openDevice() {
        System.out.println("打开键盘设备");
    }

    @Override
    public void closeDevice() {
        System.out.println("关闭键盘设备");
    }
    //键盘特有的方法
    public void type(){
        System.out.println("键盘打字输入");
    }
}
//创建USB接口的鼠标实现类
public class Mouse implements USB {
    @Override
    public void openDevice() {
        System.out.println("打开鼠标设备");
    }

    @Override
    public void closeDevice() {
        System.out.println("关闭鼠标设备");
    }
	//鼠标特有的方法
    public void click(){
        System.out.println("鼠标点击输入");
    }
}
//创建笔记本类
public class Computer {

    public void openComputer(){//电脑的开机,成员方法
        System.out.println("开机");
    }
    public void closeComputer(){//电脑的关机,成员方法
        System.out.println("关机");
    }
    public void useDevice(USB usb){//电脑的使用USB设备,成员方法
        usb.openDevice();
        if (usb instanceof Keyboard){//先判断
            Keyboard keyboard = (Keyboard) usb;//向下转型为键盘类
            keyboard.type();
        }else if(usb instanceof Mouse){
            Mouse mouse = (Mouse) usb;//向下转型为鼠标类
            mouse.click();
        }
        usb.closeDevice();

    }
}
//创建Computer类的对象
public class MyComputer {
    public static void main(String[] args) {
        Computer myComputer = new Computer();//创建电脑对象
        myComputer.openComputer();//开机

        USB mouse = new Mouse();//对象向上转型
        myComputer.useDevice(mouse);
        //打开鼠标设备
        //鼠标点击输入
        //关闭鼠标设备
        USB keyboard = new Keyboard();//对象向上转型
        myComputer.useDevice(keyboard);
        //打开键盘设备
        //键盘打字输入
        //关闭键盘设备

        myComputer.closeComputer();//关机
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值