当前位置:网站首页>abstract class or interface

abstract class or interface

2022-08-09 23:13:00 shepherd..

抽象类 or 接口



1.回顾 前文 要点

学到这里 面向对象 的 三 大特征 我们 已经 学习过 了.

1.封装

2.继承

3.多态

下面我们 Just review it first.

1.啥是 封装 ?

封装 就是 将 对象 的 属性 和 实现的 细节 通过 关键字 private 给 隐藏 起来 ,对外 提供 特有的 get 和 set 方法来进行 访问,

2.啥是 继承 ?

继承 就是 通过 一个 已有 的 类的 基础上 派生 处 新类(如: 动物 类 就能 派生出 猫 类 和 狗 类 等等) 子类 继承 父类 的 特征 和 行为 ,使得 子类 对象 拥有 父类 的 实例 域 和 方法,

(简单来说 就是 对 共性 的 抽取, 使 子类 具有 父类 相同的 行为 ) , 使用 关键字 extends 来实现

如: A extends B A 就 是 子类 , B 就是 父类 属于 A is B 的 关系.

继承的 意义 : 提高 了 代码的 复用 性 .

3.啥是 多态 ?

多态是 一种 思想, 表示的 是 The same behavior has multiple different manifestations 或 morphological ability .

如:黑白打印机和彩色打印机相同的打印行为却有着不同的打印效果,

但 光有 这句话 是 不能行 的 我们 还需要理解 啥是 向上转型,动态绑定 (重写).

1.向上转型: 父类引用 引用 了 子类 对象.

2.动态绑定:通过 父类引用 调用 子类和 父类 同名 的 覆盖(重写) 方法.

注意: 在发生 动态 绑定时 一定 会 涉及到 重写 , 这个 也需要我们 重点理解.

重写特征
1.方法 名 相同
2. 参数类型 和 个数 相同,
3.返回值相同 (特例 : 返回值 构成 父子类 ).


重写 注意 事项:

1.static 修饰的 方法 不能 重写
2.final 修饰的 方法 不能 重写
3. private 修饰的 方法 不能重写
4.子类 重写 的 方法 访问 修饰 限定 需要 大于 等于 父类 访问 修饰 限定 (子类方法的访问Permissions must be greater than or equal to the parent class方法的访问权限)


动态 除了 上面 这些 比较 重要的 我们 还学习 了

静态 绑定 :通过方法的重载实现的.编译的时候,会根据你调用方法时,所给参数的类型和个数,来决定调用哪个同名方法

向下 转型 : 子类 引用父类 对象 , 因为 不太 安全 所以 不推荐 使用.

注意事项:

1.子类 继承 父类 , 子类 需要 在 构造方法中 加入 super(…) 来显示 调用 父类构造方法 , 帮助 父类 完成 构造 .

2.super 和 this 的 区别 : super 是 A reference to the parent class, 而 this 针对 当前 对象的 引用 .

3.重写 和 重载 的 区别 :

重载重写
相同点:1.方法名相同1.方法名相同
不同点:2.返回值 可以不同2.返回值必须相同
特例:The return value constitutes parent and child classes
不同点:3.参数列表不同
数据类型 ,The order numbers are different
3.参数列表相同
数据类型,The order numbers are the same
不同点:There is no permission requirement for overloading5.Overriding is a permission requirement
子类的 Permissions must be greater than or equal to the parent class
另外:父类被privateDecorations cannot be overridden


4.四种方法 权限 :

1.private被 private 修饰的 字段 或 方法,只能在 同一个类中使用,
如果 这个 类 被 继承, 被 private 修饰的 方法 或 字段 , 是 被 继承下来的 ,But can't visit
2.default (包访问 权限)只要在 同一个包底下 都能够使用.
3.protected在 同一个包底下 随便使用, 但 Needs to be subclassed in other packages 才能 够 使用
4.publicWhether it's the same package 还是 不同 的 包 都能 够使用 .
注意上面 说的使用 是 被 这几种 修饰限定符 给 修饰的 字段 或 方法.

到此我们 就 回顾 完 了 , 下面 我们 就 来 使用 多态 来 引出 我们 接下来 学习 的 抽象类 .

