【Java成王之路】第十六篇:Java SE(面向对象编程—抽象类、接口)

本节目标

抽象类

接口

一、什么是抽象类

没有实际工作的方法, 我们可以把它设计成一个 抽象方法(abstract method), 包含抽象方法的类我们称为 抽象类(abstract class)。

举例:

abstract class shape{
    public abstract void draw();//抽象方法
}

1、包含抽象方法的类叫做抽象类。

2、什么是抽象方法:一个没有具体实现的方法,被abstract关键字来修饰。

抽象类和普通类的区别

1、抽象类是不可以被实例化的。

 2、因为不能被实例化,所以,抽象类其实只能被继承。一个普通类继承了一个抽象类,那么这个普通类当中,需要重写这个抽象类的所有的抽象方法

 3、抽象类当中,也可以包含,和普通类一样的成员和方法

 4、抽象类的最大作用,就是为了被继承。

abstract class Shape{
    public int a;
    public void func(){
        System.out.println("测试普通方法");
    }
    public abstract void draw();//抽象方法
}
class Rect extends  Shape{
    @Override
    public void draw() {
        System.out.println("❀");
    }
}

public class Test {
    public static void drawMap(Shape shape){
        shape.draw();
    }
    public static void main(String[] args) {
        Shape shape = new Rect() ;
        drawMap(new Rect());

    }
}

 5.一个抽象类A,如果继承了一个抽象类B,那么这个抽象类A,可以不实现抽象父类B的抽象方法

6、结合第5点,当A类再次被一个普通类继承后,那么A和B这两个抽象类当中抽象方法,必须被重写 

bstract class Shape{
    public int a;
    public void func(){
        System.out.println("测试普通方法");
    }
    public abstract void draw();//抽象方法
}
abstract class A extends Shape{
    public abstract void func();

}
class B extends A{
    @Override
    public void func() {
        
    }

    @Override
    public void draw() {

    }

}
class Rect extends  Shape{
    @Override
    public void draw() {
        System.out.println("❀");
    }
}

public class Test {
    public static void drawMap(Shape shape){
        shape.draw();
    }
    public static void main(String[] args) {
        Shape shape = new Rect() ;
        drawMap(new Rect());

    }
}

为什么要使用抽象类 

使用抽象类的场景就如上面的代码, 实际工作不应该由父类完成, 而应由子类完成. 那么此时如果不小心误用成父类了, 使用普通类编译器是不会报错的. 但是父类是抽象类就会在实例化的时候提示错误, 让我们尽早发现问题

二、什么是接口

接口是抽象类的更进一步. 抽象类中还可以包含非抽象方法, 和字段. 而接口中包含的方法都是抽象方法, 字段只能包含 静态常量

 语法规则

在刚才的打印图形的示例中, 我们的父类 Shape 并没有包含别的非抽象方法, 也可以设计成一个接口

interface IShape { 
 void draw(); 
} 
class Cycle implements IShape { 
 @Override 
 public void draw() { 
 System.out.println("○"); 
 } 
} 
public class Test { 
 public static void main(String[] args) { 
 IShape shape = new Rect(); 
 shape.draw(); 
 } 
} 

使用 interface 定义一个接口

接口中的方法一定是抽象方法, 因此可以省略 abstract

接口中的方法一定是 public, 因此可以省略 public

Cycle 使用 implements 继承接口. 此时表达的含义不再是 "扩展", 而是 "实现"

在调用的时候同样可以创建一个接口的引用, 对应到一个子类的实例.

接口不能单独被实例化.

扩展(extends) vs 实现(implements)

扩展指的是当前已经有一定的功能了, 进一步扩充功能.

实现指的是当前啥都没有, 需要从头构造出来 

接口中只能包含抽象方法. 对于字段来说,接口中只能包含静态常量(final static).

interface IShape { 
 void draw(); 
 public static final int num = 10; 
} 

 其中的 public, static, final 的关键字都可以省略. 省略后的 num 仍然表示 public 的静态常量

提示:

