Java面向對象特徵之三多態

定義解析

某一類事物的多種存在形態,
比如:人存在男人和女人兩種形態
動物存在貓、狗、豬、鴨、鵝等諸多形態。

  • 多態的體現
    父類的引用指向了自己的子類對象,父類的引用可以接受自己的子類對象
    提高代碼的擴展性。
  • 多態的前提
    必須是類與類之間有關係,要麼繼承,要麼實現,
    通常還有個前提,方法存在覆蓋
  • 多態的好處
    多態的出現,大大的提高了程序的擴展性。
  • 多態的弊端
    提高了擴展性,但是隻能使用父類引用訪問父類中的成員,
  • 多態的應用
    可以直接調用父類已經定義的方法,但是實現的是自己重寫父類的方法。
    若想使用子類自己特有的方法,則可以通過強制將父類的引用,轉成子類類型。比如:
    Student stu = new BaseStudent();//類型提升(向上轉型)。就好象 byte b =2; int x=b-》b就會提升int類型
    BaseStudent bstu = (BaseStudent)stu;//強制將父類引用轉成子類類型。

多態自始至終都是子類對象在做着變化(變成父親,去講自己的課,脫掉父親的僞裝去看電影)

abstract class Student{
    int age = 18;
	public abstract void study();
	public void sleep() {
		System.out.println("躺着睡");
	}
	public static void cry() {
		System.out.println("不用哄");
	}
}
//將對象調用變簡單了,找到這批對象的共同點,抽了出來。相當於叫一批學生學習和睡覺,而不是單獨的叫某個學生。
class DoStudent{
	public void doSome(Student stu) {
		stu.study();
		stu.sleep();
		if(stu instanceof BaseStudent) {//instanceof 用於判斷是否爲某個對象
			BaseStudent bstu = (BaseStudent)stu;
			bstu.play();
		}else if(stu instanceof AdvStudent) {
			AdvStudent astu = (AdvStudent)stu;
			astu.sing();
		}
	}
}
class BaseStudent extends Student{
    int age = 16;
	@Override
	public void study() {
		System.out.println("base study");
	}
	public void sleep() {
		System.out.println("坐着睡");
	}
	public void play() {
		System.out.println("打籃球");
	}
	public static void cry() {
		System.out.println("要糖哄");
	}
}
class AdvStudent extends Student{
	@Override
	public void study() {
		System.out.println("Adv study");
	}
	public void sleep() {
		System.out.println("撅着屁股睡");
	}
	public void sing() {
		System.out.println("唱歌");
	}
}
public class DuoTaiDemo2 {
	public static void main(String[] args) {
		DoStudent ds = new DoStudent();
		ds.doSome(new BaseStudent());//Student stu = new BaseStudent();
		ds.doSome(new AdvStudent());//Student stu1 = new AdvStudent();
	}
}

結果:

base study
坐着睡
打籃球
Adv study
撅着屁股睡
唱歌

  • 在多態中成員函數的特點:
  • 在編譯時期,參閱引用型變量所屬的的類中是否有調用的方法,如果有,編譯通過,如果沒有,編譯失敗.。
    比如:如果學生裏沒有play的方法,若不轉換成BaseStudent 的話,直接是stu.play()調用的話,編譯是無法通過的。

  • 在運行時,參閱對象所屬的類中是否有調用的方法。
    比如:所有的學生都有睡覺的方法,但是默認學生是躺着睡(父類),基礎班學生重寫了父類方法,變成坐睡。在運行時,直接stu.sleep()則會得出坐着睡。

Student stu = new BaseStudent();
stu.sleep();
  • 在多態中,成員變量的特點
  • 無論編譯和運行,都參考左邊(引用型變量所屬的類)
    比如:
    默認學生年齡是18歲,基礎班的學生年齡變成16歲,直接打印還是會打印父類的年齡。
Student stu = new BaseStudent();
System.out.println(stu.age);

靜態成員變量也是一樣。

  • 在多態中,靜態成員函數的特點
  • 無論編譯運行都參考左邊。因爲靜態不需要對象存在,父類引用還在,找的就是引用型的變量先加載。
    比如:默認學生哭都不用哄,但想調用基礎班要糖哄的哭,卻因爲靜態修飾調用不起來了,
Student stu = new BaseStudent();
stu.cry();

解釋:當cry()方法一進內存,就已經被綁定,綁定在方法所屬的類上,所屬於父。屬於靜態綁定, 對象是誰就是誰的是動態綁定。非靜態的時候。

Object類中equals方法

Object類是所有類的父類,當我們創建類時,其實默認是集成了Object類的。
Object 類中已經提供了對象是否相同的比較方法,equals方法,但是此方法只比較的對象是否相等,比較的是內存地址值。

        BaseStudent bstu = new BaseStudent();
		BaseStudent bstu2 = new BaseStudent();
		BaseStudent bstu3 = bstu;
		System.out.println(bstu.equals(bstu2));
		System.out.println(bstu==bstu2);
		System.out.println(bstu.equals(bstu3));
		System.out.println(bstu==bstu3);

結果

false
false
true
true

如果自定義中也有比較相同的功能,沒有必要重新定義,只要沿襲父類中的功能,建立自己特有比較內容即可,這就是覆蓋。

public boolean equals(Object obj) {//Object obj = new BaseStudent();
		if(!(obj instanceof BaseStudent)) {
			return false;
		}//或者拋出異常
		BaseStudent bstu =(BaseStudent)obj;
		return this.age ==bstu.age;//複寫比較自身要比較的地方,判斷和轉換的動作。這樣就是正常比較的是兩個對象的年齡,而不是對象的本身
	}
main
        BaseStudent bstu = new BaseStudent(16);
		BaseStudent bstu2 = new BaseStudent(16);
		BaseStudent bstu3 = bstu;
		System.out.println(bstu.equals(bstu2));
		System.out.println(bstu==bstu2);
		System.out.println(bstu.equals(bstu3));
		System.out.println(bstu==bstu3);

結果

true
false
true
true

Object類中toString方法

toString方法其實就是getClass().getName+’@’+Integer.toHexString(hashCode());
當沒有重寫這個方法時,打印出來的是:

com.hira.Per
com.hira.Per@2c13da15
2c13da15

當重寫這個方法,則打印

com.hira.Per
Per:4
2c13da15

package com.hira;
class Per{
	private int num = 4;
	Per(int num){
		this.num = num;
	}
	public String toString() {
		return "Per:"+num;
	}
}
public class Object_toString {
	public static void main(String[] args) {
		Per per = new Per(4);
		Class c = per.getClass();//返回類文件
		System.out.println(c.getName());//獲取類文件名字
	    System.out.println(per.toString());//toString=getClass().getName+'@'+Integer.toHexString(hashCode());
		System.out.println(Integer.toHexString(per.hashCode()));//哈希值的十六進制表達式

	}

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章