一、類與對象
類是用來對一組具有相同特性事物的描述,而對象就是類的執行個體,類用來描述對象,就像一座大樓與樓的設計圖的關系,蓋成一座大樓需要一張設計圖來确定這座樓有多高,有多大,一層有幾個房間等。萬物皆對象。
例如:
//一個描述人的類
public class Person {
private String name; //人的姓名
private int age; //人的年齡
private String sex ; //人的性别
public void spaek() {
System.out.println("說話");
}
}
上面的代碼,是一個關于人的類, 類中描述了一個人的屬性如姓名,年齡;還有人的一個動作說話,可以說,通過這個類,我們就能簡單的得到一個‘人’。
Person people1 = new Person(); //java中通過new關鍵字可以建立一個對象。
people1.speak(); // 通過對象可以調用該對象的speak方法。
建立一個對象後就可以調用其中的成員變量和方法,要注意成員變量的修飾符,public(在所有的類中都能通路),private(隻能在自身類中通路,也不能在子類中通路),protected(隻能被自身類,子類和同一包中的類通路),一般常用的就這三個。在上述代碼中,調用了speak方法,其修飾符public,說明可以任意類中的通路,而name,age屬性,都是私有的private,隻能在本類中通路,如果需要通路,我們可以在Person類設定return方法來傳回,這樣可以保護類中的資料,起到封裝的特性,如:
public String getName(){
return this.name;
}
二、構造方法
構造方法就是對對象的初始化,就是在new對象時,使對象當出現時就自帶有一些屬性值,比如說一個人,剛出生是父母一般都會起好名字,那麼我們為什麼不在建立對象時就給對像的名字指派呢?這就需要構造方法。
public class Person {
private String name;
protected int age;
//構造方法,需要傳入名字。
public Person(String name) {
this.name = name;
}
public void spaek() {
System.out.println("說話");
}
public String getName(){
return this.name;
}
}
構造方法是與類同名,公共的,沒有傳回值的方法,不用使用者調用,會在建立對象是自動調用。
Person people1 = new Person("小王");
people1.getName(); //調用people1的getName方法得到name的值 此時name的值同過構造方法的指派,為“小王”。
三、 重構
上面我們講解了構造方法,那麼問題來了,如果一個人一出生還沒有起好名字,那怎麼辦呢?這就需要說到方法的重構了。就是方法名稱一樣,傳回值一樣,就是方法的傳參不一樣。建立對象是根據傳入參數的個數。類型的不同,來調用不同的構造方法。不止是構造方法,成員方法也能重構(注意:重構時的參數要麼要在個數上不同,要麼要在傳入參數的類型上不同)。
public class Person {
private String name;
protected int age;
public Person() { //沒有參數的構造方法
this.name = "無名";
}
public Person(String name) {
this.name = name;
}
public void spaek() {
System.out.println("說話");
}
public String getName(){
return this.name;
}
}
當我們調用時,可以傳入不同的參數來建立對象。
Person people1 = new Person("小王"); //建立一個名字為小王的人,調用有參構造方法。
Person people2 = new Person(); //建立一個沒有名稱的人,調用無參構造方法
System.out.println(people1.getName()); // 輸出為 小王
System.out.println(people2.getName() //輸出為 無名
四、封裝
封裝、繼承、多态是面向對象的三大特性,現在我們來說封裝, 封裝就是每個對象都包含他能進行操作所需要的所有資訊,把這些資訊包裝在類中,這樣就實作了封裝。
封裝有很多好處,第一、良好的封裝能夠減少耦合,第二、類内部的實作可以自由的修改。
類的封裝就好比一座房子,裡面擺放了精美的家具,如果沒有圍牆,那房子内的物品任何人都可以看或者改動,由于有了圍牆(封裝),房屋内的物品就不會被外人動了,但是如果沒有門窗,那麼房子就成了一個鐵盒子,就算裡面的東西再怎麼豪華,再怎麼精美,人不能住進去,也沒用。是以要有門窗,使主人能夠住進來。就像剛才的那個Person類,其中的name屬性是私有的,不能夠在類外通路,我們加了個getName()方法,是我們能夠通路到name 的值,這就是封裝對象暴露在外的屬性和方法。
五、繼承
繼承就是子類繼承父類 ,會繼承父類的非private的成員變量和成員方法,子類也能擁有屬于自及的成員變量和成員方法,并且能夠重寫父類的成員方法。
例如:人是一種總稱,但是人有分為中國人,美國人,德國人等,各個不同國家的人擁有相同的屬性,如姓名,性别,年齡等,那麼我們可以使各個國家人的類繼承人的類,人類中包括姓名、性别、年齡等一些共有屬性。而各個國家的人類中可以有一些輸入自己的一些行屬性等。
class Person {
public String name;
public int age;
public Person() {
this.name = "無名";
}
public Person(String name) {
this.name = name;
}
public void spaek() {
System.out.println("說話");
}
public void run () {
System.out.println("跑");
}
}
//繼承父類
class Chinese extends Person {
//構造方法,super()調用父類的方法
public Chinese(String name) {
super(name);
}
//子類特有的方法,中國人唱豫劇
public void sing() {
System.out.println("豫劇");
}
}
在上述代碼中,有Chinese子類繼承了Person父類,(需要說明的是,在子類中的構造方法,如果父類中有構造方法的重構,而父類中沒有無參數的構造方法的聲明,那麼在子類中的構造方法必須指定調用那個父類的構造方法,否則,将會出錯。)會擁有父類的所有成員和方法,而在子類中則增加類中國人特有的平劇。如果我們在main函數中new出Chinese的對象,那麼是可以調用父類的成員屬性和方法的。
如果之後我們想加入美國人、德國人等,隻需要建立相應的類,然後繼承Person類,同樣可以擁有name,age等屬性,以此,提高了代碼的可讀性、和複用性。
使用繼承是需要注意的是,兩事物A和B之間的關系必須是A包含B,那麼才能讓B繼承A。
六、多态
現在假設要舉行一場跑步運動會。各個國家的熱都要參加,要怎樣才能讓不同國家的人同時賽跑呢,那麼這就用到了多态,多态就是不同的對像可以執行相同的動作,就拿豫劇來說吧,有一位非常出名的老父親,演豫劇演的特别好,他兒子每天跟老父親學習,也學是非常像,有一天,老父親生病了,上不了台表演,他兒子可以替父親上台表演,因為他們表演的特别像,再因為在台上化了妝,觀衆根本認不出來。這就是多态的原理,聲明對像是聲明父類對象,new對象時new出子類對象。
class Person {
public String name;
public int age;
public Person() {
this.name = "無名";
}
public Person(String name) {
this.name = name;
}
public void spaek() {
System.out.println("說話");
}
public void run () {
System.out.println("跑");
}
}
class Chinese extends Person {
public Chinese(String name) {
super(name);
}
public void run(){
System.out.println("我是中國人"+this.name+",我參加運動會");
}
public void sing() {
System.out.println("豫劇");
}
}
public class RunSport {
public static void main(String[] args) {
Person chinese = new Chinese("小王"); //用父類指向子類對象。
chinese.run(); // 調用子類中重寫後的run方法 ,輸出 "我是中國人小王,我參加運動會"
}
}
使用多态時要注意 1.子類以父類的身份出現,2. 子類的工作方式以自己的工作方式實作;3. 子類以父類的身份出現時,子類特有的屬性和方法不可以使用(子類中重寫父類的方法可以使用);
下面,我們來運用多态來實作運動會。我們先來增加幾個國家:
//美國人
class American extends Person {
public American(String name) {
super(name);
}
public void run(){
System.out.println("我是美國人"+this.name+",我參加運動會");
}
}
//德國人
class German extends Person {
public German(String name) {
super(name);
}
public void run(){
System.out.println("我是德國人"+this.name+",我參加運動會");
}
}
俄羅斯人
class Russians extends Person {
public Russians(String name) {
super(name);
}
public void run(){
System.out.println("我是俄羅斯人"+this.name+",我參加運動會");
}
}
我們用Java中的容器來存儲參賽人員,來實作比賽。
public class RunSport {
public static void main(String[] args) {
ArrayList<Person> athletes = new ArrayList<Person>();
athletes.add (new Chinese("小王"));
athletes.add (new American("邁克"));
athletes.add (new German("約翰"));
athletes.add (new Russians("鮑裡斯"));
for (int i = ; i < athletes.size(); i++) {
athletes.get(i).run();
}
}
}
/* 運作結果
我是中國人小王,我參加運動會
我是美國人邁克,我參加運動會
我是德國人約翰,我參加運動會
我是俄羅斯人鮑裡斯,我參加運動會
*/
這就是不同的對象可以執行相同的動作,但要通過他們自己的代碼實作來執行。
七、抽象類
在上述代發中我們可以發現Person類根本不用執行個體化,那麼我們就可以把他設為抽象類,抽象類是不能執行個體化的。把需要重寫的方法設定為抽象方法。
abstract class Person {
public String name;
public int age;
public Person() {
this.name = "無名";
}
public Person(String name) {
this.name = name;
}
//普通方法,可以被繼承,也可被重寫
public void spaek() {
System.out.println("說話");
}
//抽象方法,在子類中必須重寫
public abstract void run ();
}
class Chinese extends Person {
public Chinese(String name) {
super(name);
}
//重寫父類的抽象方法,以自己的方式實作
public void run(){
System.out.println("我是中國人"+this.name+",我參加運動會");
}
}
抽象方法在使用時應該注意:
- 抽象類不能執行個體化
- 抽象方法是必須被子類重寫的方法
- 如果父類中擁有抽象方法,那麼父類必須被聲明稱抽象類
八、接口
根據上述例子,當一個國家或幾個國家的人擁有特别的功能時怎麼辦呢,有人會說再各自國家的子類中定義各自特殊的方法,但是那樣的話會使代碼變得雜亂,使用接口是讓使用者和其他開發人員更容易了解他人的代碼。
接下來我們以我們的國球為例,假設一個人會打乒乓球,那麼我們先要有一個打乒乓球的接口,聲明接口是需要注意,接口中不允許出現任何成員的執行方式,不能聲明無值得成員變量,若定義成員變量是賦初值,那麼這個成員變量會預設聲明為public static final 類型。
interface PingPong{
//聲明打乒乓球方法
public void play();
}
那麼在子類中就需要實作該方法
class Chinese extends Person implements PingPong{
public Chinese(String name) {
super(name);
}
public void run(){
System.out.println("我是中國人"+this.name+",我參加運動會");
}
public void sing() {
System.out.println("豫劇");
}
//實作接口中方法
public void play() {
System.out.println("打乒乓球");
}
}
有了這個接口,當在出先一個人會打乒乓球時,我們直接讓這個人繼承PingPong類就行了。
現在來說一下接口和抽象類的差別,抽象類可以給出一些成員變量的實作,而接口不能包含有實作,抽象類的抽象成員可被子類部分實作,接口的成員需要需要實作類完全實作。
參考文獻《大話設計模式》程傑著