进一步理解Java中的多态概念_java

多态性有两种:
1)编译时多态性
对于多个同名方法,如果在编译时能够确定执行同名方法中的哪一个,则称为编译时多态性.
2)运行时多态性
如果在编译时不能确定,只能在运行时才能确定执行多个同名方法中的哪一个,则称为运行时多态性.

方法覆盖表现出两种多态性,当对象获得本类实例时,为编译时多态性,否则为运行时多态性,例如:
XXXX x1 = new XXXX(参数列表); //对象获得本类实例,对象与其引用的实例类型一致
XXX xx1 = new XXX(参数列表);
x1.toString(); //编译时多态性,执行XXX类的方法.
xx1.toString(); //编译时多态性,执行XXXX类覆盖的方法.
XXXX为XXX的父类.
由于子类对象既是父类对象,父类对象与子类对象之间具有赋值相容性,父类对象能够被赋值为子类对象.例如,
XXXX x2 = new XXX(参数列表); //父类对象获得子类实例,子类对象即是父类对象
x2.toString(); //运行时多态
 
x2声明为父类对象却获得子类XXX的实例,那么x2.toString()究竟执行父类方法还是执行子类覆盖的方法呢?
这分为两种情况:
取决于子类是否覆盖父类方法.如果子类覆盖父类方法,则执行子类方法;
如果没有覆盖,则执行父类方法.
在编译时,仅仅依据对象所属的类,系统无法确定到底应该执行那个类的方法,只有运行时才能确定,因此这是运行时多态.
父类对象并不能执行所有的子类方法,只能执行那些父类中声明\子类覆盖的子类方法.

java多态实现
java的多态和c++一样,是通过动态绑定或者说运行时绑定来实现的。当调用某一个对象引用的方法时,因为编译器并不知道这个引用到底指向的是变量声明时说明的类型对象,还是该类型子类的对象。因此编译器无法为这次调用绑定到具体的某个方法。只有通过java中运行时类型识别(RTT)在运行时绑定到具体的方法

方法的重写overriding和方法的重载overloading是java多态的不同表现。重写overriding是父类和子类之间多态性的一种表现,重载overloading是一个类中多态性的表现。

给出一个具体例子:

  

 class People {
  public String toString() {
   return "I am a people!";
  } 

  public void eat() {
  }; 

  public void speak() {
  };
 } 

 class Boy extends People {
  public String toString() {
   return "I am a boy!";
  } 

  public void fight() {
  }; 

  public void speak() {
  };
 } 

 class Girl extends People {
  public String toString() {
   return "I am a girl!";
  } 

  public void sing() {
  }; 

  public void speak() {
  };
 } 

 public class TestToString {
  public static void main(String args[]) {
   People p = new Girl();
   System.out.println(p.toString());
  }
 }

运行结果是:

I am a girl!

p是People的一个引用,但是在运行时因为是Girl对象,所以还是调用了Girl的toString方法

深入理解java多态
声明,这里借鉴了其他同学的例子,原文链接:http://blog.csdn.net/thinkghoster/article/details/2307001

测试题目

 class A {
  public String show(D obj) {
   return "A and D";
  } 

  public String show(A obj) {
   return "A and A";
  }
 } 

 class B extends A {
  public String show(B obj) {
   return "B and B";
  } 

  public String show(A obj) {
   return "B and A";
  }
 } 

 class C extends B { 

 } 

 class D extends B { 

 } 

 public class Main {
  public static void main(String args[]) {
   A a1 = new A();
   A a2 = new B();
   B b = new B();
   C c = new C();
   D d = new D(); 

   System.out.println(a1.show(b)); // 1
   System.out.println(a1.show(c)); // 2
   System.out.println(a1.show(d)); // 3
   System.out.println(a2.show(b)); // 4
   System.out.println(a2.show(c)); // 5
   System.out.println(a2.show(d)); // 6
   System.out.println(b.show(b)); // 7
   System.out.println(b.show(c)); // 8
   System.out.println(b.show(d)); // 9
  }
 } 

答案

 A and A
 A and A
 A and D
 B and A
 B and A
 A and D
 B and B
 B and B
 A and D 

解析
我开始做这道题目,4、5、6、9全部做错了,原因就是没能很好的理解java的多态性,这里说明一下

首先,要深刻的理解重写和重载,重写不仅仅包括了函数名称相同,也包括参数类型和返回值类型

其次,深刻理解这句话“当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类重写的方法”

然后,我们在来分析一下这几道题目

问题:你认为B重写了父类A的show方法了吗?如果重写了,重写了几个?

答案:重写了,重写了一个,也就是public String show(A obj),为什么public String show(B obj)不算重写父类方法呢,很简单,因为参数类型不同

举例分析
看了上面的分析,我们也来分析两个例子:

一、a2.show(b):

a2是一个引用变量,类型为A,b是B的一个实例。首先,在类A中找show(B obj),没有找到。于是到A的超类中找,而A没有超类,因此转向了A.this((super)B),(super)B为A,因此在A中找到了show(A obj)的方法,但是由于a2引用的类B的一个对象,B重写了A的show(A obj)方法,因此最终锁定到类B的show(A obj),输出为“B and A”

