当前位置: 首页 > news >正文

JAVA学习*接口

接口

在生活中我们常听说USB接口,那接口是什么呢?
在Java中,接口相当于多个类的一种公共规范,是一种引用数据类型。

定义接口

public interface IUSB {public static final String SIZE = "small";public abstract void openDevice();void closeDevice();public static void test() {System.out.println("调用静态方法test()");}public default void test1() {System.out.println("调用default修饰的test1");}
}

上述代码定义了IUSB接口。
创建接口如下:
在这里插入图片描述
基本语法:

public interface 接口名 {}

接口类中的成员

在接口中

1、定义成员变量:

public static final 数据类型 成员变量名 = 初始化;

编译器会默认加上public static final,所以不写这个也可以。

数据类型 成员变量名 = 初始化;

但要注意:一定要初始化,因为有final关键字

2、定义成员方法:

//抽象类方法
public abstract 返回类型 方法名();

编译器会默认加上public abstract,所以不写这个也可以。

返回类型 方法名();

一般成员方法定义为抽象方法。
由于是抽象方法,所以在接入接口的类中一定要重写抽象方法!

但接口中的方法也可以具体实现的(有两种方法)。

//1、使用static修饰
public static void test1() {}
//要调用的话,就直接 接口名.方法名
IUSB.test();
//2、使用default修饰
public default void test2() {}
//要调用的话,可以通过类的对象访问
public default void test1() {//接口中System.out.println("调用default修饰的test1()");
}
Screen screen = new Screen();//Screen是实现接口的类
screen.test1();//没有报错//要调用的话,也可以重写方法
@Override//在Screen中重写
public void test1() {System.out.println("调用重写的test1()方法");
}
Screen screen = new Screen();//Screen是实现接口的类
screen.test1();//调用

3、在接口类中,没有静态代码块和构造方法

接口的使用

基本语法:

public class 类名 implements 接口名{
}

1、接口不能直接使用,实例化对象。
在这里插入图片描述
2、必须要有类来接入接口。通过重写抽象方法来实现接口中的抽象方法。

public class Screen implements IUSB {@Overridepublic void openDevice() {System.out.println("打开显示屏");}@Overridepublic void closeDevice() {System.out.println("关闭显示屏");}public void show() {System.out.println("开始显示");}
}
public class Keyborad implements IUSB{@Overridepublic void openDevice() {System.out.println("启动键盘");}@Overridepublic void closeDevice() {System.out.println("关闭键盘");}public void inPut() {System.out.println("输入数据");}}
public class Computer {public void openComputer() {System.out.println("打开电脑");}public void closeComputer() {System.out.println("关闭电脑");}public void useDevice(IUSB usb){usb.openDevice();usb.test1();if(usb instanceof Screen) {Screen screen = (Screen)usb;screen.show();}if (usb instanceof Keyborad keyborad){keyborad.inPut();}usb.closeDevice();}
}
public class Test {public static void main(String[] args) {Computer computer = new Computer();computer.openComputer();computer.useDevice(new Keyborad());computer.useDevice(new Screen());computer.closeComputer();System.out.println("-----------");IUSB.test();Screen screen = new Screen();screen.test1();}
}

3、根据重写规则,重写的方法访问权限修饰符一定是public。
4、代码中的向上转型和向下转型。
发生向上转型:

computer.useDevice(new Keyborad());
computer.useDevice(new Screen());

发生向下转型:

if(usb instanceof Screen) {Screen screen = (Screen)usb;//强制类型转换screen.show();
}
if (usb instanceof Keyborad keyborad){keyborad.inPut();
}

向下转型的时候不知道实际指向是哪个引用的,这时候需要if语句来判断。
两种if的写法都是可以的。
第一种,先通过 instanceof 判断类型,再手动强制转换并声明变量。
第二种,在 instanceof 表达式中直接完成类型判断和变量声明,keyborad 会被自动推导为 Keyborad 类型,无需手动强制转换。

上述代码输出:
打开电脑
启动键盘
调用default修饰的test1()
输入数据
关闭键盘
打开显示屏
调用重写的test1()方法
开始显示
关闭显示屏
关闭电脑
-----------
调用静态方法test()
调用重写的test1()方法

实现多个接口

一个类虽然不能继承多个类,但可以使用多个接口

public class Animal {public String name;public int age;
}
public interface ISwimming {void swim();
}
public interface IRunning {void run();
}
public class Dog extends Animal implements ISwimming, IRunning {@Overridepublic void run() {System.out.println("狗在跑步");}@Overridepublic void swim() {System.out.println("狗会狗刨");}
}
public class People implements IRunning{@Overridepublic void run() {System.out.println("人在跑步");}
}
public class Test {public static void main(String[] args) {Dog dog = new Dog();dog.run();dog.swim();People people = new People();people.run();}
}

上述代码输出:
狗在跑步
狗会狗刨
人在跑步

对于Dog类来说,继承了Animal类,并使用了ISwimming和IRunning两个接口。这时候Dog类中要重写两个抽象方法。

注意:

我们此外还定义了People类,来实现IRunning接口。这时候我们并没有注重类型,而是专注于某个类具体的实现功能、能力。
在前面继承的时候说过,继承是 is - a 的关系。而接口就是 can - do 的关系,用于定义一组行为规范,一个类实现某个接口意味着它具备了该接口所定义的行为能力。

