Java--接口

news2024/11/14 13:35:45

目录

语法规则

例子

实现多个接口

接口之间的继承

抽象类和接口的区别

接口使用实例--Comparable接口

Clonable接口

浅拷贝

深拷贝


在现实生活中,接口的例子比比皆是,比如:电源插座,主机上的USB接口等。这些插口中可以插所有符合规范的设备。通过这个例子我们知道,接口就是公共的行为规范标准,大家在实现时,只要符合规范标准,就可以通用。在java中,接口可以看成是:多个类的公共规范,是一种引用数据类型。

语法规则

通过关键字interface来定义一个接口。在创建接口时,接口的命名一般以大写字母I开头。

接口中的成员默认都是public static final的,接口中的成员方法默认都是public abstract的,所以一般都不写,保持代码简洁性。

interface IShape {
    //public static final int a = 10;
    int a = 0;
    //public abstract void draw();
    void draw();
}

在接口中,不可以有普通成员方法

java8开始,允许在接口当中定义一个default方法,这个方法可以有具体的实现

interface IShape {
    int a = 0;
    void draw();
    default public void test() {
        System.out.println("test()");
    }
}

接口当中的方法,如果是static修饰的方法,那么可以有具体的实现

    public static void test2() {
        System.out.println("static方法");
    }

接口当中不能有构造方法和代码块

接口不可以通过new关键字进行实例化

类和接口之间可以通过关键字implements来实现接口,且类中要重写接口中的抽象方法

class Rect implements IShape {
    @Override
    public void draw() {
        System.out.println("矩形");
    }
}

 当一个类实现接口当中的方法之后,当前类中的方法不能不加public

 接口可以发生向上转型,也可以发生动态绑定

public class Test8_4 {
    public static void drawMap(IShape iShape) {
        iShape.draw();
    }
    public static void main(String[] args) {
        IShape iShape = new Rect();
        drawMap(iShape);
        drawMap(new Flower());
    }
}

输出结果:

一个接口也会产生独立的字节码文件

例子

我们来看一个具体的例子:

新建一个名为IUSB的接口

public interface IUSB {
    void openDevice();//打开服务
    void closeDevice();//关闭服务
}

新建一个类Mouse,通过implements实现IUSB

public class Mouse implements IUSB{
    @Override
    public void openDevice() {
        System.out.println("打开鼠标");
    }
    @Override
    public void closeDevice() {
        System.out.println("关闭鼠标");
    }
    public void click() {
        System.out.println("点击鼠标");
    }
}

新建一个类keyBoard类,通过implements实现IUSB

public class keyBoard implements IUSB{
    @Override
    public void openDevice() {
        System.out.println("打开键盘");
    }
    @Override
    public void closeDevice() {
        System.out.println("关闭键盘");
    }
    public void inPut() {
        System.out.println("输入");
    }
}

新建一个Computer类,类中分别有三个方法,分别是打开电脑、关闭电脑、使用服务

public class Computer {
    public void powerOn() {
        System.out.println("打开笔记本电脑");
    }
    public void powerOff() {
        System.out.println("关闭笔记本电脑");
    }
    public void useDevice(IUSB iusb) {
        //启动服务
        iusb.openDevice();
        if (iusb instanceof Mouse) {
            //如果是鼠标调用 那么将iusb强转成Mouse类并调用click方法
            Mouse mouse = (Mouse) iusb;
            mouse.click();
        } else if (iusb instanceof keyBoard) {
            //如果是键盘调用 那么将iusb强转成keyBoard类并调用inPut方法
            keyBoard keyBoard = (demo4.keyBoard) iusb;
            keyBoard.inPut();
        }
        //关闭服务
        iusb.closeDevice();
    }
}

下面我们来测试一下useDevice方法

public static void main(String[] args) {
        Computer computer = new Computer();
        computer.powerOn();//打开电脑
        
        computer.useDevice(new Mouse());//鼠标
        computer.useDevice(new keyBoard());//键盘

        computer.powerOff();//关闭电脑
    }

你可以自己分析一下程序的输出结果是什么。

这里我直接给出运行结果:

实现多个接口

