在繼承關(guān)系中,子類如果定義了一個(gè)與父類方法簽名完全相同的方法难咕,被稱為覆寫(Override)
Person類
class Person {
public void run() {
System.out.println("Person.run");
}
}
Student類
class Student extends Person {
@Override
public void run() {
System.out.println("Student.run");
}
}
Override和Overload不同的是诀姚,如果方法簽名如果不同,就是Overload滥朱,Overload方法是一個(gè)新方法员咽;如果方法簽名相同毒涧,并且返回值也相同,就是Override贝室。
注意:
方法名相同契讲,方法參數(shù)相同,但方法返回值不同滑频,也是不同的方法捡偏。#在Java程序中,出現(xiàn)這種情況峡迷,編譯器會(huì)報(bào)錯(cuò)霹琼。
加上@Override可以讓編譯器幫助檢查是否進(jìn)行了正確的覆寫。希望進(jìn)行覆寫,但是不小心寫錯(cuò)了方法簽名枣申,編譯器會(huì)報(bào)錯(cuò)。
但是@Override不是必需的
多態(tài)
Java的實(shí)例方法調(diào)用是基于運(yùn)行時(shí)的實(shí)際類型的動(dòng)態(tài)調(diào)用看杭,而非變量的聲明類型忠藤。
這個(gè)非常重要的特性在面向?qū)ο缶幊讨蟹Q之為多態(tài)
public class Main {
public static void main(String[] args) {
// 給一個(gè)有普通收入、工資收入和享受國務(wù)院特殊津貼的小伙伴算稅:
Income[] incomes = new Income[] {
new Income(3000),
new Salary(7500),
new StateCouncilSpecialAllowance(15000)
};
System.out.println(totalTax(incomes));
}
public static double totalTax(Income... incomes) {
double total = 0;
for (Income income: incomes) {
total = total + income.getTax();
}
return total;
}
}
class Income {
protected double income;
public Income(double income) {
this.income = income;
}
public double getTax() {
return income * 0.1; // 稅率10%
}
}
class Salary extends Income {
public Salary(double income) {
super(income);
}
@Override
public double getTax() {
if (income <= 5000) {
return 0;
}
return (income - 5000) * 0.2;
}
}
class StateCouncilSpecialAllowance extends Income {
public StateCouncilSpecialAllowance(double income) {
super(income);
}
@Override
public double getTax() {
return 0;
}
}
結(jié)果:800
覆寫Object方法
因?yàn)樗械腸lass最終都繼承自O(shè)bject楼雹,而Object定義了幾個(gè)重要的方法:
1.toString():把instance輸出為String模孩;
2.equals():判斷兩個(gè)instance是否邏輯相等;
3.hashCode():計(jì)算一個(gè)instance的哈希值贮缅。
在必要的情況下榨咐,我們可以覆寫Object的這幾個(gè)方法。例如
class Person {
...
// 顯示更有意義的字符串:
@Override
public String toString() {
return "Person:name=" + name;
}
// 比較是否相等:
@Override
public boolean equals(Object o) {
// 當(dāng)且僅當(dāng)o為Person類型:
if (o instanceof Person) {
Person p = (Person) o;
// 并且name字段相同時(shí)谴供,返回true:
return this.name.equals(p.name);
}
return false;
}
// 計(jì)算hash:
@Override
public int hashCode() {
return this.name.hashCode();
}
}
調(diào)用super
在子類的覆寫方法中块茁,如果要調(diào)用父類的被覆寫的方法,可以通過super來調(diào)用桂肌。
class Person {
protected String name;
public String hello() {
return "Hello, " + name;
}
}
Student extends Person {
@Override
public String hello() {
// 調(diào)用父類的hello()方法:
return super.hello() + "!";
}
}
final
繼承可以允許子類覆寫父類的方法数焊。如果一個(gè)父類不允許子類對(duì)它的某個(gè)方法進(jìn)行覆寫,可以把該方法標(biāo)記為final崎场。用final修飾的方法不能被Override:
class Person {
protected String name;
public final String hello() {
return "Hello, " + name;
}
}
Student extends Person {
// compile error: 不允許覆寫
@Override
public String hello() {
}
}
如果一個(gè)類不希望任何其他類繼承自它佩耳,那么可以把這個(gè)類本身標(biāo)記#為final。用final修飾的類不能被繼承
final class Person {
protected String name;
}
// compile error: 不允許繼承自Person
Student extends Person {
}
對(duì)于一個(gè)類的實(shí)例字段谭跨,同樣可以用final修飾干厚。用final修飾的字段在初始化后不能被修改
class Person {
public final String name = "Unamed";
}
對(duì)final字段重新賦值會(huì)報(bào)錯(cuò)
Person p = new Person();
p.name = "New Name"; //compile error!
可以在構(gòu)造方法中初始化final字段:
class Person {
public final String name;
public Person(String name) {
this.name = name;
}
}
總結(jié):
1、子類可以覆寫父類的方法(Override)螃宙,覆寫在子類中改變了父類方法的行為蛮瞄;
2、Java的方法調(diào)用總是作用于運(yùn)行期對(duì)象的實(shí)際類型污呼,這種行為稱為多態(tài)裕坊;
3、final修飾符有多種作用:
4燕酷、final修飾的方法可以阻止被覆寫籍凝;
4、final修飾的class可以阻止被繼承苗缩;
4饵蒂、final修飾的field必須在創(chuàng)建對(duì)象時(shí)初始化,隨后不可修改酱讶。