图灵日记之java奇妙历险记--抽象类和接口

目录

  • 抽象类
    • 概念
    • 抽象类语法
  • 接口
    • 概念
    • 规则
    • 使用
    • 特性
    • 实现多个接口
    • 接口的继承
    • 接口使用实例
    • Clonable接口和深拷贝
    • 抽象类和接口的区别
  • Object类

抽象类

概念

在面向对象的概念中,所有对象都是通过类来描述的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息描绘一个具体的对象,这样的类就是抽象类

  1. 使用abstract修饰的方法称为抽象方法
  2. 使用abstract修饰的类称为抽象类
  3. 抽象类是不可以进行实例化的
  4. 抽象类当中可以和普通类一样定义成员变量和成员方法
  5. 当一个普通的类继承了这个抽象类,那么需要重写这个抽象类当中的所有抽象方法
  6. 抽象类的出现就是为了被继承
  7. abstract和final不能共存
  8. 被private static修饰抽象方法也不可以

抽象类语法

在java中,一个类如果被abstract修饰称为抽象类,抽象类中被abstract修饰的方法称为抽象方法,抽象方法不用给出具体的实现体
注意:抽象类也是类,内部也可以包含普通方法和属性,甚至构造方法

接口

概念

接口是公共的行为规范标准,大家在实现时,只要符合规范标准
就可以调用
在java中,接口可以看成是:多个类的公共规范,是一种引用数据类型

规则

  1. 接口是使用interface方法修饰的
  2. 接口当中不能有被实现的方法,意味着只能有抽象方法.但是两个方法除外:一个是static修饰的方法 一个是被default修饰的方法
  3. 接口当作的抽象方法默认都是public abstract修饰的
    什么都不写的时候默认abstract修饰
  4. 接口当中的成员变量默认都是public static final 修饰的
  5. 接口不能进行实例化
  6. 类和接口之间的关系,可以使用implements来进行关联
  7. 接口也是有对应的字节码文件的

接口定义格式与定义类的格式基本相同,将class关键字换成interface关键字,就定义了一个接口

interface 接口名称 {
    
}

使用

接口不能直接使用,必须要有一个"实现类"来实现该接口,实现接口中所有的抽象方法

class 类名称 implements 接口名称{
  // ...
}

注意:子类和父类之间是extends继承关系,类和接口之间是implements实现关系

特性

  1. 接口类型是一种引用类型,但是不能直接new接口的对象,无法实例化
  2. 接口的每个方法都是public修饰的抽象方法,即接口中的方法被隐式的指定为public abstract(只能是public abstract, 其他修饰符都会报错)
  3. 接口的方法是不能在接口实现的,只能由实现接口的类来实现
    但在接口的方法里非要实现需要static或者default修饰
    static修饰的方法不能重写
    default修饰方法可重写可不重写
  4. 重写接口方法时,不能使用默认的访问权限
    因为接口方法里默认就是public abstract,又因为子类的访问权限大于等于父类,子类只能被public修饰
  5. 接口中可以含有变量,但是接口中的变量会被隐式的指定为public static final 变量
  6. 接口不能有代码块(实例代码块和静态代码块)和构造方法
  7. 接口虽然不是类,但是接口编译完成后字节码文件的后缀格式也是class
  8. 如果类没有实现接口中的所有的抽象方法,则类必须被设置为抽象

实现多个接口

接口解决java多继承的问题

abstract class Animal{
    public String name;
    Animal(String name) {
        this.name = name;
    }
    abstract public void eat();
    abstract public void swim();
}

动物里并不是所有的动物都可以游泳,所以把swim写在Animal这个类里面不好,但是如果你把swim写到一个类就行了嘛?但是java不支持同时继承多个类,所以写进类里也不行,所以我们把他封装成了接口

注意:一个类实现多个接口时,每个接口中的抽象方法都要实现,否则类
必须设置为抽象类

接口的继承

在java中,类和类之间是单继承的,一个类可以实现多个接口,接口和接口之间可以多继承.即用接口可以达到多继承的目的

