【詳識JAVA語言】抽象類和接口

抽象類

抽象類概念

在面向對象的概念中,所有的對象都是通過類來描繪的,但是反過來,并不是所有的類都是用來描繪對象的,如果 一個類中沒有包含足夠的信息來描繪一個具體的對象,這樣的類就是抽象類。 比如:

?

?

在打印圖形例子中, 我們發現, 父類 Shape 中的 draw 方法好像并沒有什么實際工作, 主要的繪制圖形都是由 Shape 的各種子類的 draw 方法來完成的. 像這種沒有實際工作的方法, 我們可以把它設計成一個 抽象方法(abstract method), 包含抽象方法的類我們稱為 抽象類(abstract class).?

抽象類語法?

在Java中,一個類如果被?abstract 修飾稱為抽象類,抽象類中被 abstract 修飾的方法稱為抽象方法,抽象方法不用給出具體的實現體。

// 抽象類:被abstract修飾的類 public abstract class Shape {// 抽象方法:被abstract修飾的方法,沒有方法體 abstract public void draw(); abstract void calcArea();// 抽象類也是類,也可以增加普通方法和屬性 public double getArea(){ return area; }protected double area; // 面積}

注意:抽象類也是類,內部可以包含普通方法和屬性,甚至構造方法

抽象類特性

1. 抽象類不能直接實例化對象

Shape shape = new Shape();// 編譯出錯Error:(30, 23) java: Shape是抽象的; 無法實例化

2. 抽象方法不能是 private 的

abstract class Shape {abstract private void draw();}// 編譯出錯Error:(4, 27) java: 非法的修飾符組合: abstract和private

3. 抽象方法不能被?nal和static修飾,因為抽象方法要被子類重寫

public abstract class Shape {abstract ?nal void methodA();abstract public static void methodB();}// 編譯報錯:// Error:(20, 25) java: 非法的修飾符組合: abstract和?nal// Error:(21, 33) java: 非法的修飾符組合: abstract和static

4.抽象類必須被繼承,并且繼承后子類要重寫父類中的抽象方法,否則子類也是抽象類,必須要使用修飾abstract

// 矩形類public class Rect extends Shape {private double length;private double width;Rect(double length, double width){this.length = length;this.width = width;}public void draw(){System.out.println("矩形: length= "+length+" width= " + width);}public void calcArea(){area = length * width;}}// 圓類:public class Circle extends Shape{private double r;?nal private static double PI = 3.14;public Circle(double r){this.r = r;}public void draw(){System.out.println("圓:r = "+r); }public void calcArea(){area = PI * r * r;}}// 三角形類:public abstract class Triangle extends Shape {private double a;private double b;private double c;@Overridepublic void draw() {System.out.println("三角形:a = "+a + " b = "+b+" c = "+c);}// 三角形:直角三角形、等腰三角形等,還可以繼續細化//@Override//double calcArea(); // 編譯失敗:要么實現該抽象方法,要么將三角形設計為抽象類}

5. 抽象類中不一定包含抽象方法,但是有抽象方法的類一定是抽象類

6. 抽象類中可以有構造方法,供子類創建對象時,初始化父類的成員變量

抽象類的作用

抽象類本身不能被實例化, 要想使用, 只能創建該抽象類的子類. 然后讓子類重寫抽象類中的抽象方法.

有些同學可能會說了, 普通的類也可以被繼承呀, 普通的方法也可以被重寫呀, 為啥非得用抽象類和抽象方法 呢?

確實如此. 但是使用抽象類相當于多了一重編譯器的校驗.

使用抽象類的場景就如上面的代碼, 實際工作不應該由父類完成, 而應由子類完成. 那么此時如果不小心誤用成父類 了, 使用普通類編譯器是不會報錯的. 但是父類是抽象類就會在實例化的時候提示錯誤, 讓我們盡早發現問題.

很多語法存在的意義都是為了 "預防出錯", 例如我們曾經用過的 ?nal 也是類似. 創建的變量用戶不去修改, 不 就相當于常量嘛? 但是加上 ?nal 能夠在不小心誤修改的時候, 讓編譯器及時提醒我們.

