一、Java多态性

面向对象的三大特性:封装、继承、多态。

多态的类型,分为以下两种:

  • 编译时多态: 指的是 方法重载。编译时多态是在编译时确定调用处选择那个重载方法,所以也叫 静态多态,算不上真正的多态。所以,一般说的多态都是运行时的多态。
  • 运行时多态: 由于 方法重写,所以想要确定引用变量所调用的方法的入口,必须根据运行时的引用变量所指向的实例对象来确定。从而使得同一个引用变量调用同一个方法,但不同的实例对象表现出不同的行为。再简单点来说,就是在运行时,可以通过指向基类的指针,来调用实现子类中的方法。

下面讲的多态都是指 运行时的多态。

多态的定义: 指允许不同类的对象对同一消息做出不同的响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。(发送消息就是函数调用);

上面的定义参考了网上的说法,定义中的不同类,都是由同一个基类扩展而来。

多态的好处:

  • 可替换性(substitutability)。多态对已存在代码具有可替换性。例如,draw函数对圆Circle类工作,对其他任何圆形几何体,如圆环,也同样工作。
  • 可扩充性(extensibility)。多态对代码具有可扩充性。增加新的子类不影响已存在类的多态性、继承性,以及其他特性的运行和操作。实际上新加子类更容易获得多态功能。例如,在实现了圆锥、半圆锥以及半球体的多态基础上,很容易增添球体类的多态性。
  • 接口性(interface-ability)。多态是超类通过方法签名,向子类提供了一个共同接口,由子类来完善或者覆盖它而实现的。如图8.3 所示。图中超类Shape规定了两个实现多态的接口方法,computeArea()以及computeVolume()。子类,如Circle和Sphere为了实现多态,完善或者覆盖这两个接口方法。
  • 灵活性(flexibility)。它在应用中体现了灵活多样的操作,提高了使用效率。
  • 简化性(simplicity)。多态简化对应用软件的代码编写和修改过程,尤其在处理大量对象的运算和操作时,这个特点尤为突出和重要。

java的多态性三要素:

  1. 继承;
  2. 重写;
  3. 父类的引用指向子类的引用

多态性的实现: 依靠动态绑定

绑定: 将一个方法调用与方法主体关联起来。

前期绑定: 在程序执行前绑定,由编译器和链接程序完成,C语言的函数调用便是前期绑定。

动态绑定: 也称 后期绑定。在运行时,根据具体的对象类型进行方法调用绑定。除了static方法、final方法(private方法也是final方法),其他方法都是动态绑定;

二、方法重写 与 隐藏

方法重写: 就是子类中覆盖了从父类继承下来的方法(不是所有的父类方法都可以覆盖),从而使得通过父类的引用来调用重写后的方法。也就是说,父类类型与子类类型只保留重写后的方法。

隐藏: 覆盖是相对重写而言的。当子类中出现与父类相同的方法时,重写是子类与父类只保持一份,但方法隐藏则是子类与父类各自独立保持一份,也就两份。从父类继承下来的成员中,除了部分方法是可以重写外,其余成员都是隐藏,如变量、内部类、静态方法等。

注意: final方法既不能重写,也不能隐藏。

class ParentClass{
public int a = 5;
protected final String name = "parentClass"; public final void finalMethod() {//final方法,子类既不能重写,也不能隐藏
System.out.println("final方法");
} public static void monday() {//静态方法
System.out.println("父类ParentClass的monday()方法");
} public void count() {//可继承的成员方法
System.out.println("父类ParentClass的count()方法");
} class InnerClass{//内部类
public InnerClass() {
System.out.println("父类ParentClass的内部类");
}
}
} class ChildClass extends ParentClass{
public int a = 5;
protected final String name = "ChildClass"; /*//编译不通过
* public final void finalMethod() {
System.out.println("final方法");
}*/ public static void monday() {//静态方法
System.out.println("子类ChildClass的monday()方法");
} public void count() {//可继承的成员方法
System.out.println("子类ChildClass的count()方法");
} class InnerClass{//内部类
public InnerClass() {
System.out.println("子类ChildClass的内部类");
}
}
} public class MyTest {
public static void main(String[] args) {
ChildClass child = new ChildClass2();
ParentClass parent = child; //类型上转 System.out.println("---------------变量的隐藏测试-----------------");
child.a = 10;
System.out.println("parent.a: "+parent.a);
System.out.println("child.a: "+child.a); System.out.println("\n---------------静态方法的隐藏测试-----------------");
parent.monday();
child.monday(); System.out.println("\n---------------方法的重写测试-----------------");
parent.count();
child.count(); System.out.println("\n---------------内部类的隐藏测试-----------------");
ParentClass.InnerClass pa = parent.new InnerClass();
ChildClass.InnerClass ch = child.new InnerClass();
}
}