interface walk {
    public void walk();
}
interface run extends walk {
    public void run();
}

run接口有walk接口的特性,可以使用extends关键字来实现复用的效果,extends理解为拓展的意思,即run拓展了walk的功能
run接口不仅具备run接口本身的功能,而且具备walk这个接口的功能

interface A {
    public void a();
}
interface B extends A{
    public void a();
}
class test implements B{
    @Override
    public void a() {

    }
}

接口B和接口A有一样的方法,当接口B拓展接口A时,类test获得B接口,要实现a这个方法
在这里插入图片描述
实现的是接口B的方法a

两个关系:

  1. 类和接口之间的关系–>>implements实现
  2. 接口和接口之间的关系–>>extends拓展

接口之间的继承相当于把多个接口并在一起

接口使用实例

    public static void main(String[] args) {
        int a = 10;
        int b = 20;
        System.out.println(a>b);
    }

在这里插入图片描述

public class Test {
    public static void main(String[] args) {
        Person person01 = new Person();
        Person person02 = new Person();
        System.out.println(person01>person02);
    }
}

class Person {
    public String name;
    public int age;
    public int height;
}

引用类型比较就不可以了,因为比较两个引用类型没有意义,但是你想比较引用类型里的成员变量的话,他也不知道是哪一个

public class Test {
    public static void main(String[] args) {
        Person person01 = new Person();
        Person person02 = new Person();
        System.out.println(person01.compareTo(person02));
    }
}

class Person implements Comparable<Person>{
    public String name;
    public int age;
    public int height;

    @Override
    public int compareTo(Person o) {
        if(this.age>o.age) {
            return 1;
        } else if(this.age==o.age) {
            return 0;
        }
        else {
            return -1;
        }
    }
}

后续文章会讲,此处仅供参考

但是如果用如上代码,在比较身高等其他值的时候就不方便

public class Test {
    public static void main(String[] args) {
        Person person01 = new Person("张三",1,1);
        Person person02 = new Person("李四",2,2);
        System.out.println(new AgeCompare().compare(person01, person02));
    }
}

class AgeCompare implements Comparator<Person> {
    @Override
    public int compare(Person o1, Person o2) {
        return o1.age-o2.age;
    }
}

class Person{
    public String name;
    public int age;
    public int height;
    public Person(String name, int age, int height) {
        this.name = name;
        this.age = age;
        this.height = height;
    }
}

比较器来进行年龄比较,之后同样的方法比较身高等

第一种方式比较对类的侵入性比较强,一旦写好了规定的比较方式,之后只能使用这种方式来进行比较
第二种方式就会比较灵活,单独创建一个类实现比较方法,调用方法时,传入要比较的两个对象即可


public class Test {
    public static void main(String[] args) {
        Person[] people = new Person[3];
        people[0] = new Person(111,"a");
        people[1] = new Person(101,"b");
        people[2] = new Person(121,"c");
        System.out.println(Arrays.toString(people));
        System.out.println("===========================");
        Arrays.sort(people);
        System.out.println("===========================");
        System.out.println(Arrays.toString(people));

    }
}


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

    int age;
    String name;
    Person(int age, String name) {
        this.age = age;
        this.name = name;
    }
}

同理,对自定义类型的数组排序此处也会报错
在这里插入图片描述
Array.sort的源代码追根溯源发现比较是依托compareTo来实现比较的,所以我们可以在类里自己实现compareTo方法


public class Test {
    public static void main(String[] args) {
        Person[] people = new Person[3];
        people[0] = new Person(111,"a");
        people[1] = new Person(101,"b");
        people[2] = new Person(121,"c");
        System.out.println(Arrays.toString(people));
        System.out.println("===========================");
        Arrays.sort(people);
        System.out.println("===========================");
        System.out.println(Arrays.toString(people));

    }
}


class Person implements Comparable<Person>{
    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }

    int age;
    String name;
    Person(int age, String name) {
        this.age = age;
        this.name = name;
    }

    @Override
    public int compareTo(Person o) {
        return this.age-o.age;

    }
}

