第七章-----多态和接口 抽象类

1.内容回顾

2.本章重点

2.1.多态

2.2.抽象类和抽象方法

2.3.接口

3.具体内容

3.1.多态

3.1.1.什么是多态

多态(Polymorphism)按字面的意思就是“多种状态”。在面向对象语言中,接口的多种不同的实现方式即为多态。引用Charlie Calverts对多态的描述——多态性是允许你将父对象设置成为一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作(摘自“Delphi4 编程技术内幕”)。简单的说,就是一句话:允许将子类类型赋值给父类类型。

多态的前提是继承和方法重写。

多态是父类对象表现多种子类的形态的能⼒的特征。⼀句话多态就是⽗类引⽤⼦类对象。 向同⼀个⽗类的不同⼦类发送同⼀条消息,⾏为不同

对于父类中的一个方法,在不同子类中有不同的实现。父类引用子类对象,调用父类被重写的方法时,子类有不同的响应。

3.1.2.为什么使用多态

实现程序设计的开-闭原则,对扩张开放,对修改关闭

3.1.3.如何实现多态

1).继承:子类继承父类

2).重写:子类方法重写父类方法

3).向上转型:父类引用指向子类对象

4).调用父类被重写的方法时,不同的子类效果不同

实例:主人喂养宠物

public class Pet {
    // 访问修饰符:public protected 默认 private
    // protected:1.同包内的类都可以访问 2.不同包的子类可以访问
    protected  String name;
    protected  String color;
    public Pet(String name, String color) {
        this.name = name;
        this.color = color;
    }
    public void eat(){
        System.out.println("宠物吃");
    }
}
public class Cat extends Pet{
    public Cat(String name, String color) {
        super(name, color);
    }
    // 重写方法
    @Override
    public void eat() {
        System.out.println(this.color+"的"+this.name+"吃小鱼");
    }
    public void catchMouse(){
    }
}
public class Dog  extends  Pet{
    // alt+enter 修复错误  alt+insert 生成代码
    public Dog(String name, String color) {
        super(name, color);
    }
    @Override
    public void eat() {
        System.out.println(this.color+"的"+this.name+"吃骨头");
    }
}
public class Test2 {
    public static void main(String[] args) {
        /*Cat cat = new Cat("花花","白色");
        Dog dog = new Dog("旺财","黄色");
        Turtle turtle = new Turtle("龟丞相","黑色");
        Parrow p = new Parrow("八阿哥","绿色");*/
        Pet p1 = new Cat("花花","白色");
        Pet p2 = new Dog("旺财","黄色");
        Pet p3 = new Turtle("龟丞相","黑色");
        Pet p4 = new Parrow("八阿哥","绿色");
        Pet p5 = new Snake("竹叶青","青色");
        Master m = new Master("小明");
        m.feed(p1);
        m.feed(p2);
        m.feed(p3);
        m.feed(p4);
        m.feed(p5);
    }
}

3.1.4 向上转型/向下转型

向上转型:⽗类引⽤⼦类对象(⾃动成⽴,缺点是失去调⽤⼦类独有⽅法的能⼒)

向下转型:⼦类引⽤⽗类对象(强制转换,慎重) ,需要使用instanceof进行类型判断

public static void main(String[] args) {
    // 父类变量指向子类对象: 向上转型(装箱)
    Pet p1 = new Cat("花花","白色");
    Pet p2 = new Dog("旺财","黄色");
    // 父类变量指向对象,此时只能通过父类变量访问父类中定义的内容,子类的东西是访问不到的
    // 向上转型之后,子类的细节被屏蔽
    // 如果想要访问子类的内容,需要进行向下转型(拆箱)
    // 向下转型不安全
    /*Cat cat =  (Cat)p1;
    cat.eat();
    Dog dog = (Dog) p1;
    dog.eat();*/
    // 向下转型时可以通过instanceof(返回true/false) 关键字测试父类指向的对象类型
    // 测试p1指向的对象是否是Cat类型的对象
    if(p1 instanceof Cat){
        Cat cat = (Cat) p1;
        cat.eat();
        cat.catchMouse();
    }
    if(p1 instanceof  Dog){
        Dog dog = (Dog) p1;
        dog.eat();
        dog.seeDoor();
    }
}

