定義解析
某一類事物的多種存在形態,
比如:人存在男人和女人兩種形態
動物存在貓、狗、豬、鴨、鵝等諸多形態。
- 多態的體現
父類的引用指向了自己的子類對象,父類的引用可以接受自己的子類對象
提高代碼的擴展性。 - 多態的前提
必須是類與類之間有關係,要麼繼承,要麼實現,
通常還有個前提,方法存在覆蓋 - 多態的好處
多態的出現,大大的提高了程序的擴展性。 - 多態的弊端
提高了擴展性,但是隻能使用父類引用訪問父類中的成員, - 多態的應用
可以直接調用父類已經定義的方法,但是實現的是自己重寫父類的方法。
若想使用子類自己特有的方法,則可以通過強制將父類的引用,轉成子類類型。比如:
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()));//哈希值的十六進制表達式
}
}