1. 我们创建接口的时候, 接口的命名一般以大写字母 I 开头.

2. 接口的命名一般使用 "形容词" 词性的单词.

3. 阿里编码规范中约定, 接口中的方法和属性不要加任何修饰符号, 保持代码的简洁性.

实现多个接口

有的时候我们需要让一个类同时继承自多个父类. 这件事情在有些编程语言通过 多继承 的方式来实现的. 然而 Java 中只支持单继承, 一个类只能 extends 一个父类. 但是可以同时实现多个接口, 也能达到多继承类似的效果. 现在我们通过类来表示一组动物.

class Animal { 
 protected String name; 
 
 public Animal(String name) { 
 this.name = name; 
 } 
} 

 另外我们再提供一组接口, 分别表示 "会飞的", "会跑的", "会游泳的".

interface IFlying { 
 void fly(); 
} 
interface IRunning { 
 void run(); 
} 
interface ISwimming { 
 void swim(); 
} 

接下来我们创建几个具体的动物 猫, 是会跑的.

class Cat extends Animal implements IRunning { 
 public Cat(String name) { 
 super(name); 
 } 
 @Override 
 public void run() { 
 System.out.println(this.name + "正在用四条腿跑"); 
 } 
} 

鱼, 是会游的.

class Fish extends Animal implements ISwimming { 
 public Fish(String name) { 
 super(name); 
 } 
 @Override 
 public void swim() { 
 System.out.println(this.name + "正在用尾巴游泳"); 
 } 
} 

青蛙, 既能跑, 又能游(两栖动物)

class Frog extends Animal implements IRunning, ISwimming { 
 public Frog(String name) { 
 super(name); 
 } 
 @Override 
 public void run() { 
 System.out.println(this.name + "正在往前跳"); 
 } 
 @Override 
 public void swim() { 
 System.out.println(this.name + "正在蹬腿游泳"); 
 } 
}

还有一种神奇的动物, 水陆空三栖, 叫做 "鸭子"

class Duck extends Animal implements IRunning, ISwimming, IFlying { 
 public Duck(String name) { 
 super(name); 
 } 
 @Override 
 public void fly() { 
 System.out.println(this.name + "正在用翅膀飞"); 
 } 
 @Override 
 public void run() { 
 System.out.println(this.name + "正在用两条腿跑"); 
 } 
 @Override 
 public void swim() { 
 System.out.println(this.name + "正在漂在水上"); 
 } 
}

上面的代码展示了 Java 面向对象编程中最常见的用法: 一个类继承一个父类, 同时实现多种接口

继承表达的含义是 is - a 语义, 而接口表达的含义是 具有 xxx 特性

猫是一种动物, 具有会跑的特性.

青蛙也是一种动物, 既能跑, 也能游泳

鸭子也是一种动物, 既能跑, 也能游, 还能飞

这样设计有什么好处呢? 时刻牢记多态的好处, 让程序猿忘记类型. 有了接口之后, 类的使用者就不必关注具体类型, 而 只关注某个类是否具备某种能力.

例如, 现在实现一个方法, 叫 "散步

public static void walk(IRunning running) { 
 System.out.println("我带着伙伴去散步"); 
 running.run(); 
} 

在这个 walk 方法内部, 我们并不关注到底是哪种动物, 只要参数是会跑的, 就行

Cat cat = new Cat("小猫"); 
walk(cat); 
Frog frog = new Frog("小青蛙"); 
walk(frog); 
// 执行结果
我带着伙伴去散步
小猫正在用四条腿跑
我带着伙伴去散步
小青蛙正在往前跳

甚至参数可以不是 "动物", 只要会跑

class Robot implements IRunning { 
 private String name; 
 public Robot(String name) { 
 this.name = name; 
 } 
 @Override 
 public void run() { 
 System.out.println(this.name + "正在用轮子跑"); 
 } 
} 
Robot robot = new Robot("机器人"); 
walk(robot); 
// 执行结果
机器人正在用轮子跑

 

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>