抽象类

先来看 这段 代码 :

class Shape{
    
    public void drow(){
    
        System.out.println("Shape :: drow()");
    }
}
// Rect : 矩形
class Rect extends Shape{
    
    @Override
    public void drow() {
    
        System.out.println("矩形");
    }
}
// Flower : 花
class Flower extends Shape{
    
    @Override
    public void drow() {
    
        System.out.println("* 花");
    }
}
public class Test {
    

    public static void func(Shape shape){
    
        shape.drow();
    }
    public static void main(String[] args) {
    
        Rect rect = new Rect();
        func(rect);
        Flower flower = new Flower();
        func(flower);
    }
}

在这里插入图片描述

这里 我们 就 实现了 我们的 多态 , 通过 shape 这 一个 引用 , 表现出 了不同 中 状态 ,如 : 矩形 , 花 .

这里 你 有没有 想过 只要 父类 引用 了 子类 对象 , 调用 drow 方法 ,都会 发生 动态 绑定 ,原本 自己 的 drow 方法 实现的 功能 就没有 用 了 ,我们是否 可以 将 这个 方法 实现 省略 掉 呢?

这里就 可以 将 drow() 这个 方法 设置 为 抽象 方法 ,此时 包含抽象 方法的 类 我们 就称为 抽象 类 .

抽象类语法规则

在Java中,一个类如果被 abstract 修饰称为抽象类,抽象类中被 abstract 修饰的方法称为抽象方法,抽象方法不用
给出具体的实现体.

abstract class Shape{
    
 abstract public void drow();
}


此时 我们 被 abstract 修饰 的 Shape就 是 抽象类,

而 被 abstract 修饰 的 方法就 是 抽象 方法, 这个 The method can be specific 类容.

下面我们 来 对比一下 抽象 类 普通类 的 区别:

1.抽象类 不能实例化

在这里插入图片描述


2.抽象类 与 普通 类 一样 可以 定义 普通 方法 和 成员变量.

在这里插入图片描述

这我们 虽然 不能 通过 new 这个 类来 创建 对象,但 抽象类 ,发明出来 就是 用来 继承的 , 我们 可以 通过 继承 , 来 调用 这些 普通 方法 或 成员变量.

如:

在这里插入图片描述

当我们尝试 继承 后 会发现 ,报红线 了 ,不要着急,这里 是因为 我们没有 重写 抽象 方法 .

注意: 当 继承 抽象类 的同时 我们 需要 重写 All abstract 方法.

It's also a good idea :我们抽象 method as it is 什么 It didn't come true ,如果 You don't rewrite ,别人 调用 这个 方法 有什么 用 呢? 还不如 不写.

在这里插入图片描述


重写 完 就没有 报错了 ,下面 继续 .

通过 子类 访问 ,父类 (父类 为 抽象 类 )的 普通 方法 :

abstract class Shape{
    
    abstract public void drow();
    public int a;
    public String b;
    public void func(){
    
        System.out.println("测试 抽象类 是否能 定义普通方法");
    }
}
class A extends Shape{
    
    @Override
    public void drow() {
    
        System.out.println("重写 的 抽象 方法");
    }
}
public class Test {
    

    public static void main(String[] args) {
    
        A a = new  A();
        a.func();
        a.drow();
    }
}


在这里插入图片描述

同样 的 我们 的 抽象类 ,也 是 可以 发生 Bind up ,和 多态的 , 这里 就 来 看一下.

1.向上 转型:

在这里插入图片描述

2.多态:

abstract class Shape{
    
    abstract public void drow();
    public int a;
    public String b;
    public void func(){
    
        System.out.println("测试 抽象类 是否能 定义普通方法");
    }
}
class A extends Shape{
    
    @Override
    public void drow() {
    
        System.out.println(" A 中 重写 的 抽象 方法");
    }
}
class B extends Shape{
    
    @Override
    public void drow() {
    
        System.out.println(" B 中 重写 的 抽象 方法");
    }
}
public class Test {
    
    
    public static void func(Shape shape){
    
        shape.drow();
    }

    public static void main(String[] args) {
    
        A a = new A();
        B b = new B();
        func(a);
        func(b);
    }
}