---------------变量的隐藏测试-----------------

parent.a: 5

child.a: 10

---------------静态方法的隐藏测试-----------------

父类ParentClass的monday()方法

子类ChildClass的monday()方法

---------------方法的重写测试-----------------

子类ChildClass的count()方法

子类ChildClass的count()方法

---------------内部类的隐藏测试-----------------

父类ParentClass的内部类

子类ChildClass的内部类

  上面的例子中,只有count()方法是被重写了,父类类型与子类类型只保持重写后的方法,而其他成员都是隐藏,父类类型保持一份,子类类型也保持一份。

方法重写的条件

  • 重写的方法是子类从父类继承下来的实例方法,不能是静态方法
  • 子类重写后的方法的 返回类型 必须是 原父类方法的返回类型的可替换类型
  • 子类重写后的方法的访问权限 不能比 原父类方法的访问权限低;
  • 子类重写后的方不能比父类方法抛出更多的异常;
  • 当重写泛型方法时,先进行类型擦除。再按照上面的4个小点,重写类型擦除后的方法;

可替换类型补充:

  • 对于返回类型是基本类型、void,重写方法的返回类型必须是一样;
  • 对于返回类型是引用类型,返回类型可替换成该类型的 子类型;

class ParentClass{//父类 public int count() {//
return 0;
} Object method() {
return "aa";
} <T extends ParentClass> T getValue(T t) {//泛型方法
System.out.println();
return t;
}
} class ChildClass extends ParentClass{//子类 public int count() {//重写count()方法,由于返回类型是基本类型,不能变,必须是一致
return 0;
} public String method() {//重写method():访问权限增大,返回类型是Object的子类String
return "aa";
} ChildClass getValue(ParentClass ch) {//重写泛型方法getValue()
return null;
}
}

  解析一下此例子中的泛型方法重写,父类中的泛型方法getValue()进行类型擦除后,是:

ParentClass getValue(ParentClass t){
return null;
}

所以,子类ChildClass的方法重写是合理的。

