java多态的实现机制(Java多中包括态理解)

文章目录
  • (1)重写(override)(2)向上转型和向下转型B:向下转型(基本不用)
  • 三:静态绑定与动态绑定
  • 四:不要在构造方法中调用重写的方法
一:对于多态的理解多态:面向对象方法学中多态是指子类对象可以像父类对象那样使用,同样的消息既可以发送给父类对象也可以发送给子类对象。即在类等级的不同层次中可以共享一个方法的名字, 不同层次中的每个类各自按自己的需要来实现这个行为。通俗点理解就是指完成某个行为时,不同对象有着不同的完成方法

比如买票行为,学生和普通人都属于人,但是学生买票可以半价,而普通人是全票

java多态的实现机制(Java多中包括态理解)(1)

二:Java多态实现Java多态实现:和C 类似,在Java中要实现多态,必须满足以下条件
  • 继承是多态的前提, 没有继承就没有多态
  • 子类要对父类的方法完成 重写
  • 需要通过 父类的引用 调用重写的方法
(1)重写(override)重写(override):也即覆盖,是子类对父类的非静态、非private修饰、非final修饰和非构造方法等的实现过程进行重新编写,返回值和形参都不能改变A:重写规则重写规则:
  • 子类重写父类时 与父类方法原型保持一致 ,也即 修饰符 返回值类型 方法名(参数列表) 需要完全一致(注意:JDK7以后,被重写的方法返回值类型可以不同,但是必须是 具有父子关系的 ,这称之为 协变
  • 访问权限不能比父类中被重写的方法的访问权限更低 :例如,如果父类方法被 public 修饰,那么子类中重写该方法时不可以被声明为 protected
  • 父类被 static 、 private 、 final 所修饰以及构造方法都不能被重写
  • 重写的方法可以使用 @Override 注解来显式指定。 此注解可以帮助我们进行一些合法性检验

<pre class="prettyprint hljs java" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">class Animal{ String name; int age; public Animal(String name, int age){ this.name = name; this.age = age; } public void eating(){ System.out.println(name "吃饭"); } } class Dog extends Animal{ public Dog(String name, int age){ super(name, age); } @Override //重写父类 public void eating(){ System.out.println(name "吃鱼"); } } class Cat extends Animal{ public Cat(String name, int age){ super(name, age); } @Override//重写父类 public void eating(){ System.out.println(name "啃骨头"); } }</pre>

B:重写和重载的区别
  • 方法重载 :是类的多态性表现
  • 方法重写 :是子类与父类的一种多态性表现

java多态的实现机制(Java多中包括态理解)(2)

java多态的实现机制(Java多中包括态理解)(3)

(2)向上转型和向下转型A:向上转型向上转型:使用父类的引用指向子类对象,语法格式为:父类类型 对象名 = new 子类类型()
  • 向上转型 是合理、安全的 ,因为 大范围可以囊括小范围
  • 优点 :让代码实现更为简单、灵活
  • 缺点 :不能调用子类特有的方法

<pre class="prettyprint hljs java" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">class Animal{ String name; int age; public Animal(String name, int age){ this.name = name; this.age = age; } public void eating(){ System.out.println(name "吃饭"); } } class Dog extends Animal{ public Dog(String name, int age){ super(name, age); } @Override //重写父类 public void eating(){ System.out.println(name "啃骨头"); } } class Cat extends Animal{ public Cat(String name, int age){ super(name, age); } @Override//重写父类 public void eating(){ System.out.println(name "吃小鱼"); } } public class TestDemo { public static void main(String[] args) { Animal animal = new Dog("旺财", 3);//向上转型 } }</pre>

向上转型一般会有用于以下场景
  • **直接赋值 **:上面代码已经说过
  • **方法传参 **:形参为父类引用,可以 接受任意子类对象
  • **方法返回 **:返回值为父类引用,此时可以 返回任意子类对象

<pre class="prettyprint hljs java" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">class Animal{ String name; int age; public Animal(String name, int age){ this.name = name; this.age = age; } public void eating(){ System.out.println(name "吃饭"); } } class Dog extends Animal{ public Dog(String name, int age){ super(name, age); } @Override //重写父类 public void eating(){ System.out.println(name "啃骨头"); } } class Cat extends Animal{ public Cat(String name, int age){ super(name, age); } @Override//重写父类 public void eating(){ System.out.println(name "吃小鱼"); } } public class TestDemo { //形参为父类引用,可以接受任意子类对象 public static void eatFood(Animal animal){ animal.eating(); } public static void main(String[] args) { Cat cat = new Cat("喵喵", 3); eatFood(cat); } }</pre>

java多态的实现机制(Java多中包括态理解)(4)

<pre class="prettyprint hljs java" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">class Animal{ String name; int age; public Animal(String name, int age){ this.name = name; this.age = age; } public void eating(){ System.out.println(name "吃饭"); } } class Dog extends Animal{ public Dog(String name, int age){ super(name, age); } @Override //重写父类 public void eating(){ System.out.println(name "啃骨头"); } } class Cat extends Animal{ public Cat(String name, int age){ super(name, age); } @Override//重写父类 public void eating(){ System.out.println(name "吃小鱼"); } } public class TestDemo { //方法返回值为父类引用,此时可以返回任意子类对象 public static Animal buyAnAnimal(String animal_name){ if(animal_name.equals("狗")) { return new Dog("旺财", 2); } else if(animal_name.equals("猫")) { return new Cat("喵喵", 3); } else{ return null; } } public static void main(String[] args) { System.out.println("进入宠物店:请问你需要什么动物"); Scanner sc = new Scanner(System.in); String animal_name = sc.nextLine(); Animal animal = buyAnAnimal(animal_name); System.out.println("你得到了:" animal.name); sc.close(); } }</pre>

java多态的实现机制(Java多中包括态理解)(5)

B:向下转型(基本不用)向下转型:使用子类的引用指向父类对象,但是向下转型很不安全,所以基本不会使用

如下是向上转型, Animal animal = new Dog("旺财", 2) ,所以 animal 是无法调用 Dog 的特有方法 dog_method() 的

<pre class="prettyprint hljs java" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">class Animal{ String name; int age; public Animal(String name, int age){ this.name = name; this.age = age; } public void eating(){ System.out.println(name "吃饭"); } } class Dog extends Animal{ public Dog(String name, int age){ super(name, age); } @Override //重写父类 public void eating(){ System.out.println(name "啃骨头"); } public void dog_method(){ System.out.println(name "的特有方法"); } } class Cat extends Animal{ public Cat(String name, int age){ super(name, age); } @Override//重写父类 public void eating(){ System.out.println(name "吃小鱼"); } } public class TestDemo { public static void function(Animal animal){ animal.eating(); } public static void main(String[] args) { Animal animal = new Dog("旺财", 2); animal.dog_mehtod(); } }</pre>

java多态的实现机制(Java多中包括态理解)(6)

但是我们可以向下转型,也即 让一个子类的引用指向强转后的父类对象 ,此时便可以调用 Dog 的特有方法 dog_method() 了

<pre class="prettyprint hljs java" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">public class TestDemo { public static void function(Animal animal){ animal.eating(); } public static void main(String[] args) { Animal animal = new Dog("旺财", 2); Dog dog = (Dog)animal;//向下转型 dog.dog_method(); } }</pre>

java多态的实现机制(Java多中包括态理解)(7)

向下转型很不安全,而且有时会有严重的歧义。 Java中为 了提高向下转型的安全性,引入了 instanceof ,如果该表达式为 true ,则可以安全转换

(3)实现多态

讲到这里,其实已经完成了多态,所以日后我们就可以利用继承和转型来完成 传哪个对象就调用哪个对象的方法的目的

<pre class="prettyprint hljs java" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">class Animal{ String name; int age; public Animal(String name, int age){ this.name = name; this.age = age; } public void eating(){ System.out.println(name "吃饭"); } } class Dog extends Animal{ public Dog(String name, int age){ super(name, age); } @Override //重写父类 public void eating(){ System.out.println(name "啃骨头"); } } class Cat extends Animal{ public Cat(String name, int age){ super(name, age); } @Override//重写父类 public void eating(){ System.out.println(name "吃小鱼"); } } public class TestDemo { public static void function(Animal animal){ animal.eating(); } public static void main(String[] args) { Dog dog = new Dog("旺财", 2); Cat cat = new Cat("喵喵", 3); function(dog); function(cat); } }</pre>

java多态的实现机制(Java多中包括态理解)(8)

三:静态绑定与动态绑定
  • **静态绑定 **:也称为 早绑定 ,是指 在编译时根据用户所传递实参类型确定所调用的方法 ,最典型的例子就是 方法重载
  • **动态绑定 **:也称为 晚绑定 ,是指 在编译时不能确定该调用的方法,需要在程序运行确定 ,最典型的例子就是 多态 ,在程序运行时才能拿到具体的类型
四:不要在构造方法中调用重写的方法

下面的代码中,B继承自A, func 方法被重写。在构造B对象时会调用A的构造方法,在A的构造方法中调用了 func 方法,但此时是B对象,所以会调用到B的 func ,而B对象而没有完成构造,所以 num 处于未被初始化状态,为0

<pre class="prettyprint hljs java" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">class A{ public A(){ func(); } public void func(){ System.out.println("A的func()方法"); } } class B extends A{ private int num = 1; @Override public void func(){ System.out.println("B的func()方法,num=" num); } } public class TestDemo{ public static void main(String[] args) { B b = new B(); b.func(); } }</pre>

java多态的实现机制(Java多中包括态理解)(9)

五:抽象类(1)一个例子

如下一个类 Shape ,其中有一个方法 draw ,作用是向屏幕打印某个具体的图形(没有具体实现),图形有很多种,这里给出了 Rectangle 、 Triangle 和 Circle 三个类,分别用于描述矩形、三角形和圆形,它们各自内部也有一个方法 draw ,重写了父类的方法,形成多态

<pre class="prettyprint hljs scala" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">class Shape{ public void draw(){ System.out.println("画一个图形"); } } class Rectangle extends Shape{ @Override public void draw(){ System.out.println("画一个矩形"); } } class Triangle extends Shape{ @Override public void draw(){ System.out.println("画一个三角形"); } } class Circle extends Shape{ @Override public void draw(){ System.out.println("画一个三角形"); } } public class TestDemo { public static void drawing(Shape input){ input.draw(); } public static void main(String[] args) { Circle circle = new Circle(); drawing(circle); } }</pre>

java多态的实现机制(Java多中包括态理解)(10)

对于父类的方法,它的实现是没有意义的, 因为“画一个图形”这样的话太过抽象 ,无法具体去描述。 所以,我们可以不用实现它,将其改造为抽象方法,需要在方法返回值前加入关键字 abstract ,当某个类拥有抽象方法后它就变成了抽象类,也需要在其前面加入关键字 abstract 进行修饰

  • 注意
  • 注意:抽象方法就是C 中的纯虚函数

java多态的实现机制(Java多中包括态理解)(11)

<pre class="prettyprint hljs scala" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">abstract class Shape{ abstract public void draw();//抽象方法 } class Rectangle extends Shape{ @Override public void draw(){ System.out.println("画一个矩形"); } } class Triangle extends Shape{ @Override public void draw(){ System.out.println("画一个三角形"); } } class Circle extends Shape{ @Override public void draw(){ System.out.println("画一个三角形"); } } public class TestDemo { public static void drawing(Shape input){ input.draw(); } public static void main(String[] args) { Circle circle = new Circle(); drawing(circle); } }</pre>

(2)抽象类概念抽象类:在面向对象方法学中,所有对象都是需要通过类来描绘的,但这不意味着所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就应该设计为抽象类
  • 例如上例中 Shape 类中也存在 draw 方法,但是 Shape 它并代表某个具体图形,是没有办法来实现的

java多态的实现机制(Java多中包括态理解)(12)

(3)抽象类语法及特性抽象类语法:在Java中,如果一个类被abstract修饰,就称它为抽象类,抽象类中被abstract修饰的方法称之为抽象方法,注意以下几点①:抽象类无法进行实例化

java多态的实现机制(Java多中包括态理解)(13)

②:抽象方法 不能是private的

java多态的实现机制(Java多中包括态理解)(14)

③:抽象类存在的意义是为了被继承,它所体现的是接口继承。也就是说我只需要你存在这样一个方法名,你的实现我是不关心的④:抽象必须被继承,并且继承后子类要重写父类中的抽象方法,否则子类也将会是抽象类

java多态的实现机制(Java多中包括态理解)(15)

⑤:抽象方法 不能被 final 和 static 修饰

,

免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com

    分享
    投诉
    首页