JDK類庫的根類:Object
- 這個老祖宗類中的方法我們需要先研究一下,因為這些方法都是所有子類通用的,任何一個類預設繼承Object,就算沒有直接繼承,最終也會間接繼承
-
Object類當中的有哪些常用的方法?
我們去哪裡找這些方法呢?
第一種方法:去源代碼當中。(但是這種方式比較麻煩,源代碼也比較難)
第二種方法:去查閱java的類庫的幫助文檔(java8 API幫助文檔)
什麼是API?
應用程式程式設計接口(Application Program Interface)
整個JDK的類庫就是一個javase的API
每一個API都會配置一套API幫助文檔
SUN公司提前寫好的這套類庫就是API(一般每一份API都對應一份API幫助文檔)
目前為止我們隻需要知道這幾個方法即可:
protected Object clone() // 負責對象克隆的。
int hashCode() // 擷取對象哈希值的一個方法。
boolean equals(Object obj) // 判斷兩個對象是否相等
String toString() // 将對象轉換成字元串形式
protected void finalize() // 垃圾回收器負責調用的方法
關于Object類中的toString()方法
- 源代碼長什麼樣?
public String toString() {
return this.getClass().getName() + "@" + Integer.toHexString(hashCode());
}
-
SUN公司設計toString()方法的目的是什麼?
toString()方法的作用是什麼?
toString()方法的設計目的是:通過調用這個方法可以将一個“Java對象”轉換成“字元串表示形式”
-
其實SUN公司開發java語言的時候,建議所有的子類都去重寫toString()方法
toString()方法應該是一個簡潔的、詳實的、易閱讀的。
public class Test01{
public static void main(String[] args){
MyTime t1 = new MyTime(1970, 1, 1);
// 一個日期對象轉換成字元串形式的話,我可能還是希望能看到具體的日期資訊。
String s1 = t1.toString();
//MyTime類重寫toString()方法之前
//System.out.println(s1); // [email protected]
//MyTime類重寫toString()方法之後
System.out.println(s1); // 1970年1月1日
//System.out.println(t1.toString()); //1970年1月1日
// 注意:輸出引用的時候,會自動調用該引用的toString()方法。
System.out.println(t1);
}
}
class MyTime{
int year;
int month;
int day;
public MyTime(){
}
public MyTime(int year, int month, int day){
this.year = year;
this.month = month;
this.day = day;
}
// 重寫toString()方法
// 這個toString()方法怎麼重寫呢?
// 越簡潔越好,可讀性越強越好。
// 向簡潔的、詳實的、易閱讀的方向發展
public String toString(){
//return this.year + "年" + this.month + "月" + this.day + "日";
return this.year + "/" + this.month + "/" + this.day;
}
}
關于Object類中的equals方法
- equals方法的源代碼
public boolean equals(Object obj) {
return (this == obj);
}
以上這個方法是Object類的預設實作
-
SUN公司設計equals方法的目的是什麼?
以後程式設計過程當中,都要通過equals方法來判斷兩個對象是否相等。
equals方法是判斷兩個對象是否相等的。
-
我們需要研究一下Object類給的這個預設的equals方法夠不夠用!!!
在Object類中的equals方法當中,預設采用的是“==” 判斷兩個java對象是否相等。而“ = =”判斷的是兩個java對象的記憶體位址,我們應該判斷兩個java對象的内容是否相等。是以老祖宗的equals方法不夠用,需要子類重寫equals。
- 判斷兩個java 對象是否相等,不能使用“==”,因為“= =”比較的是兩個對象的記憶體位址。
public class Test02{
public static void main(String[] args){
// 判斷兩個基本資料類型的資料是否相等直接使用“==”就行。
int a = 100;
int b = 100;
// 這個“==”是判斷a中儲存的100和b中儲存的100是否相等。
System.out.println(a == b); //true(相等) false(不相等)
// 判斷兩個java對象是否相等,我們怎麼辦?能直接使用“==”嗎?
// 建立一個日期對象是:2008年8月8日。
MyTime t1 = new MyTime(2008, 8, 8); //MyTime t1 = 0x1234;
// 建立了一個新的日期對象,但表示的日期也是:2008年8月8日。
MyTime t2 = new MyTime(2008, 8, 8); //MyTime t2 = 0x3698;
//測試以下,比較兩個對象是否相等,能不能使用“==”???
// 這裡的“==”判斷的是:t1中儲存的對象記憶體位址和t2中儲存的對象記憶體位址是否相等。
System.out.println(t1 == t2); // false
// 重寫Object equals方法之前(比較的是對象記憶體位址)
/*
boolean flag = t1.equals(t2);
System.out.println(flag); //false
*/
// 重寫Object equals方法之後(比較的是内容。)
boolean flag = t1.equals(t2);
System.out.println(flag); //true
// 再建立一個新的日期
MyTime t3 = new MyTime(2008, 8, 9);
// 兩個日期不相等,就是false。
System.out.println(t1.equals(t3)); // false
// 我們這個程式有bug嗎?可以運作,但是效率怎麼樣?低(怎麼改造。)
MyTime t4 = null;
System.out.println(t1.equals(t4)); //false
}
}
class MyTime { //extends Object{
int year;
int month;
int day;
public MyTime(){
}
public MyTime(int year, int month, int day){
this.year = year;
this.month = month;
this.day = day;
}
// 預設的equals方法
/*
public boolean equals(Object obj) {
return (this == obj);
}
*/
/*
// 重寫Object類的equals方法
// 怎麼重寫?複制粘貼。相同的傳回值類型、相同的方法名、相同的形式參數清單。
// equals到底應該怎麼重寫?你自己定,你認為兩個對象什麼相等的時候表示相等,你就怎麼重寫。
public boolean equals(Object obj) {
// 當年相同,月相同,并且日也相同的時候,表示兩個日期相同。兩個對象相等。
// 擷取第一個日期的年月日
int year1 = this.year;
int month1 = this.month;
int day1 = this.day;
// 擷取第二個日期的年月日
//int year2 = obj.year;
//int month2 = obj.month;
//int day2 = obj.day;
if(obj instanceof MyTime){
MyTime t = (MyTime)obj;
int year2 = t.year;
int month2 = t.month;
int day2 = t.day;
if(year1 == year2 && month1 == month2 && day1 == day2){
return true;
}
}
// 程式能夠執行到此處表示日期不相等。
return false;
}
*/
/*
// 改良equals方法
public boolean equals(Object obj) {
// 如果obj是空,直接傳回false
if(obj == null){
return false;
}
// 如果obj不是一個MyTime,沒必要比較了 ,直接傳回false
if(!(obj instanceof MyTime)){
return false;
}
// 如果this和obj儲存的記憶體位址相同,沒必要比較了,直接傳回true。
// 記憶體位址相同的時候指向的堆記憶體的對象肯定是同一個。
if(this == obj){
return true;
}
// 程式能夠執行到此處說明什麼?
// 說明obj不是null,obj是MyTime類型。
MyTime t = (MyTime)obj;
if(this.year == t.year && this.month == t.month && this.day == t.day){
return true;
}
// 程式能到這裡傳回false
return false;
}
*/
//再次改良。
/*
public boolean equals(Object obj) {
// 如果obj是空,直接傳回false
if(obj == null){
return false;
}
// 如果obj不是一個MyTime,沒必要比較了 ,直接傳回false
if(!(obj instanceof MyTime)){
return false;
}
// 如果this和obj儲存的記憶體位址相同,沒必要比較了,直接傳回true。
// 記憶體位址相同的時候指向的堆記憶體的對象肯定是同一個。
if(this == obj){
return true;
}
// 程式能夠執行到此處說明什麼?
// 說明obj不是null,obj是MyTime類型。
MyTime t = (MyTime)obj;
return this.year == t.year && this.month == t.month && this.day == t.day ;
}
*/
public boolean equals(Object obj) {
if(obj == null || !(obj instanceof MyTime)){
return false;
}
if(this == obj){
return true;
}
MyTime t = (MyTime)obj;
return this.year == t.year && this.month == t.month && this.day == t.day ;
}
}
/*
class Person{
private String idCard;
}
*/
Java語言當中的字元串String有沒有重寫toString()方法,有沒有重寫equals方法???
總結:
- String類已經重寫了equals方法,比較兩個字元串不能使用==,必須使用equals,equals是通用的。
- String類已經重寫了toString()方法。
大結論:
-
java中什麼類型的資料可以使用”= =“判斷
Java中基本資料類型比較是否相等,使用==
-
java中什麼類型的資料需要使用equals判斷
java中所有的引用資料類型統一使用equals方法來判斷是否相等。【這是規矩!!】
public class Test03{
public static void main(String[] args){
// 大部分情況下,采用這樣的方式建立字元串對象
String s1 = "hello";
String s2 = "abc";
// 實際上String也是一個類。不屬于基本資料類型。
// 既然String是一個類,那麼一定存在構造方法。
String s3 = new String("Test1");
String s4 = new String("Test1");
// new兩次,兩個對象記憶體位址,s3儲存的記憶體位址和s4儲存的記憶體位址不同。
// == 判斷的是記憶體位址。不是内容。
System.out.println(s3 == s4); // false
// 比較兩個字元串能不能使用雙等号?
// 不能,必須調用equals方法。
// String類已經重寫equals方法了。
System.out.println(s3.equals(s4)); // true
// String類有沒有重寫toString方法呢?
String x = new String("動力節點");
// 如果String沒有重寫toString()方法,輸出結果:java.lang.String@十六進制的位址
// 經過測試:String類已經重寫了toString()方法。
System.out.println(x.toString()); //動力節點
System.out.println(x); //動力節點
}
}
// String對象比較的時候必須使用equals方法。
public class Test04{
public static void main(String[] args){
/*
Student s1 = new Student(111, "北京大興亦莊二小");
Student s2 = new Student(111, "北京大興亦莊二小");
System.out.println(s1 == s2); // false
System.out.println(s1.equals(s2)); // true
*/
Student s1 = new Student(111, new String("北京大興亦莊二小"));
Student s2 = new Student(111, new String("北京大興亦莊二小"));
System.out.println(s1 == s2); // false
System.out.println(s1.equals(s2)); // true
}
}
class Student{
// 學号
int no; //基本資料類型,比較時使用:==
// 所在學校
String school; //引用資料類型,比較時使用:equals方法。
public Student(){}
public Student(int no,String school){
this.no = no;
this.school = school;
}
// 重寫toString方法
public String toString(){
return "學号" + no + ",所在學校名稱" + school;
}
// 重寫equals方法
// 需求:當一個學生的學号相等,并且學校相同時,表示同一個學生。
// 思考:這個equals該怎麼重寫呢?
// equals方法的編寫模式都是固定的。架子差不多。
public boolean equals(Object obj){
if(obj == null || !(obj instanceof Student)) return false;
if(this == obj) return true;
Student s = (Student)obj;
return this.no == s.no && this.school.equals(s.school);
//字元串用雙等号比較可以嗎?
// 不可以
//return this.no == s.no && this.school == s.school;
}
}
// equals方法重寫的時候要徹底。
public class Test05{
public static void main(String[] args){
// 多态(自動類型轉換。)
Object o1 = new String("hello world!");
Object o2 = new User();
Object o3 = new Address();
User u1 = new User("zhangsan", new Address("北京","大興區","11111"));
User u2 = new User("zhangsan", new Address("北京","大興區","11111"));
System.out.println(u1.equals(u2)); // true
User u3 = new User("zhangsan", new Address("北京","朝陽區","11112"));
System.out.println(u1.equals(u3)); // false
}
}
class User{
// 使用者名
String name;
// 使用者的住址
Address addr;
public User(){
}
public User(String name, Address addr){
this.name = name;
this.addr = addr;
}
// 重寫equals方法
// 重寫規則:當一個使用者的使用者名和家庭住址都相同,表示同一個使用者。
// 這個equals判斷的是User對象和User對象是否相等。
public boolean equals(Object obj){
// 使用者名和使用者名相同,住址和住址相同的時候,認定是同一個使用者。
if(obj == null || !(obj instanceof User)) return false;
if(this == obj) return true;
User u = (User)obj;
if(this.name.equals(u.name) && this.addr.equals(u.addr)){
return true;
}
return false;
}
}
class Address{
String city;
String street;
String zipcode;
public Address(){
}
public Address(String city,String street,String zipcode){
this.city = city;
this.street = street;
this.zipcode = zipcode;
}
// 注意:這裡并沒有重寫equals方法。
// 這裡的equals方法判斷的是:Address對象和Address對象是否相等。
public boolean equals(Object obj){
if(obj == null || !(obj instanceof Address)) return false;
if(this == obj) return true;
// 怎麼算是家庭住址相同呢?
// 城市相同,街道相同,郵編相同,表示相同。
Address a = (Address)obj;
if(this.city.equals(a.city)
&& this.street.equals(a.street)
&& this.zipcode.equals(a.zipcode)){
return true;
}
return false;
}
}
關于Object類中的finalize()方法(非重點 非重點 非重點 了解即可)
- 在Object類中的源代碼:
GC:負責調用finalize()方法。
- finalize()方法隻有一個方法體,裡面沒有代碼,而且這個方法是protected修飾的。
-
這個方法不需要程式員手動調用,JVM的垃圾回收器負責調用這個方法
不像equals toString , equals和toString()方法是需要程式員寫代碼調用的。finalize()隻需要重寫,重寫完将來自動會有程式來調用。
-
finalize()方法的執行時機:
當一個java對象即将被垃圾回收器回收的時候,垃圾回收器負責調用finalize()方法。
- finalize()方法實際上是SUN公司為java程式員準備的一個時機,垃圾銷毀時機。如果希望在對象銷毀時機執行一段代碼的話,這段代碼要寫到finalize()方法當中。
-
靜态代碼塊的作用是什麼?
static{
…
}
靜态代碼塊在類加載時刻執行,并且隻執行一次。
這是一個SUN準備的類加載時機。
finalize()方法同樣也是SUN為程式員準備的一個時機。
這個時機是垃圾回收時機。
-
提示:
java中的垃圾回收器不是輕易啟動的,
垃圾太少,或者時間沒到,種種條件下,
有可能啟動,也有可能不啟動。
public class Test06{
public static void main(String[] args){
/*
// 建立對象
Person p = new Person();
// 怎麼把Person對象變成垃圾?
p = null;
*/
// 多造點垃圾
/*
for(int i = 0; i < 100000000; i++){
Person p = new Person();
p = null;
}
*/
for(int i = 0; i < 1000; i++){
Person p = new Person();
p = null;
// 有一段代碼可以建議垃圾回收器啟動。
if(i % 2 == 0){
System.gc(); // 建議啟動垃圾回收器。(隻是建議,可能不啟動,也可能啟動。啟動的機率高了一些。)
}
}
}
}
// 項目開發中有這樣的業務需求:所有對象在JVM中被釋放的時候,請記錄一下釋放時間!!!
// 記錄對象被釋放的時間點,這個負責記錄的代碼寫到哪裡?
// 寫到finalize()方法中。
class Person{
// 重寫finalize()方法
// Person類型的對象被垃圾回收器回收的時候,垃圾回收器負責調用:p.finalize();
protected void finalize() throws Throwable {
// this代表目前對象
System.out.println(this + "即将被銷毀!");
}
}
hashCode方法:
在Object中的hashCode方法是怎樣的?
這個方法不是抽象方法,帶有native關鍵字,底層調用C++程式。
hashCode()方法傳回的是哈希碼:
實際上就是一個java對象的記憶體位址,經過雜湊演算法,得出的一個值。
是以hashCode()方法的執行結果可以等同看做一個java對象的記憶體位址。
public class Test07{
public static void main(String[] args){
Object o = new Object();
int hashCodeValue = o.hashCode();
// 對象記憶體位址經過雜湊演算法轉換的一個數字。可以等同看做記憶體位址。
System.out.println(hashCodeValue); //798154996
MyClass mc = new MyClass();
int hashCodeValue2 = mc.hashCode();
System.out.println(hashCodeValue2); //1392838282
MyClass mc2 = new MyClass();
System.out.println(mc2.hashCode()); // 523429237
}
}
class MyClass
{
}
回顧總結:
toString()方法
以後所有類的toString()方法是需要重寫的。
重寫規則,越簡單越明了就好。
System.out.println(引用); 這裡會自動調用“引用”的toString()方法。
String類是SUN寫的,toString方法已經重寫了。
equals()方法
以後所有類的equals方法也需要重寫,因為Object中的equals方法比較的是兩個對象的記憶體位址,我們應該比較内容,是以需要重寫。
重寫規則:自己定,主要看是什麼和什麼相等時表示兩個對象相等。
基本資料類型比較實用:==
對象和對象比較:調用equals方法
String類是SUN編寫的,是以String類的equals方法重寫了。
以後判斷兩個字元串是否相等,最好不要使用==,要調用字元串對象的equals方法。
注意:重寫equals方法的時候要徹底。
finalize()方法。
這個方法是protected修飾的,在Object類中這個方法的源代碼是?
下一篇:内部類