多态(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 "); } }