本次只是围绕着多态性的概念来进行讲解,但是所讲解的代码与实际的开发几乎没有关系,而且多态一定是在继承性的基础上才可以操作的,
        而本次将使用类继承的关系来描述多态的性质,实际的开发中不会出现普通类的继承关系(一个已经完善的类不应该再被继承),开发中都要求继承抽象类和接口       
        多态性要想实现有两个前提:继承,覆写       
        范例:引出代码

class A {
public void print(){
System.out.println("hello");
}
}
class B extends A{
public void print(){
System.out.println("你好!");
}
}
public class polymorphism{
public static void main(String args[]){
B b = new B();
b.print();
}
}

覆写调用的前提:看new 的是那个类的对象,而后看方法是否被子类所覆写
        在java中多态性主要由两个方面组成:
            方法的多态性:
                方法重载:方法调用时根据不同的参数个数及类型可以实现不同的功能
                方法覆写:不同的子类针对于同样的一个方法可以有不同的实现
            对象的多态性:父类与子类对象间的转换操作;发生在继承关系之中
                【自动】对象的向上转型:子类对象变为父类对象  父类 父类对象 = 子类实例,自动完成的
                【强制】对象的向下转型;父类对象变为子类对象  子类 子类对象 = (子类)父类实例,强制转换
            除了转型之外,还有一些操作是不转型的,例如:String

对象多态性基础实现
        观察一道程序      
        范例:

class Member{
public String getInfo(){
return "Member:我是一个会员";
}
}
class VIPMember extends Member{ // 产生继承
public String getInfo(){
return "VIPMember:我是一个贵宾会员";
}
}
public class polymorphism{
public static void main(String args[]){
VIPMember mam = new VIPMember();
System.out.println(mem.getInfo());
}
}

方法覆写观察:
                观察现在 new 的是那个子类
                观察这个子类调用的方法是否被覆写,如果被覆写了则调用的就是被覆写过的方法
        
        范例:对象的向上转型

class A {
public void print(){
System.out.println("hello");
}
}
class B extends A{
public void print(){
System.out.println("你好!");
}
}
public class polymorphism{
public static void main(String args[]){
A a = new B(); // 向上转型
a.print();
}
}           

可以发现向上转型是自动完成的,除了向上转型之外,也可以实现对象的向下转型操作
向上转型最大的特点在于:所有的子类对象按照统一的父类类型进行接收,但是由于实例化子类的不同,有可能同一个父类的方法会有不同的调用实现
为了更好的理解对象的向上转型问题就做一个简单的分析:要求设计一个方法,这个方法可以接收用户的参数信息
        如果这个时候采用原始的技术:方法重载
        
        范例:

class Member{
public String getInfo(){
return "Member:我是一个会员";
}
}
class VIPMember extends Member{ // 产生继承
public String getInfo(){
return "VIPMember:我是一个贵宾会员";
}
}
class CIPMember extends Member{ // 产生继承
public String getInfo(){
return "CIPMember:我是一个商务会员";
}
}
public class polymorphism{
public static void main(String args[]){
income(new Member());
income(new VIPMember());
income(new CIPMember());
}
public static void income(Member mem){
System.out.println(mem.getInfo());
}
public static void income(VIPMember mem){
System.out.println(mem.getInfo());
}
public static void income(CIPMember mem){
System.out.println(mem.getInfo());
}
}

缺点:
                如果突然有一天你的用户类型分为了十万种,那么就需要有十万个 Member 子类,这个方法会重载十万次
                所有的方法体执行的功能都一样,那么这样是一个明显重复
            当子类众多又需要考虑参数统一的时候,按恶魔最好用的做法就是进行对象的向上转型(自动,调用被覆写过的方法)

class Member{
public String getInfo(){
return "Member:我是一个会员";
}
}
class VIPMember extends Member{ // 产生继承
public String getInfo(){
return "VIPMember:我是一个贵宾会员";
}
}
class CIPMember extends Member{ // 产生继承
public String getInfo(){
return "CIPMember:我是一个商务会员";
}
}
public class polymorphism{
public static void main(String args[]){
income(new Member());
income(new VIPMember());
income(new CIPMember());
}
public static void income(Member mem){
System.out.println(mem.getInfo());
} }           