在这里插入图片描述
sort方法的重载中还可以传入比较器


public class Test {
    public static void main(String[] args) {
        Person[] people = new Person[3];
        people[0] = new Person(111,"a");
        people[1] = new Person(101,"b");
        people[2] = new Person(121,"c");
        System.out.println(Arrays.toString(people));
//        Arrays.sort(people);
        AgeCompare ageCompare = new AgeCompare();
        Arrays.sort(people,ageCompare);
        System.out.println("===========================");
        System.out.println(Arrays.toString(people));
    }
}
//名字比较器
class NameCompare implements Comparator<Person> {
    @Override
    public int compare(Person o1, Person o2) {
        return o2.name.compareTo(o1.name);
    }
}
//年龄比较器
class AgeCompare implements Comparator<Person> {
    @Override
    public int compare(Person o1, Person o2) {
        return o2.age-o1.age;
    }
}

class Person implements Comparable<Person>{
    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }

    int age;
    String name;
    Person(int age, String name) {
        this.age = age;
        this.name = name;
    }

    @Override
    public int compareTo(Person o) {
        return this.name.compareTo(o.name);
    }
}

也可以自己实现排序方法来进行比较,如下

public class Test {
    public static void bubbleSort(Comparable[] comparables) {
        for (int i = 0; i < comparables.length-1; i++) {
            for (int j = 0; j < comparables.length-i-1; j++) {
                if(comparables[j].compareTo(comparables[j+1])>0) {
                    Comparable tem = comparables[j];
                    comparables[j] = comparables[j+1];
                    comparables[j+1] = tem;
                }
            }
        }
    }
    public static void main(String[] args) {
        Person[] people = new Person[3];
        people[0] = new Person(111,"a");
        people[1] = new Person(101,"b");
        people[2] = new Person(121,"c");
        System.out.println(Arrays.toString(people));
        bubbleSort(people);
        System.out.println(Arrays.toString(people));

    }
}

class Person implements Comparable<Person>{
    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }

    int age;
    String name;
    Person(int age, String name) {
        this.age = age;
        this.name = name;
    }

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

Clonable接口和深拷贝


public class Test {
    public static void main(String[] args) {
        Animal animal = new Animal("张三",10);
        Animal animal1 = animal.clone();
    }
}

class Animal {
    String name;
    int height;
    @Override
    public String toString() {
        return "Animal{" +
                "name='" + name + '\'' +
                ", height=" + height +
                '}';
    }

    public Animal(String name, int height) {
        this.name = name;
        this.height = height;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

在这里插入图片描述
创建了一个Animal类,实例化对象animal,想利用clone克隆animal到animal1,但是发生报错
在这里插入图片描述
可能会抛出异常,这个异常叫作不支持克隆异常
编译时期的异常

处理这种异常,对main函数也申请如上操作
在这里插入图片描述
发现依旧报错

在这里插入图片描述
观察clone方法里返回值是Object,但是main方法里animal1是Animal类,类型不匹配,需要强转一下
对main方法如下处理解决刚才的异常问题


public class Test {
    public static void main(String[] args) throws CloneNotSupportedException{
        Animal animal = new Animal("张三",10);
        Animal animal1 = (Animal)animal.clone();
    }
}

按照剧本来走的话
在这里插入图片描述
animal1克隆animal,一切祥和

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException{
        Animal animal = new Animal("张三",10);
        Animal animal1 = (Animal)animal.clone();
        System.out.println(animal);
        System.out.println(animal1);
    }
}

运行起来却又报错
在这里插入图片描述
我们要想对自己写的类型进行克隆的时候,要实现Clonable 接口
在这里插入图片描述
在这里插入图片描述
运行成功,但是当我们点进Clonable 接口去看源代码的时候
在这里插入图片描述
就会发现这个接口是空的,所以我们实现这个接口的意义在哪里
刚才这种接口我们叫作空接口或者标记接口
他的作用在于类实现了Clonable 接口这种空接口,代表这个类是可以被克隆的


public class Test {
    public static void main(String[] args) throws CloneNotSupportedException{
        Stu stu = new Stu("张三",1);
        Stu stu1 = (Stu)stu.clone();

        System.out.println(stu.index.i);
        System.out.println(stu1.index.i);
        stu1.index.i = 0;
        System.out.println(stu.index.i);
        System.out.println(stu1.index.i);

    }
}

class Index {
    public int i = 1;
}

class Stu implements Cloneable{

