記錄一下自己在學習 Java 的一些筆記。
重載#
重載: 重載指的是方法的重載,重載的特徵就是兩個或多個方法具有同名。
經典的重載方法#
重載多用於構造器方法,因為構造器作用是初始化構建對象的,構造器的名字必須與類名相同,這就形成經典的無參構造器與有參構造器這一對重載方法。
下面給出了示例:
/**
* @author mingyu
*/
public class User {
private Integer id;
private String userName;
// 無參構造器
public User() {
}
// 單個參數的構造器
public User(Integer id) {
this.id = id;
}
// 全參構造器
public User(Integer id, String userName) {
this.id = id;
this.userName = userName;
}
}
為什麼需要重載#
我們都知道,Java 中最重要的一個概念就是:對象。那方法就是對象的一個個行為。一個對象在做相同名字的行為也可以是在做不同的事情,比如:小明打麻將。
字面意思:小明在和其他人一起玩麻將這類娛樂活動
其他意思:小明在 "打" 一個名字叫 "麻將" 的人
所以說,現實生活中語言當中的歧義也會出現在代碼裡。
還比如說,一個人在吃東西,我給他什麼,他就在吃什麼,我給他麵條,他的行為就是吃麵條,我給他米飯,他就是在吃米飯,但是他的行為都叫吃東西。
總結:重載在代碼當中是很必要的。
重載的區分#
如果不同的方法都是一個名字,要怎麼分辨它們呢?
分辨重載的重要原則:每個重載的方法必須有獨一無二的參數類型列表(即每個方法都有與其他同名方法不同的入參)
那不同的參數列表,到底哪裡不同呢?
參數類型的不同#
public class Test {
public static void main(String[] args) {
// age 的類型不同可以區分兩個同名的方法
getPerson("mingyu", 18);
getPerson("mingyu", "18");
}
static void getPerson(String name, int age) {
System.out.println("name: " + name + ", " + "int_age: " + age);
}
static void getPerson(String name, String age) {
System.out.println("name: " + name + ", " + "String_age: " + age);
}
}
輸出結果:
name: mingyu, int_age: 18
name: mingyu, String_age: 18
參數順序的不同#
雖然參數順序不同可以區分同名的重載方法,但是不推薦使用這種使用方式進行區分,因為這樣寫代碼很難維護
public class Test {
public static void main(String[] args) {
getPerson("mingyu", 18);
getPerson(18,"mingyu");
}
static void getPerson(String name, int age) {
System.out.println("name: " + name + ", " + "behind_age: " + age);
}
static void getPerson(int age, String name) {
System.out.println("name: " + name + ", " + "first_age: " + age);
}
}
輸出結果:
name: mingyu, behind_age: 18
name: mingyu, first_age: 18
返回值區分重載方法#
除了參數列表的類型、順序可以區分方法外,我們能否用方法的返回值來區分呢?
答案是不行的,下面給出了例子。
void f() {}
int f() { return 1; }
當我們只想調用 f()
方法,但不需要該方法的返回值(如 System.out.println
方法),這時如果只是調用方法 f()
,Java 是無法區分我們需要調用的是哪個方法的。
基本類型的重載#
對於只有基本類型不同的重載方法,會出現基本類型可以從小類型自動提升到較大類型的情況
public class Test {
public static void main(String[] args) {
int x = 5;
checkBasicTypes(x);
}
static void checkBasicTypes(long x) {
System.out.println("Type long: " + x);
}
static void checkBasicTypes(float x) {
System.out.println("Type float: " + x);
}
static void checkBasicTypes(double x) {
System.out.println("Type double: " + x);
}
}
輸出結果:
Type long: 5
變量 x 為 int 類型,但是 checkBasicTypes()
方法並沒有 int 類型的入參,當程序運行時,會找到類型比 int 類型大的方法進行調用,即傳入數據類型小於方法的參數類型,傳入的數據類型會自動被提升。( int -> long)
重寫#
重寫一般出現在父子類關係之間,父類與子類有兩個名稱與參數列表都相同的方法,由於它們具有相同的方法名稱,所以在方法調用的時候,子類的方法會覆蓋同名的父類方法。
下面是重寫的一個例子
public class Test {
public static void main(String[] args) {
Animal animal = new Dog();
animal.say();
}
}
class Animal {
public void say() {
System.out.println("I'm animal.");
}
}
class Dog extends Animal {
@Override
public void say() {
System.out.println("I'm Dog.");
}
public void eat() {
System.out.println("Dog like eat meat.");
}
}
輸出結果:
I'm Dog.
上面的例子中,父類與子類都定義了 say()
方法,實際上稱之為子類重寫了父類的 say()
方法。
重寫方法之後,當我們調用子類對象的 say()
方法,儘管 Dog 對象的類型是 Animal ,Java 依然會調用 Dog 的 say()
方法,因為子類的方法會覆蓋同名的父類方法。
重寫的原則#
如果需要重寫方法,需要滿足里式替換原則:
- 子類方法的訪問權限必須大於等於父類方法
- 如父類方法修飾符為 protected,那子類方法的修飾符只能是 protected 或 public
- 子類方法的返回類型必須是父類方法返回類型或為其子類型。
- 如 B extends A : 父方法返回類型為 A,那麼子類方法可以返回 A 類型,也可以是 B 類型
- 子類方法拋出的異常類型必須是父類拋出異常類型或為其子類型。
@Override 註解#
@Override
註解並不是 Java 中的關鍵字,但可以當做關鍵字一樣使用,如果在重寫方法上加上這個註解,編譯器就會幫助你檢查是否滿足上面的三個限制條件,檢測這個重寫方法是否合法。有時候還可以有效的防止意外重載。