3.2.抽象类

3.2.1.概念

抽象类:如果一个类只是一个概念,没有具体的形象,我们可以把这个类定义为抽象类

抽象类的关键字:abstract

抽象类的使用场景:一般作为顶层类(父类),被子类继承

3.2.2 抽象类和抽象方法的定义

抽象类的存在不是为了创建对象,是为了让子类继承用的。

抽象类:使用abstract关键字修饰的类。

[权限修饰符]  abstract  class  类名{}

抽象方法: 使用abstract关键字修饰的方法 注意:抽象方法没有方法体,也没有{}

[权限修饰符]  abstract  返回值  方法名();//没有大括号

抽象类的特点:

1.抽象类不能创建对象,不能new对象。抽象类的关键字是abstract。

2.抽象类可以定义抽象方法,也可以没有抽象方法

3.有抽象方法的类一定要定义成抽象类

4.抽象类中可以定义实例方法

5.抽象类可以定义构造方法,在子类中可以调用抽象类的构造方法

6.子类继承了抽象类,则一定要重写/实现其中的抽象方法,如果没有实现父类的抽象方法,则子类也要变成抽象类

7.抽象方法需要在方法前写abstract关键字,并且不能有方法体(不能写大括号)

实例:宠物类

public abstract class Pet {
    protected String name;
    protected String color;
    public Pet(String name, String color) {
        this.name = name;
        this.color = color;
    }
    public void test(){
    }
    // 抽象方法:1.用abstract修饰 2.没有方法体,直接用分号结束 3.抽象方法需要在子类中重写
    public abstract void eat();
}
public class Cat extends Pet{
    public Cat(String name, String color) {
        super(name, color);
    }
    // 子类必须实现(重写)父类的抽象方法,如果子类不实现父类的抽象方法,那么子类也要变成抽象类
    public void eat(){
        System.out.println(this.color+"的"+this.name+"吃小鱼");
    }
}
public class Test {
    public static void main(String[] args) {
        // 抽象类不能被实例化
        // Pet p = new Pet("xxx","xxx");
        // 抽象类的关键字 abstract
        // 抽象类可以有构造方法
        // 抽象类不能实例化
        // 抽象类可以定义普通方法
        // 抽象类可以定义抽象方法,抽象方法必须被子类重写,如果子类没有重写抽象方法,子类也必须是抽象的
        // 有抽象方法的类,必须定义成抽象类
        // 抽象类的目的是作为顶级类存在,让子类继承
        // 抽象方法用abstract修饰,抽象方法不能有方法体
        Pet p = new Cat("花花","白色");
        p.eat();
    }
}

3.3 接口

3.3.1 概念

接口:

  • 一种标准、规范,大家都要遵从这个规范使用;
  • 对行为(方法)的抽象(与抽象类对比,抽象类有特征和行为,而接口只关注行为);
  • 一系列抽象方法的集合;
  • 定制规则,展现多态;
  • 接口和抽象类的地位等同,作为顶级存在(父类)
  • 实现接口意味着拥有了接口所表示的能力

接口关键字:interface

实现接口:implements

接口关键字:interface

实现接口:implements

3.3.2 java中的接口

接口定义的格式:

[权限修饰符] interface 接口名{}

接口的使用步骤:

1.接口中的方法不能直接使用,必须有一个实现类来实现接口
[权限修饰符] class 类名 implements 接口1,接口2,接口3。。。{}
public class Mouse implements USB{}
2.接口的实现类必须(覆盖重写)实现 接口中所有的抽象方法
3.创建实现类的对象,进行方法的调用。
注意:如果实现类没有覆盖重写接口中的方法,那么这个实现类自己就必须是抽象类。

接口中可以包含的内容:

  • 常量
 // 接口中的常量使用public static final 三个关键字修饰。
 // 定义常量的格式
 public static final int AGE = 10;
 // 使用接口中的常量
 接口名.常量名
  • 抽象方法

接口中的抽象方法必须是两个固定的关键字修饰  public abstract。这两个关键字可以省略不写。

  • 默认方法(jdk1.8之后新增)

