IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 【Java SE系列】抽象类与接口 -> 正文阅读

[Java知识库]【Java SE系列】抽象类与接口

1 抽象类

1.1 语法规则

在之前的打印图形例子中, 我们发现, 父类 Shape 中的 draw 方法好像并没有什么实际工作, 主要的绘制图形都是由Shape 的各种子类的 draw 方法来完成的. 像这种没有实际工作的方法, 我们可以把它设计成一个 抽象方法(abstractmethod), 包含抽象方法的类我们称为抽象类(abstract class).

abstract class Shape { 
     abstract public void draw(); 
}
  • 在 draw 方法前加上 abstract 关键字, 表示这是一个抽象方法. 同时抽象方法没有方法体(没有 { }, 不能执行具体代码).
  • 对于包含抽象方法的类, 必须加上 abstract 关键字表示这是一个抽象类.

注意事项

  1. 抽象类不能实例化
    在这里插入图片描述
    2.抽象方法不能是 private 的()
    在这里插入图片描述

3.抽象类中可以包含其他的非抽象方法, 也可以包含字段. 这个非抽象方法和普通方法的规则都是一样的, 可以被重写,也可以被子类直接调用.(抽象类除了包含抽象方法和不能实例化之外和普通类相似
4.final修饰的抽象方法也不能被重写,因为final修饰就代表方法不能进行修改即不能重写.
在这里插入图片描述

🔑打印图形栗子:

abstract class Printf{
    String name = "ant";
     abstract public  void printf();
}
class Rect extends Printf{
    @Override
    public void printf() {
        System.out.println("△");
    }

}
class Cur extends Printf{
    @Override
    public void printf() {
        System.out.println("○");
    }

}
class Flower extends Printf{
    @Override
    public void printf() {
        System.out.println("?");
    }
}
public class Test {
    public static void printY(Printf pintf){

        pintf.printf();
    }
    public static void main(String[] args) {
        printY(new Cur());
        printY(new Rect());
        printY(new Flower());
    }
}

在这里插入图片描述

1.2 抽象类的作用

抽象类存在的最大意义就是为了被继承.
抽象类本身不能被实例化, 要想使用, 只能创建该抽象类的子类. 然后让子类重写抽象类中的抽象方法.
使用抽象类的场景就如上面的代码, 实际工作不应该由父类完成, 而应由子类完成. 那么此时如果不小心误用成父类了,使用普通类编译器是不会报错的. 但是父类是抽象类就会在实例化的时候提示错误, 让我们尽早发现问题.

💡小知识:
使用抽象类相当于多了一重编译器的校验.

2 接口

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

2.1 语法规则

我们仍然通过打印图案的栗子来看:

interface Printf{
     public static final String name = "ant";
     abstract public  void printf();
}
class Rect implements Printf{
    @Override
    public void printf() {
        System.out.println("△");
    }

}
class Cur implements Printf{
    @Override
    public void printf() {
        System.out.println("○");
    }

}
class Flower implements Printf{
    @Override
    public void printf() {
        System.out.println("?");
    }
}
public class Test {
    public static void printY(Printf printf){

        printf.printf();
    }
    public static void main(String[] args) {
        printY(new Cur());
        printY(new Rect());
        printY(new Flower());
    }
}

在这里插入图片描述

💡知识点:
接口中的方法一定是抽象方法, 因此可以省略 abstract。
接口中的方法一定是 public, 因此可以省略 public。
接口中可以有static方法。
抽象方法默认是public abstract的
接口中成员变量默认是public static final修饰的
在调用的时候同样可以创建一个接口的引用, 对应到一个子类的实例。
接口不能单独被实例化
当一个类实现了一个接口后,重写方法必须加上public。
一个类可以通过关键字extends继承一个抽象类或普通类,但是只能继承一个类,同时可以通过implement实现多个接口,接口之间用逗号隔开。

🐾我们来看一个错误案例:

interface IShape {
    abstract void draw() ; // 即便不写public,也是public 
}
class Rect implements IShape {
    void draw() {
        System.out.println("□") ; //权限更加严格了,所以无法覆写。
    }
}

在这里插入图片描述

这里报错就是因为接口中方法默认是public的,而Rect中的draw方法是包访问修饰符修饰的,作用范围比public小,由于重写方法的作用范围要大于等于父类的方法,所以程序就报错了。

2.2 接口使用实例

接下来我们用接口来实现给对象数组排序
方法一:实现Comparator接口
在这里插入图片描述

Comparator接口中含有比较方法,所以我们只需要创建几个类然后实现Comparator接口并重写compara方法就能实现排序功能。

💫代码实现:

package demo3;

import java.util.Arrays;
import java.util.Comparator;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: admin
 * Date: 2021-11-13
 * Time: 下午5:11
 */
class Student {
    String name;
    int age;
    double score;

    public Student(String name, int age, double score) {
        this.name = name;
        this.age = age;
        this.score = score;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", score=" + score +
                '}';
    }

   /* @Override
    public int compareTo(Student o) {
        return (this.age-o.age);
    }*/

}
class AgeComparator implements Comparator<Student>{
    @Override
    public int compare(Student o1, Student o2) {

        return o1.age-o2.age;
    }
}
class NameComparator implements Comparator<Student>{
    @Override
    public int compare(Student o1, Student o2) {
        return o1.name.compareTo(o2.name);
    }
}
class ScoreComparator implements Comparator<Student>{
    @Override
    public int compare(Student o1, Student o2) {
        return (int)(o1.score-o2.score);
    }
}
public class Test {
    public static void main(String[] args) {
        Student[] student = new Student[3];
        student[0] = new Student("zhangsan",12,98.9);
        student[1] = new Student("lisi",6,95.9);
        student[2] = new Student("wangwu",18,88.9);
        AgeComparator ageComparator = new AgeComparator();
        NameComparator nameComparator = new NameComparator();
        ScoreComparator scoreComparator = new ScoreComparator();
        System.out.println(Arrays.toString(student));
        Arrays.sort(student,ageComparator);
        System.out.println(Arrays.toString(student));
        Arrays.sort(student,nameComparator);
        System.out.println(Arrays.toString(student));
        Arrays.sort(student,scoreComparator);
        System.out.println(Arrays.toString(student));
    }
}

在这里插入图片描述
方法一:实现Comparable接口

在 sort 方法中会自动调用 compareTo 方法.所以我们只需要在Student类中实现Comparable接口并重写compara To方法即可实现排序。

package demo3;

import java.util.Arrays;
import java.util.Comparator;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: admin
 * Date: 2021-11-13
 * Time: 下午5:11
 */
class Student implements Comparable<Student>{
    String name;
    int age;
    double score;

    public Student(String name, int age, double score) {
        this.name = name;
        this.age = age;
        this.score = score;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", score=" + score +
                '}';
    }

    @Override
    public int compareTo(Student o) {
        return this.age-o.age;
    }
}
public class Test {
    public static void main(String[] args) {
        Student[] student = new Student[3];
        student[0] = new Student("zhangsan",12,98.9);
        student[1] = new Student("lisi",6,95.9);
        student[2] = new Student("wangwu",18,88.9);
        System.out.println(Arrays.toString(student));
        Arrays.sort(student);
        System.out.println(Arrays.toString(student));
    }
}

在这里插入图片描述

注意:
实现Comparable接口有个局限性,即只能排序指定的类型,若要根据其他规则去排序则需要重新修改compara To函数的内容。

2.3 克隆接口

前面我们已经知道创建对象的方法有new,克隆的方式就是第二种创建对象的方式。

Object 类中存在一个 clone 方法, 调用这个方法可以创建一个对象的 “拷贝”. 但是要想合法调用 clone 方法, 必须要先实现 Clonable 接口, 否则就会抛出CloneNotSupportedException 异常.

代码实现:

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: admin
 * Date: 2021-11-18
 * Time: 下午7:36
 */
class Person implements Cloneable{
    int age;

    public Person(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                '}';
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
public class Test {
    public static void main(String[] args)throws CloneNotSupportedException {
        Person person = new Person(20);
        Person person1 = (Person) person.clone();
        System.out.println(person.age);
        System.out.println(person1.age);
    }
}

注意:
1.类必须要实现克隆接口才能进行克隆
2.类中必须要重写clone方法
3.主函数中必须要进行异常抛出
4.当前克隆属于浅拷贝(不会克隆引用指向的对象)后面会实现深拷贝的克隆

在这里插入图片描述
深拷贝克隆实现:

class Money implements Cloneable{
    int num = 10;


    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
class Person extends Money implements Cloneable{
    int age;
    Money money = new Money();


    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                '}';
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Person tep = (Person) super.clone();
        tep.money = (Money)super.clone();
        return tep;
    }
}
public class Test {
    public static void main(String[] args)throws CloneNotSupportedException {
        Person person = new Person();
        Person person1 = (Person) person.clone();
        person1.money.num = 13;
        System.out.println(person.money.num);
        System.out.println(person1.money.num);
    }
}

在这里插入图片描述

此时Person和Person1中的money引用指向不同的对象。

小知识:
深拷贝浅拷贝不是方法自带,是看编程人员如何去设计的。

总结:
1.抽象类可以有普通成员函数,接口一般只存在public abstract方法(jdk1.8中接口也可以有静态方法)。
2.抽象类中的成员变量可以是各种类型的,接口中只能是public static final类型。
3.抽象类只能继承一个,接口可以实现多个。
4.抽象类和接口都不能实例化。
5.抽象类不一定有抽象方法(但是声明为抽象类没有抽象方法也不能实例化),但是包含抽象方法的类一定为抽象类。
6.抽象类是对类本质的抽象,表达的是 is a的关系,抽象类包含并实现子类的通用特性,将子类存在差异化的地方进行抽象,交给子类去实现。
7.接口是对行为的抽象,表达的是 like a的关系,比如鸟可以像飞行器一样飞,但是其本质还是鸟。接口的核心是定义行为即功能,也就是实现类可以做什么,至于主体是谁、如何实现接口都不关心。

作者水平有限,若文章有任何问题欢迎私聊或留言,希望和大家一起学习进步!!!
创作不易,再次希望大家👍支持下,谢谢大家🙏

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-11-19 17:30:07  更:2021-11-19 17:30:40 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 3:00:02-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码