2020年12月9日星期三

Java基础之:OOP——多态

Java基础之:OOP——多态

多态(polymorphic)即多种形态,是程序基于封装和继承之后的另外一种应用。

首先我们先看一个案例,了解为什么要使用多态。

实现一个应用 : 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..........");// }}

 

结合实际案例理解编译类型与运行类型

  •   对于编译类型和运行类型,通过这样一个现实的例子来理解。
  •   大家都知道披着羊皮的狼,那可能也会有披着羊皮的人。
  •   那么这里的羊皮就是编译类型,羊皮是始终不变的,不管是谁披上它,它都是羊皮。
  •   而我们可以把编译器看成一个很"肤浅"的家伙,它只会看到表面的东西,所以如果在编译类型中没有的方法,不可以通过对象进行调用(即使在运行类型中确实存在此方法)。
  •   这里的狼和人就是运行类型,运行类型是可变的。(羊皮可能被任何东西给披上)
  •   相对于编译器而言JVM就显得有"内涵"一些了,运行类型就是在JVM运行程序时,对象实际的类型,所以运行类型可以调用在运行类型中有的方法。
  •   就好比,披着羊皮的狼,你以为它是吃草的,编译器也认为它是吃草的。但它实际上是吃肉的,JVM在运行时也认为它是吃肉的。

 

案例说明(向上转型与向下转型)

向上转型 语法:父类类型 父类对象 = new 子类类型();

  对于向上转型而言,就是将父类引用指向子类对象。

  向上转型可以通过改变运行类型的方式,通过一个父类引用访问多个子类对象。

    例如:

      Animal animal = new Dog();

      animal = new Cat();

向下转型 语法: 子类类型 子类对象 = (子类类型)父类对象;

  对于向下转型而言,就是将父类对象强制转换为子类对象。

  所以要做到向下转型,前提条件就是父类对象原本的运行类型就是子类类型。

    例如:

      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关键字

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{  }

 

Java的动态绑定机制

  1. 当调用对象方法的时候,该方法会和该对象的内存地址/运行类型绑定。

  1. 当调用对象属性时,没有动态绑定机制,哪里声明,哪里使用。

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的值。 }}

 

多态应用案例

应用实例:现有一个继承结构如下:要求创建五个年龄不等的Person1、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 "); } }

 

 









原文转载:http://www.shaoqun.com/a/497401.html

达方物流:https://www.ikjzd.com/w/2562

斑马物流:https://www.ikjzd.com/w/1316

cima是什么:https://www.ikjzd.com/w/1372


Java基础之:OOP——多态多态(polymorphic)即多种形态,是程序基于封装和继承之后的另外一种应用。首先我们先看一个案例,了解为什么要使用多态。实现一个应用:1.小范既是儿子也是父亲(多种形态),2.儿子用钱买糖,父亲卖报纸给商家赚钱packagepolymorphic_ClassTest;​publicclassPolyTest{​publicstaticvoidmain(Strin
环球b2b:环球b2b
好东东网:好东东网
中国多地公布今年前三季度多项外贸"成绩单":中国多地公布今年前三季度多项外贸"成绩单"
陕西华山自由行最新攻略:陕西华山自由行最新攻略
巴伐利亚庄园有学生票吗?河源巴伐利亚庄园学生门票多少钱?:巴伐利亚庄园有学生票吗?河源巴伐利亚庄园学生门票多少钱?

没有评论:

发表评论