充分利用編譯器的校驗, 在實際開發中是非常有意義的.

接口

接口的概念

在現實生活中,接口的例子比比皆是,比如:筆記本上的USB口,電源插座等。

電腦的USB口上,可以插:U盤、鼠標、鍵盤...所有符合USB協議的設備

電源插座插孔上,可以插:電腦、電視機、電飯煲...所有符合規范的設備

通過上述例子可以看出:接口就是公共的行為規范標準,大家在實現時,只要符合規范標準,就可以通用。

在Java中,接口可以看成是:多個類的公共規范,是一種引用數據類型。

語法規則

接口的定義格式與定義類的格式基本相同,將class關鍵字換成interface關鍵字,就定義了一個接口。

public interface 接口名稱{// 抽象方法public abstract void method1(); // public abstract 是固定搭配,可以不寫public void method2();abstract void method3();void method4();// 注意:在接口中上述寫法都是抽象方法,跟推薦方式4,代碼更簡潔}

提示:

1. 創建接口時, 接口的命名一般以大寫字母 I 開頭.

2. 接口的命名一般使用 "形容詞" 詞性的單詞.

3. 阿里編碼規范中約定, 接口中的方法和屬性不要加任何修飾符號, 保持代碼的簡潔性.

接口使用?

接口不能直接使用,必須要有一個"實現類"來"實現"該接口,實現接口中的所有抽象方法。

public class 類名稱 implements 接口名稱{// ...}

注意:子類和父類之間是extends 繼承關系,類與接口之間是 implements 實現關系。

請實現筆記本電腦使用USB鼠標、USB鍵盤的例子

1. USB接口:包含打開設備、關閉設備功能

2. 筆記本類:包含開機功能、關機功能、使用USB設備功能

3. 鼠標類:實現USB接口,并具備點擊功能

4. 鍵盤類:實現USB接口,并具備輸入功能

// USB接口public interface USB {void openDevice();void closeDevice();}// 鼠標類,實現USB接口public class Mouse implements USB {@Overridepublic void openDevice() {System.out.println("打開鼠標");}@Override public void closeDevice() { System.out.println("關閉鼠標"); }public void click(){ System.out.println("鼠標點擊"); }}// 鍵盤類,實現USB接口public class KeyBoard implements USB {@Override public void openDevice() {System.out.println("打開鍵盤");}@Overridepublic void closeDevice() {System.out.println("關閉鍵盤");}public void inPut(){System.out.println("鍵盤輸入");}}// 筆記本類:使用USB設備public class Computer {public void powerOn(){System.out.println("打開筆記本電腦");}public void powerO?(){System.out.println("關閉筆記本電腦");}public void useDevice(USB usb){usb.openDevice();if(usb instanceof Mouse){Mouse mouse = (Mouse)usb;mouse.click();}else if(usb instanceof KeyBoard){KeyBoard keyBoard = (KeyBoard)usb;keyBoard.inPut(); }usb.closeDevice();}}// 測試類:public class TestUSB {public static void main(String[] args) {Computer computer = new Computer();computer.powerOn();// 使用鼠標設備computer.useDevice(new Mouse());// 使用鍵盤設備computer.useDevice(new KeyBoard());computer.powerO?();}}

接口特性

1. 接口類型是一種引用類型,但是不能直接new接口的對象

public class TestUSB {public static void main(String[] args) {USB usb = new USB();} }// Error:(10, 19) java: day20210915.USB是抽象的; 無法實例化

2. 接口中每一個方法都是public的抽象方法, 即接口中的方法會被隱式的指定為 public abstract(只能是 public abstract,其他修飾符都會報錯)

public interface USB {// Error:(4, 18) java: 此處不允許使用修飾符private private void openDevice();void closeDevice();}

3. 接口中的方法是不能在接口中實現的,只能由實現接口的類來實現

public interface USB {void openDevice();// 編譯失敗:因為接口中的方式默認為抽象方法// Error:(5, 23) java: 接口抽象方法不能帶有主體void closeDevice(){System.out.println("關閉USB設備");}}

4. 重寫接口中方法時,不能使用默認的訪問權限

public interface USB {void openDevice(); // 默認是public的void closeDevice(); // 默認是public的}public class Mouse implements USB {@Overridevoid openDevice() {System.out.println("打開鼠標");}// ...}// 編譯報錯,重寫USB中openDevice方法時,不能使用默認修飾符 // 正在嘗試分配更低的訪問權限; 以前為public

5. 接口中可以含有變量,但是接口中的變量會被隱式的指定為 public static ?nal 變量

public interface USB {double brand = 3.0; // 默認被:?nal public static修飾void openDevice();void closeDevice();}public class TestUSB {public static void main(String[] args) {System.out.println(USB.brand); // 可以直接通過接口名訪問,說明是靜態的// 編譯報錯:Error:(12, 12) java: 無法為最終變量brand分配值 USB.brand = 2.0;// 說明brand具有?nal屬性}}

6. 接口中不能有靜態代碼塊和構造方法

public interface USB {// 編譯失敗 public USB(){}{}// 編譯失敗void openDevice();void closeDevice();}

7. 接口雖然不是類,但是接口編譯完成后字節碼文件的后綴格式也是.class

8. 如果類沒有實現接口中的所有的抽象方法,則類必須設置為抽象類

9. jdk8中:接口中還可以包含default方法。

實現多個接口

在Java中,類和類之間是單繼承的,一個類只能有一個父類,即Java中不支持多繼承,但是一個類可以實現多個接口。下面通過類來表示一組動物.

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

另外我們再提供一組接口, 分別表示 "會飛的", "會跑的", "會游泳的".

interface IFlying { void ?y(); }interface IRunning { void run(); }interface ISwimming { void swim(); }

接下來我們創建幾個具體的動物 貓, 是會跑的.

class Cat extends Animal implements IRunning {public Cat(String name) {super(name);}@Overridepublic void run() {System.out.println(this.name + "正在用四條腿跑");}}

魚, 是會游的.

class Fish extends Animal implements ISwimming { public Fish(String name) {super(name);}@Overridepublic void swim() {System.out.println(this.name + "正在用尾巴游泳");}}

青蛙, 既能跑, 又能游(兩棲動物)

class Frog extends Animal implements IRunning, ISwimming {public Frog(String name) {super(name);}@Overridepublic void run() {System.out.println(this.name + "正在往前跳");}@Overridepublic void swim() {System.out.println(this.name + "正在蹬腿游泳");}}

注意:一個類實現多個接口時,每個接口中的抽象方法都要實現,否則類必須設置為抽象類。

提示, IDEA 中使用 ctrl + i 快速實現接口 還有一種神奇的動物, 水陸空三棲, 叫做 "鴨子"

class Duck extends Animal implements IRunning, ISwimming, IFlying { public Duck(String name) {super(name);}@Overridepublic void ?y() {System.out.println(this.name + "正在用翅膀飛");}@Overridepublic void run() {System.out.println(this.name + "正在用兩條腿跑");} @Override public void swim() {System.out.println(this.name + "正在漂在水上");}}

上面的代碼展示了 Java 面向對象編程中最常見的用法: 一個類繼承一個父類, 同時實現多種接口. 繼承表達的含義是 is - a 語義, 而接口表達的含義是 具有 xxx 特性 .

貓是一種動物, 具有會跑的特性.

青蛙也是一種動物, 既能跑, 也能游泳

鴨子也是一種動物, 既能跑, 也能游, 還能飛

這樣設計有什么好處呢? 時刻牢記多態的好處, 讓程序猿忘記類型. 有了接口之后, 類的使用者就不必關注具體類型, 而只關注某個類是否具備某種能力.

例如, 現在實現一個方法, 叫 "散步"

public static void walk(IRunning running) {System.out.println("我帶著伙伴去散步");running.run();}

在這個 walk 方法內部, 我們并不關注到底是哪種動物, 只要參數是會跑的, 就行

Cat cat = new Cat("小貓");walk(cat);Frog frog = new Frog("小青蛙");walk(frog);// 執行結果我帶著伙伴去散步小貓正在用四條腿跑我帶著伙伴去散步小青蛙正在往前跳

甚至參數可以不是 "動物", 只要會跑!

class Robot implements IRunning {private String name; public Robot(String name) {this.name = name;}@Overridepublic void run() {System.out.println(this.name + "正在用輪子跑");} }Robot robot = new Robot("機器人");walk(robot);// 執行結果 機器人正在用輪子跑

接口間的繼承?

在Java中,類和類之間是單繼承的,一個類可以實現多個接口,接口與接口之間可以多繼承。即:用接口可以達到 多繼承的目的。

接口可以繼承一個接口, 達到復用的效果. 使用 extends 關鍵字.

interface IRunning { void run(); }interface ISwimming { void swim(); }// 兩棲的動物, 既能跑, 也能游 interface IAmphibious extends IRunning, ISwimming {}class Frog implements IAmphibious { ...}

通過接口繼承創建一個新的接口 IAmphibious 表示 "兩棲的". 此時實現接口創建的 Frog 類, 就繼續要實現 run 方 法, 也需要實現 swim 方法.

接口間的繼承相當于把多個接口合并在一起.

接口使用實例

給對象數組排序

class Student {private String name;private int score;public Student(String name, int score) {this.name = name;this.score = score;}@Overridepublic String toString() {return "[" + this.name + ":" + this.score + "]";}}

再給定一個學生對象數組, 對這個對象數組中的元素進行排序(按分數降序).

Student[] students = new Student[] {new Student("張三", 95),new Student("李四", 96),new Student("王五", 97),new Student("趙六", 92),};

按照我們之前的理解, 數組我們有一個現成的 sort 方法, 能否直接使用這個方法呢?

Arrays.sort(students);System.out.println(Arrays.toString(students));// 運行出錯, 拋出異常.Exception in thread "main" java.lang.ClassCastException: Student cannot be cast to java.lang.Comparable

仔細思考, 不難發現, 和普通的整數不一樣, 兩個整數是可以直接比較的, 大小關系明確. 而兩個學生對象的大小關系 怎么確定? 需要我們額外指定.

讓我們的 Student 類實現 Comparable 接口, 并實現其中的 compareTo 方法

class Student implements Comparable {private String name;private int score;public Student(String name, int score) {this.name = name;this.score = score;}@Overridepublic String toString() {return "[" + this.name + ":" + this.score + "]";}@Overridepublic int compareTo(Object o) {Student s = (Student)o;if (this.score > s.score) {return -1;} else if (this.score < s.score) {return 1;} else {return 0;}}}

在 sort 方法中會自動調用 compareTo 方法. compareTo 的參數是 Object , 其實傳入的就是 Student 類型的對象. 然后比較當前對象和參數對象的大小關系(按分數來算).

如果當前對象應排在參數對象之前, 返回小于 0 的數字;

如果當前對象應排在參數對象之后, 返回大于 0 的數字;

如果當前對象和參數對象不分先后, 返回 0;

再次執行程序, 結果就符合預期了.

// 執行結果

[[王五:97], [李四:96], [張三:95], [趙六:92]]

注意事項: 對于 sort 方法來說, 需要傳入的數組的每個對象都是 "可比較" 的, 需要具備 compareTo 這樣的能力. 通 過重寫 compareTo 方法的方式, 就可以定義比較規則.

為了進一步加深對接口的理解, 我們可以嘗試自己實現一個 sort 方法來完成剛才的排序過程(使用冒泡排序)

public static void sort(Comparable[] array) {for (int bound = 0; bound < array.length; bound++) {for (int cur = array.length - 1; cur > bound; cur--) {if (array[cur - 1].compareTo(array[cur]) > 0) {// 說明順序不符合要求, 交換兩個變量的位置Comparable tmp = array[cur - 1];array[cur - 1] = array[cur];array[cur] = tmp;}}}}

再次執行代碼

sort(students);System.out.println(Arrays.toString(students));// 執行結果[[王五:97], [李四:96], [張三:95], [趙六:92]]

Clonable 接口和深拷貝?

Java 中內置了一些很有用的接口, Clonable 就是其中之一.

Object 類中存在一個 clone 方法, 調用這個方法可以創建一個對象的 "拷貝". 但是要想合法調用 clone 方法, 必須要 先實現 Clonable 接口, 否則就會拋出 CloneNotSupportedException 異常.

class Animal implements Cloneable {private String name;@Overridepublic Animal clone() {Animal o = null;try {o = (Animal)super.clone();} catch (CloneNotSupportedException e) {e.printStackTrace();}return o;}}public class Test {public static void main(String[] args) {Animal animal = new Animal();Animal animal2 = animal.clone();System.out.println(animal == animal2);}}// 輸出結果// false

淺拷貝 VS 深拷貝

Cloneable 拷貝出的對象是一份 "淺拷貝"

觀察以下代碼:

class Money { 
public double m = 99.99; 
}class Person implements Cloneable{ public Money money = new Money();@Override 
protected Object clone() throws CloneNotSupportedException { return super.clone(); }}public class TestDemo3 {public static void main(String[] args) throws CloneNotSupportedException { Person person1 = new Person(); Person person2 = (Person) person.clone(); System.out.println("通過person2修改前的結果"); System.out.println(person1.money.m); System.out.println(person2.money.m); person2.money.m = 13.6; System.out.println("通過person2修改后的結果"); System.out.println(person1.money.m); System.out.println(person2.money.m);}}// 執行結果 通過person2修改前的結果99.9999.99通過person2修改后的結果13.613.6

如上代碼,我們可以看到,通過clone,我們只是拷貝了Person對象。但是Person對象中的Money對象,并 沒有拷貝。通過person2這個引用修改了m的值后,person1這個引用訪問m的時候,值也發生了改變。這里 就是發生了淺拷貝。那么同學們想一下如何實現深拷貝呢?

抽象類和接口的區別

抽象類和接口都是 Java 中多態的常見使用方式. 都需要重點掌握. 同時又要認清兩者的區別(重要!!! 常見面試題).

核心區別: 抽象類中可以包含普通方法和普通字段, 這樣的普通方法和字段可以被子類直接使用(不必重寫), 而接口中 不能包含普通方法, 子類必須重寫所有的抽象方法.

如之前寫的 Animal 例子. 此處的 Animal 中包含一個 name 這樣的屬性, 這個屬性在任何子類中都是存在的. 因此此 處的 Animal 只能作為一個抽象類, 而不應該成為一個接口.

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

再次提醒:

抽象類存在的意義是為了讓編譯器更好的校驗, 像 Animal 這樣的類我們并不會直接使用, 而是使用它的子類. 萬一不小心創建了 Animal 的實例, 編譯器會及時提醒我們.

Object類?

Object是Java默認提供的一個類。Java里面除了Object類,所有的類都是存在繼承關系的。默認會繼承Object父 類。即所有類的對象都可以使用Object的引用進行接收。

范例:使用Object接收所有類的對象

class Student{} 
public class Test {public static void main(String[] args) { function(new Person()); 
function(new Student()); 
} public static void function(Object obj) {System.out.println(obj); }} 
//執行結果: 
Person@1b6d3586 
Student@4554617c

所以在開發之中,Object類是參數的最高統一類型。但是Object類也存在有定義好的一些方法。如下:

對于整個Object類中的方法需要實現全部掌握。

本小節當中,我們主要來熟悉這幾個方法:toString()方法,equals()方法,hashcode()方法?

獲取對象信息?

如果要打印對象中的內容,可以直接重寫Object類中的toString()方法,之前已經講過了,此處不再累贅。

// Object類中的toString()方法實現:public String toString() {return getClass().getName() + "@" + Integer.toHexString(hashCode());}

對象比較equals方法

在Java中,==進行比較時:

a.如果==左右兩側是基本類型變量,比較的是變量中值是否相同

b.如果==左右兩側是引用類型變量,比較的是引用變量地址是否相同

c.如果要比較對象中內容,必須重寫Object中的equals方法,因為equals方法默認也是按照地址比較的:

// Object類中的equals方法public boolean equals(Object obj) {return (this == obj); // 使用引用中的地址直接來進行比較 }class Person{private String name ;private int age ;public Person(String name, int age) {this.age = age ;this.name = name ;}}public class Test {public static void main(String[] args) {Person p1 = new Person("gaobo", 20) ;Person p2 = new Person("gaobo", 20) ;int a = 10;int b = 10;System.out.println(a == b); // 輸出trueSystem.out.println(p1 == p2); // 輸出falseSystem.out.println(p1.equals(p2)); // 輸出false}}

Person類重寫equals方法后,然后比較:

class Person{...@Overridepublic boolean equals(Object obj) {if (obj == null) {return false ;} if(this == obj) {return true ;}// 不是Person類對象if (!(obj instanceof Person)) {return false ;}Person person = (Person) obj ; // 向下轉型,比較屬性值return this.name.equals(person.name) && this.age==person.age ;}}

結論:比較對象中內容是否相同的時候,一定要重寫equals方法。

hashcode方法

回憶剛剛的toString方法的源碼:

public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode());}

我們看到了hashCode()這個方法,他幫我算了一個具體的對象位置,這里面涉及數據結構,但是我們還沒學數據結 構,沒法講述,所以我們只能說它是個內存地址。然后調用Integer.toHexString()方法,將這個地址以16進制輸 出。

hashcode方法源碼:

public native int hashCode();

該方法是一個native方法,底層是由C/C++代碼寫的。我們看不到。 我們認為兩個名字相同,年齡相同的對象,將存儲在同一個位置,如果不重寫hashcode()方法,我們可以來看示例 代碼:

class Person {public String name; public int age; public Person(String name, int age) {this.name = name;this.age = age; }} public class TestDemo4 {public static void main(String[] args) {Person per1 = new Person("gaobo", 20) ;Person per2 = new Person("gaobo", 20) ;System.out.println(per1.hashCode());System.out.println(per2.hashCode());}}//執行結果4601419581163157884

注意事項:兩個對象的hash值不一樣。

像重寫equals方法一樣,我們也可以重寫hashcode()方法。此時我們再來看看。

class Person {public String name;public int age;public Person(String name, int age) {this.name = name;this.age = age;}@Overridepublic int hashCode() {return Objects.hash(name, age);}}public class TestDemo4 {public static void main(String[] args) {Person per1 = new Person("gaobo", 20) ;Person per2 = new Person("gaobo", 20) ;System.out.println(per1.hashCode());System.out.println(per2.hashCode());}} //執行結果 460141958 460141958

注意事項:哈希值一樣。

結論:

1、hashcode方法用來確定對象在內存中存儲的位置是否相同

2、事實上hashCode() 在散列表中才有用,在其它情況下沒用。在散列表中hashCode() 的作用是獲取對象的 散列碼,進而確定該對象在散列表中的位置。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/717731.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/717731.shtml
英文地址,請注明出處:http://en.pswp.cn/news/717731.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

水印相機小程序源碼

水印相機前端源碼&#xff0c;本程序無需后端&#xff0c;前端直接導入即可&#xff0c;沒有添加流量主功能&#xff0c;大家開通后自行添加 源碼搜索&#xff1a;源碼軟件庫 注意小程序后臺的隱私權限設置&#xff0c;前端需要授權才可使用 真實時間地址拍照記錄&#xff0c…

Endnote x9 最快方法批量導入.enw格式文件

按照網上看到的一個方法直接選中所有enw批量拖拽到 All references 附件不行啊&#xff0c; 以為只能寫bat腳本方式了 經過一番嘗試&#xff0c;驚人的發現拖到下面這個符號的地方就行了&#xff01;&#xff01;&#xff01; 如果不成功的話&#xff0c;可能&#xff1a; 我…

使用typescript實現引入vue3生命周期函數的基礎知識整理

在Vue 3中&#xff0c;生命周期函數被更改為組合式API&#xff0c;并且不再使用官方命名的生命周期鉤子函數。不過&#xff0c;我們仍然可以模擬類似的功能&#xff0c;使用onBeforeMount、onMounted、onBeforeUpdate、onUpdated、onBeforeUnmount、onUnmounted等組合式API。 …

淺談vue的自定義指令

Vue 的自定義指令是一種強大的工具&#xff0c;允許你為 DOM 元素添加自定義行為。自定義指令可以通過 Vue 的 Vue.directive() 全局 API 或組件內的 directives 選項來定義。 下面是如何使用 Vue 的自定義指令的基本步驟&#xff1a; 全局注冊自定義指令 Vue.directive(foc…

js 手寫深拷貝方法

文章目錄 一、深拷貝實現代碼二、代碼講解2.1 obj.constructor(obj)2.2 防止循環引用手寫一個深拷貝是我們常見的面試題,在實現過程中我們需要考慮的類型很多,包括對象、數組、函數、日期等。以下就是深拷貝實現邏輯 一、深拷貝實現代碼 const originalObject = {string: H…

藍橋杯復習之差分

題目&#xff1a;空調 題目鏈接&#xff1a;https://www.acwing.com/problem/content/description/4265/ 思路&#xff1a; 對希望溫度與實際溫度做差&#xff0c;再對這個做差數組做差分。我們的每次操作等價于在差分數組中選一個數加一或者選兩個數一個加一&#xff0c…

【小沐學GIS】QGIS安裝和入門使用

文章目錄 1、簡介2、下載和安裝3、使用3.1 XYZ Tiles3.2 WMS / WMTS3.3 GeoJson文件加載 4、在線資源結語 1、簡介 QGIS是一款開源地理信息系統。該項目于2002年5月誕生&#xff0c;同年6月作為SourceForge上的一個項目建立。QGIS目前運行在大多數Unix平臺、Windows和macOS上。…

奧爾特曼被曝身價超過140億,但并未在OpenAI持股

作為OpenAI CEO和新一輪AI熱潮代表人物&#xff0c;奧爾特曼&#xff08;Sam Altman&#xff09;卻沒有在OpenAI公司賺到“身價”。 鈦媒體AGI 3月3日消息&#xff0c;據彭博億萬富翁指數最新數據顯示&#xff0c;今年38歲的奧爾特曼最新身價&#xff08;凈收入&#xff09;至少…

什么是區塊鏈粉塵攻擊?

文章目錄 一、什么是粉塵&#xff1f;二、什么是粉塵攻擊&#xff1f;三、粉塵攻擊的危害3.1 釣魚式攻擊3.2 揭露該錢包和其所有者的詳細信息3.3 造成鏈上網絡擁堵 四、可能使用粉塵交易的人群五、如何避免粉塵攻擊&#xff1f; 一、什么是粉塵&#xff1f; 粉塵的含義為小額資…

無窮積分例子

以下幾個題容易出錯&#xff0c;特意記錄一下。 判斷積分式的斂散性 ∫ ? ∞ ∞ 1 x 2 e 1 x d x \int _{-\infty } ^ {\infty} \frac{1}{x^2} e ^{\frac{1}{x}} dx ∫?∞∞?x21?ex1?dx 要注意瑕點0的處理。無窮積分&#xff0c;一般將積分域按瑕點拆分并分別積分。 判斷…

阿里面試,有點焦慮。。

恭喜發現寶藏&#xff01;搜索公眾號【TechGuide】回復公司名&#xff0c;解鎖更多新鮮好文和互聯網大廠的筆經面經&#xff0c;目前已更新至美團、字節… 作者TechGuide【全網同名】 聊聊春招 春招來了&#xff0c;有些24屆校招生可能還在做最后的努力&#xff0c;有些25屆的…

國辰智企MES系統優化企業管理,讓生產制造更高效

在制造業的舞臺上&#xff0c;MES制造執行管理系統如同一位出色的導演&#xff0c;將生產過程中的各個場景巧妙地連接起來&#xff0c;演繹出一場場精彩的制造盛宴。讓我們一同走進MES在制造業的具體應用場景&#xff0c;感受它帶來的變革與創新。 在生產計劃與調度的場景中&am…

[數據結構]棧

1.棧的概念及結構 棧&#xff1a;一種特殊的線性表&#xff0c;其只允許在固定的一端進行插入和刪除元素操作。進行數據插入和刪除操作的一端稱為棧頂&#xff0c;另一端稱為棧底。棧中的數據元素遵守后進先出的原則。 壓棧&#xff1a;棧的插入操作叫做進棧/壓棧/入棧&#…

[ai筆記14] 周鴻祎的ai公開課筆記1

歡迎來到文思源想的ai空間&#xff0c;這是技術老兵重學ai以及成長思考的第14篇分享&#xff01; 本周二月的最后一周&#xff0c;并不是閑下來了&#xff0c;反而是開始進行一些更多的深入實踐&#xff0c;關于gpt的主體架構、關于prompt&#xff0c;同時也看了不少書和直播&…

行業獨角獸—Matic Network來臨,成就百萬富翁的項目!

Matic Network由印度Bangalore及日本超級節點打造 &#xff0c;獨創保險倉九倉共振循環模式。 Mtc于2023年初完成了700萬美元的種子輪融資&#xff0c; Paradigm領投&#xff0c;a16z、Variant、Solana Ventures和Jump Crypto參投&#xff0c;旨在全方位布局Web3.0的去中心化生…

web開發:如何用Echarts來自動給網頁設計各種統計圖

很多時候web開發也會需要用到統計圖&#xff0c;如果單純靠我們自己那點拙劣的css和js水平設計的話&#xff0c;又耗時間又做得跟史一樣&#xff0c;這時候就需要引入別人設計師為我們設計好的動態統計圖——echarts Echarts的官網是&#xff1a;Apache ECharts 1、第一步&…

Spring Boot整合Mybatis配置多數據源

Spring Boot 專欄&#xff1a;https://blog.csdn.net/dkbnull/category_9278145.html Spring Cloud 專欄&#xff1a;https://blog.csdn.net/dkbnull/category_9287932.html GitHub&#xff1a;https://github.com/dkbnull/SpringBootDemo Gitee&#xff1a;https://gitee.com/…

【HTML5】瀏覽器不能顯示字體報錯Failed to decode downloaded font問題解決

把網上的項目中字體通過鏈接保存下來在本地上使用&#xff0c;在本地服務器上運行站點發現&#xff0c;用Chrome瀏覽器訪問的時候&#xff0c;出現錯誤提示不能正常顯示字體&#xff0c;怎么解決呢&#xff0c;看看怎么搞。 文章目錄 發現問題提示警告提示錯誤 字體檢查打開文件…

【C++】每周一題——2024.3.3

題目 Cpp 【問題描述】 字符環&#xff08;來源&#xff1a;NOI題庫&#xff09;。有兩個由字符構成的環&#xff0c;請寫一個程序&#xff0c;計算這兩個字符環上最長公共字符串的長度。例如&#xff0c;字符串“ABCEFAGADEGKABUVKLM”的首尾連在一起&#xff0c;構成一個環&a…

k8s常見的命令集錦

Kubernetes&#xff08;K8s&#xff09;是一個開源的容器編排系統&#xff0c;它提供了一系列的命令行工具 kubectl 來管理和操作集群中的資源。以下是一些常見的 kubectl 命令集錦&#xff1a; kubectl get&#xff1a;用于獲取集群中的資源對象信息&#xff0c;如pods、nodes…