在java中,类和类之间是单继承的,一个类只能有一个父类,不支持多继承,但是一个类可以实现多个接口。我们认识了很多动物,有会飞的,会跑的,会游的,现在我们写一个代码来实现它。

新建一个IFlying接口

public interface IFlying {
    void fly();
}

新建一个ISwimming接口

public interface ISwimming {
    void swim();
}

新建一个IRunning接口

public interface IRunning {
    void run();
}

新建一个Animal类,这是一个抽象类

public abstract class Animal {
    public String name;
    public int age;
    public abstract void eat();
    //构造方法
    public Animal(String name,int age) {
        this.name = name;
        this.age = age;
    }
}

新建一个Dog类,继承Animal,并重写Animal中的抽象方法

public class Dog extends Animal{
    @Override
    public void eat() {
        System.out.println(this.name+"吃狗粮");
    }
    //构造方法
    public Dog(String name,int age) {
        super(name, age);
    }
}

对于狗来说,他会狗刨(游泳),会跑,他的功能不止一个,通过implements实现IRunning和ISwimming,并重写接口中的方法

public class Dog extends Animal implements IRunning,ISwimming{
    @Override
    public void eat() {
        System.out.println(this.name+"吃狗粮");
    }
    //构造方法
    public Dog(String name,int age) {
        super(name, age);
    }

    @Override
    public void run() {
        System.out.println(this.name+"用狗腿跑");
    }

    @Override
    public void swim() {
        System.out.println(this.name+"正在狗刨");
    }
}

【注】一定是先继承,再实现;在java中只能继承一个类,实现多个接口。

新建一个Bird类,继承Animal,实现IRunning,IFlying接口

public class Bird extends Animal implements IFlying,IRunning{
    @Override
    public void eat() {
        System.out.println(this.name+"吃鸟食");
    }
    public Bird(String name,int age) {
        super(name, age);
    }

    @Override
    public void run() {
        System.out.println(this.name+"用鸟腿跑");
    }

    @Override
    public void fly() {
        System.out.println(this.name+"正在飞");
    }
}

新建一个测试类Test10_1

public class Test10_1 {
    public static void test1(Animal animal) {
        animal.eat();
    }
    public static void test2(IRunning iRunning) {
        iRunning.run();
    }
    public static void test3(ISwimming iSwimming) {
        iSwimming.swim();
    }
    public static void test4(IFlying iFlying) {
        iFlying.fly();
    }
    public static void main(String[] args) {
        Dog dog = new Dog("小狗",2);
        Bird bird = new Bird("小鸟",1);
        test1(bird);
        test1(dog);
        System.out.println("==========================");
        //dog和bird都实现了IRunning
        test2(bird);
        test2(dog);
        System.out.println("==========================");
        //只有dog实现了ISwimming
        test3(dog);
        System.out.println("==========================");
        //只有bird实现了IFlying
        test4(bird);
        System.out.println("==========================");
    }
}

你可以自己分析一下输出结果是什么。

这里我直接给出结果:

现在我们再新建一个Robot类,它不属于动物,但有跑的功能

public class Robot implements IRunning{
    @Override
    public void run() {
        System.out.println("机器人在跑");
    }
}
    public static void main(String[] args) {
        test2(new Robot());
    }

输出结果为:

只有具备功能即可,十分灵活。

通过上面这个例子,我们知道,继承表达的是is-a的语义,而接口表达的是具有xxx特性

接口之间的继承

现在我们定义三个接口A、B、C

interface A {
    void testA();
}
interface B {
    void testB();
}
interface C {
    void testC();
}

现有一个接口具备B和C接口的功能,难道要再新建一个接口D,把B、C的功能放进去吗?

interface D {
    void testB();
    void testC();
}

这样写不太合适,不能解决长久的问题,我们可以用关键字extends,此时extends意为拓展

interface D extends B,C{
   //D这个接口具备了B和C的功能,同时D可以也定义属于自己的功能
    void testD();
}

那么当一个类实现D接口时,要重写B、C、D的方法

public class Test10_2 implements D{
    @Override
    public void testB() {
        System.out.println("B");
    }

    @Override
    public void testC() {
        System.out.println("C");
    }

    @Override
    public void testD() {
        System.out.println("D");
    }
}

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

抽象类和接口的区别

