這篇文章記錄了學 java 以來的的全部筆記並不斷進行更新,希望能堅持住吧~
這篇文章記錄了學 java 以來的的全部筆記並不斷進行更新,希望能堅持住吧~
方法的重載和重寫 Overload 和 Override#
方法的重載 Overload:一個類中,多個方法的方法名相同,但是參數列表不同(可以是個數不同,類型不同,順序不同)。讓類以統一的方式處理不同的數據類型的實現方法,調用方法時傳遞不同個數或者類型的參數來決定調用哪一個方法。注意,方法名字相同,參數列表不同,返回類型等其他的可以相同也可以不同,Java 虛擬機通過參數列表進行判斷。所以需要一個獨一無二的參數列表。
方法的重寫 Override:在子類中重寫父類存在的方法,對父類的方法進行擴展,新增加功能,重寫是建立在繼承的關係之上的。重寫的方法的方法簽名需要與父類對應的方法簽名完全一致(方法簽名指的是方法名稱和參數列表)。Override 體現了 java 的多態性。
多態是同一個行為具有多個不同表現形式或形態的能力。
多態性是對象多種表現形式的體現。
現實中,比如我們按下 F1 鍵這個動作:
如果當前在 Flash 界面下彈出的就是 AS 3 的幫助文檔;
如果當前在 Word 下彈出的就是 Word 幫助;
在 Windows 下彈出的就是 Windows 幫助和支持。同一個事件發生在不同的對象上會產生不同的結果。多態存在的三個必要條件:1. 繼承 2. 重寫 3. 父類引用指向子類對象。針對某個類型的方法調用,其真正執行的方法取決於運行時期實際類型的方法。
重寫時可以修改訪問權限修飾符,要求:子類重寫方法的權限修飾符應大於或者等於父類方法的權限修飾符,比如父類的是 protect,你重寫完可以改為 public,或者父類是 default 權限,你也可以改為 public 權限或者 protect 權限,訪問權限只能大,不能小。
重寫時可以修改為不同的返回值類型,要求:僅當返回值為引用數據類型時 (返回值類型是引用數據類型,而不能是 int 等基本數據類型),這樣才可以修改返回值類型,且必須是 - 父類方法返回值類型的子類;要麼就不修改,與父類返回值類型相同,比如父類的返回值類型是 Object,這時候,你子類的返回值類型可以為 Object,也可以任意一個類。只能小,不能大。
訪問修飾符#
訪問修飾符 | 本類 | 同包 | 子類 | 其他 |
---|---|---|---|---|
private | √ | × | × | × |
default | √ | √ | × | × |
protected | √ | √ | √ | × |
public | √ | √ | √ | √ |
參數綁定#
調用方把參數傳遞給實例方法時,調用時傳遞的值會按參數位置一一綁定。
public class Main {
public static void main(String[] args) {
Person p = new Person();
int n = 15; // n的值為15
p.setAge(n); // 傳入n的值
System.out.println(p.getAge()); // 15
n = 20; // n的值改為20
System.out.println(p.getAge()); // 15還是20?
}
}
class Person {
private int age;
public int getAge() {
return this.age;
}
public void setAge(int age) {
this.age = age;
}
}
運行代碼,從結果可知,修改外部的局部變量 n,不影響實例 p 的 age 欄位,原因是 setAge () 方法獲得的參數,複製了 n 的值,因此,p.age 和局部變量 n 互不影響。
結論:基本類型參數的傳遞,是調用方值的複製。雙方各自的後續修改,互不影響。
我們再看一個傳遞引用參數的例子:
public class Main {
public static void main(String[] args) {
Person p = new Person();
String[] fullname = new String[] { "Homer", "Simpson" };
p.setName(fullname); // 傳入數組fullname
System.out.println(p.getName()); // "Homer Simpson"
fullname[0] = "Bart"; // fullname數組的第一個元素修改為"Bart"
System.out.println(p.getName()); // "Homer Simpson"還是"Bart Simpson"?
}
}
class Person {
private String[] name;
public String getName() {
return this.name[0] + " " + this.name[1];
}
public void setName(String[] name) {
this.name = name;
}
}
注意到 setName () 的參數現在是一個數組。一開始,把 fullname 數組傳進去,然後,修改 fullname 數組的內容,結果發現,實例 p 的欄位 p.name 也被修改了!
結論:引用類型參數的傳遞,調用方的變量,和接收方的參數變量,指向的是同一個對象。雙方任意一方對這個對象的修改,都会影響對方(因為指向同一個對象嘛)。
下面這個例子:
public class Main {
public static void main(String[] args) {
Person p = new Person();
String bob = "Bob";
p.setName(bob); // 傳入bob變量
System.out.println(p.getName()); // "Bob"
bob = "Alice"; // bob改名為Alice
System.out.println(p.getName()); // "Bob"還是"Alice"?
}
}
class Person {
private String name;
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
結論沒問題:
1、整數、浮點數、字符是基本類型。
2、字符串、數組是引用類型(內存數據的索引)
3、基本類型參數的傳遞,是調用方值的複製。雙方各自的後續修改,互不影響。
4、引用類型參數的傳遞,調用方的變量和接收方的參數變量,指向的是同一個對象。雙方任意一方對這個對象的修改,都会影響對方。
那麼 3 個例子中,
1、整數的參數傳遞理解了,複製出來的,分家了,自己管理自己的,類讀出數據不變。
2、字符串數組的參數傳遞也理解了,都是指向同一個地方,數組的一個元素改了,類讀出數據也就變了(類一直指向這裡)。
3、字符串也是引用參數,為什麼類讀出數據不變?因為重寫了整個字符串(新開內存和指向,參看字符串更改章節),類依然指向之前內存塊,類讀出數據不變,同結論 1。如果只是修改字符串內存中某一個字符的值,則同結論 2。
簡單總結:類對基本類型是複製數據本身,新開內存。對引用類型是複製指向地址,內存數據本身變化了,類讀出數據跟著變化。但字符串修改,是新開內存新指向,已經不能影響類數據。
(以上例子和總結來自於廖雪峰老師博客以及評論
構造方法#
Person p = new Person("Xiao Ming", 15);
new 後面的 person 指的是構造方法,調用構造方法必須使用 new 操作符。
在 Java 中,創建對象實例的時候,按照如下順序進行初始化:
-
先初始化欄位,例如,int age =10; 表示欄位初始化為 10,double salary; 表示欄位默認初始化為 0,String name; 表示引用類型欄位默認初始化為 null;
-
執行構造方法的代碼進行初始化。
構造方法的代碼由於後運行。
構造方法也有多態性,可以自動根據參數列表匹配;
構造方法可以調用構造方法,使用 this. 關鍵字
native 關鍵字#
剛在看一問題:兩個對象的 hashCode () 相同,則 equals () 也一定為 true 嗎? 查一下 hashCode () 的定義,
public native int hashCode();
第一次看到 native 關鍵字,好奇是什麼東東。查了一番資料。
JNI#
首先要了解的是 JNI 即 Java Native Interface Java 本地方法接口,通過這個允許 Java 語言和 C 或 C++ 進行交互。維基百科是這樣解釋的:“當應用無法完全用 Java 編程語言實現的時候,(例如,標準 Java 類庫不支持的特定平台特性或者程序庫時),JNI 使得編程者能夠編寫 native 方法來處理這種情況”。這就意味著,在一個 Java 應用程序中,我們可以使用我們需要的 C++ 類庫,並且直接與 Java 代碼交互,而且在可以被調用的 C++ 程序內,反過來調用 Java 方法(回調函數)。 (這也太牛逼了吧…
總結來說就是:使用 native 關鍵字修飾的函數 (方法),說明這個方法是原生函數,也就是這個方法是用 C/C++ 語言實現的,並且被編譯成了 DLL,由 java 去調用。 完活兒~
補充一個實現步驟 :
可以將 native 方法比作 Java 程序同C程序的接口,其實現步驟:
-
在 Java 中聲明 native () 方法,然後編譯;
-
用 javah 產生一個. h 文件;
-
寫一個. cpp 文件實現 native 導出方法,其中需要包含第二步產生的. h 文件(注意其中又包含了 JDK 帶的 jni.h 文件);
-
將第三步的. cpp 文件編譯成動態鏈接庫文件;
-
在 Java 中用 System.loadLibrary () 方法加載第四步產生的動態鏈接庫文件,這個 native () 方法就可以在 Java 中被訪問了。
後續學習網址:IBM 社區在 Windows 中實現 Java 本地方法為什麼說多態可以消除類型之間的耦合關係?#
給你說了也白搭,你大概知道就行了,這個需要代碼量。。。簡單地說就是,沒有多態,那麼等號左邊是啥度右邊就得是啥,這就叫耦合,有了多態,知左邊是父類(或者接口),右邊是子類(或實現類),我只管調用接道口裡面的方法就是了,至於你實現類怎麼去實現,那是你的事,你要修改一下專實現,你只管去把實現類換屬掉,我這邊一行代碼都不用變,這就解耦了