发现利用对象的向上转型可以有效的实现参数的统一处理。这一点在程序中至关重要
        
对象向下转型

        范例:对象的向下转型

class A {
public void print(){
System.out.println("hello");
}
}
class B extends A{
public void print(){
System.out.println("你好!");
}
}
public class polymorphism{
public static void main(String args[]){
A a = new B(); // 向上转型
B b = (B)a; // 向下转型
b.print();
}
}           

具体的转型的概念没有什么难理解,那么程序的执行结果也很好理解,但是这样做有什么意义呢?
        
        分析:向上转型的意义
            现在要求定义一个 fun()方法,这个方法要求可以接收A以及A类所有子类的实例化对象
            于是根据这样的描述可以有两种实现方案
                方案一:使用方法重载的概念来完成

class A {
public void print(){
System.out.println("hello");
}
}
class B extends A{
public void print(){
System.out.println("你好!");
}
}
class C extends A{
public void print(){
System.out.println("不好!");
}
}
public class polymorphism{
public static void main(String args[]){
fun(new A());
fun(new B());
fun(new C());
}
public static void fun(A a){
a.print();
}
public static void fun(B b){
b.print();
}
public static void fun(C c){
c.print();
}
}
/*
结果:
Hello
你好!
不好
*/                

如果说这个时候A类有3000W个子类,并且这个子类还在以倍数的方式增长
                那么就表示:在设计之初此方法就需要重载3000W次,并且随着子类的追加,此方法继续重载,继续不断的修改类,于是你就疯了......
                
                方案二:发现所有的子类调用的方法实际上都只是println()一个,那么现在可以利用对象自动向上转型的概念就直接使用A类接收

class A {
public void print(){
System.out.println("hello");
}
}
class B extends A{
public void print(){
System.out.println("你好!");
}
}
class C extends A{
public void print(){
System.out.println("不好!");
}
}
public class polymorphism{
public static void main(String args[]){
fun(new A());
fun(new B());
fun(new C());
}
public static void fun(A a){
a.print();
}
}
/*
结果:
Hello
你好!
不好
*/

所以对象的向上转型给开发者最大的帮助在于其数据操作的统一性上
        
        分析:向下转型的意义
        范例:观察问题

class A {
public void print(){
System.out.println("hello");
}
}
class B extends A{
public void print(){
System.out.println("你好!");
}
public void funB(){ // 子类自己扩充的新方法
System.out.println("********************");
}
}
public class polymorphism{
public static void main(String args[]){
A a = new B(); // 向上转型
a.print();
a.funB();// 不能够调用
}
}
//结果:出错           

一旦发生了向上转型之后,父类对象是不可能调用子类中新建的方法的,只能够调用父类自己本身所定义的方法名称,也就是说向上转型之后牺牲的是子类的个性化特征
        但是如果说现在要想调用子类定义的特殊方法,那么就必须采用向下转型

class A {
public void print(){
System.out.println("hello");
}
}
class B extends A{
public void print(){
System.out.println("你好!");
}
public void funB(){ // 子类自己扩充的新方法
System.out.println("********************");
}
}
public class polymorphism{
public static void main(String args[]){
A a = new B(); // 向上转型 (把A改为B??)
a.print();
B b = (B)a;
b.funB();
}
}
/*
结果:
你好!
******************
*/

解释:为什么现在你的代码里面需要先向上转型,在进行向下转型,啰嗦

class A {
public void print(){
System.out.println("hello");
}
}
class B extends A{
public void print(){
System.out.println("你好!");
}
public void funB(){ // 子类自己扩充的新方法
System.out.println("********************");
}
}
class C extends A{
public void print(){
System.out.println("不好!");
}
public void funC(){ // 子类自己扩充的新方法
System.out.println("###################");
}
}
public class polymorphism{
public static void main(String args[]){
fun(new B());
fun(new C());
}
public static void fun(A a){
a.print()
// 由于某种特殊需求必须调用B类中的funB()方法,所以要进行向下转型
B b = (B)a;
b.funB();
}
}
/*
结果:
你好!
不好
*/

