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

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. redis学习笔记-01 string类型命令

    一.set key value set joker 123456 #设定key为joker,value为123456的数据 二.keys * keys * #用于查看该数据库中所有的key值 三.se ...

  2. 试题 算法训练 区间k大数查询 java题解

    资源限制 时间限制:1.0s   内存限制:256.0MB 问题描述 给定一个序列,每次询问序列中第l个数到第r个数中第K大的数是哪个. 输入格式 第一行包含一个数n,表示序列长度. 第二行包含n个正 ...

  3. Kubernetes client-go 源码分析 - Reflector

    概述入口 - Reflector.Run()核心 - Reflector.ListAndWatch()Reflector.watchHandler()NewReflector()小结 概述 源码版本: ...

  4. Golang通脉之接口

    接口(interface)定义了一个对象的行为规范,只定义规范不实现,由具体的对象来实现规范的细节. 接口类型 在Go语言中接口(interface)是一种类型,一种抽象的类型. interface是 ...

  5. 【UE4 C++ 基础知识】<3> 基本数据类型、字符串处理及转换

    基本数据类型 TCHAR TCHAR就是UE4通过对char和wchar_t的封装 char ANSI编码 wchar_t 宽字符的Unicode编码 使用 TEXT() 宏包裹作为字面值 TCHAR ...

  6. 【二食堂】Beta - 测试报告

    Beta - 测试报告 测试过程中发现的bug Beta阶段的新bug 我们在Beta阶段的开发过程中就进行了测试,发现了许多bug.这其中后端的bug比较多,在这里我列举一些比较重要的功能性bug. ...

  7. 设计的MOS管三极管简单开关电路驱动能力不够3

    16楼说得非常明白,补充一点,R3如果不要,会有下冲产生.4 Q: Z/ G  G1 s8 Z- } 能解释下为什么会产生过冲吗?9 i, P* D* X) u. t/ b  ^ 让我们这些菜鸟学习学 ...

  8. 零基础学习C语言入门必备知识

    今天跟大家一起从零学C语言: 1. C语言简介 1.1 C语言发展史 C语言是一种广泛使用的面向过程的计算机程序设计语言,既适合于系统程序设计,又适合于应用程序设计.C语言的发展历程大致如图1-1所示 ...

  9. 洛谷 P4867 Gty的二逼妹子序列

    链接: P4867 题意: 给出长度为 \(n(1\leq n\leq 10^5)\) 的序列 \(s\),保证\(1\leq s_i\leq n\).有 \(m(1\leq m\leq 10^6)\ ...

  10. 洛谷 P3147 [USACO16OPEN]262144 P

    链接: P3147 P3146双倍经验 前言: 今天发现的一道很有意思的DP题 分析: 第一眼以为是区间DP,于是设f[i][j]为从第i个数到第j个数可以合出的最大值,但思考后发现并不能简单合并,并 ...