    public String name;
    public int weight;

    Index index = new Index();
    public Stu(String name, int weight) {
        this.name = name;
        this.weight = weight;
    }

    @Override
    public String toString() {
        return "Stu{" +
                "name='" + name + '\'' +
                ", weight=" + weight +
                '}';
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

在这里插入图片描述
修改stu1里通过引用修改对象index里的成员变量i,但是stu里index的i值也改变
在这里插入图片描述
stu1克隆stu,stu和stu1两者共用同一个引用,而非另外开辟空间,所以当你通过引用改变stu1里index的i值时,也时改变stu里面index的i值,这种是浅拷贝,要实现stu里index和stu1里的index的引用不同,要进行深拷贝,Index也要支持克隆

在这里插入图片描述

如上,让Index也支持克隆,但这样仅仅是支持克隆,但是并未让Stu类里的克隆方法里进行实现对index的克隆,如下
在这里插入图片描述
这样就之后,改变stu1里index的i值就不会影响stu的了
在这里插入图片描述


public class Test {
    public static void main(String[] args) throws CloneNotSupportedException{
        Stu stu = new Stu("张三",1);
        Stu stu1 = (Stu)stu.clone();

        System.out.println(stu.index.i);
        System.out.println(stu1.index.i);
        stu1.index.i = 0;
        System.out.println(stu.index.i);
        System.out.println(stu1.index.i);

    }
}

class Index implements Cloneable{
    public int i = 1;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

class Stu implements Cloneable{

    public String name;
    public int weight;

    Index index = new Index();
    public Stu(String name, int weight) {
        this.name = name;
        this.weight = weight;
    }

    @Override
    public String toString() {
        return "Stu{" +
                "name='" + name + '\'' +
                ", weight=" + weight +
                '}';
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Stu tmp = (Stu) super.clone();
        tmp.index = (Index) this.index.clone();
        return tmp;
    }
}

抽象类和接口的区别

**核心区别:**抽象类中可以包含普通方法和普通字段,这样的普通方法和字段可以被子类直接使用(不需要重写),而接口中不能包含普通方法,子类必须重写所有的抽象方法

在这里插入图片描述

Object类

Object是Java默认提过的一个类.Java里面除了Object类,所有的类都是存在继承关系的.默认会继承Object父类,即所有类的对象都可以使用Object的引用进行接收.

public class Test {
    public static void main(String[] args){
        Animal animal = new Animal("张三");
        Animal animal1 = new Animal("张三");
        System.out.println(animal1 == animal);
    }
}

class Animal {
    String name;

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

如上比较两个对象是否相等,这种比较是比较引用,所以会打印false
Object里equals方法用来比较对象是否相等
在这里插入图片描述

public class Test {
    public static void main(String[] args){
        Animal animal = new Animal("张三");
        Animal animal1 = new Animal("张三");
        System.out.println(animal.equals(animal1));
    }

}

在这里插入图片描述
结果仍是false

在这里插入图片描述
源码和第一次比较方式是一样的,在对引用进行比较相等,所以我们在Animal类里重写这个方法,自己来设计比较方法

class Animal {
    String name;

    public Animal(String name) {
        this.name = name;
    }
    @Override
    public boolean equals(Object obj) {
        Animal animal = (Animal) obj;
        return animal.name.equals(this.name);
    }
}
public class Test {
    public static void main(String[] args){
        Animal animal = new Animal("张三");
        Animal animal1 = new Animal("张三");
        System.out.println(animal.equals(animal1));
    }


}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/355863.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Axios使用方法详解,从入门到进阶

目录 &#x1f333; Axios的诞生 &#x1f333; Axios的介绍 定义 原理 特性 浏览器支持情况 如何安装 &#x1f333; Axios的使用 ◼️ 创建vue项目 ◼️ Axios的基础用法&#xff08;get、post、put 等请求方法&#xff09; get方法 post方法 put和patch方法 …

Jenkins打包、发布、部署

目录 前言 一、安装jdk 二、安装maven 三、安装git 四、安装jenkins 五、访问jenkins 六、创建用户 七、配置jenkins 八、执行 总结 前言 服务器&#xff1a;CentOS 7.9 64位 jdk&#xff1a;1.8 maven&#xff1a;3.9.1 git&#xff1a;git version 1.8.3.1 jenkins&a…

C++中的智能指针

目录 背景 裸指针 智能指针 原理 智能指针 auto_ptr unique_ptr 1. unique_ptr禁止拷贝构造(copy constructor)和赋值运算() 1.1 C提供了标准库函数move() 1.2.如果unique_ptr是一个临时右值 2. unique_ptr可用于数组 shared_ptr 环状引用问题 weak_ptr 注意&#xf…

CRM管理系统有哪些应用价值?

如何杜绝员工飞单、走私单&#xff1f; 如何避免员工离职带走客户&#xff1f; ——crm管理系统 企业要想取得成功&#xff0c;有强大的技术支持和合适的工具辅助&#xff0c;crm管理系统这类工具就是客户管理系统&#xff0c;它是一种先进的管理模式&#xff0c;crm管理系统通…

浅析透明图片显示

1、理解图片构成 上面是一个飞机的透明图片&#xff0c;每个图片都是有一个个像素点构成的&#xff0c;每个像素点都是一个颜色&#xff0c;在内存中占4个字节&#xff0c;由透明度、红、绿、蓝构成。如下图&#xff1a; 该飞机图片飞机图片长51像素&#xff0c;宽63像素。就是…

苹果m1、m2安装blender GIS,解决not Imageio 报错

blender-GIS 能够在地图上生成地形&#xff0c;如下图所示&#xff1a; 使用blenderGIS过程中会有 imageio 找不到的情况&#xff0c; 网上的 imageio 用在苹果电脑的M1、M2芯片上好像还是没有出图&#xff0c;似乎这个 imageio 这个已经是好几年前的代码&#xff0c;没能适配…

Sphinx的原理详解和使用

一、Sphinx介绍 1.1 简介 Sphinx是由俄罗斯人Andrew Aksyonoff开发的一个全文检索引擎。意图为其他应用提供高速、低空间占用、高结果 相关度的全文搜索功能。Sphinx可以非常容易的与SQL数据库和脚本语言集成。当前系统内置MySQL和PostgreSQL 数据库数据源的支持&#xff0c;也…

Vue3 + Express 实现大文件分片上传、断点续传、秒传

目录 前言原理实现项目搭建获取文件文件分片hash计算文件上传文件合并秒传&断点续传 完整代码 前言 在日常开发中&#xff0c;文件上传是常见的操作之一。文件上传技术使得用户可以方便地将本地文件上传到Web服务器上&#xff0c;这在许多场景下都是必需的&#xff0c;比如…

比特币ETF通过为BiFinance带来全新机遇

2013年7月&#xff0c;Winklevoss兄弟提交了首个比特币交易所交易基金&#xff08;ETF&#xff09;申请&#xff0c;随后多家公司纷纷效仿&#xff0c;但美国证券交易委员会&#xff08;SEC&#xff09;均以“容易受到市场操纵”为由驳回了这些申请。时至2024年伊始&#xff0c…

TCP_拥塞控制

引言 24年春节马上就要到了&#xff0c;作为开车党&#xff0c;最大的期盼就是顺利回家过年不要堵车。梦想是美好的&#xff0c;但现实是骨感的&#xff0c;拥堵的道路让人苦不堪言。 在网络世界中&#xff0c;类似于堵车的问题也存在&#xff0c;而TCP&#xff08;Transmissi…

环形链表找入环点----链表OJ---三指针

https://leetcode.cn/problems/linked-list-cycle-ii/description/?envTypestudy-plan-v2&envIdtop-100-liked 首先&#xff0c;需要判断是否有环&#xff0c;而这里我们不单纯判断是否有环&#xff0c;还要为下一步做准备&#xff0c;需要让slow指针和fast都从头结点开始…

【数据结构1-1】线性表

线性表是最简单、最基本的一种数据结构&#xff0c;线性表示多个具有相同类型数据“串在一起”&#xff0c;每个元素有前驱&#xff08;前一个元素&#xff09;和后继&#xff08;后一个元素&#xff09;。根据不同的特性&#xff0c;线性表也分为数组&#xff08;vector&#…

MySQL 学习记录

基本常识 row-size-limitsblob&#xff1a; BLOB and TEXT columns cannot have DEFAULT values.Instances of BLOB or TEXT columns in the result of a query that is processed using a temporary table causes the server to use a table on disk rather than in memory b…

C++11——新的类功能与可变参数模板

系列文章目录 文章目录 系列文章目录一、新的类功能默认成员函数类成员变量初始化强制生成默认函数的关键字default禁止生成默认函数的关键字delete继承和多态中的final与override关键字 二、可变参数模板递归函数方式展开参数包逗号表达式展开参数包STL容器中的empalce_back与…

写点东西《JWT 与会话身份验证》

写点东西《JWT 与会话身份验证》 身份验证与授权 JWT 与session身份验证 - 基本差异 什么是 JWT&#xff1f; JWT 结构&#xff1a; JWT 工作流程&#xff1a;优势: 安全问题&#xff1a; 处理令牌过期&#xff1a; 基于session的身份验证&#xff08;通常称为基于 cookie 的身…

工程对接大模型流式和非流式对话底层原理解析

文章目录 前言一、非流式输出设计二、stream流式输出设计三、手撸一个流式输出项目总结 前言 之前对接过OpenAi大模型的官方API&#xff0c;可以看到它有一个Stream参数&#xff0c;设置成true的时候就是流式的对话输出&#xff0c;现象就是一段一段的往外崩。 官方手册的地址…

蓝桥杯训练|基础语言Day1 - STL pair vector list stack queue set map容器

学习目标&#xff1a; 博主介绍: 27dCnc 专题 : 算法题入门 &#x1f44d;&#x1f44d;&#x1f44d;&#x1f44d;&#x1f44d;&#x1f44d;&#x1f44d;&#x1f44d;&#x1f44d;&#x1f44d;&#x1f44d;&#x1f44d; ☆*: .&#xff61;. o(≧▽≦)o .&#xff61…

Python爬虫案例展示:实现花猫壁纸数据采集

嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! python更多源码/资料/解答/教程等 点击此处跳转文末名片免费获取 环境使用: Python 3.10 Pycharm 模块使用: import requests >>> pip install requests win R 输入cmd 输入安装命令 pip install requests 安装即…

Springboot各种请求参数详解

文章目录 请求Postman**为什么需要Postman****什么是Postman****Postman使用教程** 请求参数简单参数实体参数数组参数集合参数![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/eba0ca80e3724412ae4c79af72b859c3.png#pic_center)日期参数json参数路径参数总结 请求…

STM32CubeMX教程31 USB_DEVICE - HID外设_模拟键盘或鼠标

目录 1、准备材料 2、实验目标 3、模拟鼠标实验流程 3.0、前提知识 3.1、CubeMX相关配置 3.1.0、工程基本配置 3.1.1、时钟树配置 3.1.2、外设参数配置 3.1.3、外设中断配置 3.2、生成代码 3.2.0、配置Project Manager页面 3.2.1、设初始化调用流程 3.2.2、外设中…