为什么要有默认方法? default 增强接口的通用能力

default   返回值 方法名(){} //默认方法有方法体

  • 静态方法(jdk1.8之后新增)

提供通用实现,接口中的静态方法只能通过接口名调用,不能通过实现类调用

static 返回值 方法名(){} // 静态方法有方法体

3.3.3 接口特点

1、接口不能实例化,不能有构造方法

2、接口中的方法都是抽象方法,jdk8之后接口中可以定义默认方法和静态方法

3、接口中的成员变量默认都是public static final修饰的

4、实现类实现接口必须实现接口中的所有方法

5、多实现:一个类可以实现多个接口

6、接口可以继承接口:A extends B

3.3.4 面向接口编程

世界末日,事物在跑

public interface IRun {
    // 接口中的变量默认都是静态常量: public static  final
    //int num = 10;
    // 接口中的方法,默认就是公有抽象的
    void pao();
}

public class Person implements IRun {
    @Override
    public void pao() {
        System.out.println("人用两条腿跑");
    }
}

public class Rabbit implements  IRun{
    @Override
    public void pao() {
        System.out.println("兔子用四条腿跑");
    }
}

public class Test {
    public static void main(String[] args) {
        System.out.println("世界末日来临,一切事物都在跑...");
        // 接口变量,引用实现类对象
        // 调用接口被实现的方法时,不同实现类有不同效果
        IRun r1 = new Person();
        IRun r2 = new Rabbit();
        r1.pao();
        r2.pao();
    }
}

USB接口

// 电脑usb接口
public interface IUsb {
    // 定义工作的方法
    void work();
}

public class Mouse implements IUsb{
    @Override
    public void work() {
        System.out.println("使用鼠标选择文件");
    }
}

public class KeyBoard implements IUsb{
    @Override
    public void work() {
        System.out.println("使用键盘写文档");
    }
}

public class Computer {
    // 定义多个usb接口
   private IUsb u1;
   private IUsb u2;
   private IUsb u3;
    // 电脑启动时,各个usb设备开始work
    public void start(){
        System.out.println("电脑启动了,各个usb设备开始工作了....");
        this.u1.work();
        this.u2.work();
        this.u3.work();
    }
    // 通过setter为每个usb设置对象
    public void setU1(IUsb u1) {
        this.u1 = u1;
    }
    public void setU2(IUsb u2) {
        this.u2 = u2;
    }
    public void setU3(IUsb u3) {
        this.u3 = u3;
    }
}

public class Test {
    public static void main(String[] args) {
        // 创建usb接口对象
        IUsb u1 = new Mouse();
        IUsb u2 = new KeyBoard();
        IUsb u3 = new FengShan();
        // 创建移动硬盘
        IUsb uu = new MovePan();
        // 创建电脑对象
        Computer c = new Computer();
        // 设置电脑上的各个usb接口对象(把usb设备插入到电脑的usb接口上)
        //c.setU1(u1);
        c.setU1(uu);
        c.setU2(u2);
        c.setU3(u3);
        // 启动电脑
        c.start();
    }
}

使用不同打印机打印富豪的不同财产

 

 // 打印机接口
public interface IPrint {
    // 打印方法
    void print(String info);
}

public class BlackWhitePrinter implements IPrint{
    @Override
    public void print(String info) {
        System.out.println("使用黑白打印机打印信息。。。。");
        System.out.println(info);
    }
}

public class ColorPrinter implements IPrint{
    @Override
    public void print(String info) {
        System.out.println("使用彩色打印机打印....");
        System.out.println(info);
    }
}
// 显示信息接口
public interface IShow {
    // 所有财产都是可以显示信息的
    String show();
}

public class Plane implements IShow{
    @Override
    public String show() {
        return "价值1.74亿美元的波音747飞机";
    }
}