现在如果使用了向下转型,那么在之前好不容易建立起来的参数统一的局面就被打破了,所以这样的操作就属于不合理的操作形式
        但是转型的意义却可以更加明确了:为了调用子类自己的特殊支持
        
        但是在进行对象向下转型前也需要有一个注意点:
        范例:错误的向下转型

class A {
public void print(){
System.out.println("hello");
}
}
class B extends A{
public void print(){
System.out.println("你好!");
}
public void funB(){ // 子类自己扩充的新方法
System.out.println("********************");
}
}
public class polymorphism{
public static void main(String args[]){
A a == new A(); // 父类对象
B b = (B)a;// 强制转换
b.print()
}
}
//结果:出错           

此时出现了“java.langClassException”异常信息,,表示的是类转换异常,本质指的是两个没有关系的类对象发生了强制转换所带来的问题
        所以要想进行向下转型操作之前一定要首先保证发生了向上转型,这样才可以建立父子对象的关系
        但是可以发现这样的转型本身是会存在有安全隐患的,所以正在java中提供有一个关键字:instanceof,利用此关键字可以判断某一个对象是否是指定类的实例
            对象 instanceof 类  返回boolean类型
        范例:观察instanceof关键字的使用

class A {
public void print(){
System.out.println("hello");
}
}
class B extends A{
public void print(){
System.out.println("你好!");
}
public void funB(){ // 子类自己扩充的新方法
System.out.println("********************");
}
}
public class polymorphism{
public static void main(String args[]){
A a == new A(); // 父类对象
System.out.println(a instanceof A);
System.out.println(a instanceof B);
//B b = (B)a;// 强制转换
//b.print()
}
}
/*
结果:
true
false
*/           

范例:如果发生了向上转型之后的判断

class A {
public void print(){
System.out.println("hello");
}
}
class B extends A{
public void print(){
System.out.println("你好!");
}
public void funB(){ // 子类自己扩充的新方法
System.out.println("********************");
}
}
public class polymorphism{
public static void main(String args[]){
A a == new B(); // 父类对象
System.out.println(a instanceof A);
System.out.println(a instanceof B);
//B b = (B)a;// 强制转换
//b.print()
}
}
/*
结果:
true
true
*/

范例:利用 instanceof 保证转型的正确性

class A {
public void print(){
System.out.println("hello");
}
}
class B extends A{
public void print(){
System.out.println("你好!");
}
public void funB(){ // 子类自己扩充的新方法
System.out.println("********************");
}
}
public class polymorphism{
public static void main(String args[]){
A a == new B(); // 父类对象
System.out.println(a instanceof A);
System.out.println(a instanceof B);
if(a instanceof B){
B b = (B)a;// 强制转换
b.print()
}
}
}
/*
结果:
true
true
你好
*/

总结
        向上转型(90%):为了实现参数类型的统一,但是向上转型一定要与方法覆写产生关联
        向上转型(1%):为了调用子类特殊的方法实现,但是向下转型前必须要首先发生向上转型,会存在操作的安全性隐患,可以使用 instanceof 进行判断,但是不推荐这样使用
        不转型(9%):为了方便操作直接使用系统类或者是一些功能类,例如String 简单java类