接口中的继承

public interface IRunAndSwim extends ISwimming,IRunning{void test();
}
public interface ISwimming {void swim();
}
public interface IRunning {void run();
}
public class Dog extends Animal implements IRunAndSwim {@Overridepublic void run() {System.out.println("狗在跑步");}@Overridepublic void swim() {System.out.println("狗会狗刨");}@Overridepublic void test() {System.out.println("重写test()抽象方法");}
}

接口可以继承多个接口,使用 extends 关键字。

接口中的继承有点像将一些接口拼合起来了

使用现成的接口

对象之间进行大小关系比较

使用Comparable接口
代码展示:
//定义学生类实现接口Comparable
public class Student implements Comparable<Student>{public String name;public int age;public double score;public Student(String name, int age, double score) {this.name = name;this.age = age;this.score = score;}//重写输出方法@Overridepublic String toString() {return "Student1{" +"name='" + name + '\'' +", age=" + age +", score=" + score +'}';}//重写compareTo比较方法@Overridepublic int compareTo(Student o) {if(this.age>o.age) {return 1;}else  if(this.age<o.age){return -1;}else return 0;//可以简写语句,效果是一样的//return Integer.compare(this.age, o.age);//return this.age - o.age;}
}
public class Test {public static void main(String[] args) {test1();}public static void test1() {Student student1 = new Student("zhangsan",18,99);Student student2 = new Student("lisi",20,60);if (student1.compareTo(student2) > 0) {System.out.println("student1.age > student2.age");}else if(student1.compareTo(student2) < 0) {System.out.println("student1.age < student2.age");}else   System.out.println("student1.age = student2.age");}
}

输出:
student1.age < student2.age

代码解释:

1、 当我们查看Comparable接口时:

public interface Comparable<T> {public int compareTo(T o);
}

T代表泛型,里面写谁就比较谁。
根据接口知识,这时候我们需要重写compareTo方法了。
需要注意的是,其方法返回类型为int,在写返回值的时候需要注意。
2、 重写方法中的this表示调用这个方法的对象的调用。
3、 对于这个接口,是有缺点。当我们重写了compareTo方法就不能同时再重写compareTo方法来实现其他的比较(eg.比较成绩、比较姓名)
4、 为了解决这个接口的缺点,我们可以使用Comparator接口,来定义一些比较器来供我们使用。