public class Ship implements IShow{
    @Override
    public String show() {
        return "价值3000W的豪华游艇";
    }
}
public class Master {
    // 属性
    private String name;
    private IPrint printer;
    // 构造
    public Master(String name) {
        this.name = name;
    }
    // 普通方法
    public void dayin(IShow s){
        // 调用方法,返回财产信息
        String info = s.show();
        // 使用打印机打印信息
        this.printer.print(info);
    }
    // 设置打印机
    public void setprinter(IPrint printer) {
        this.printer = printer;
    }
}
public class Test {
    public static void main(String[] args) {
        IShow s1 = new House();
        IShow s2 = new Plane();
        IShow s3 = new Ship();
        IPrint p1 = new BlackWhitePrinter();
        IPrint p2 = new ColorPrinter();
        Master m = new Master("小明");
        // 设置打印机
        m.setprinter(p1);
        m.dayin(s1);
        m.dayin(s2);
        m.dayin(s3);
        m.setprinter(p2);
        m.dayin(s1);
        m.dayin(s2);
        m.dayin(s3);
    }
}

3.4 接口和抽象类的区别

应用场景:抽象类是对事物属性和行为的抽象,符合is...a关系;

                 接口是对行为的抽象,实现接口,拥有相应的功能;

相同点:都是顶级的父类存在的

抽象类和接口的对比

 

参数

抽象类

接口

默认的方法实现

它可以有默认的方法实现

接口完全是抽象的。jdk1.8之前不存在方法的实现。jdk1.8之后有默认方法和静态方法。

实现

子类使用extends关键字来继承抽象类。如果子类不是抽象类的话,它需要提供抽象类中所有声明的抽象方法的实现。

子类使用关键字implements来实现接口。它需要提供接口中所有声明的方法的实现

构造器

抽象类可以有构造器

接口不能有构造器

与正常Java类的区别

除了你不能实例化抽象类之外,它和普通Java类没有任何区别

接口是完全不同的类型

访问修饰符

抽象方法可以有publicprotected默认这些修饰符

接口方法默认修饰符是public。你不可以使用其它修饰符。

main方法

抽象类可以有main方法并且我们可以运行它

接口没有main方法,因此我们不能运行它。(java8以后接口可以有default和static方法,所以可以运行main方法)

多继承

抽象类可以继承一个类和实现多个接口

接口只可以继承一个或多个其它接口

速度

它比接口速度要快

接口是稍微有点慢的,因为它需要时间去寻找在类中实现的方法。

添加新方法

如果你往抽象类中添加新的方法,你可以给它提供默认的实现。因此你不需要改变你现在的代码。

如果你往接口中添加方法,那么你必须

改变实现该接口的类。jdk8之后可以添加默认方法,不用实现类实现

面试题:接口和抽象类的区别? (提问)

1.构造方法

抽象类里面有构造方法 但是不能被new出来

接口里面没有构造方法

2.继承

抽象里面 java单继承 一个类只能继承一个抽象父类

接口可以继承多个接口,一个类可以实现多个接口

3.抽象方法

抽象类里面可以没有抽象方法,有抽象方法的类必须是抽象类

接口里面的方法是必须是抽象方法,只有方法名没有方法体,如果不是抽象方法就必须是default修饰的方法

抽象类里面的抽象方法是用public abstarct来修饰的 接口中的方法public abstract可以省略

4.变量

接口中的变量是用public static final修饰的

3.5 面向对象的三大特征

特征

定义

实现

封装

隐藏实现细节,提供公共的访问接口

将属性私有化,提供公共的访问接口

继承

从一个类中派生出一个新的子类,子类拥有父类中非私有的成员

子类 extends 父类

多态

父类的同一个方法在不同的子类中会有不同的实现

1、继承2、重写 3、向上转型

4.本章总结

4.1 本章内容

    • 多态
    • 抽象类和抽象方法
    • 接口

4.2 注意事项

类与类之间是单继承的

类与接口是多实现的:一个类可以实现多个接口(这个要将所有实现的接口中的抽象方法都实现),方便后期维护(修改,扩展)

接口与接口之间是多继承的:一个接口A如果继承了接口B和接口C,那么A接口可以同时拥有B和C接口的所有功能,并且还可以拥有属于自己的方法。

接口没有构造方法。

接口多态:一个USB接口可以表现出鼠标形态,键盘的形态,U盘的形态。。。。。。

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值