区别抽象类(abstract)接口(interface)
结构组成普通类+抽象方法抽象方法+全局常量
权限各种权限public
子类使用使用extends关键字继承抽象类使用implements关键字实现接口
关系一个抽象类可以实现若干接口接口不能继承抽象类,但是接口可以使用extends关键字继承多个父接口
子类权限一个子类只能继承一个抽象类一个子类可以实现多个接口

接口使用实例--Comparable接口

现在我们有一个Student类

class Student implements Comparable<Student>{
    public String name;
    public int age;
    public Student(String name,int age) {
        this.name = name;
        this.age = age;
    }

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

思考一下,如果想比较两个学生的年龄大小应该如何比较呢?难道跟以前学的一样直接比较吗?我们来试一下:

我们会发现代码报错了,因为我们的student1和student2不是基本数据类型,那么此时要想比较年龄大小,我们就需要借助接口Comparable了,让Student类实现Comparable接口

我们发现代码报错了,现在我们看一下Comparable的代码:

Comparable后面的<T>叫做泛型,这里你先记为固定写法,所以我们应该这样写:

class Student implements Comparable<Student>{
……

并在Student类中重写compareTo方法:

    @Override
    public int compareTo(Student o) {
        //return this.age - o.age;
        //谁调用compareTo方法 谁就是this
        if (this.age > o.age) {
            return 1;
        }else if (this.age < o.age) {
            return -1;
        }else {
            return 0;
        }
    }

此时我们就可以在main方法中进行比较了

public static void main(String[] args) {
        Student student1 = new Student("张三",10);
        Student student2 = new Student("李四",15);
        System.out.println(student1.compareTo(student2));//student1这个对象和student2这个对象 
                                                         //比较
    }

自定义类型要想比较大小,要实现Comparable接口,并重写compareTo方法来实现比较的逻辑。

再举个例子,现在我们有一个Student数组,我们想要数组按照年龄大小排序,排序我们可以调用sort()方法,因为要进行比较,所以必须要实现Comparable接口,代码如下:

    public static void main(String[] args) {
        Student[] students = new Student[3];
        students[0] = new Student("张三",10);
        students[1] = new Student("李四",5);
        students[2] = new Student("王五",18);
        Arrays.sort(students);
        System.out.println(Arrays.toString(students));
    }

输出结果:

没有实现Comparable接口就运行代码的情况在这里就不做展示了,感兴趣的朋友可以自己动手试一下。

实现Comparable接口后,我们也可以重写一个冒泡排序方法:

    public static void bubbleSort(Comparable[] comparable) {
        for (int i = 0; i < comparable.length; i++) {
            for (int j = 0; j < comparable.length-1-i; j++) {
                if (comparable[j].compareTo(comparable[j+i]) > 0) {
                    Comparable temp = comparable[j];
                    comparable[j] = comparable[j+1];
                    comparable[j+1] = temp;
                }
            }
        }
    }

这个接口对类的侵入性比较强,如果我们现在想根据姓名排序,方法改了之后,前面实现的根据年龄比较的方法可能就实现不了了,因此我们也有另外一种比较方式---比较器。

如果我们先要根据年龄排序,可以定义一个类AgeComparator,这个类实现Comparator接口,Comparator中有一个方法,叫做compara,你只需要在AgeComparator类中重写这个方法即可。

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

在main方法中我们需要实例化一个AgeComparator的对象,通过这个对象引用compara方法,比较学生年龄

    public static void main(String[] args) {
        Student student1 = new Student("张三",10);
        Student student2 = new Student("李四",15);
        AgeComparator ageComparator = new AgeComparator();
        System.out.println(ageComparator.compare(student1, student2));
    }

根据姓名比较就定义一个NameComparator类,实现Comparator接口,那么重写方法时,name是一个String类型,应该如何比较呢?我们来看一下String这个类

我们发现在源码中String实现的是Comparable接口,那么它一定实现了comparaTo方法

所以我们就可以通过String变量直接调用这个comparaTo方法

class NameComparator implements Comparator<Student> {
    @Override
    public int compare(Student o1, Student o2) {
        return o1.name.compareTo(o2.name);
    }
}
    public static void main(String[] args) {
        Student student1 = new Student("zhangsan",10);
        Student student2 = new Student("lisi",15);
        NameComparator nameComparator = new NameComparator();
        System.out.println(nameComparator.compare(student1, student2));//14
    }

通过这个方法实现,两种比较方法互不干扰,非常灵活。

Clonable接口

我们新建一个Person类

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

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

并在main方法中实例化一个对象

