菜鸡的Java笔记 第二十二 - java 对象多态性
本次只是围绕着多态性的概念来进行讲解,但是所讲解的代码与实际的开发几乎没有关系,而且多态一定是在继承性的基础上才可以操作的,
而本次将使用类继承的关系来描述多态的性质,实际的开发中不会出现普通类的继承关系(一个已经完善的类不应该再被继承),开发中都要求继承抽象类和接口
多态性要想实现有两个前提:继承,覆写
范例:引出代码
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 对象多态性的更多相关文章
- 菜鸡的Java笔记 第二十八 - java 包的定义
包的主要作用以及定义 包的导入操作 系统常见的开发包 jar 程序命令 包的定义 在任何的操作系统之中都有一个统一的共识:同一个目录下不能够存在有相同的文 ...
- 菜鸡的Java笔记 第二十九 - java 单例设计模式
SingleCase 单例设计模式 1.单例设计模式的特点 2.多例设计模式的特点 内容 单例设计模式 现在如果说有这么一个程序类 class S ...
- 菜鸡的Java笔记 第二十六 - java 内部类
/* innerClass 从实际的开发来看,真正写到内部类的时候是在很久以后了,短期内如果是自己编写代码,几乎是见不到内部类出现的 讲解它的目的第一个是为了解释概念 ...
- 菜鸡的Java笔记 第二十四 - java 接口的基本定义
1.接口的基本定义以及使用形式 2.与接口有关的设计模式的初步认识 3.接口与抽象类的区别 接口与抽象类相比,接口的使用几率是最高的,所有的 ...
- 菜鸡的Java笔记 第十二 - java 构造方法与匿名对象
1.点 构造方法的作用以及定义要求 匿名对象的使用 构造方法: 只要出现()的都表示方法 构造方法就是类构造对象时调用的方法,主要用来实例化对象.> ...
- “全栈2019”Java多线程第二十二章:饥饿线程(Starvation)详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- “全栈2019”Java异常第二十二章:try-with-resources语句详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java异 ...
- 菜鸡的Java笔记 第二十五 wrapperClass 包装类
wrapperClass 包装类 1.包装类的特点 2.装箱与拆箱操作 3.数据转型处理 内容 Object 类可以接收 ...
- 菜鸡的Java笔记 第二十 - java 方法的覆写
1.方法的覆写 当子类定义了与父类中的完全一样的方法时(方法名称,参数类型以及个数,返回值类型)这样的操作就称为方法的覆写 范例:观察方法的覆写 class A{ public void ...
随机推荐
- CSS 小技巧 | 一行代码实现头像与国旗的融合
到国庆了,大家都急着给祖国母亲庆生. 每年每到此时,微信朋友圈就会流行起给头像装饰上国旗,而今年又流行这款: emm,很不错. 那么,将一张国旗图片与我们的头像,快速得到想要的头像,使用 CSS 如何 ...
- MyBatis的缓存玩法
重要概念 SqlSession:代表和数据库的一次会话,提供了操作数据库的方法. MappedStatement:代表要发往数据执行的命令,可以理解为SQL的抽象表示. Executor:和数据库交互 ...
- vite首次启动加载慢
背景 随着vue3的到来,vite开始被各大vue3组件库使用,公司开始一个新项目,准备尝试用vite试一波. 问题发现 当把公司新项目移植到vite后,启动非常快,但发现页渲染时间慢了很多 可以看到 ...
- SPOJ2939 QTREE5(LCT维护子树信息)
QWQ嘤嘤嘤 此题正规题解应该是边分治??或者是树剖(总之不是LCT) 但是我这里还是把它当成一个LCT题目来做 首先,这个题的重点还是在update上 因为有\(makeroot\)这个操作的存在, ...
- 多项式(polynomial)
多项式(polynomial) 题目大意: 给出一个 n 次多项式 \(f(x)=\sum_{i=0}^na_ix^i\) 对于\(k ≤ x ≤ k + l − 1\) 的\(l\) 个\(x\), ...
- Linux中使用dd制作文件的.img
dd if=/dev/zero of=new_img.img bs=1M count=20 //生成20M的文件,bs块的大小,count块的数量 mkfs.ext3 new_img.img / ...
- SharkCTF2021 The_nature_of_the_human
(信安数基的quiz1写不出来 来这放题解泄愤) crypto类题. 题面 其加密的大致过程是,对明文flag中的逐个字符,随机使用三种加密方式: 第一种,对该字符进行sha256加密后以16进制形式 ...
- jdbc简单学生管理系统
这个是java连接mysql数据库的一个简单学生系统,通过jdbc连接数据库. 工具类 JDBCuntils. package Student; import java.io.IOException; ...
- MarkDown之Typora使用
Typora:所见即所得 常用快捷键 加粗:ctrl + B 标题:ctrl + 16,对于与16级标题 插入公式:ctrl + Shift + m 插入代码:ctrl + Shift + K 插入图 ...
- 权限管理RBAC模型概述
一.什么是RBAC模型 RBAC模型(Role-Based Access Control:基于角色的访问控制)模型是比较早期提出的权限实现模型,在多用户计算机时期该思想即被提出,其中以美国George ...