在这里插入图片描述


另外 : 我们 一个 抽象类 继承 一个 抽象 类 可以 不重写 抽象 方法 .


如: 抽象类 B 继承 了 抽象 类 A 此时 抽象 类 B 是 不需要 重写 抽象 A 的 抽象方法 (对比 一个 普通类 C 继承 抽象类 A ,就必须 重写抽象方法, 要不然 报错)
在这里插入图片描述


俗话 说的 父债子还 , 如果此时 一个 普通的 类 继承 了 这个抽象 类 B ,此时 这个子类 不仅 需要 重写 抽象类 A 的 抽象 方法 , 还需要 重写抽象 类B的 抽象方法.

1.只重写 了 抽象类 B 的 抽象 方法

在这里插入图片描述

2.重写了 抽象类 A 和 抽象 类 B 的 抽象 方法 .

在这里插入图片描述

如果 我们 在 拿一个 抽象类 继承 呢 ?

这样 就会 形成 套娃 ,这个 类 也 不需要 重写 父类 的 抽象 方法 ,知道 有 一个 普通类 继承 了 ,那么 就得 全部 重写 ,
在这里插入图片描述

在 来 一个 注意事项:

抽象 class cannot 被 final修饰的

之前我们 学过final,说过 其中 的 一种用法 , 被 final 修饰 的 类 是 不能 被 继承 的 ,我们的 抽象类 本 身就是 用来 被继承的 ,

final 就好比 与 火 , 而 抽象类 Just like water , 两者 本身 就不 合 , 强行 放在 一起 肯定 会出问题.

在这里插入图片描述

既然 抽象 类 不能 被 final 修饰 ,那么 our abstraction 方法 同理 也是 不能 被 final修饰的, 之前 还 提过 被final修饰的 方法 是不能 重写的 ,这样与 抽象方法 必须 重写 ,又有 冲突 .

在这里插入图片描述

看完上面这些 内容 你 能 总结 出什么 ?

下面 就 直接 抛出 总结.


总结 :

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

2、什么是抽象类,一个没有具体实现方法,被abstract修饰

3、抽象类是不可以被实例化的.不能 new

4、因为不能被实例化,所以,这个抽象类,其实只能被继承

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

6、一个普通类,继承了一个抽象类,那么这个普通类当中,需要重写这个抽象类的All abstract方法.

7.抽象类的最大的作用,就是为了被继承

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

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

10、抽象类不能被final修饰,抽象方法也不可以被 final 修饰

同理 抽象 方法 不能 被 privatestatic 修饰 (导致 这个方法无法被重写).

抽象类的 作用

抽象类 最大 的意义 就是为了 继承 ,

抽象类本身不能被实例化, 要想使用, Only subclasses of this abstract can be created. 然后让子类重写抽象类中的抽象方法.

有些小伙伴 可能会说了, 普通的类也可以被继承呀, 普通的方法也可以被重写呀, 为啥非得用抽象类和抽象方法
呢?

其实 使用 抽象类 It is equivalent to an additional check of the compiler(如果你没有重写抽象方法,编译器会报错,提醒你)

我们 充分利用编译器的校验, 在实际开发中是非常有意义的.


抽象类 完了,接下来 学习 我们的 接口 .

接口


什么是 接口 ?

答: 接口是 对 公共的 行为规范 标准 (再实现 接口 时, 只要 符合 规范 标准 , 就可以 通用).

再java 中 ,接口 可以看成 是 :多个类 public norms,是 一种 引用 数据类型 .

看完 上面 这些 概述 是不是 很 懵逼 下面 就通过 例子 来 解释 一下.

笔记本 上的 USB 接口 , 电源插座等 .

在这里插入图片描述

在这里插入图片描述

电脑的USB口上,可以插:U盘、鼠标、键盘…所有符合USB协议的设备

电源插座插孔上,可以插:电脑、电视机、电饭煲…所有符合规范的设备

当满足 满足 这两个 接口 的规范 协议 ,就 能够 插入 其中使用 , 如果 你 强行 Insert when I didn't say,

