??謝謝大家捧場,祝屏幕前的小伙伴們每天都有好運相伴左右,一定要天天開心哦!???
🎈🎈作者主頁:?🎈丠丠64-CSDN博客🎈
???帥哥美女們,我們共同加油!一起進步!???
目錄
一、前言
二、Obiect類
1.獲取對象信息的打印
2.比較類中對象的異同
-equals方法
-hashcode方法
三、接口實現實例
-Comparable接口
-排序一個數組成員元素
1.直接使用接口Comparable
2.構造新的比較器
四、對象的拷貝
1.Cloneable拷貝
-淺拷貝
-深拷貝
一、前言
上一篇我們介紹了抽象類以及接口的相關知識,這篇我們來接著探討一下關于接口的實例,并且認識一下所有類的父類Object
二、Obiect類
Object時JAVA中默認提供的一個類,所有的類都是繼承Oject,換句話來說Oject是所有類的父類,這樣就可以說在有需要實現一些功能的時候,子類方法就可以用重寫來實現
1.獲取對象信息的打印
我們首先來看這樣一段代碼
public class Person {public int age;public String name;public Person(int age, String name) {this.age = age;this.name = name;}
}
public class Test {public static void main(String[] args){Person person = new Person(16,"張三");System.out.println(person);}
}
我們目的想要實現傳入變量名字以后,打印出對應的成員屬性,傳入println()中是否能實現呢?
事實卻是輸出了這樣一個值,為什么呢?我們跳轉println函數定義去看
我們發現實現的最終函數是這個toString()前半部分是全路徑,后面部分是類似地址一樣的東西(后面會說)
toString()是Object的子類,所以我們只需要重寫toString(),就可以隨意實現我們的功能,所以修改一下這個代碼重寫toString()
public class Person {public int age;public String name;public Person(int age, String name) {this.age = age;this.name = name;}@Overridepublic String toString() {return "Person{" + "age=" + age + ", name='" + name + '\'' + '}';}
}
即可實現我們的功能
2.比較類中對象的異同
首先我們先來看一段代碼
Person person1 = new Person(16,"張三");System.out.println(person1);Person person2 = new Person(16,"張三");System.out.println(person2);System.out.println(person1 == person2);
對于兩個不同的變量,但是里面的成員屬性卻相同,比較person1和person2,他兩會相等嗎?
運行結果來看,兩者是不同的,我們屏蔽掉剛寫的toString()來看一下結果
發現原來是他們類似于地址一樣的東西不一樣!兩個對象比較的其實是類似于地址的地址!
兩個對象以不同的位置進行分配
-equals方法
在JAVA在有一個方法也是用來比較兩個對象是否相等,就是equals(),我們跳轉到定義去看
System.out.println(person1.equals(person2));
我發現它的定義只是這樣(其中的this指誰調用equals誰就是this),跟剛才的person1 == person2沒有區別,我們要實現我們的功能,對成員中的屬性進行比較,因為equals是Object的子類,就要對其進行重寫
@Overridepublic boolean equals(Object o) {if (this == o) { return true; //如果指向同一個對象為真}if (o == null || getClass() != o.getClass()) {return false; //如果對象屬性為空或者不是一個東西了為假}Person person = (Person) o;//向下轉型比較屬性值//判斷對象中各個屬性,都為真才為真return age == person.age && Objects.equals(name, person.name);}
通過調用自己重寫的方法,這樣這段代碼就可以實現我們所需要的功能了,比較兩個對象中各屬性是否相等
System.out.println(person1.equals(person2));
-hashcode方法
剛才在調用toString方法時我們看見了hashCode()這個方法,他幫我算了一個具體的對象位置,該方法是一個native方法,底層是由C/C++代碼寫的。我們看不到。
public native int hashCode();
我們來看一下這兩個的值為多少?
System.out.println(person1.hashCode());
System.out.println(person2.hashCode());
因為兩者所分配的空間不同,所以對象位置也不相同,返回的值也就不相同,倘若我們現在想要實現,為兩個名字相同,年齡相同的對象,將存儲在同一個位置,hashcode是Object的子類,我們就要重寫hashcode()方法
@Overridepublic int hashCode() {return Objects.hash(age, name);}
再輸出我們結果,發現經過一系列算法,兩個對象出現了同一位置
三、接口實現實例
我們先看這樣一個代碼
public class Student {public int age;public String name;public Student(int age, String name) {this.age = age;this.name = name;}@Overridepublic String toString() {return "Student{" +"age=" + age +", name='" + name + '\'' +'}';}}
當我們想實現兩個變量之間的比較,是不是直接比較他們兩個變量是否相等然后返回布爾值就行了呢?答案是錯的,引用類型變量不可以這樣比較,直接比較會報錯
public class Test {public static void main(String[] args){Student student1 = new Student(12,"小明");Student student2 = new Student(15,"小美");System.out.println(student1 > student1);}}
-Comparable接口
自定義想要比較大小,就要實現這個接口
我們應該在Student這個類給它加上一個Comparable接口,再把Student傳進去就可以進行比較了
public class Student implements Comparable<Student>{public int age;public String name;public Student(int age, String name) {this.age = age;this.name = name;}@Overridepublic String toString() {return "Student{" +"age=" + age +", name='" + name + '\'' +'}';}}
但是我們發現還是會報錯,我們跳轉過去定義查看
發現需要按照自己的需求去重寫這個compareTo方法
假如說我們需要按照年齡去比較兩個對象,于是就可以這樣重寫
@Overridepublic int compareTo(Student o) {return this.age - o.age; //大于輸出正數,小于輸出負數,相等輸出0}
這樣就不會報錯了
System.out.println(student1.compareTo(student2));
System.out.println(student2.compareTo(student1));
輸出結果
-排序一個數組成員元素
1.直接使用接口Comparable
先實現一個學生的類,并且使用接口Comparable
public class Student implements Comparable<Student>{public int age;public String name;public Student(int age, String name) {this.age = age;this.name = name;}@Overridepublic String toString() {return "Student{" +"age=" + age +", name='" + name + '\'' +'}';}@Overridepublic int compareTo(Student o) {return this.age - o.age; //大于輸出正數,小于輸出負數,相等輸出0}
}
定義一個學生的數組
Student[] students = new Student[3];students[0] = new Student(18,"小明");
students[1] = new Student(15,"小禮");
students[2] = new Student(21,"小花");
然后根據冒泡排序對學生的年齡對其排序
public static void my_sort(Comparable[] comparable){for (int i = 0; i < comparable.length - 1; i++) {for (int j = 0; j < comparable.length - 1 - i; j++) {if (comparable[j].compareTo(comparable[j+1]) > 0){Comparable tmp = comparable[j];comparable[j] = comparable[j+1];comparable[j+1] = tmp;}}}}
打印出結果,對其學生年齡進行排序
my_sort(students);
System.out.println(Arrays.toString(students));
結果成立
但是這種方法也有很大的危害,對類的侵入性比較強,也不夠靈活
2.構造新的比較器
所以基于上述的的危害我們可以進行優化
對于年齡比較,我們新建一個類AgeComparator,并對其compare進行重寫即可
class AgeComparator implements Comparator<Student> {@Overridepublic int compare(Student o1,Student o2) {return o1.age - o2.age; }
}
對于名字比較,我們新建一個類NameComparator,并對其compare進行重寫即可
class NameComparator implements Comparator<Student> {@Overridepublic int compare(Student o1, Student o2) {return o1.name.compareTo(o2.name);}
}
我們來實現一下,分別以年齡跟名字比較
Student student1 = new Student(12,"zahngsan");Student student2 = new Student(15,"lisi");NameComparator nameComparator = new NameComparator();System.out.println(nameComparator.compare(student1, student2));AgeComparator ageComparator = new AgeComparator();System.out.println(ageComparator.compare(student1, student2));
結果成立,且互不干擾,這就是比較器的好處,比較靈活,對類的侵入性不強
四、對象的拷貝
我們先構造一個類,并且實例化一個對象
public class Person {public int age;public Person(int age) {this.age = age;}@Overridepublic String toString() {return "Person{" +"age=" + age +'}';}
}
public class Test {public static void main(String[] args){Person person1 = new Person(19);}
}
實例化的對象person1他在內存中是這樣分配的,對象的屬性在堆區開辟了空間地址由persin1保存
倘若我們要實現對變量person1進行一份拷貝,如何實現呢?
1.Cloneable拷貝
我們先介紹Cloneable接口,我們先跳轉過定義,可以看到是一個空接口
又稱為標記接口:證明當前類是可以被克隆的
我們實例化第二個對象,用JAVA中提供的clone 方法,創建一個對象的 "拷貝"
Person person2 = person1.clone();
但是我們發現報錯了,我們還要經過以下三步
clone屬于Obiect中的方法,我們轉到clone的定義,發現他的訪問權限是protected,直接訪問不到只能夠重寫這個方法
但是同時呢我們發現還多了一個 throws CloneNotSupportedException這樣的東西,必須是編譯時處理,所以我們也要在main主函數上加上 throws CloneNotSupportedException
同時呢用我們發現它的返回值為Object,父類訪問子類中的方法就是發生向下轉型強轉為Person類型
@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
public class Test {public static void main(String[] args) throws CloneNotSupportedException {Person person1 = new Person(19);Person person2 = (Person) person1.clone();}
}
同時也要加接口,來證明這個類可以被克隆
public class Person implements Cloneable{public int age;public Person(int age) {this.age = age;}@Overridepublic String toString() {return "Person{" +"age=" + age +'}';}protected Object clone() throws CloneNotSupportedException {return super.clone();}
}
不加接口則會報錯
至此編譯正常通過
public class Test {public static void main(String[] args) throws CloneNotSupportedException {Person person1 = new Person(19);Person person2 = (Person) person1.clone();System.out.println(person1);System.out.println(person2);}
}
成功克隆
-淺拷貝
我們來看以下的這段代碼
構造了個Money、Perso兩個類,重寫了clone
class Money {public double m = 99.99;
}class Person implements Cloneable{public Money money = new Money();@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}
person1拷貝一份persona2,并且修改persinal2的值,理想的結果應該是persinal2的m值被修改,person1的不變
public class Test{public static void main(String[] args) throws CloneNotSupportedException {Person person1 = new Person();Person person2 = (Person) person1.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);}
但是輸出結果并不是這樣,我們發現persona1中的m也被修改了,為什么會這樣呢?
我們發現拷貝只拷貝了一份新的對象,并沒有拷貝對象中的元素,對象中的元素位置沒有被改變,兩個對象中的m指向了同一塊內存,同一個嗎,對象中的元素沒有被克隆,所以兩者都可以修改,這種沒有完全拷貝就稱為淺拷貝
-深拷貝
? 我們對以上的代碼進行修改,將clone進行重寫,將對象中的對象也進行拷貝,這個問題就解決了
@Overrideprotected Object clone() throws CloneNotSupportedException {Person tmp = (Person) super.clone();tmp.money = this.money.clone();}
深淺拷貝說白了就是重寫clone方法實現的,方法內部實現的不一樣
希望對你有幫助