SpringMVC中Model機制
這裡我們定義一個Person的類:
class Person {
private String name;
private int age;
public String getName() {...}
public void setName(String name) {...}
public int getAge() {...}
public void setAge(int age) {...}
}
在定義一個Student類:
class Student { private String name; private int age; private int score; public String getName() {...} public void setName(String name) {...} public int getAge() {...} public void setAge(int age) {...} public int getScore() { … } public void setScore(int score) { … } }
可以發現,這兩個類中,有很多相同的欄位和方法,那麼我們可不可以在Sutdent類中不用再寫相同的欄位和方法,只寫其特有的屬性和方法呢?
當然可以! 但是,要用到java的 extends關鍵字,他表示繼承。
class Person { private String name; private int age; public String getName() {...} public void setName(String name) {...} public int getAge() {...} public void setAge(int age) {...} } class Student extends Person { // 不要重複name和age欄位/方法, // 只需要定義新增score欄位/方法: private int score; public int getScore() { … } public void setScore(int score) { … } }
這樣我們就可以自寫需要新增的程式碼。
注意:子類自動獲得了父類的所有欄位,嚴禁定義與父類重名的欄位!
在OOP的術語中,我們把Person
稱為超類(super class)、父類(parent class)、基類(base class),把Student
稱為子類(subclass),擴充套件類(extended class)。
繼承樹
在編寫父類,person的時候我們並沒有,給person寫extends。它同樣會有一個繼承關係,不過這個關係是java的機制中的預設繼承關係,Java中預設Obect類為所有類的父類。
繼承關係如下:
java只允許一個class繼承一個父類。也就是說在java中的所有繼承關係都是單繼承。一個類有且只有一個父類。object類是特例,它沒有父類。
我們再定義一個別的類時,繼承樹如下:
一個類可以被多個類繼承,但是它只能繼承一個父類。
繼承中的欄位修飾關係和普通的一樣,有 private ,預設,protect和public。但是,繼承中有個特點,就是子類無法訪問父類的private字元或者private方法,
class Person {
private String name; //私有化欄位
private int age; //私有化欄位,不能被訪問
}
class Student extends Person {
public String hello() {
return "Hello, " + name; // 編譯錯誤:無法訪問name欄位
}
}
這樣一來 ,繼承的作用就削弱了,如果要訪問欄位,我們可以將private,改成protect。被這個關鍵字修飾的欄位可以被子類訪問。
class Person {
protected String name;
protected int age;
}
class Student extends Person {
public String hello() {
return "Hello, " + name; // OK!
}
}
super關鍵字
super關鍵字表示父類(超類)。子類引用父類的欄位時,可以使用super.filedNama。
class Student extends Person {
public String hello() {
return "Hello, " + super.name;//這裡可以不用spuer,用this.name 或則 name 也可以,編譯器會自動定位到父類欄位
}
}
但是,以下的這個時候就必須要用 super關鍵字。
class Person {
protected String name;
protected int age;
//定義個無參的構造方法
//public Person() { }
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
class Student extends Person {
protected int score;
//直接執行會報錯,因為編譯器會自動給子類新增一個 sper();
// super();//但是父類並沒有無參的構造方法,解決辦法可以給父類新增一個無參的構造方法 或者 有suer(name,age);指定呼叫有參構造方法
public Student(String name, int age, int score) {
this.score = score;
}
}
public class Main {
public static void main(String[] args) {
Student s = new Student("Xiao Ming", 12, 89);
}
}
可以得出一個結論:如果父類沒有預設的狗雜方法,子類就必須顯示的呼叫super()並且給出引數以便讓編譯器定位到父類的一個合適的構造方法。
這裡也可以看出,子類不會繼承父類的任何狗雜方法,子類預設的構造方法是編譯器自己生成的,不是繼承的。
區分繼承和組合
在使用繼承時,我們要注意邏輯一致性。
class Book {
protected String name;
public String getName() {...}
public void setName(String name) {...}
}
再寫一個繼承類、我們能不能讓子類繼承父類的 nama欄位:
class Student extends Book {
protected int score;
}
顯然,從邏輯上講,這是不合理的,Student
不應該從Book
繼承,而應該從Person
繼承。
究其原因,是因為Student
是Person
的一種,它們是is關係,而Student
並不是Book
。實際上Student
和Book
的關係是has關係。
具有has關係不應該使用繼承,而是使用組合,即Student
可以持有一個Book
例項:
class Student extends Person {
protected Book book;
protected int score;
}
因此,繼承是is關係,組合是has關係。