如: 有线鼠标 键盘 , 如果 他们的 线 的 插头 与 电脑 规定 的 USB接口 相同 此时 就能够 使用 ,不同那么 就不能使用.这里 就是 接口 规定了标准 范围,而我们的 鼠标 和 键盘 就 满足 这种 规范 ,就可以使用 这个 接口 .

知道 了 概念 下面就来 了解 一下 语法 规则 .

接口的 语法 规则



使用 关键字 interface 修饰 的类 就 是 接口

创建 完 了 接口,来 了解 一下我们的 接口 .



1.接口 当中 ,Can't create normal 方法

在这里插入图片描述


如果这 非要 创建 普通方法 需要 再 方法 前 加上 关键字 default ,表示 该方法 是此 接口 的 默认 方法

在这里插入图片描述


注意 : 在 JDK 1.8 开始 才 允许 接口 可以 实现 方法 , 但 必须是 被关键字 default 修饰的 方法 .

另外 : 在 接口 中 是 可以 存在 静态 方法 的 但 静态 方法 不能 被重写

在这里插入图片描述

除了 默认方法 , 静态 方法 , 接口 还 包括 抽象方法 ,

在这里插入图片描述

接口 与 抽象类 相比 之下, 接口 只能 包括 抽象 方法 或 接口 默认方法 , 字段 只能 包括 静态 常量, 而 抽象类 除了 抽象方法 , Can also contain non-abstract methods, 和字段. , 所以 说 接口 相比 抽象类 更进 一步 .

观察 上面 A few pictures ,有没有 发现 , 我们 创建 的 方法 中 的 关键字 public 都是 灰色 的 ,这里 意味 这 在 接口中 所有的 方法 ,都是默认 被 public 修饰 的.


2.在 all of the interfaces 方法 默认 都是 被 public 修饰的 ,抽象方法 默认 是 被 public abstract 修饰的

在这里插入图片描述


尝试 使用 其他 访问 修饰 限定符 :

在这里插入图片描述

可以 看到 只有 public 修饰 , 或者 不写 (此时 会默认 为 是 public 修饰 )才能 Enough not to report an error .


3.接口 The same cannot be instanced 化对象

刚刚 说过 ,接口 是 抽象 类 的更进一步 , 抽象类 不能 实例化对象, 接口 也应该 不能 实例化对象.

下面演示 :

在这里插入图片描述


下面 就来 使用 Let's take a look at our interface.

4.类 与 接口 之间 使用关键字 implements 来实现


模拟 场景: Used by Pikachu 技能 A

1.通过 implements 实现 接口 ,同样需要 将 接口 中 所有的 抽象类 方法, 全部重写 ,(注意:默认方法,或 static 修饰的 方法 就 不需要 重写, 但 默认 方法 是 可以按照 自己的 Willing to choose 重写 的 ,而static 修饰 的方法 无法被 重写).

在这里插入图片描述


重写 完 drow 方法.

在这里插入图片描述

// 技能 A
interface A {
    
    void drow();
}

// 技能 B
interface B {
    
    void drow();
}

// 皮卡丘
class Pikachu implements A {
    
    @Override
    public void drow() {
    
        System.out.println("Pikachu uses 100,000 volts");
    }
}

// 喷火龙
class Charizard {
    

}

public class Test {
    
    public static void main(String[] args) {
    
        Pikachu pikachu = new Pikachu();
        pikachu.drow();
    }
}


在这里插入图片描述

此时 就完成 了 我们 的 场景 模拟 .

同样我们 的接口 是可以 完成 我们 的向上 转型 的 , 既然 有 了 向上 转型 (父类 引用 引用 了 子类 对象) ,那么 子类 发生 重写 ,调用 重写 的方法 ,发生 动态绑定 ,最后 也 能够 完成 我们 的 多态 .

1.向上转型 和 动态绑定:

在这里插入图片描述

2.多态:

// 技能 A
interface A {
    
    void drow();
}

// 技能 B
interface B {
    
    void Skill();
}

// 皮卡丘
class Pikachu implements A {
    
    @Override
    public void drow() {
    
        System.out.println("Pikachu uses 100,000 volts");
    }
}

// 喷火龙
class Charizard implements A,B {
    
    @Override
    public void drow() {
    
        System.out.println("Charizard used 撞击 ");
    }