二、a2.show(c):
a2是一个引用变量,类型为A,b是B的一个实例。首先,在类A中找show(C obj),没有找到。于是到A的超类中找,而A没有超类,因此转向了A.this((super)C),(super)C为B,到这里为止,这个a2.show(c)变成了a2.show(b)的问题,而a2.show(b)上面已经分析了是输出"B and A",因此这里也是输出“B and A”

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索java
多态
java多态的概念、java中多态的概念、java多态概念、java 多态理解、java中多态的理解,以便于您获取更多的相关知识。

时间: 2024-09-19 08:18:30

进一步理解Java中的多态概念_java的相关文章

深入理解Java中的字符串类型_java

1.Java内置对字符串的支持: 所谓的内置支持,即不用像C语言通过char指针实现字符串类型,并且Java的字符串编码是符合Unicode编码标准,这也意味着不用像C++那样通过使用string和wstring类实现与C语言兼容和Unicode标准.Java内部通过String类实现对字符串类型的支持.这意味着:我们可以直接对字符串常量调用和String对象同样的方法: //可以再"abc"上直接调用String对象的所有方法 int length="abc".l

10分钟带你理解Java中的弱引用_java

前言 本文尝试从What.Why.How这三个角度来探索Java中的弱引用,帮助大家理解Java中弱引用的定义.基本使用场景和使用方法. 一. What--什么是弱引用? Java中的弱引用具体指的是java.lang.ref.WeakReference<T>类,我们首先来看一下官方文档对它做的说明:      弱引用对象的存在不会阻止它所指向的对象被垃圾回收器回收.弱引用最常见的用途是实现规范映射(canonicalizing mappings,比如哈希表).      假设垃圾收集器在某个

全面理解java中的异常处理机制_java

一.java异常总结: 异常就是程序运行时出现不正常运行情况 1.异常由来: 通过java的类的形式对现实事物中问题的描述,并封住成了对象 其实就是java对不正常情况描述后的对象体现 2.对于问题的划分有两种:一种是严重的问题,一种是非严重的问题 对于严重的,java通过Error类来描述 对于Error一般不编写针对性的代码对其进行处理 对于非严重的,java通过Exception类来描述 对于Exception可以使用针对性的处理方式进行处理 3.常见的异常有:数组角标越界异常,空指针异常

深入理解java中的synchronized关键字_java

synchronized 关键字,代表这个方法加锁,相当于不管哪一个线程A每次运行到这个方法时,都要检查有没有其它正在用这个方法的线程B(或者C D等),有的话要等正在使用这个方法的线程B(或者C D)运行完这个方法后再运行此线程A,没有的话,直接运行它包括两种用法:synchronized 方法和 synchronized 块. 1. synchronized 方法:通过在方法声明中加入 synchronized关键字来声明 synchronized 方法.如: 复制代码 代码如下: publ

十分钟理解Java中的动态代理_java

若代理类在程序运行前就已经存在,那么这种代理方式被成为 静态代理 ,这种情况下的代理类通常都是我们在Java代码中定义的. 通常情况下, 静态代理中的代理类和委托类会实现同一接口或是派生自相同的父类. 一.概述1. 什么是代理我们大家都知道微商代理,简单地说就是代替厂家卖商品,厂家"委托"代理为其销售商品.关于微商代理,首先我们从他们那里买东西时通常不知道背后的厂家究竟是谁,也就是说,"委托者"对我们来说是不可见的;其次,微商代理主要以朋友圈的人为目标客户,这就相当

深入理解Java中的Lambda表达式_java

 Java 8 开始出现,带来一个全新特性:使用 Lambda 表达式 (JSR-335) 进行函数式编程.今天我们要讨论的是 Lambda 的其中一部分:虚拟扩展方法,也叫做公共辩护(defender)方法.该特性可以让你在接口定义中提供方法的默认实现.例如你可以为已有的接口(如 List 和 Map)声明一个方法定义,这样其他开发者就无需重新实现这些方法,有点像抽象类,但实际却是接口.当然,Java 8 理论上还是兼容已有的库. 虚拟扩展方法为 Java 带来了多重继承的特性,尽管该团队声称

由ArrayList来深入理解Java中的fail-fast机制_java

1. fail-fast简介"快速失败"也就是fail-fast,它是Java集合的一种错误检测机制.某个线程在对collection进行迭代时,不允许其他线程对该collection进行结构上的修改. 例如:假设存在两个线程(线程1.线程2),线程1通过Iterator在遍历集合A中的元素,在某个时候线程2修改了集合A的结构(是结构上面的修改,而不是简单的修改集合元素的内容),那么这个时候程序就会抛出 ConcurrentModificationException 异常,从而产生fa

理解java中的深复制和浅复制_java

 Java语言的一个优点就是取消了指针的概念,但也导致了许多程序员在编程中常常忽略了对象与引用的区别,本文会试图澄清这一概念.并且由于Java不能通过简单的赋值来解决对象复制的问题,在开发过程中,也常常要要应用clone()方法来复制对象.本文会让你了解什么是影子clone与深度clone,认识它们的区别.优点及缺点.       看到这个标题,是不是有点困惑:Java语言明确说明取消了指针,因为指针往往是在带来方便的同时也是导致代码不安全的根源,同时也会使程序的变得非常复杂难以理解,滥用指针写

深入理解java中i++和++i的区别_java

今天简单谈谈关于java的一个误区,相信很多刚开始学习java的朋友都会遇到这个问题,虽然问题很简单,但是经常容易搞混,说说java的i++和++i的区别. 先看一下代码: <span style="font-size:18px;">public class test { public static void main(String[] args) { int i = 0; for (int j = 0; j < 10; j++) { i=i++; } System.