a.使用new關鍵字產生物件會呼叫構造方法_java基礎類與物件
1.java是面向物件程式設計 OOP
面向物件程式設計(Object Oriented Programming,OOP)是一種計算機程式設計架構。OOP的一條基本原則是計算機程式由單個能夠起到子程式作用的單元或物件組合而成。OOP達到了軟體工程的三個主要目標:重用性、靈活性和擴充套件性。OOP=物件+類+繼承+多型+訊息,其中核心概念是類
和物件
。
1.1 類(class)
一個共享相同結構和行為的物件的集合。類(Class)定義了一件事物的抽象特點。通常來說,類定義了事物的屬性和它可以做到的(它的行為)。舉例來說,“狗”這個類會包含狗的一切基礎特徵,例如它的孕育、毛皮顏色和吠叫的能力。類可以為程式提供模版和結構。一個類的方法和屬性被稱為“成員”。
在java中類(class) 是構造物件的模板或藍圖。由類構造(construct) 物件的過程稱為建立類的例項 (instance ).
與類緊密關聯的還有另一個概念叫做封裝。
封裝有兩層意思,第一層意思:將資料和操作捆綁在一起,創造出一個新的型別的過程。第二層意思:將介面與實現分離的過程。
從形式上看, 封裝不過是將資料和行為組合在一個包中, 並對物件的使用者隱藏了資料的實現方式。物件中的資料稱為例項域,也就是我們常說的屬性、欄位。操縱資料的過程稱為方法( method ) 。對於每個特定的類例項(物件)都有一組特定的例項域值。這些值的集合就是這個物件的當前狀態( state )。無論何時,只要向物件傳送一個訊息,它的狀態就有可能發生改變。
1.2 物件
物件是指可以對其做事情的一些東西。一個物件有狀態、行為和標識三種屬性。這三個屬性分別對應的如下:
物件的行為(behavior) — 可以對物件施加哪些操作,或可以對物件施加哪些方法
物件的狀態(state ) — 當施加那些方法時,物件如何響應
物件標識(identity ) — 如何辨別具有相同行為與狀態的不同物件
同一個類的所有物件例項, 由於支援相同的行為而具有家族式的相似性。物件的行為是用可呼叫的方法定義的。此外,每個物件都儲存著描述當前特徵的資訊。這就是物件的狀態。物件的狀態可能會隨著時間而發生改變,但這種改變不會是自發的。物件狀態的改變必須通過呼叫方法實現 (如果不經過方法呼叫就可以改變物件狀態,只能說明封裝性遭到了破壞)。
1.3 類之間的關係
類與類之間主要存在以下幾種關係:
依賴
依賴( dependence ), 即 “ uses-a” 關係, 是一種最明顯的、 最常見的關係。例如,User
類(使用者類)使用 Role
類(角色類)是因為 User
物件需要訪問 Role
物件檢視使用者具有什麼角色。但是 Student
類不依賴於 Role
類, 這是因為 Student
物件與角色無關。因此, 如果一個類的方法操縱另一個類的物件,我們就說一個類依賴於另一個類。應該儘可能地將相互依賴的類減至最少。如果類 A 不知道 B 的存在, 它就不會關心 B 的任何改變(這意味著 B 的改變不會導致 A 產生任何 bug )。用軟體工程的術語來說,就是 讓類之間的耦合度最小。儘量做到低耦合的設計要求。
聚合
聚合(aggregation ), 即“ has-a ” 關係, 是一種具體且易於理解的關係。例如, 一個 User
物件包含一些 Student
物件。聚合關係意味著類 A 的物件包含類 B 的物件。
繼承
繼承( inheritance ), 即“ is-a” 關係, 是一種用於表示特殊與一般關係的。例如,Tiger
類(老虎類)由 Animals
類(動物類)繼承而來。在具有特殊性的 Tiger
類中包含了一些用於優先處理的特殊方法, 以及一個計算運費的不同方法;而其他的方法, 如會行走、會捕獵等都是從 Animals
類繼承來的。一般而言, 如果類 A 擴充套件類 B, 類 A 不但包含從類 B 繼承的方法,還會新增一些額外的功能。
2. 用引用操縱物件
2.1物件引用
在java 程式設計思想中有一句經典的介紹說“一切接物件”,也就是說在java語言中可以將所有都當成物件來處理,但是在操縱的識別符號實際上是物件的引用。如下:
String name;
上面的程式碼中name直接只用String物件中的方法,如toString()方法會報java.lang.NullPointException
空指標錯誤,因為name 只是建立了一個引用,並沒有建立物件,所以一般情況都是在建立引用的時候對其進行初始化,如下:
String name = "Jack";
上面的這種建立物件的方式是java提供的,只使用與String 物件,還有一種更通用的方式建立物件如下:
String name = new String("Jack");
這裡的這個關鍵字 new
所代表的意思就是建立一個新物件。
物件的引用還存於變數之間,如:
String name = new Strin("Jack");String userName;userName = name;
通過userName = name,這個操作之後這兩個變數都引用了同一個String物件。
2.2 初始化物件引用
初始化這些引用變數,可以在程式碼中的下列位置進行:
在定義物件的地方。這意味著它們總是能夠在構造器被呼叫之前被初始化
在類的構造器中
在正要使用這些物件之前,這種方式稱為惰性初始化 delayed initialization
使用例項初始化
如下程式碼中有對應的各種初始化場景介紹:
public class HelloWord { String name; //在定義物件的地方進行初始化 String address = "103 Queen Street"; Student student; public static void main(String[] args) { } public HelloWord(){ //在類的構造器中進行初始化 name = new String("Jack"); // 使用例項時進行初始化(當需要使用Student 這個物件的時候才去初始化) System.out.println(new Student(name).toString()); } public String getName() { // 在正要使用這些物件之前進行初始化 if (name == null){ name = "Jessie"; } return name; }}
3. 記憶體分配
在我們的程式執行的時候在程式中流轉的資料需要儲存,對應有以下幾個地方可以儲存資料:
暫存器:最快的儲存區,位於處理器內部。數量有限且我們無法直接控制。
棧:位於通用 RAM(隨機訪問儲存器)中。棧指標下移,則分配新的記憶體;若上移,則釋放那些記憶體。這是一種快速有效的分配儲存方法,僅次於暫存器。
注意 java的物件引用和基本資料型別都是儲存在棧中。
堆
一種通用的記憶體池,位於 RAM 中,用於存放所有的 Java 物件(new 出來都存在堆中)。堆不同於棧的好處就是:編譯器不需要知道儲存的資料在堆裡存活多長時間。
常量儲存
常量值 (指被static
修飾的值)通常直接存放在程式程式碼內部,這樣做是安全的,因為它們永遠不會被改變
非 RAM 儲存
如果資料完全存活於程式之外,那麼它可以不受程式的任何控制,在程式沒有執行時也可以存在。比如流物件和持久化物件。
4. 作用域 scope
4.1什麼是作用域
作用域決定了在其內定義的變數名的可見性和生命週期。在 Java、作用域由花括號({})的位置決定。如下:
if (name == null){name = "Jessie";}
if所具有的作用域就是在他後面的{}中。
4.2 物件作用域
Java 物件不具備和基本型別一樣的生命週期。當用 new 建立一個 Java 物件時,它可以存活於作用域之外。比如:
public void TestScope(){ String name; if (4<5){ String userName = new String("張三"); name = userName; } System.out.println("name = " +name);}
如上程式碼中name 在if之外定義,userName在if之內建立,並在其中賦值給了name,userName這個變數的生命週期就只在if的作用域中,但是在外面還是能打印出name的值,這就是因為userName所指向的String物件仍然佔據儲存空間,雖然我們不能在作用域之外訪問這個物件。
Java 有一個垃圾回收器,用來監視 new
建立的所有物件,並辨別那些不會被再引用的物件,然後釋放這些物件的記憶體空間。
5. 物件的初始化
5.1 構造方法
構造方法(也叫建構函式),是一種特殊的方法。主要用來在建立物件時初始化物件, 即為物件成員變數賦初始值,總與new運算子一起使用在建立物件的語句中。特別的一個類可以有多個構造方法 ,可根據其引數個數的不同或引數型別的不同來區分它們 即構造方法的過載。
在java中
構造方法的命名必須和類名完全相同,普通方法可以和構造方法同名,但是必須帶有返回值;
如下程式碼:
public class HelloWord { String name; //在定義物件的地方進行初始化 String address = "103 Queen Street"; Student student; public static void main(String[] args) { } public HelloWord(){ //在類的構造器中進行初始化 name = new String("Jack"); // 使用例項時進行初始化(當需要使用Student 這個物件的時候才去初始化) System.out.println(new Student(name).toString()); }}
可以看到, 構造方法與類同名且沒有返回值。在構造 HelloWord
類的物件時, 構造方法會執行,以便將例項域初始化為所希望的狀態。
對於構造方法需要注意一下幾點:
構造方法與類同名
每個類可以有一個以上的構造方法
構造方法可以有 0 個、1 個或多個引數
構造方法沒有返回值
構造方法總是伴隨著 new 操作一起呼叫
5.2 過載 (@Overload)
如下程式碼:
public class HelloWord { public HelloWord(){ //在類的構造器中進行初始化 name = new String("Jack"); // 使用例項時進行初始化(當需要使用Student 這個物件的時候才去初始化) System.out.println(new Student(name).toString()); } public HelloWord(String name){ //在類的構造器中進行初始化 this.name = name; // 使用例項時進行初始化(當需要使用Student 這個物件的時候才去初始化) System.out.println(new Student(this.name).toString()); }}
在上面的程式碼中HelloWord 類中有兩個構造方法,他們主要是在引數上的區別,一個是不帶引數,一個帶了String 型別的引數。
這種特徵叫做過載(overloading) 。如果多個方法(比如, HelloWord構造方法)有相同的名字、 不同的引數,便產生了過載。編譯器必須挑選出具體執行哪個方法,它通過用各個方法給出的引數型別與特定方法呼叫所使用的值型別進行匹配來挑選出相應的方法。如果編譯器找不到匹配的引數, 就會產生編譯時錯誤,因為根本不存在匹配, 或者沒有一個比其他的更好。這個過程被稱為過載解析(overloading resolution)。
除了構造方法具有這種過載的情況,普通方法也可以。
5.3 this 關鍵字
如下程式碼:
public class Student{ public void setSno(String sno) { this.sno = sno; } public String getSname() { return sname; }}
在上面的程式碼中setSno這個方法有兩個引數:
隱式 implict 引數:出現在方法名前的
Student
類物件。在每一個方法中, 關鍵字
this
表示隱式引數。顯式 explicit 引數:位於方法名後面括號中的引數
sno
在 Java 中, 所有的方法都必須在類的內部定義, 但並不表示它們是內聯方法。是否將某個方法設定為內聯方法是 Java 虛擬機器的任務。即時編譯器會監視呼叫那些簡潔、經常被呼叫、 沒有被過載以及可優化的方法。
5.4 java中的初始化程式碼塊
靜態初始化塊
使用 static
定義, 只有當類裝載到系統時執行一次,之後不再執行。在靜態初始化塊中僅能初始化 static
修飾的資料成員。
非靜態初始化塊
非靜態初始化塊: 在每個物件生成時都會被執行一次, 可以初始化類的例項變數。
程式碼塊執行順序:
主調類的靜態程式碼塊
物件父類的靜態程式碼塊
物件的靜態程式碼塊
物件父類的非靜態程式碼塊
物件父類的建構函式
物件的非靜態程式碼塊
物件的建構函式
6. 訪問許可權控制
6.1 Java 訪問許可權修飾詞
主要分為以下幾種情況:
①包訪問許可權
如果沒有指定訪問修飾符, 這部分(類、方法或變數)可以被同一個包中的所有方法訪問。包訪問許可權允許將包內所有相關的類組合起來,以使得它們彼此之間可以輕鬆的相互使用。
對於繼承來說,子類是無法訪問父類中具有包訪問許可權的成員
②public 介面訪問許可權
標記為 public
的部分可以被任意的類使用
③private 私有訪問許可權
標記為 private
的部分只能被定義它們的類使用。等於說是隔離了自己。
④protected 繼承訪問許可權
protected
也提供包訪問許可權,也就是說相同包內的其他類可以訪問 protected
元素,無法跨包訪問。
注意:對於繼承來說,所有子類都可以訪問父類的 protected
元素
6.2 基於類的訪問許可權
修飾詞出現在關鍵字 class
之前,用來控制某個類的訪問許可權,如:
public class Student { private String sno; private String sname;}
這個類中的public
就是在告訴大家任何程式設計師寫的java程式碼都能訪問到Student類,沒有限制。
注意:
每個
.java
檔案(編譯單元)只能有一個public
類。這表示每個編譯單元都有單一的公共介面。public
類的名稱必須與含有該編譯單元的檔名一致,包括大小寫。類(內部類除外)的訪問許可權只能是包訪問許可權或
public
。
如果不希望其他任何人對該類擁有訪問許可權,可以把所有的構造器都指定為 private
,從而阻止任何人建立該類的物件。不過,在該類的 static
成員內部可以建立。
7. static 關鍵字
7.1靜態域 / 靜態欄位
如果將域定義為 static
, 每個類中只有一個這樣的域,而每一個物件對於所有的例項域卻都有自己的一份拷貝。例如:
class Test{ private static int sno = 1; private int id; public static int getSno{ return nextId; // return static field } ...}
現在, 每一個 Test
物件都有一個自己的 id
域, 但這個類的所有例項將共享一個 sno
域。換句話說, 如果有 1000 個 Test
類的物件, 則有 1000
個例項域 id
。但是, 只有一 個靜態域 sno
。即使沒有一個 Test
物件, 靜態域 sno
也存在,它屬於類,而不屬於任何獨立的物件。
static
初始化只有在第一次建立 Test
物件或者呼叫 Test.sno
的時候才會呼叫,在那之後,靜態域不會重新初始化。初始化的順序是首先 static,再是其他非 static 物件。
靜態域可直接用類名進行呼叫,例如:
System.out.println(Test.sno);
7.2靜態常量 static final
靜態變數使用得比較少,但靜態常量卻使用得比較多。例如在 Math
類中定義了一個 靜態常量:
public class Math{ public static final double PI = 3.14159265358979323846; ...}
在程式應用中,可以採用 Math.PI
的形式獲得這個常量。無法更改且只初始化一次。
7.3靜態方法
靜態方法是一種不能向物件實施操作的方法。例如, String
類的 valueOf
方法就是一個靜態方法。
public final class String implements java.io.Serializable, Comparable<String>, CharSequence { public static String valueOf(Object obj) { return (obj == null) ? "null" : obj.toString(); }}
在運算時,不使用任何 String
物件。換句話說,沒有隱式的引數。可以認為靜態方法是沒有 this 引數的方法。
在下面兩種情況下使用靜態方法:
方法不需要訪問物件狀態,其所需引數都是通過顯式引數提供(例如:
Math.valueOf
)一個方法只需要訪問類的靜態域(例如:
Test.getSno
)
**8. 物件的清理
在java中當一個物件不再被引用的時候java 的就會任務這個儲存垃圾,java會自動呼叫垃圾回收機制對其進行處理,在一般情況下我們是不需要手動去處理垃圾回收的事情,但也可以手動進行垃圾回收處理,主要有一下兩種方式告訴程式需要進行垃圾回收:
System.gc();
:告訴垃圾收集器打算進行垃圾收集,而垃圾收集器進不進行收集是不確定的System.runFinalization();
:強制呼叫已經失去引用的物件的finalize
方法
? ? 掃碼關注獲後獲取更多精彩內容!!!!❤️ ❤️