1. 什么是類?
類(Class)是藍圖或者模板。它定義了對象的屬性和行為。
- 類就是一種抽象的模板,你可以通過它創建多個對象。
- 類定義了對象的屬性(變量)和行為(方法)。
- 我們可以把類理解成是一種文字一種方法,通過將這個方法具體應用可以完成很多同類型的具體的事件。這個方法我們叫做類,將這個方法具體應用的過程我們叫做類的實例化,著一個個具體的同類型的按照這個方法操作的事件我們叫做對象。注意:(不是Java里的那個方法,就是我們生活中用來解決問題的方法,此處只是打比方,便于理解)
類的結構:
// 類的定義
class Animal{
// 屬性(成員變量)String name;int age;public Animal(String name){this.name = name;}// 行為(方法)void bark() {System.out.println(name + " says woof!");}void eat(){System.out.println(name + "is eating food~");}void sleep(){System.out.println(name + "is sleeping~");}}class Main{public static void main(String args[]){Animal dog = new Animal("dog");dog.bark();dog.eat();dog.sleep();}
}
在這個例子中:
Dog
是類的名稱。name
和age
是屬性(變量)。bark()
是方法,它定義了Dog
對象能做的事情。
2. 什么是對象?
對象是類的實例。你可以把類當做工廠或模板,使用它來生產對象。
貓爪冰棍模具 = 貓爪冰棍類;
用貓爪冰棍模具做出來的冰棍 = 貓爪冰棍對象。
模具只有一個,但是可以做出很多個冰棍,即一個類可以產生很多對象。
- 對象就是通過類創建出來的具體實體,它擁有類中定義的屬性和行為。
- 類是一個模板,它描述了所有同類型對象共有的屬性和行為。
- 對象是類的實例,它具體化了類中定義的屬性和行為。
創建對象的方式:
public class Main {public static void main(String[] args) {// 創建一個 Dog 類的對象Dog myDog = new Dog();// 賦值給對象的屬性myDog.name = "Buddy";myDog.age = 3;// 調用對象的方法myDog.bark(); // 輸出:Buddy says woof!}
}
在這個例子中:
myDog
是一個 對象,它是Dog
類的一個實例。myDog.name
和myDog.age
是對象的屬性。myDog.bark()
是對象的行為。
3. 如何創建對象?
(類的實例化就是創建對象,把貓爪冰棍模具變成能吃的貓爪冰棍)
3.1 創建對象的語法格式:
new
關鍵字在 Java 中用于創建對象,創建對象時會調用類的構造方法(Constructor)。- 每次創建對象時,
new
會在內存中分配一塊空間給對象。
Dog myDog = new Dog(); // 創建一個 Dog 類型的對象無需向類的構造函數傳參的時候的定義格式
類名 對象名 = new 類名();需要通過類的構造函數傳遞參數的時候給實例對象的成員傳參的時候的定義格式
類名 對象名 = new 類名(參數列表);
3.2 創建對象的具體過程:
3.2.1 聲明類類型的變量:
聲明一個類類型的變量,就是告訴編譯器你要使用該類的對象。例如,假設有一個 Dog
類:
class Dog {String name;// 構造方法public Dog(String name) {this.name = name;}// 方法public void bark() {System.out.println(name + " says Woof!");}
}
?聲明一個Dog類型的變量:
Dog myDog;
?此時,myDog
只是一個變量,指向 Dog
類型的對象,但并沒有指向具體的實例。
3.2.2 使用new關鍵字創建對象
為了實際創建一個 Dog
類的對象,并讓 myDog
變量指向這個對象,你需要使用 new
關鍵字:
myDog = new Dog("Buddy");
這行代碼的作用是:
new Dog("Buddy")
創建了一個新的Dog
類的實例,并調用了構造方法Dog(String name)
來為這個新對象的name
屬性賦值為"Buddy"
。myDog
變量被指向了新創建的Dog
對象。
3.2.3?調用構造方法
new
關鍵字不僅創建對象,還會調用類的構造方法來初始化對象。構造方法通常用于設置對象的初始狀態,比如給屬性賦值。
完整的創建對象過程(示例)
class Dog {String name;// 構造方法public Dog(String name) {this.name = name;}// 方法public void bark() {System.out.println(name + " says Woof!");}
}public class Main {public static void main(String[] args) {// 創建 Dog 類的一個對象,并將其賦值給 myDogDog myDog = new Dog("Buddy");// 調用對象的方法myDog.bark(); // 輸出: Buddy says Woof!}
}
關鍵點總結:
- 聲明變量:
Dog myDog;
聲明了一個Dog
類型的變量myDog
,但是它還沒有指向任何對象。 - 使用
new
創建對象:new Dog("Buddy")
創建了一個新的Dog
對象,并通過構造方法初始化了對象的屬性。 - 調用構造方法:構造方法
Dog(String name)
設置了name
屬性的初始值。 - 通過對象調用方法:
myDog.bark()
調用了Dog
類的bark()
方法。
4.?對象的屬性(成員變量)
屬性是定義在類中的變量,它描述了對象的狀態。每個對象都有自己的屬性值。
class Dog {String name; // name 是屬性int age; // age 是屬性
}
在創建對象時,我們可以賦值給這些屬性:
Dog myDog = new Dog();
myDog.name = "Buddy";
//通過 對象名.成員變量名 可以用對象里的共有成員變量,給成員變量賦值或者初始化或者改變其值
myDog.age = 3;//也可以通過 對象名.成員方法名(有參數需要傳遞的話就寫,沒參數就不用寫) 來使用成員方法
5.?對象的方法(成員方法)
方法是定義在類中的函數,描述了對象的行為。方法可以操作對象的屬性,也可以執行某些操作。
class Dog {String name;int age;// 方法:行為void bark() {System.out.println(name + " says woof!");}
}
調用方法時,可以通過對象來訪問它:
Dog myDog = new Dog();
myDog.name = "Buddy";
myDog.bark(); // 輸出:Buddy says woof! 通過 對象名.成員方法名 調用對象的成員方法
6. 構造方法
6.1 定義:
構造方法(Constructor)是 Java 中一種特殊的方法,用于在創建對象時對對象進行初始化。構造方法的主要作用是確保對象在創建時的正確初始化,并且可以為對象設置初始狀態。它在創建對象時被自動調用,用于傳入參數,用來初始化對象的狀態。構造方法的名稱必須與類名相同。
6.2 構造方法的特點:
- 名稱與類名相同:構造方法的名稱必須與類名相同。
- 沒有返回類型:構造方法沒有返回值類型(也不需要寫
void
)。 - 自動調用:當你創建對象時,構造方法會自動調用。
- 自動提供默認構造方法:如果你不定義構造方法,Java 會自動提供一個默認的隱式的無參構造方法。
- 構造方法沒有返回類型,并且是對象在創建的時候會被自動調用,且是先于對象中的類的任何方法的。
6.3 構造方法的分類:
6.3.1 默認構造方法:
如果你沒有顯式定義構造方法,Java 會自動提供一個默認構造方法。默認構造方法沒有參數,它什么也不做,僅僅是初始化一個空對象。如果你定義了一個帶參數的構造方法,Java 將不再自動提供默認構造方法。
class Dog {String name;int age;// void Dog(){// //}
//這里有一個什么都沒有的構造方法的,系統自己給這個類的,
//但是它是隱式的,平時我們寫代碼的時候如果不特意寫出來的話,
//系統也會默認我們有這個,只是沒有顯示出來而已
}// 默認構造方法:沒有參數
Dog myDog = new Dog(); // 創建對象時,會調用默認構造方法
class Dog {String name;// 定義帶參數的構造方法public Dog(String name) {this.name = name;}
}public class Main {public static void main(String[] args) {// Dog dog = new Dog(); // 編譯錯誤,默認構造方法沒有提供Dog dog = new Dog("Buddy"); // 正確,調用帶參數的構造方法System.out.println(dog.name); // 輸出: Buddy}
}
解釋:
- 因為
Dog
類中已經顯式定義了帶參數的構造方法Dog(String name)
,Java 不會自動生成默認構造方法。 - 如果沒有顯式定義任何構造方法,Java 會自動生成一個無參的默認構造方法。
6.3.2 自定義構造方法:
你也可以定義帶參數的構造方法來初始化對象:
class Dog {String name;// 構造方法public Dog(String name) {this.name = name; // 初始化對象的實例變量}
}public class Main {public static void main(String[] args) {Dog dog = new Dog("Buddy"); // 創建對象時調用構造方法System.out.println(dog.name); // 輸出: Buddy}
}
6.4 構造方法重載: (有多個自定義的構造方法)
構造方法是可以重載的,即在同一個類中,可以定義多個構造方法,只要它們的參數列表不同。重載的構造方法允許用不同的參數來初始化對象。
class Dog {String name;int age;// 默認構造方法public Dog() {this.name = "Unknown";this.age = 0;}// 帶參數的構造方法public Dog(String name, int age) {this.name = name;this.age = age;}public void displayInfo() {System.out.println("Name: " + name + ", Age: " + age);}
}public class Main {public static void main(String[] args) {Dog dog1 = new Dog(); // 調用默認構造方法dog1.displayInfo(); // 輸出: Name: Unknown, Age: 0Dog dog2 = new Dog("Buddy", 3); // 調用帶參數的構造方法dog2.displayInfo(); // 輸出: Name: Buddy, Age: 3}
}
解釋:
Dog()
是一個默認構造方法,沒有參數,默認將name
設置為"Unknown"
,age
設置為0
。Dog(String name, int age)
是一個帶參數的構造方法,用來通過外部提供的值來初始化name
和age
。- 在
main
方法中,創建了兩個Dog
對象,分別調用了不同的構造方法。
構造方法的重載可以讓你為對象提供不同的初始化方式,增強代碼的靈活性和可重用性。
6.5 構造方法的調用規則:
- 自動調用:每次通過
new
關鍵字創建對象時,構造方法會被自動調用。
// 類的定義
class Animal{
// 屬性(成員變量)String name;int age;public Animal(String name){this.name = name;System.out.println("構造方法被調用");}void bark(){System.out.println(name + "can bark");}
}class Main{public static void main(String args[]){Animal dog = new Animal("dog");
//在創建對象的時候就會第一時間調用構造方法,
//如果有多個構造方法則程序會根據傳入的參數的情況確定要調用哪個構造方法,
//反正只要創建對象就一定會調用構造方法dog.bark();}
}/*
輸出:
構造方法被調用
dog can bark
*/
7. 對象初始化:
輸出結果:
- 默認初始化:當對象創建時,實例變量會被自動初始化為默認值,比如
int
類型的變量默認為0
,boolean
默認為false
,引用類型的變量默認為null
。 - 顯式初始化:在構造方法中,可以顯式地初始化實例變量。
- 就地初始化:在實例變量聲明時直接進行初始化。
class Dog {// 1. 就地初始化(直接在聲明時賦值)String name = "Unknown"; // 默認值為 "Unknown"// 2. 默認初始化(沒有賦值的實例變量會自動初始化)int age; // 默認值為 0// 3. 顯式初始化(在構造方法中初始化實例變量)boolean isAdopted;// 構造方法:顯式初始化實例變量public Dog(String name, int age, boolean isAdopted) {this.name = name; // 顯式初始化this.age = age; // 顯式初始化this.isAdopted = isAdopted; // 顯式初始化}// 打印信息public void displayInfo() {System.out.println("Name: " + name);System.out.println("Age: " + age);System.out.println("Adopted: " + isAdopted);} }public class Main {public static void main(String[] args) {// 使用構造方法初始化Dog dog1 = new Dog("Buddy", 3, true);dog1.displayInfo();// 輸出:// Name: Buddy// Age: 3// Adopted: true// 使用默認構造方法,name 使用就地初始化,age 使用默認初始化,isAdopted 使用默認初始化Dog dog2 = new Dog("Max", 0, false);dog2.displayInfo();// 輸出:// Name: Max// Age: 0// Adopted: false} }
解釋:
-
就地初始化:
String name = "Unknown";
這是在實例變量聲明時直接賦值,稱為就地初始化。即在定義變量時就給它一個初始值。
-
默認初始化:
int age;
這行代碼聲明了一個int
類型的變量,但沒有給它顯式賦值。在 Java 中,所有的實例變量都會有默認值。對于int
類型,默認值是0
。因此,即使沒有給age
賦值,它在對象創建時也會自動初始化為0
。
- 當我們創建
dog1
對象時,構造方法會顯式初始化實例變量,因此會使用傳入的值"Buddy"
,3
,true
來初始化name
,age
和isAdopted
。 - 當我們創建
dog2
對象時,由于構造方法中為age
傳入了0
,而name
使用了就地初始化的值"Max"
,isAdopted
使用默認初始化值false
。 -
顯式初始化:
- 在構造方法中,使用
this.name = name;
,this.age = age;
,this.isAdopted = isAdopted;
進行了顯式初始化。這種初始化方式通常在構造方法中進行,通過外部傳入的值來設置實例變量的值。
- 在構造方法中,使用
8. this 關鍵字
8.1 定義:
在 Java 中,this
關鍵字是一個引用,指向當前對象的實例。this
可以用在類的實例方法、構造方法以及內部類中,它有許多用途,主要是區分局部變量和實例變量、引用當前對象、調用構造方法等。
8.2 理解:
8.2.1 區分實例變量和局部變量(或參數)
有時,在方法中,局部變量(或方法參數)和類的實例變量同名,導致代碼中看起來不清楚到底是操作局部變量還是實例變量。此時,this
關鍵字就可以幫助我們區分。
class Dog {String name; // 實例變量1// 構造方法,參數和實例變量名相同public Dog(String name) {this.name = name; // this.name 表示實例變量,name 表示構造方法參數
// this.name 指的是當前對象的實例變量,也就是Dog類中注釋實例變量1處的變量name,
//而this.name = name;等號右邊的name是傳參進來的變量name,
//當傳入的參數的名字和類中原本定義的變量名字一樣的時候我們就會使用到this來區分傳入的參數和類本身就有的參數,否則有兩個name將會無法區分,代碼會報錯?}public void displayName() {System.out.println("The dog's name is: " + this.name); // this.name 引用的是實例變量}
}public class Main {public static void main(String[] args) {Dog dog = new Dog("Buddy");dog.displayName(); // 輸出: The dog's name is: Buddy}
}
解釋:
- 在
Dog
類的構造方法中,name
既是構造方法的參數,也是實例變量。 this.name
指的是類中的實例變量name
,而name
單獨寫時指的是構造方法的參數。- 使用
this
可以明確地告訴編譯器我們要修改的是實例變量。
8.2.2?引用當前對象
this
關鍵字還可以用于引用當前對象。也就是說,它表示當前類的對象實例。這對于在實例方法中傳遞當前對象或返回當前對象時非常有用。
示例:
class Dog {String name;public Dog(String name) {this.name = name;}public Dog getCurrentObject() {
//getCurrentObject() 方法返回的是當前對象,即 this 關鍵字所代表的對象return this; // 返回當前對象}public void displayName() {System.out.println("The dog's name is: " + name);}
}public class Main {public static void main(String[] args) {Dog dog = new Dog("Buddy");dog.displayName(); // 輸出: The dog's name is: BuddyDog anotherDog = dog.getCurrentObject(); // 獲取當前對象anotherDog.displayName(); // 輸出: The dog's name is: Buddy}
}
解釋:
- 在上述代碼中,
this
在getCurrentObject()
方法中返回的是當前對象的引用。當你調用dog.getCurrentObject()
時,實際上this
返回的是dog
本身,并且將其賦值給anotherDog
。這兩者dog
和anotherDog
指向同一個對象。
8.2.3?在構造方法中調用其他構造方法(構造方法的鏈式調用)
this
關鍵字還可以在構造方法中調用同一個類的其他構造方法。這稱為構造方法鏈式調用。通過這種方式,我們可以在多個構造方法中復用代碼,避免重復代碼。
示例:
class Dog {String name;int age;// 默認構造方法public Dog() {this("Unknown", 0); // 調用另一個構造方法,如果還有其他的構造方法,會根據參數確定在中國默認的構造方法中使用this去再調用哪個方法}// 帶參數的構造方法public Dog(String name, int age) {this.name = name;this.age = age;}public void displayInfo() {System.out.println("Name: " + name + ", Age: " + age);}
}public class Main {public static void main(String[] args) {Dog dog1 = new Dog(); // 調用默認構造方法dog1.displayInfo(); // 輸出: Name: Unknown, Age: 0Dog dog2 = new Dog("Buddy", 3); // 調用帶參數的構造方法dog2.displayInfo(); // 輸出: Name: Buddy, Age: 3}
}
解釋:
- 在
Dog
類的默認構造方法Dog()
中,使用this("Unknown", 0)
調用了另一個帶參數的構造方法。 - 這就避免了重復的代碼:
name
和age
的賦值只需要寫在帶參數的構造方法中,其他構造方法可以通過this()
調用進行復用。
8.2.4?作為內部類引用外部類的實例
在 Java 中,內部類如果需要訪問外部類的實例變量或方法時,可以使用 this
來引用外部類的實例。
示例:
class OuterClass {String name = "OuterClass";class InnerClass {String name = "InnerClass";public void printNames() {System.out.println("Outer class name: " + OuterClass.this.name); // 訪問外部類的變量System.out.println("Inner class name: " + this.name); // 訪問內部類的變量}}public static void main(String[] args) {OuterClass outer = new OuterClass();OuterClass.InnerClass inner = outer.new InnerClass();inner.printNames();}
}
解釋:
OuterClass.this.name
用來引用外部類OuterClass
的name
變量。this.name
直接引用內部類InnerClass
的name
變量。OuterClass.this
是引用外部類實例的方式,通過它可以訪問外部類的成員。
9. 類和對象的生命周期
9.1?類的生命周期
類的生命周期從它的加載開始,到它的卸載結束。在 Java 中,類是由 JVM(Java 虛擬機)加載、管理和卸載的。類的卸載指的是類從 JVM(Java Virtual Machine) 內存中被移除的過程。這是一個由 JVM 類加載器(ClassLoader) 管理的過程,當類不再被使用時,JVM 會將它從內存中卸載,以釋放資源。這個過程和類的加載一樣,通常是自動管理的,程序員無法直接控制。
類加載(Class Loading)
- 當一個類首次被使用時,JVM 會加載它。
- 類的加載由 類加載器(ClassLoader) 負責。類加載的過程包括:
- 加載:JVM 查找并加載類的字節碼文件(.class 文件)。
- 鏈接:類加載后的字節碼會被鏈接到 JVM 內存中。鏈接包括驗證、準備和解析。
- 初始化:類的靜態變量和靜態代碼塊會被初始化。
類的卸載
- 類的生命周期結束時,JVM 會卸載它。
- 一般情況下,類會在類加載器不再使用時被卸載,但類的卸載通常由 JVM 自動管理,開發者無需手動干預。
9.2?對象的生命周期
對象的生命周期是指對象從創建到銷毀的過程。Java 中的對象生命周期由 堆內存(Heap Memory) 和 垃圾回收機制(Garbage Collection) 控制。
對象的創建(Instantiation)
- 當你使用
new
關鍵字時,會在 堆內存 中分配空間來創建對象。每次調用new
都會創建一個新的對象實例。 - 對象的構造方法會在創建時自動調用,以初始化對象的字段。
示例:對象的創建
class Dog {String name;// 構造方法Dog(String name) {this.name = name;}
}public class Main {public static void main(String[] args) {// 創建一個對象Dog dog = new Dog("Buddy"); // Dog 類的對象在堆內存中創建}
}
對象的使用(Reference)
- 創建對象后,你可以通過引用變量(如
dog
)來訪問對象的屬性和方法。對象的生命周期管理是由引用變量控制的。 - 如果有多個引用指向同一個對象,那么該對象仍然存在,直到沒有任何引用指向它為止。
對象的銷毀(Garbage Collection)
- 在 Java 中,垃圾回收(GC)負責回收不再使用的對象。對象會在以下情況下被銷毀:
- 沒有引用指向它:當對象不再被任何引用變量引用時,GC 會自動回收它。
- 垃圾回收器:Java 會自動運行垃圾回收器來清理沒有引用的對象,這個過程是自動的,開發者不需要手動銷毀對象。
示例:對象的銷毀
public class Main {public static void main(String[] args) {Dog dog = new Dog("Buddy"); // 創建對象// 當 dog 變量不再引用該對象時,Buddy 對象將變成垃圾等待被回收dog = null; // 取消引用對象,垃圾回收器會銷毀該對象}
}
垃圾回收(GC)詳細描述
- 在 Java 中,垃圾回收器(GC)會自動查找和回收無用的對象,釋放內存空間。
- 當對象不再有任何引用指向它時,JVM 會標記該對象為 垃圾,并在下一次垃圾回收時銷毀它。
9.3?類和對象生命周期的對比
生命周期階段 | 類 | 對象 |
---|---|---|
加載/創建 | 類在第一次使用時加載到內存 | 使用 new 創建對象,分配內存 |
使用 | 類在內存中一直存在,直到程序結束 | 對象在內存中存在,直到沒有引用指向它 |
銷毀 | 類在程序結束時卸載 | 對象通過垃圾回收機制被銷毀 |
9.4?總結
-
類的生命周期:從類加載開始,到類卸載結束。類的生命周期由類加載器控制,類的靜態變量和靜態方法在內存中存在,直到類卸載。
-
對象的生命周期:從對象創建開始,到對象被垃圾回收結束。對象的生命周期由引用變量控制,垃圾回收機制負責銷毀不再使用的對象。
10. 類和對象的區別總結
- 類是一個模板,用來創建對象,它描述了對象的屬性和行為。
- 對象是類的實例,是通過類創建出來的具體實體。
總結
- 類是描述一組對象共有特征的模板。
- 對象是通過類創建出來的實例,擁有類中定義的屬性和行為。
- 創建對象時,使用
new
關鍵字,調用構造方法。 - 對象的屬性描述它的狀態,方法描述它的行為。
- 通過構造方法初始化對象的狀態,可以用
this
關鍵字來區分實例變量和局部變量。