多態(polymorphic)即多種形態,是程序基於封裝和繼承以後的另一種應用。java
首先咱們先看一個案例,瞭解爲何要使用多態。程序員
實現一個應用 : 1.小范既是兒子 也是 父親 (多種形態),2.兒子用錢買糖 , 父親賣報紙給商家賺錢數組
package polymorphic_ClassTest; public class PolyTest { public static void main(String[] args) { Father father = new Father("父親(小范)",40); Son son = new Son("兒子(小范)",20); Candy candy = new Candy("買糖果"); Newspaper newspaper = new Newspaper("賣報紙"); tarding(son,candy); //兒子買糖果 tarding(father,newspaper); //父親賣報紙 //經過多態引入,咱們也能夠體現 兒子賣報紙 , 父親買糖果 tarding(father,candy); tarding(son, newspaper); } //試想若是 父親也要買糖果,那麼就又須要重寫一個tarding方法..... //會有不少的組合方式,爲了避免重寫tarding方法。引入多態的概念 //使用之前的封裝+繼承方法實現: public static void tarding(Son son,Candy candy) { System.out.println(son.getName() + "買" + candy.getName()); } public static void tarding(Father father,Newspaper newspaper) { System.out.println(father.getName() + "賣" + newspaper.getName()); } //使用多態來實現: public static void tarding(Person person,Goods goods) { //實現原理: Son和Father繼承於Person類,Candy和Newspaper繼承於Goods類 System.out.println(person.getName() + " 交易 " + goods.getName()); } } class Person{ private String name; public Person(String name) { super(); this.name = name; } public Person() { super(); } public String getName() { return name; } public void setName(String name) { this.name = name; } } class Son extends Person{ private int age; public Son(String name, int age) { super(name); this.age = age; } } class Father extends Person{ private int age; public Father(String name, int age) { super(name); this.age = age; } } class Goods{ //商品 private String name; public Goods(String name) { super(); this.name = name; } public Goods() { super(); } public String getName() { return name; } public void setName(String name) { this.name = name; } } class Candy extends Goods{ public Candy(String name) { super(name); } } class Newspaper extends Goods{ public Newspaper(String name) { super(name); } }
public class PolyOverLoad { public static void main(String[] args) { //方法重載體現多態 T t = new T(); t.say(100); t.say("tom"); } } class T { public void say(String name) { System.out.println("hi " + name); } public void say(int num) { System.out.println("hello" + num); } } //======================================================= public class PolyOverride { public static void main(String[] args) { AA a = new AA(); a.hi("jack"); BB b = new BB(); b.hi("tom"); } } class AA { public void hi(String name) { System.out.println("AA " + name); } } class BB extends AA { @Override public void hi(String name) { //子類hi 重寫 父類的 hi System.out.println("BB " + name); } }
package polymorphic; public class PolyTest { public static void main(String[] args) { /* * 語法:父類名 對象 = new 子類構造器;(父類引用指向子類對象) * 此時animal實際存在兩種類型:1.編譯類型 ;2.運行類型 * 編譯類型:編譯器識別時的類型,即等號左邊的類型。這裏animal的編譯類型就是Animal * 在程序員編譯時,只能訪問編譯類型有的 方法和屬性 * 對於對象的編譯類型而言,是不變的。 * 運行類型:JVM運行時的類型,即等號右邊的類型。這裏animal的運行類型就是Dog * 對於對象的運行類型而言,是可變的。 */ //向上轉型 語法:父類類型 父類對象 = new 子類類型(); Animal animal = new Dog(); animal.eat(); // animal.run(); //報錯 :The method run() is undefined for the type Animal animal = new Cat();//改變了animal的運行類型,但編譯類型不變 animal.eat(); animal.show(); //1.首先尋找在Cat中的show 2.若沒有則向上尋找父類Animal的show //向下轉型 語法: 子類類型 子類對象 = (子類類型)父類對象 Cat cat = (Cat)animal;//這裏是建立了一個Cat引用,讓cat 指向 animal指向的那個堆地址空間 // Dog dog = (dog)animal;//要想這樣向下強行轉換類型,必須知足 animal堆空間中的類型就是cat cat.drink(); } } class Animal{ public void eat() { System.out.println("eat......"); } public void show() { System.out.println("show.........."); } } class Dog extends Animal{ @Override public void eat() { System.out.println("Dog eat......"); } public void run() { System.out.println("run........"); } } class Cat extends Animal{ @Override public void eat() { System.out.println("Cat eat......"); } public void drink() { System.out.println("drink........"); } // public void show() { // System.out.println("Cat show.........."); // } }
對於向上轉型而言,就是將父類引用指向子類對象。ide
向上轉型能夠經過改變運行類型的方式,經過一個父類引用訪問多個子類對象。this
例如:spa
Animal animal = new Dog();對象
animal = new Cat();blog
對於向下轉型而言,就是將父類對象強制轉換爲子類對象。繼承
因此要作到向下轉型,前提條件就是父類對象本來的運行類型就是子類類型。內存
例如:
Animal animal = new Dog();
Dog dog = (dog)animal;
但要注意的是,向下轉型是將一個子類引用Dog指向了原來在堆空間建立的那個Dog對象。
而animal一樣指向堆空間中的Dog對象,因此向下轉型以後 animal (父類引用)自己不受影響。
對於類型的屬性而言,沒有編譯類型與運行類型的說法。
即屬性只認編譯類型,經過多態聲明後,訪問屬性時,也只會返回編譯類型中的屬性對應的值。
public class PolyProperties { public static void main(String[] args) { Base base = new Base(); System.out.println(base.n); // 200 Base base2 = new Sub(); System.out.println(base2.n); // 屬性沒有重寫之說!屬性的值看編譯類型 } } class Base { public int n = 200; } class Sub extends Base { public int n = 300; }
instanceOf關鍵字用於比較 對象的類型 是不是指定類型或其子類
public class InstanceOfTest { public static void main(String[] args) { AA bb = new BB(); //instanceOf 比較操做符,用於判斷某個對象的運行類型是否爲XX類型或XX類型的子類型 System.out.println(bb instanceof BB); // T System.out.println(bb instanceof AA); // T System.out.println(bb instanceof Object); // T Object obj = new Object(); System.out.println(obj instanceof AA);// F } } class AA{ } class BB extends AA{ }
當調用對象方法的時候,該方法會和該對象的內存地址/運行類型綁定。
當調用對象屬性時,沒有動態綁定機制,哪裏聲明,哪裏使用。
class A { public int i = 10; public int sum() { return getI() + 10; } public int sum1() { return i + 10; } public int getI() { return i; } } class B extends A { public int i = 20; // public int sum() {//註銷? // return i + 20; //} public int getI() { return i; } // public int sum1() {//註銷? // return i + 10; // } } public class Test{ public static void main(String args[]){ A a = new B(); //不註銷 註銷 System.out.println(a.sum()); //40 =》 30 System.out.println(a.sum1()); //30 =》 20 //這裏要注意,getI()方法是動態綁定在B對象上的,因此在調用A類的sum()方法時,getI()仍然會返回B類中的I的值。 } }
應用實例:現有一個繼承結構以下:要求建立五個年齡不等的Person一、Student [2]和Teacher[2]對象。
調用子類特有的方法,好比Teacher 有一個 teach , Student 有一個 study怎麼調用
提示 : [實如今多態數組調用各個對象的方法]遍歷+instanceof + 向下轉型
package polymorphic_PolyArrays; public class PolyArrays { public static void main(String[] args) { Person[] persons = {new Person("jack", 10), new Student("tom",20, 78), new Student("king",21, 68) , new Teacher("老王", 50, 10000), new Teacher("老李", 45, 20000)}; Traverse(persons); } public static void Traverse(Person[] person) { for (int i = 0; i < person.length; i++) { if(person[i] instanceof Student) { // ((Student)person[i]).study(); //這種方式更好 Student stu = (Student)person[i]; stu.study(); }else if(person[i] instanceof Teacher) { // ((Teacher)person[i]).teach(); //這種方式更好 Teacher tea = (Teacher)person[i]; tea.teach(); }else { System.out.println(person[i].say()); } } } } class Person { private String name; private int age; public Person(String name, int age) { super(); this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String say() { return "信息 name= " + name + " age= " + age; } } class Student extends Person { private double score; public double getScore() { return score; } public void setScore(double score) { this.score = score; } public Student(String name, int age, double score) { super(name, age); this.score = score; } public void study() { System.out.println("學生 " + getName() + " is studying java..."); } } class Teacher extends Person { private double salary; public Teacher(String name, int age, double salary) { super(name, age); this.salary = salary; } public double getSalary() { return salary; } public void setSalary(double salary) { this.salary = salary; } public void teach() { System.out.println("老師 " + getName() + " is teaching java "); } }