菜鸡的Java笔记 第二十二 - java 对象多态性的更多相关文章

  1. 菜鸡的Java笔记 第二十八 - java 包的定义

    包的主要作用以及定义    包的导入操作    系统常见的开发包    jar 程序命令        包的定义        在任何的操作系统之中都有一个统一的共识:同一个目录下不能够存在有相同的文 ...

  2. 菜鸡的Java笔记 第二十九 - java 单例设计模式

    SingleCase 单例设计模式        1.单例设计模式的特点        2.多例设计模式的特点    内容    单例设计模式        现在如果说有这么一个程序类 class S ...

  3. 菜鸡的Java笔记 第二十六 - java 内部类

    /*    innerClass        从实际的开发来看,真正写到内部类的时候是在很久以后了,短期内如果是自己编写代码,几乎是见不到内部类出现的        讲解它的目的第一个是为了解释概念 ...

  4. 菜鸡的Java笔记 第二十四 - java 接口的基本定义

    1.接口的基本定义以及使用形式        2.与接口有关的设计模式的初步认识        3.接口与抽象类的区别                 接口与抽象类相比,接口的使用几率是最高的,所有的 ...

  5. 菜鸡的Java笔记 第十二 - java 构造方法与匿名对象

    1.点    构造方法的作用以及定义要求    匿名对象的使用    构造方法:        只要出现()的都表示方法        构造方法就是类构造对象时调用的方法,主要用来实例化对象.> ...

  6. “全栈2019”Java多线程第二十二章:饥饿线程(Starvation)详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  7. “全栈2019”Java异常第二十二章:try-with-resources语句详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java异 ...

  8. 菜鸡的Java笔记 第二十五 wrapperClass 包装类

    wrapperClass 包装类         1.包装类的特点        2.装箱与拆箱操作        3.数据转型处理            内容        Object 类可以接收 ...

  9. 菜鸡的Java笔记 第二十 - java 方法的覆写

    1.方法的覆写    当子类定义了与父类中的完全一样的方法时(方法名称,参数类型以及个数,返回值类型)这样的操作就称为方法的覆写    范例:观察方法的覆写 class A{ public void ...

随机推荐

  1. Docker安装ElasticSearch5.6.8

    前言 因实验室项目需要,准备docker安装个ES , 使用TransportClient练练手,然后死活连接不上 环境准备 系统:centos7 软件:docker ElasticSearch版本: ...

  2. Go语言核心36讲(Go语言基础知识一)--学习笔记

    01 | 工作区和GOPATH 从 Go 1.5 版本的自举(即用 Go 语言编写程序来实现 Go 语言自身),到 Go 1.7 版本的极速 GC(也称垃圾回收器),再到 2018 年 2 月发布的 ...

  3. 从零入门 Serverless | 企业级 CI/CD 工具部署 Serverless 应用的落地实践

    背景知识 通过以往几节课程的学习,相信大家对于 SAE 平台已经有了一定的了解.SAE 为客户免除了很多复杂的运维工作,开箱即用.按用量付费:与此同时 SAE 提供了丰富的 Open API,可以很容 ...

  4. SpringBoot配置文件application

    配置文件 SpringBoot使用一个全局的配置文件 , 配置文件名称是固定的,有两种文件格式: application.properties 语法结构 :key=value application. ...

  5. k8s学习笔记(2)- Rancher2.x部署springboot应用及高可用、扩容

    前言:上一篇介绍基于k3s环境,使用kubectl部署springboot简单项目应用,本篇介绍基于rancher2.x部署应用程序 1.上篇已部署一个springboot应用,我们可以通过ranch ...

  6. MC-BE基岩版服务器搭建与日常维护

    有部分内容被csdn和谐,强烈建议移步我的个人博客以获得更好的排版和阅读体验: xzajyjs.cn. 目录 环境搭建 开始部署 日常维护 服务器的白名单机制 定时备份 服务器升级 服务器模组安装 搭 ...

  7. HashMap、ConcurrentHashMap红黑树实现分析

    本文学习知识点 1.二叉查找树,以及二叉树查找带来的问题. 2.平衡二叉树及好处. 3.红黑树的定义及构造. 4.ConcurrentHashMap中红黑树的构造. 在正式分析红黑树之前,有必要了解红 ...

  8. tomcat内存马原理解析及实现

    内存马 简介 ​ Webshell内存马,是在内存中写入恶意后门和木马并执行,达到远程控制Web服务器的一类内存马,其瞄准了企业的对外窗口:网站.应用.但传统的Webshell都是基于文件类型的,黑客 ...

  9. Spring 5 MVC 中的 Router Function 使用

    Spring 5 发行已经好几年了,里面提出了好几个新点子.其中一个就是 RouterFunction,这是个什么东西呢? Spring框架给我们提供了两种http端点暴露方式来隐藏servlet原理 ...

  10. 大闸蟹的OO第二单元总结

    OO的第二单元是讲多线程的协作与控制,三次作业分别为FAFS电梯,ALS电梯和三部需要协作的电梯.三次作业由浅入深,让我们逐渐理解多线程的工作原理和运行状况. 第一次作业: 第一次作业是傻瓜电梯,也就 ...