类与接口(五)java多态、方法重写、隐藏的更多相关文章

  1. Java学习笔记二十二:Java的方法重写

    Java的方法重写 一:什么是方法的重写: 如果子类对继承父类的方法不满意,是可以重写父类继承的方法的,当调用方法时会优先调用子类的方法. 语法规则 返回值类型.方法名.参数类型及个数都要与父类继承的 ...

  2. java的方法重写 ,多态和关键字 instanceof和final

    package cn.pen; /*final 是一个java的关键字,用于修饰局部变量.属性.方法.类,表示最终的意思. final修饰类表示最终类,无法被继承.public final class ...

  3. Java中方法重写和方法重载

     首先方法重写和方法重载是建立在Java的面向对象的继承和多态的特性基础上而出现的.至于面向对象的继承和多态的特性我就不在这里多说了.继承是指在一个父类的基础再创建一个子类,这样子类就拥有了父类的非私 ...

  4. 从虚拟机角度看Java多态->(重写override)的实现原理

    工具与环境:Windows 7 x64企业版Cygwin x64jdk1.8.0_162 openjdk-8u40-src-b25-10_feb_2015Vs2010 professional 0x0 ...

  5. 乐字节Java继承|方法重写、super和final关键字

    大家好,乐字节的小乐又来了,上一篇是:乐字节Java|JavaBean.继承与权限修饰,也是属于Java继承的,今天继续Java继承. 一. 方法的重写 父类不满足子类的要求,按需改写.注意 方法签名 ...

  6. 所有的Java虚拟机必须实现在每个类或接口被Java程序 “ 首次主动使用 ” 时才初始化他们

    原文:https://www.cnblogs.com/fanjie/p/6916784.html Java程序对类的使用方式可分为两种– 主动使用– 被动使用 被动使用以后再讲,这里说说什么是主动使用 ...

  7. Java基础——方法重写

    什么是方法重写? 子类中出现和父类中完全一样的方法声明 什么时候可以进行方法重写? 在子类需要父类的功能的同时,功能主体子类有自己的特有内容时,可以重写,一面沿袭了父类的功能一面又定义了子类特有的内容 ...

  8. Java 多态方法构造器执行方法

    我们参考下面这个例子: 读者可以提前考虑一下,这段程序的输出会是什么. public class Polymorphism { /** * 创建一个类A * 该类中有一个方法draw,以及一个构造方法 ...

  9. JAVA多态中的隐藏和覆盖

    Java的引用变量有两个类型,一个是编译时类型,一个是运行时类型 编译时类型:由声明该变量时使用的类型决定 运行时类型:由该变量指向的对象类型决定 如果编译时类型和运行时类型不一致,会出现所谓的多态. ...

  10. java的覆盖重写隐藏和C#中的不同

    先看下C#中的: C#中覆盖 隐藏 重写这三种有不同的意义,而Java中不同. 1. java中没有new ,使用new会报错,编译不通过. 2. java中重写和覆盖应该是一个意思 static c ...

随机推荐

  1. FactoryMethod工厂方法模式(创建型模式)

    1.工厂方法模式解决的问题 现在有一个抽象的游戏设施建造系统,负责构建一个现代风格和古典风格的房屋和道路. 前提:抽象变化较慢,实现变化较快(不稳定) 整个抽象的游戏设施建造系统相对变化较慢,本例中只 ...

  2. Entity framework 预热

    Entity framework  预热 对于在应用程序中定义的每个DbContext类型,在首次使用时,Entity Framework都会根据数据库中的信息在内存生成一个映射视图(mapping ...

  3. JVM 监控工具 jstack 和 jvisualvm 的使用

    Java线程状态 线程的五种状态 * 新建:new(时间很短) * 运行:runnable * 等待:waitting(无限期等待),timed waitting(限期等待) * 阻塞:blocked ...

  4. 全网最详细的HA集群的主节点之间的双active,双standby,active和standby之间切换的解决办法(图文详解)

    不多说,直接上干货! 1. HA集群的主节点之间的双standby的解决办法: 全网最详细的Hadoop HA集群启动后,两个namenode都是standby的解决办法(图文详解) 2. HA集群的 ...

  5. node爬虫gbk中文乱码问题

    刚入坑node 写第二个node爬虫时,遇到了这个坑,记录一下. 主要步骤: 1.安装iconv-lite 输入npm install iconv-lite 2.将接收到的网页源码以二进制的方式存储下 ...

  6. webkit技术内幕读书笔记 (一)

    本文部分摘录自互联网. Chromeium与Chrome Chromium是Google为发展自家的浏览器Google Chrome而打开的项目,所以Chromium相当于Google Chrome的 ...

  7. 谈谈AsmJit

    0x01  基本介绍 AsmJit是一个完整的JIT(just In Time, 运行时刻)的针对C++语言的汇编器,可以生成兼容x86和x64架构的原生代码,不仅支持整个x86/x64的指令集(包括 ...

  8. 【IT笔试面试题整理】二叉搜索树转换为双向链表

    [试题描述] 将二叉搜索树转换为双向链表 对于二叉搜索树,可以将其转换为双向链表,其中,节点的左子树指针在链表中指向前一个节点,右子树指针在链表中指向后一个节点. 思路一: 采用递归思想,对于二叉搜索 ...

  9. 制作openstack使用的Ubuntu镜像

    一.环境准备 OS:Ubuntu-14.04 制作镜像版本:Ubuntu-14.04.4-server-amd64.iso 查看是否支持虚拟化(有输出代表支持,否则在BIOS页面中设置即可): egr ...

  10. 【区块链Go语言实现】Part 1:区块链基本原型

    0x00 介绍 区块链(Blockchain)是21世纪最具革命性的技术之一,目前它仍处于逐渐成熟阶段,且其发展潜力尚未被完全意识到.从本质上讲,区块链只是一种记录的分布式数据库.但它之所以独特,是因 ...