    public static void main(String[] args) {
        Person person1 = new Person(10);
    }

现在我们的要求是,能不能把person1指向的这个对象克隆一份呢?我们需要调用一个方法clone方法。但是如果我们直接在main方法中调是会报错的

因为我们现在没有clone()这个方法。那谁有呢?Object有。(可以看这篇博客简单了解一下http://t.csdnimg.cn/qKuOZ)

我们知道,Object是所有类的父类,那现在为什么不能调用呢?因为访问权限,protected修饰的只能在同一个包同一个类同一个包不同类以及不同包中的子类中访问。且要使用super来访问父类的属性。那现在怎么办,我们只能重写clone方法:在Person类中右键-->Generate-->Override Methods-->

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

重写了方法之后,你会发现仍然是报错的,

这是什么原因呢,我们看到重写的clone()方法上

抛出了一个异常叫做编译时异常,解决它很简单,鼠标放在报红的地方,Alt+Enter

点击这个此时代码是这样的

现在你会发现报红变长了,这又是另一个错误了。clone()方法的返回值类型是Object,但是你用Person类接受了,向下转型范围变小了,要进行强转,强转成Person

现在代码就不报错了。

    public static void main(String[] args) throws CloneNotSupportedException {
        Person person1 = new Person(10);
        Person person2 = (Person) person1.clone();
        System.out.println(person1);
        System.out.println(person2);
    }

此时当你运行你的代码时,你会发现报错了

他说不支持克隆,如果你自定义的类型想要进行克隆,那么一定要实现Cloneable接口

class Person implements Cloneable{
……

我们点开接口的代码会发现没有任何东西,那这个接口有什么用呢?这个Cloneable接口叫做空接口或者标记接口:证明当前类是可以克隆的。

这个时候我们再运行代码发现可以了。

此时,clone()方法就帮你完成了克隆。当然这里也会存在一个问题,就是深拷贝和浅拷贝什么是深拷贝,什么是浅拷贝呢?

浅拷贝

现在我们添加一个Money类,将Money类和Person类组合

class Money {
    public double money = 19.9;
}
class Person implements Cloneable{
    public int age;
    public Money m;
    public Person(int age) {
        this.age = age;
        this.m = new Money();
    }
……
    public static void main(String[] args) throws CloneNotSupportedException {
        Person person1 = new Person(10);
        Person person2 = (Person) person1.clone();
        System.out.println(person1.m.money);
        System.out.println(person2.m.money);
    }

此时我们运行代码输出的是两个19.9。

        person2.m.money = 99.99;
        System.out.println(person1.m.money);
        System.out.println(person2.m.money);

现在我们把克隆之后的money值改成99.99,再来输出结果,理论上我们希望输出19.9和99.99,但是我们发现程序输出并不是这样的

两个money的值都改了,这种情况就叫做浅拷贝。下面我们来分析一下他的原因。

现在这个现象就是浅拷贝,并没有将对象中的对象进行克隆。

深拷贝

深拷贝就是,我们希望把对象中的对象也拷贝一份。如何做到深拷贝呢?回到代码上,跟刚刚一样,我们需要在Money类中重写clone方法并实现cloneable接口

class Money implements Cloneable{
    public double money = 19.9;

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

接下来我们需要调用这个clone()方法,那么怎么调用呢?person2是在Person person2 = (Person) person1.clone();这条语句执行时克隆出来的,那么我们回到Person类的clone()方法中,我们定义一个temp接受克隆出来的对象。

现在我们想让person1所指向的m这个对象也克隆一份出来,怎么调用它的clone()方法呢?很简单,谁调用方法谁就是this,现在我们已经把m克隆了一份

把克隆的这份给temp.m

最后return temp把temp给person2

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Person temp = (Person) super.clone();
        temp.m = (Money) this.m.clone();
        return temp;
    }

temp是一个局部变量,当调用完clone()方法temp就被自动回收了。

因此main方法中的代码不用改变,我们再来运行,结果就正确了

深拷贝和浅拷贝看的是代码的实现过程。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C++】位运算:两整数之和

1.题目 2.算法思路 本题不能只用 -&#xff0c;那大概率用到位运算符。 异或的作用是无进位相加&#xff0c;所以需要通过异或运算&#xff08;^&#xff09;来替代加法运算&#xff0c;但是我们无法确定进位的信息。所以需要与运算&#xff08;&&#xff09;来得到进位的…

【数据结构与算法 经典例题】翻转二叉树

&#x1f493; 博客主页&#xff1a;倔强的石头的CSDN主页 &#x1f4dd;Gitee主页&#xff1a;倔强的石头的gitee主页 ⏩ 文章专栏&#xff1a;《数据结构与算法 经典例题》C语言 期待您的关注 ​ 目录 一、问题描述 二、解题思路 三、C语言实现代码 一、问题描述 给你一…

golang 字符编码 gbk/gb2312 utf8编码相互转换,判断字符是否gbk编码函数, 字符编码转换基础原理解析, golang默认编码utf8

虽然golang里面的默认编码都是统一的unicode utf8编码&#xff0c; 但是我们在调用外部系统提供的api时&#xff0c;就可能会遇到别人的接口提供的编码非 utf8编码&#xff0c;而是gbk/gb2312编码&#xff0c; 这时候我们就必须要将别人的gbk编码转换为go语言里面的默认编码ut…

2024国内AI公司50强榜单。。。

你好&#xff0c;我是郭震 近日&#xff0c;2024国内AI公司50强榜单发布。 1 AI公司50强榜单 AI公司排名前五分别是&#xff1a;百度&#xff0c;阿里&#xff0c;华为&#xff0c;腾讯&#xff0c;科大讯飞。 6-10名分别是&#xff1a;小米&#xff0c;商汤&#xff0c;字节跳…

Jeston Orin IIC 驱动测试 —— 以MPU6050为例

前言 后续驱动需要需要使用IIC作为通讯的协议&#xff0c;但是做的板子还没来&#xff0c;因此&#xff0c;在开发板驱动加载真正的之前&#xff0c;我们需要确保IIC能够正常通信。 网上的博客基本都是教怎么使用i2c-tools进行通信的&#xff0c;但是这种方法只是在用户空间下…

【效率提升】程序员常用Shell脚本

文章目录 常用Shell脚本一. 定期更新分区数据二、获取系统资源的使用情况 常用Shell脚本 一. 定期更新分区数据 在某些场景下&#xff0c;我们需要对N年前某一分区的数据进行删除&#xff0c;并添加今年该对应分区的数据&#xff0c;实现数据的流动式存储。 #!/bin/bash dt$…

基于FPGA的数字信号处理(18)--半加器和全加器

前言 在数字系统中&#xff0c;加法运算是最常见的算术运算&#xff0c;同时它也是进行各种复杂运算的基础。 半加器 最简单的加法器叫做 半加器&#xff08;Half Adder&#xff09;&#xff0c;它将2个输入1bit的数据相加&#xff0c;输出一个2bits的和&#xff0c;和的范围为…

若依前后端获取当前用户

后端 Autowired private TokenService tokenService;LoginUser loginUser tokenService.getLoginUser(); sysInquiry.setCreateBy(loginUser.getUsername()); sysInquiry.setCreateTime(DateUtils.getNowDate()); 前端 获取使用 const nickName this.$store.state.user.nick…

最大似然估计模型及 Stata 具体操作步骤

目录 一、引言 二、理论原理 三、准备数据 四、定义似然函数 五、进行最大似然估计 六、代码解释 七、代码运行结果 八、模型评估与诊断 一、引言 最大似然估计&#xff08;Maximum Likelihood Estimation&#xff0c;MLE&#xff09;是一种在统计学中广泛应用的参数估计…

linux下磁盘分区工具GParted

最近发现安装的redhat机器部分磁盘大小分配不合理 使用gpated对磁盘重新分区 1、使用U盘制作一个启动盘 下载启动盘制作工具Index of /downloads 使用非常简单&#xff0c;选择gparted-live-1.1.0-3-i686.iso包即可 2、制作完成后&#xff0c;重启机器&#xff0c;选择U盘…

黑马点评-Postman卡住sending Requst原因解决

不知道为什么&#xff0c;用这个c1e1d5的token就会一直卡死&#xff0c;但是换了一个token就解决了&#xff0c;目前不知道为什么 解决了&#xff0c;原来是这个请求下面的函数发生了死循环&#xff01;&#xff01;太瓜皮了我超&#xff01; 把num写成了count&#xff0c;导…

Docker启动PostgreSql并设置时间与主机同步

在 Docker 中启动 PostgreSql 时&#xff0c;需要配置容器的时间与主机同步。可以通过在 Dockerfile 或者 Docker Compose 文件中设置容器的时区&#xff0c;或者使用宿主机的时间来同步容器的时间。这样可以确保容器中的 PostgreSql 与主机的时间保持一致&#xff0c;避免在使…

【iOS】Tagged Pointer

目录 前言什么是Tagged Pointer&#xff1f;引入Tagged Pointer技术之前引入Tagged Pointer之后总结 Tagged Pointer原理&#xff08;TagData分析&#xff09;关闭数据混淆MacOS分析NSNumberNSString iOS分析 判断Tagged PointerTagged Pointer应用Tagged Pointer 注意点 Tagge…

[MySQL][深入理解隔离性][上][MVCC]详细讲解

目录 0.铺垫1.初识MVCC2.三个记录隐藏列字段1.是什么&#xff1f;2.示例 3.undo日志4.模拟MVCC5.思考 0.铺垫 在RR级别的时候&#xff0c;多个事务的update&#xff0c;多个事务的insert&#xff0c;多个事务的delete&#xff0c;是否会有加锁现象&#xff1f; 现象结果是&…

【C++】deque以及优先级队列

容器适配器 deque的介绍deque的原理介绍 priority_queue的介绍与使用priority_queue的介绍priority_queue的使用constructor&#xff08;构造函数&#xff09;emptypushpoptopsize priority_queue的模拟实现 仿函数何为适配器容器适配器deque的缺陷选择deque作为适配器的理由ST…

保姆级教程:十分钟快速上手Coze自定义插件

&#x1f43c; 关注我, 了解更多 AI 前沿资讯和玩法&#xff0c;AI 学习之旅上&#xff0c;我与您一同成长&#xff01; 我已经不止一次听到这样的话&#xff1a;未来的 AI 应用属于各行各业的智能体 (Agent) &#xff5e; 无论是国内的 扣子Coze、Dify&#xff0c;还是国外的…

网易易盾图标点选验证码识别代码

简介 网易图标点选一直都是一个大难题&#xff0c;如上图所示。难点之一是图标变幻莫测&#xff0c;很难刷出有重复的图标&#xff0c;所以使用传统等等方式去标注、识别具有较大的难度。 经过我们大量的数据标注&#xff0c;终于完成了这款验证码的识别。 目前我们提供两种识…

FPGA:频闪灯设计

1、需求 若在FPGA上实现LED灯一秒闪烁一次&#xff0c;先进行计算&#xff0c;1秒闪烁一次&#xff0c;即周期为1秒&#xff0c;开发板XC7A35TFFG-2的基本时钟输入由板载 50MHz 有源晶振提供&#xff0c;即频率为f 50MHz 。 则一个周期为 T 1 f 1 50 M H z 20 n s T\frac{…

C++初阶:模版初阶【范式编程】【函数模板】【类模板】

一.范式编程 我们在写C函数重载的时候&#xff0c;可能会写许多同一类的函数。 比如交换函数&#xff1a; void Swap(int& left, int& right) {int temp left;left right;right temp; }void Swap(double& left, double& right) {double temp left;left …

多线程.下

目录 1.线程等待 2.join&#xff08;&#xff09;介绍 3.获取当前对象引用 4.线程的状态 5.线程安全 6.synchronized()关键字 7.synchronized关键字底层介绍 1.线程等待 对于操作系统而言&#xff0c;内部多个线程的执行是“随机调度&#xff0c;抢占式执行”的。简而言…