    @Override
    public void Skill() {
    
        System.out.println("喷火龙 使用了 吐息");
    }
}

public class Test {
    
    public static void func(A a){
    
        a.drow();
    }
    public static void main(String[] args) {
    
        Pikachu pikachu  = new Pikachu();
        Charizard charizard = new Charizard();
        func(pikachu);
        func(charizard);
    }
}

在这里插入图片描述


5.一个类 是 可以 拥有 多个 接口 的


另外 : 在 上面 代码 中我们 fire-breathing dragon 是 实现了 两个接口 的 ,这里 我们 通过 implements 实现 接口 多个 接口时 , implements 只需要 一个 , 接口之间使用 , 逗号隔开 即可,

在这里插入图片描述

上面 一直 将的 是 方法, 在 接口 中 同样 是 包含字段 的 只不过这个 字段 必须是 静态常量 static final 修饰的 变量 .


6.接口 中 的 字段 只能 是 被 static final修饰 .

在这里插入图片描述


7. 接口 之间 是 可以 继承的


相比 于 类 继承 类 , 类 继承 抽象类, 类 虽然 Can't inherit ours 接口 ,但 是 可以实现 多个 接口 , 但 我们的 接口 之间 是 可以 继承.

在这里插入图片描述


此时 我们的 接口 B 就 继承 了 接口 A , 当一个 普通类, 实现 了 这个 B 接口 就需要 重写 ,A 和 B 的 抽象方法 ,(这里 B继承 A 此时 就先当与 B接口 扩展 了 A 接口 的功能).

interface A{
    
    int a = 10;
    void drow();
}

interface C {
    
    int c = 30;
    void func();
}
interface B extends A{
    
    int b = 20;
    void swap();

}
class Test2 implements B{
    
    @Override
    public void swap() {
    
        System.out.println("重写 B 的 方法");
    }

    @Override
    public void drow() {
    
        System.out.println("重写 A 的 方法");
    }
}


下面 我们 就来 整点 好玩的 .

以前我们 说过 一个类 只能 继承 一个 类 或 抽象 方法 .

此时 让我们的 接口去 继承 多个 接口 试试

在这里插入图片描述


总结:

接口与接口之间,可以使用 extends来 操作它们的关系,此时,extends 在这里意为 拓展.(一个接口A 通过 extends 来拓展 另一个接口B的功能,此时当一个类 通过 implements 实现 接口A,此时重写的方法,不仅仅是 A 的抽象方法,还有从B接口,拓展来的功能【方法】)


最后 我们 将 上面 Said to come once 大总结 :

总结:
  
1.使用interface来定义一个接口,例:interface IA{},这就是一个接口
  

2.接口当中的普通方法,不能有具体的实现.非要实现,只能通过关键字 default 来修饰 这个方法.
  
3.接口当中,可以有static的方法.


4.接口 中 所有方法都是public的.

5.抽象方法,默认是 public abstract 的.

6.接口是不可以被实例化的(不可以被new的).

7.类和接口之间的关系是通过 implements(工具)实现的.

8.当一个类 实现了 一个接口,就必须要重写接口当中的抽象方法.

9.在调用的 接口的 时候 A reference to an interface can be created (如 实现接口的 类 ), 对应到一个子类的实例

10.接口当中的字段/属性/成员变量,默认是public static final 修饰的.


11. 当一个类实现接口之后,重写抽象方法的时候,Overriding methods must be prefixed withpublic,因为接口中方法默认都是public的,And override the access rights of the method,Must be greater than or equal to the access rights of the methods in the parent class

补充 : Haven't demonstrated here before 演示 一下:
在这里插入图片描述


12.一个类可以通过关键字extends继承一个抽象类或者普通类.但是只能继承一个类.同时也可以通过implements实现多个接口.接口之间使用逗号隔开.
  

13.接口与接口之间,可以使用 extends来 操作它们的关系,此时,extends 在这里意为 拓展,而不是继承,(一个接口 通过 extends 来拓展 另一个接口的功能)

本文 完 : 下文 预告 三种 常用 接口 .

原网站

版权声明
本文为[shepherd..]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/221/202208091944474468.html