使用Comparator接口
代码展示:
import java.util.Comparator;
//年龄比较器
public class AgeCompare implements Comparator<Student> {@Overridepublic int compare(Student o1, Student o2) {return  o1.age - o2.age;}
}
import java.util.Comparator;
//成绩比较器
public class ScoreCompare implements Comparator<Student> {@Overridepublic int compare(Student o1, Student o2) {return Double.compare(o1.score,o2.score);}
}
import java.util.Comparator;
//姓名比较器
public class NameCompare implements Comparator<Student> {@Overridepublic int compare(Student o1, Student o2) {return o1.compareTo(o2);//return String.CASE_INSENSITIVE_ORDER.compare(o1.name,o2.name);}
}
public class Test {public static void main(String[] args) {test2();test3();test4();}public static void test2() {Student student3 = new Student("zhangsan",21,99);Student student4 = new Student("lisi",20,60);AgeCompare ageCompare = new AgeCompare();if(ageCompare.compare(student3,student4)>0){System.out.println("student3.age > student4.age");}else if(ageCompare.compare(student3,student4)<0) {System.out.println("student3.age < student4.age");}}public static void test3() {Student student5 = new Student("zhangsan",21,91.1);Student student6 = new Student("lisi",20,91.2);ScoreCompare scoreCompare = new ScoreCompare();if(scoreCompare.compare(student5,student6)>0){System.out.println("student5.score > student6.score");}else if(scoreCompare.compare(student5,student6)<0) {System.out.println("student5.score < student6.score");}}public static void test4() {Student student7 = new Student("zhangsan",21,91.1);Student student8 = new Student("lisi",20,91.2);NameCompare nameCompare = new NameCompare();if(nameCompare.compare(student7,student8)>0){System.out.println("student7.name > student8.name");}else if(nameCompare.compare(student7,student8) < 0) {System.out.println("student7.name < student8.name");}}
}

输出:
student3.age > student4.age
student5.score < student6.score
student7.name > student8.name

代码解释:

1、 当我们查看Comparator接口时:

public interface Comparator<T> {int compare(T o1, T o2);
}

根据接口知识,这时候我们需要重写compare方法了。
(注意:Comparator接口中不只有这一个抽象方法,但现在我们只需要用这一个抽象方法)
还需要注意的是,其方法返回类型为int,在写返回值的时候需要注意。
2、 通过这个Comparator接口,我们可以实现多个比较器。当我们需要比较谁,就调用那个比较器就可以了。
3、 对于比较String类型的比较时,我们不能像比较int类型样的,返回相减的值。这时候可以调用String类中自己提供的比较方法,也可以调用compareTo方法。
这时候有人要问了,为什么可以调用compareTo方法来比较字符串大小,这不是在Comparable接口中有的吗?
当我们查看String类时,发现其实现了Comparable<T>的接口。
在这里插入图片描述
这时候我们可以调用compareTo方法,来实现字符串比较。

使用Comparable接口来实现自定义类型数组排序
基本数据类型的排序
public static void test() {int[] array = new int[]{1,2,3,4,3,2,6,3,8,4};Arrays.sort(array);System.out.println(Arrays.toString(array));
}
public static void main(String[] args) {People[] people = new People[3];people[0]= new People(18,"zhangsan");people[1] = new People(10,"lisi");people[2] = new People(22,"wangwu");System.out.println(Arrays.toString(people));Arrays.sort(people);//此时编译器不知道比较的那个成员变量,报错
}

这时候报错了。在这里插入图片描述
这时候我们进入sort的底层逻辑代码
在这里插入图片描述
这时候我们发现把数组的元素强转为Comparable接口,这时候我们需要实现Comparable接口,重写compareTo方法。

实现上述代码功能
重写compareTo方法
public class People implements Comparable<People>{public int age;public String name;@Overridepublic String toString() {return "People{" +"age=" + age +", name='" + name + '\'' +'}';}public People(int age, String name) {this.age = age;this.name = name;}@Overridepublic int compareTo(People o) {return Integer.compare(this.age,o.age);}
}
import java.util.Arrays;public class Test {public static void test2() {People[] people = new People[3];people[0]= new People(18,"zhangsan");people[1] = new People(10,"lisi");people[2] = new People(22,"wangwu");System.out.println(Arrays.toString(people));Arrays.sort(people);System.out.println("-------------");System.out.println(Arrays.toString(people));}public static void main(String[] args) {test2();}
}

输出:
[People{age=18, name=‘zhangsan’}, People{age=10, name=‘lisi’}, People{age=22, name=‘wangwu’}]
-------------
[People{age=10, name=‘lisi’}, People{age=18, name=‘zhangsan’}, People{age=22, name=‘wangwu’}]

当然此代码还是存在Comparable接口中的问题,不能同时再重写compareTo方法来实现其他的比较。

使用Comparator接口,传入比较器,来进行比较
public class People implements Comparable<People>{public int age;public String name;@Overridepublic String toString() {return "People{" +"age=" + age +", name='" + name + '\'' +'}';}public People(int age, String name) {this.age = age;this.name = name;}@Overridepublic int compareTo(People o) {return Integer.compare(this.age,o.age);}
}
public class NameCompare implements Comparator<People> {@Overridepublic int compare(People o1, People o2) {return String.CASE_INSENSITIVE_ORDER.compare(o1.name,o2.name);}
}
public class AgeCompare implements Comparator<People> {@Overridepublic int compare(People o1, People o2) {return Integer.compare(o1.age,o2.age);}
}
import java.util.Arrays;public class Test {public static void test3() {People[] peoples = new People[3];peoples[0]= new People(18,"zhangsan");peoples[1] = new People(10,"lisi");peoples[2] = new People(22,"wangwu");System.out.println("------原始顺序-------");System.out.println(Arrays.toString(peoples));NameCompare nameCompare = new NameCompare();Arrays.sort(peoples,nameCompare);System.out.println("------按姓名排序-------");System.out.println(Arrays.toString(peoples));System.out.println("------按年龄排序-------");AgeCompare ageCompare = new AgeCompare();Arrays.sort(peoples,ageCompare);System.out.println(Arrays.toString(peoples));}public static void main(String[] args) {test3();}
}

输出:
------原始顺序-------
[People{age=18, name=‘zhangsan’}, People{age=10, name=‘lisi’}, People{age=22, name=‘wangwu’}]
------按姓名排序-------
[People{age=10, name=‘lisi’}, People{age=22, name=‘wangwu’}, People{age=18, name=‘zhangsan’}]
------按年龄排序-------
[People{age=10, name=‘lisi’}, People{age=18, name=‘zhangsan’}, People{age=22, name=‘wangwu’}]

自己实现冒泡排序完成排序
import java.util.Arrays;
import java.util.Comparator;public class Test {public static void BubbleSort(Comparable[] comparables) {//发生向上转型for (int i = 0; i < comparables.length; i++) {for (int j = i; j <comparables.length-1 ; j++) {if(comparables[j].compareTo(comparables[j+1]) > 0) {Comparable temp = comparables[j];comparables[j] = comparables[j+1];comparables[j+1] = temp;}}}}public static void test4() {People[] people1 = new People[3];people1[0]= new People(18,"zhangsan");people1[1] = new People(10,"lisi");people1[2] = new People(22,"wangwu");BubbleSort(people1);System.out.println("------按年龄排序-------");System.out.println(Arrays.toString(people1));}public static void main(String[] args) {test4();}
}

输出:
------按年龄排序-------
[People{age=10, name=‘lisi’}, People{age=18, name=‘zhangsan’}, People{age=22, name=‘wangwu’}]

也可以使用传入比较器来实现冒泡排序

public static void BubbleSort(Comparable[] comparables,Comparator comparator) {for (int i = 0; i < comparables.length; i++) {for (int j = i; j <comparables.length-1 ; j++) {if(comparator.compare(comparables[j],comparables[j+1]) > 0) {Comparable temp = comparables[j];comparables[j] = comparables[j+1];comparables[j+1] = temp;}}}
}
public static void BubbleSort1(People[] people,Comparator<People> comparator) {for (int i = 0; i < people.length; i++) {for (int j = i; j <people.length-1 ; j++) {if(comparator.compare(people[j],people[j+1]) > 0) {People temp = people[j];people[j] = people[j+1];people[j+1] = temp;}}}
}
public static void test4() {People[] people1 = new People[3];people1[0]= new People(18,"zhangsan");people1[1] = new People(10,"lisi");people1[2] = new People(22,"wangwu");AgeCompare ageCompare = new AgeCompare();BubbleSort(people1,ageCompare);//或者BubbleSort1(people1,ageCompare);System.out.println("------按年龄排序-------");System.out.println(Arrays.toString(people1));
}

输出结果和上面一样

对象的拷贝

Cloneable接口
public interface Cloneable {
}

我们发现Cloneable接口是个空接口。当一个类实现了Cloneable接口表示当前这个类的对象是可以被克隆的。我们知道Object类是所有类的父类,Object类中有clone方法,这时候我们需要重写clone方法。
在这里插入图片描述
注意:其clone的返回类型为Object类

public class People implements Cloneable{//重写clone方法@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}
public class Test {public static void main(String[] args) {People people = new People();People people1 = people.clone();//报错了}
}

在这里插入图片描述
这时候我们需要加throws CloneNotSupportedException才能消除警告。

public class Test {public static void main(String[] args) throws CloneNotSupportedException{People people = new People();People people1 = people.clone();//还是报错了}
}

在这里插入图片描述
这时候需要强制类型转换,发生向下转型。

public class Test {public static void main(String[] args) throws CloneNotSupportedException{People people = new People();People people1 = (People) people.clone();}
}

这时候完成了拷贝。

总结:完成拷贝的步骤
1、实现Cloneable接口
2、声明异常throws CloneNotSupportedException
3、进行强制类型转换

代码演示:
public class People implements Cloneable{public int age;public String name;public People(int age, String name) {this.age = age;this.name = name;}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}
public class Test {public static void main(String[] args) throws CloneNotSupportedException{People people1 = new People(18,"lisi");People people2 = (People) people1.clone();System.out.println(people1.name);System.out.println(people1.age);System.out.println("------------");System.out.println(people2.name);System.out.println(people2.age);}
}

输出:
lisi
18
------------
lisi
18

在这里插入图片描述

深拷贝与浅拷贝
class Money {public double money = 99.99;
}public class People implements Cloneable{public int age;public String name;Money money = new Money();//组合public People(int age, String name) {this.age = age;this.name = name;}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}
public class Test {public static void main(String[] args) throws CloneNotSupportedException{People people1 = new People(18,"lisi");People people2 = (People) people1.clone();System.out.println(people1.name);System.out.println(people1.age);System.out.println(people1.money.money);System.out.println("------------");System.out.println(people2.name);System.out.println(people2.age);System.out.println(people2.money.money);System.out.println("------------");people1.age = 20;System.out.println(people1.age);System.out.println(people2.age);System.out.println("------------");people1.money.money = 10;System.out.println(people1.money.money);System.out.println(people2.money.money);}
}

输出:
lisi
18
99.99
------------
lisi
18
99.99
------------
20
18
------------
10.0
10.0

我们发现
1、people1.age = 20;只改变了people1.age 的值,没有改变people2.age 的值。
2、people2.money.money = 10;改变了people2.money.money的值和people1.money.money的值。这就是有关深拷贝与浅拷贝的问题了。
我们通过画图来展示:
在这里插入图片描述
上图是没有改变任何值的分布

在这里插入图片描述
上图是people1.age = 20;改变了people1.age 的值。
在这里插入图片描述
上图是people2.money.money = 10;改变了people2.money.money的值和people1.money.money的值。
上述我们就称之为浅拷贝
浅拷贝会创建一个完全一样属性的新对象。但,当属性是引用类型时,拷贝的是同一个地址,也就是说它们共用一个对象。(例如:上述代码,money是引用类型数据,拷贝的都是0x22这个地址)当改变所指向的值时,其原对象的属性也会改变!(例如:上述代码,改变了money的值,当原对象和新对象的对应属性值也都发生变化,都变成10.0)

有了上述浅拷贝的概念,深拷贝就很好理解了。深拷贝要做的就是还要将引用类型属性再创建一个新的对象。
在这里插入图片描述
需要产生上图的效果,这时候people2.money.money = 10;只会改变people2.money.money的值。

那么深拷贝是如何实现的呢?

我们需要像浅拷贝一样,再进行克隆一次。中间创建临时变量来接收和调用引用类型变量。
代码演示:

class Money implements Cloneable{public double money = 99.99;@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}public class People implements Cloneable{public int age;public String name;Money money = new Money();//组合public People(int age, String name) {this.age = age;this.name = name;}@Overrideprotected Object clone() throws CloneNotSupportedException {//return super.clone();People temp = (People) super.clone();temp.money = (Money) this.money.clone();return temp;}
}
public class Test {public static void main(String[] args) throws CloneNotSupportedException{People people1 = new People(18,"lisi");People people2 = (People) people1.clone();System.out.println(people1.name);System.out.println(people1.age);System.out.println(people1.money.money);System.out.println("------------");System.out.println(people2.name);System.out.println(people2.age);System.out.println(people2.money.money);System.out.println("------------");people1.age = 20;System.out.println(people1.age);System.out.println(people2.age);System.out.println("------------");people1.money.money = 10;System.out.println(people1.money.money);System.out.println(people2.money.money);}
}

输出:
lisi
18
99.99
------------
lisi
18
99.99
------------
20
18
------------
10.0
99.99

people2.money.money的值没有发生改变。这就完成了深拷贝。
通过画图再次理解拷贝过程:
执行

People temp = (People) super.clone();

在这里插入图片描述
执行:

temp.money = (Money) this.money.clone();

对这个代码进行拆分。
1、完成(Money)this.money.clone()
在这里插入图片描述
2、完成赋值
在这里插入图片描述
执行:

return temp;

在这里插入图片描述
这样就完成了深拷贝!!!
注意:
为了能拷贝引用类型指向的值,也需要对Money类实现Cloneable接口和重写clone方法。

相关文章:

JAVA学习*接口

接口 在生活中我们常听说USB接口&#xff0c;那接口是什么呢&#xff1f; 在Java中&#xff0c;接口相当于多个类的一种公共规范&#xff0c;是一种引用数据类型。 定义接口 public interface IUSB {public static final String SIZE "small";public abstract vo…...

Matplotlib

一、Matplotlib快速入门 学习目标 了解什么是matplotlib 为什么要学习matplotlib matplotlib简单图形的绘制 1、什么是Matplotlib 是专门用于开发2D图表(包括3D图表) 以渐进、交互式方式实现数据可视化 2、为什么要学习Matplotlib 可视化是在整个数据挖掘的关键辅助工…...

新版frp-0.61.0 实现泛解析域名穿透 以及 https启用

需要在公网服务器的域名解析平台 泛域名 *.aa.com 解析到frp 公网服务器的ip x.x.x.x 对于frpc.toml 文件的 serverAddr 绑定的ip 需要公网服务器放行 bindPort 对于的端口 frpc.toml serverPort 对于的的是 frps.toml bindPort 端口 frps.toml bindPort 7000 vhostHTTPP…...

HTTPS 加密过程详解

HTTPS 详解及其加密过程流程框架 HTTPS&#xff08;Hypertext Transfer Protocol Secure&#xff09;是一种基于 HTTP 协议的安全通信协议&#xff0c;通过 SSL/TLS 协议对传输数据进行加密和身份验证&#xff0c;解决了 HTTP 明文传输的安全隐患。以下是其核心原理和加密流程的…...

lua垃圾回收

lua垃圾回收 lua 垃圾回收 lua 垃圾回收 collectgarbage(“count”)获取当前lua脚本占用内存字节数(单位为KB)。 collectgarbage(“collect”)执行一次垃圾回收。 xxxnil 将变量置为空&#xff0c;会释放内存。 lua中的机制和c#中回收机制很类似 解除羁绊(置为空)。 --垃圾回…...

springboot继承使用mybatis-plus举例相关配置,包括分页插件以及封装分页类

以下是使用 MyBatis-Plus 分页插件的完整配置和封装步骤&#xff0c;包括日志输出、驼峰转下划线、逻辑删除以及分页属性类的封装。 1. 引入依赖 确保在 pom.xml 中已经引入 MyBatis-Plus 的依赖&#xff1a; <XML> <dependency><groupId>com.baomidou<…...

智能汽车以太网系统测试:聚焦ETH链路高负载性能表现

引言 在智能汽车高速发展的今天&#xff0c;车载以太网作为车辆信息交互的“神经网络”&#xff0c;承担着传输海量数据的关键使命。它不仅能够满足车辆对高带宽、低延迟和高可靠性的通信需求&#xff0c;还为自动驾驶、智能座舱等复杂功能提供了强大的技术支持。然而&#xf…...

学习笔记:黑马程序员JavaWeb开发教程(2025.3.21)

10.7 案例-员工管理-分页查询-分析 形参的默认值可以使用注解来设置&#xff1a;RequestParam(default “1”) 10.8 案例-员工管理-分页查询-PageHelper插件 分页插件PageHelper帮助完成有关分页的所有操作&#xff0c;我们只要正常使用查询语句就可以了。插件会自动…...

计算机网络精讲day1——计算机网络的性能指标(上)

性能指标1&#xff1a;速率 概念1&#xff1a;比特 英文全称是binary digit&#xff0c;意思是一个二进制数字&#xff0c;因此一个比特就是二进制数字中的1或0&#xff0c;比特也是信息论中使用的信息量单位。 概念2&#xff1a;速率 网络中的速率指的是数据的传送速率&#…...

gin-路由handler封装思路

约束handler入参和返回为func(ctx, req) (resp, error)。通过反射&#xff0c;封装handler&#xff0c;在调用前后写入入参和返回的处理。 package testingimport ("context""fmt""reflect""strings""testing" )type ReqPa…...

【实战案例】用STAR+3W模型拆解电商支付系统设计文档

各位开发者朋友&#xff0c;上次分享了结构化写作的黄金公式后&#xff0c;很多同学反馈需要更具象的落地方法。今天通过真实电商支付系统案例&#xff0c;手把手教你用STAR3W模型写出可执行的设计文档&#xff01; 结构化写作的「黄金公式」 STAR原则 3W模型 Situation&…...

计算机组成原理和计算机网络常见单位分类及换算

计算机组成原理&#xff08;主要用于存储、内存、缓存等&#xff09; 计算机网络&#xff08;主要用于传输速率&#xff09; 直观对比...

线性筛法求素数

时间复杂度 o&#xff08;n&#xff09; int cnt, primes[N];//cnt用来记录素数的下标 bool st[N];//用来标记合数 int minp[N];//最小质因数 void get_primes(int n) {for(int i 2;i < n;i )//从2开始找数 {if(!st[i])//如果这个数没有被筛出去过&#xff0c;说明是一…...

触动精灵对某东cookie读取并解密--记lua调用C语言

在Mac上构建Lua扩展模块&#xff1a;AES解密与Base64解码实战 今天我要分享一个实用技术&#xff1a;如何在Mac系统上为Lua编写和编译C扩展模块&#xff0c;特别是实现一个某东iOS PIN码解密功能的扩展。这对于需要在Lua环境中执行高性能计算或使用底层系统功能的开发者非常有…...

GEO:在AI时代抢占DeepSeekC位?

前言&#xff1a;当SEO遇见AGI——一场静默的流量革命 在生成式AI日均处理53亿次查询的今天&#xff0c;传统SEO的「关键词-排名-点击」逻辑正在崩塌。DeepSeek、ChatGPT、豆包等大模型用动态生成的答案&#xff0c;悄然截流了68%的搜索需求。更残酷的是&#xff1a;当用户问&q…...

【设计模式】策略模式

以下是格式优化后的Markdown文档&#xff0c;仅调整代码缩进&#xff0c;保持内容不变&#xff1a; 四、策略模式 策略(Strategy) 模式是一种行为型模式&#xff0c;其实现过程与模板方法模式非常类似——都 是以扩展的方式支持未来的变化。本章通过对一个具体范例的逐步重构…...

第J6周:ResNeXt-50实战解析

文章目录 一、前期准备1.设置GPU2.导入数据3.查看数据 二、数据预处理1.加载数据2.可视化数据3.再次检查数据4.配置数据集 四、模型复现1. 分组卷积模块2. 定义残差模块3. 堆叠残差单元4. 搭建ResNext-50网络5. 查看模型摘要 五、训练模型六、结果可视化总结&#xff1a; &…...

调试 ResNet18 cpp实现中的段错误(SIGSEGV)问题

调试 ResNet18 cpp实现中的段错误&#xff08;SIGSEGV&#xff09;问题 问题分析 您的程序在运行时遇到了段错误&#xff08;SIGSEGV&#xff09;&#xff0c;GDB显示错误发生在main()函数的第一行&#xff08;resnet18_allo_test.cpp:33&#xff09;。这种情况看起来很奇怪&…...

详细介绍IDI_APPLICATION和IDC_ARROW

书籍&#xff1a;《windows程序设计(第五版)》 环境&#xff1a;visual studio 2022 内容&#xff1a;HELLOWIN程序 说明&#xff1a;以下内容大部分来自腾讯元宝。 ​IDI_APPLICATION 与 IDC_ARROW 详解 ​1. IDC_ARROW&#xff08;光标资源标识符&#xff09;​ ​定义与…...

curl库+openssl库windows编译

一、工具准备 Visual Studio 2008&#xff1a;确保安装了 C 开发工具。 Git&#xff1a;用于克隆 cURL 的源码。 Perl&#xff1a;可以从 ActiveState Perl 下载并安装。 NASM&#xff08;可选&#xff09;&#xff1a;如果需要汇编优化&#xff0c;可以从NASM 官方网站 下载并…...

今日行情明日机会——20250321

后续投资机会分析 结合2025年3月21日盘面数据&#xff08;涨停56家&#xff0c;跌停31家&#xff09;&#xff0c;市场呈现结构性分化行情&#xff0c;海洋经济成为绝对主线&#xff0c;机器人概念局部活跃&#xff0c;人工智能表现较弱。以下是具体方向与策略建议&#xff1a…...

repo init 错误 Permission denied (publickey)

一、已经生成ssh-key并设置到gerrit上 二、已经设置.gitconfig &#xff08;此步骤是公司要求&#xff0c;设置gerrit地址为一个别名之类的&#xff0c;有的公司不需要&#xff09; 然后出现下面的错误&#xff0c;最后发现忘记设置git的用户名和邮箱 1. git config --globa…...

STM32 模拟SPI 模式0

SPI 模式 0 的时钟极性&#xff08;CPOL&#xff09;为 0&#xff0c;时钟相位&#xff08;CPHA&#xff09;为 0。CPOL 0 意味着时钟信号空闲时为低电平&#xff0c;CPHA 0 表示在时钟信号的第一个跳变沿&#xff08;上升沿&#xff09;进行数据采样。 #include "stm3…...

MySQL实现全量同步和增量同步到SQL Server或其他关系型库

在将MySQL中的两张表同步到SQL Server的过程中&#xff0c;全量同步和增量同步各有其优缺点。全量同步简单直接但可能耗时较长且资源消耗大&#xff0c;而增量同步则更加高效但需要额外的逻辑来处理数据的变更。以下是对这两种同步方式的详细解释及代码示例的完善。 完整代码示…...

详细解析GetOpenFileName()

书籍&#xff1a;《Visual C 2017从入门到精通》的2.3.8 Win32控件编程 环境&#xff1a;visual studio 2022 内容&#xff1a;【例2.34】打开文件对话框和另存为。 说明&#xff1a;以下内容大部分来自腾讯元宝。 GetOpenFileName() 是 Windows API 中用于显示标准文件打开…...

FPGA----完美解决Windows下[XSIM 43-3409][XSIM 43-3915]错误

大家好久不见&#xff0c;今天开始又要重操旧业了&#xff01;最近会更新很多关于petalinux的踩坑日记&#xff0c;敬请期待&#xff01; 先更新一个常见问题&#xff0c;使用Vivado仿真时C编译器报错问题。如下所示 ERROR: [XSIM 43-3409] Failed to compile generated C fi…...

LeetCode Hot100 刷题路线(Python版)

目录 1. LeetCode Hot100 刷题笔记&#xff08;1&#xff09;—— 哈希、双指针、滑动窗口 2. LeetCode Hot100 刷题笔记&#xff08;2&#xff09;—— 子串、普通数组、矩阵 3. LeetCode Hot100 刷题笔记&#xff08;3&#xff09;—— 链表 4. LeetCode Hot100 刷题笔记&…...

宇树科技纯技能要求总结

一、嵌入式开发与硬件设计 核心技能 嵌入式开发&#xff1a; 精通C/C&#xff0c;熟悉STM32、ARM开发熟悉Linux BSP开发及驱动框架&#xff08;SPI/UART/USB/FLASH/Camera/GPS/LCD&#xff09;掌握主流平台&#xff08;英伟达、全志、瑞芯微等&#xff09; 硬件设计&#xff1a…...

Docker学习笔记(十)搭建Docker私有仓库

一、环境配置 1、宿主机系统&#xff1a;macOS Sequoia(版本15.2) 2、虚拟机VMware Fusion版本&#xff1a;专业版 13.6.2 (24409261) 3、虚拟机系统&#xff1a;AlmaLinux-9-latest-x86_64-boot.iso 二、安装Harbor开源企业级Docker镜像 Harbor 是一个开源的企业级 Docker…...

FastAPI WebSocket 无法获取真实 IP 错误记录

FastAPI WebSocket 无法获取真实 IP 错误记录 问题描述 在使用 FastAPI WebSocket 服务时&#xff0c;发现无法获取设备的真实 Remote IP&#xff0c;所有连接均显示为内网地址 10.x.x.1。以下是完整的排查过程及解决方案。 排查步骤 1. 基础信息检查 • 现象复现&#xff1…...

DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加导出数据功能示例4,TableView15_04导出当前页数据示例

前言:哈喽,大家好,今天给大家分享一篇文章!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏+关注哦 💕 目录 DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加导出数据功能示例4,TableView15_04导出当…...

【Linux】快速上手Makeflie CMake

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:Linux ⚙️操作环境:Xshell (操作系统:Ubuntu 22.04 server 64bit) 目录 &#x1f4cc;快速上手Makefile 基本结构 变量 自动变量 常用目标 &#x1f4cc;快速上手CMake CMake与Makefile的关系 CMake的使用步骤 常用命令…...

Python连接数据库进行增删改查

更多优质文章 _>_>_>_>_>✍✈✉戳我 目录 1.导入相关库 2.创建连接 3.插入数据 4.删除数据 5.修改数据 6.查询数据 7.更多干货 1.导入相关库 import pymysql -----pip install pymysql #下载库 2.创建连接 conn pymysql.connect(hostlocalho…...

数据库的两种模式

数据库的 严格模式&#xff08;Strict Mode&#xff09; 和 宽松模式&#xff08;Non-Strict Mode&#xff09; 是数据库管理系统&#xff08;DBMS&#xff09;中用于控制数据验证和处理方式的两种不同模式。它们的主要区别在于对数据完整性、一致性和错误处理的严格程度。 1. …...

【css酷炫效果】纯CSS实现立体旋转立方体

【css酷炫效果】纯CSS实现立体旋转立方体 缘创作背景html结构css样式完整代码效果图 想直接拿走的老板&#xff0c;链接放在这里&#xff1a;https://download.csdn.net/download/u011561335/90492014 缘 创作随缘&#xff0c;不定时更新。 创作背景 刚看到csdn出活动了&am…...

Cursor与Coze结合开发电影推荐系统:一次高效的技术实践

1 项目背景 有个想法&#xff0c;和朋友打算一起看电影&#xff0c;但是不知道看什么&#xff08;吃饭也是&#xff09;&#xff0c;于是在豆瓣高分电影榜单中选择出来一些感兴趣的电影&#xff0c;随机挑选一部“天意之选”。为此&#xff0c;我尝试结合Cursor&#xff08;智…...

【总结篇】java多线程,新建线程有几种写法,以及每种写法的优劣势

java多线程 新建线程有几种写法,以及每种写法的优劣势 [1/5]java多线程 新建线程有几种写法–继承Thread类以及他的优劣势[2/5]java多线程-新建线程有几种写法–实现Runnable接口以及他的优劣势[3/5]java多线程 新建线程有几种写法–实现Callable接口结合FutureTask使用以及他的…...

idea问题(三)pom文件显示删除线

一、问题 1、现象 2、原因 分析原因和出现的流程&#xff1a;创建子模块的时候因为名称错误了&#xff0c;并且通过修改模块模块名称后&#xff0c;又删除了模块&#xff0c;因删除不干净。再次建立了同名模块&#xff0c;会让IDEA认为你再次新建的项目是已经被删除的项目。 …...

python爬虫概述

0x00 python爬虫概述 以豆瓣的选电影模块为例&#xff0c;当查看源代码搜索猫猫的奇幻漂流瓶是搜不到的 这时服务器的工作方式应该是这样的 客户端浏览器第一次访问其实服务器端是返回的一个框架(html代码) 当客户端浏览器第二次通过脚本等方式进行访问时服务器端才返回的数据…...

实现拖拽图片验证的基本步骤

前端部分 UI 设计&#xff1a; 显示一个滑块和一张背景图&#xff08;通常是带缺口的图片&#xff09;。滑块可以是拼图的一块或简单的方块。 拖拽功能&#xff1a; 监听滑块的 mousedown、mousemove、mouseup 事件&#xff0c;实现拖拽效果。 验证逻辑&#xff1a; 计算滑块最…...

conda报错activate没办法激活环境

遇到激活环境报错 # >>>>>>>>>>>>>>>>>>>>>> ERROR REPORT <<<<<<<<<<<<<<<<<<<<<< Traceback (most recent call last): File …...

numpy学习笔记3:三维数组 np.ones((2, 3, 4)) 的详细解释

numpy学习笔记3&#xff1a;三维数组 np.ones((2, 3, 4)) 的详细解释 以下是关于三维数组 np.ones((2, 3, 4)) 的详细解释&#xff1a; 1. 三维数组的形状 形状 (2, 3, 4) 表示&#xff1a; 最外层维度&#xff1a;2 个“层”&#xff08;或“块”&#xff09;&#xff1b; …...

论文笔记(七十三)Gemini Robotics: Bringing AI into the Physical World

Gemini Robotics: Bringing AI into the Physical World 文章概括1. 引言2. Gemini 2.0的具身推理2.1. 具身推理问答&#xff08;ERQA&#xff09;基准测试2.2. Gemini 2.0的具身推理能力2.3. Gemini 2.0支持零样本和少样本机器人控制 3. 使用 Gemini Robotics 执行机器人动作3…...

不用 Tomcat?SpringBoot 项目用啥代替?

在SpringBoot框架中&#xff0c;我们使用最多的是Tomcat&#xff0c;这是SpringBoot默认的容器技术&#xff0c;而且是内嵌式的Tomcat。 同时&#xff0c;SpringBoot也支持Undertow容器&#xff0c;我们可以很方便的用Undertow替换Tomcat&#xff0c;而Undertow的性能和内存使…...

ChatTTS 开源文本转语音模型本地部署 API 使用和搭建 WebUI 界面

ChatTTS&#xff08;Chat Text To Speech&#xff09;&#xff0c;专为对话场景设计的文本生成语音(TTS)模型&#xff0c;适用于大型语言模型(LLM)助手的对话任务&#xff0c;以及诸如对话式音频和视频介绍等应用。支持中文和英文&#xff0c;还可以穿插笑声、说话间的停顿、以…...

嵌入式笔记 | 正点原子STM32F103ZET6 4 | 中断补充

1. 外设引脚重映射 1.1 定义 在STM32中&#xff0c;每个外设的引脚都有默认的GPIO端口&#xff0c;但有些引脚可以通过重映射寄存器将功能映射到其他端口。这种机制称为引脚重映射&#xff0c;主要用于解决引脚复用冲突或优化PCB布线。 1.2 重映射的类型 部分重映射&#x…...

spring循环依赖

Spring 通过三级缓存机制解决单例 Bean 的循环依赖问题&#xff0c;其核心思想是提前暴露未完全初始化的 Bean 引用。以下是详细流程和原理&#xff1a; 1. 循环依赖的场景 假设两个 Bean 相互依赖&#xff1a; BeanA 依赖 BeanBBeanB 依赖 BeanA 如果没有特殊处理&#xff…...

算法刷题区域部分反转

不断创建数组&#xff0c;相加&#xff0c;利用cpp内字符串相加的性质即可。具体代码如下&#xff1a; class Solution { public: string reverseStr(string s, int k) { int size s.size(); int count size / (2*k); string a; int i 0; for ( i 0; i < count; i)…...

使用【docker】+【shell】脚本半自动化部署微服务项目

一.前言 以下是一个基于 ‌Docker Shell脚本‌ 的半自动化部署方案&#xff0c;包含镜像构建、容器管理、网络配置和日志监控等核心功能&#xff0c;适用于大多数Web应用或微服务项目。 二‌.目录结构 三.脚本代码实现 1.‌Shell脚本实现 (deploy.sh) #!/bin/bash# 设置颜…...

关于“碰一碰发视频”系统的技术开发文档框架

以下是关于“碰一碰发视频”系统的技术开发文档框架&#xff0c;涵盖核心功能、技术选型、开发流程和关键模块设计&#xff0c;帮助您快速搭建一站式解决方案 --- 随着短视频平台的兴起&#xff0c;用户的创作与分享需求日益增长。而如何让视频分享更加便捷、有趣&#xff0c…...