ChatGPT似乎有的时候并不能搞懂Java的动态分派,你懂了吗?

目录

碎碎念

ChatGPT 中出现的问题

那么正确答案应该是什么呢?

分派的相关知识点总结:

分派是什么?

静态分派与动态分派:

Java语言是静态多分派,动态单分派的;

静态分派:静态重载多分派:

动态分派:动态重写单分派:

多分派类型与单分派类型

例题

例题一:重载方法匹配优先级(基本类型):

请分析如下程序的运行结果:

运行结果:

解题关键:

例题二:重载方法匹配优先级(引用类型):

请分析如下程序的运行结果:

运行结果:

解题关键:

例题三:动态分派

请分析如下程序的运行结果:

运行结果:

解题关键:

例题四:动态分派

请分析如下程序的运行结果:

运行结果:

解题关键:

例题五:单分派和多分派:

请分析如下程序的运行结果:

运行结果:

解题关键:

例题六:【用友笔试】

根据下面这个程序的内容,判断哪些描述是正确的:( )

运行结果:

解题关键:

ChatGPT的出现引发的思考

乐一下,让ChatGPT扮演服务端开发人员,看他自己对ChatGPT有什么看法:

参考文献

碎碎念

近期英子姐推荐了一本有关JVM的书,所以最近在看这个,发现,之前看的好多八股都是从这里出来的,收益颇多(虽然不一定能记住,但是看了总比不看强,或许看多了就记住了);

这本书的名字叫:《深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)周志明》,本来是边看,不懂的就跟ChatGPT讨论,ChatGPT绝大多数时候都是靠谱的,直到第八章 虚拟机字节码执行引擎中的8.3 方法调用中的8.3.2分派这一节出现了一点问题,ChatGPT似乎有的时候并不能搞懂Java的动态分派;

PS:本来这个文章是周四晚上立的,准备周五写的flag,但是由于种种原因拖到了周日晚上,好在是在临近周一之前完成了

ChatGPT 中出现的问题

书中讲完动态分派之后,举了两个例子,ChatGPT就是在这第二个例子上翻车了,翻车实况见下图:

发现他说的有有问题之后,又让他改了两次,但可以,ChatGPT并没有把握住机会(doge)

 

那么正确答案应该是什么呢?

正确的输出结果应该是:

I am Son, i have $0
I am Son, i have $4
This gay has $2

原因如下:

  • 输出两句都是“I am Son”,这是因为Son类在创建的时候,首先隐式调用了Father的构造函数,而Father构造函数中对showMeTheMoney()的调用是一次虚方法调用,实际执行的版本是Son::showMeTheMoney()方法,所以输出的是“I am Son”;
    • 如果是父类与子类之间的重写方法的选择,则是使用动态类型
      • (如果有多个父类,那么接近上层的优先级越低)
    • 如果你想简单的理解,那就记住上面的话,动态重写多分派,因为是重写,所以这里用动态分派,所以接近上层的优先级越低,所以这里调用的是Son类中重写的方法;
  • 而这时候虽然父类的money字段已经被初始化成2了,但Son::showMeTheMoney()方法中访问的却是子类的money字段,这时候结果自然还是0,因为它要到子类的构造函数执行时才会被初始化;
    • 这里可能有人会乱套,乱套不要怕,直接IDEA debug!
  • 走完父类的构造方法,那就回到子类中继续往下走,这个应该没啥问题,就正常的赋值,调用重写方法;
  • 至此,new Son() 结束;
  • main()的最后一句通过静态类型访问到了父类中的money,输出了2;

那么让我们一起重新复习一下分派的知识点吧!

分派的相关知识点总结:

分派是什么?

  • Java中的分派(Dispatch)指的是根据方法的接收者和参数的实际类型,选择正确的方法实现的过程;
  • Java中的分派主要包括静态分派和动态分派两种类型。
    • 静态分派(Static Dispatch):
      • 发生在编译期间,由编译器根据方法接收者和参数的静态类型确定具体调用的方法实现。例如,如果在代码中定义了一个方法,它的参数是Object类型,但在调用时传入了一个String类型的实例,编译器会选择Object类型的方法实现。
    • 动态分派(Dynamic Dispatch):
      • 发生在运行期间,由Java虚拟机根据方法接收者的实际类型确定具体调用的方法实现。例如,如果在代码中定义了一个父类和一个子类,它们都有一个同名的方法,在运行时调用子类实例的方法时,Java虚拟机会选择子类的方法实现。
  • Java中的分派是基于多态的概念实现的。多态指的是同一操作作用于不同的对象,可以有不同的解释和不同的实现方式。在Java中,通过使用继承和重写方法实现多态。

静态分派与动态分派:

Java语言是静态多分派,动态单分派的;

  • 如果是重载方法之间的选择,则是使用静态类型
  • 如果是父类与子类之间的重写方法的选择,则是使用动态类型
  • (如果有多个父类,那么接近上层的优先级越低)
  • A a = new B(); 会使用类型B去查找重写的方法,使用类型A去查找重载的方法
  • 静态分派发生在编译期间,根据参数的静态类型来决定选择哪个重载方法;
  • 动态分派发生在运行期间,根据对象的实际类型来决定调用哪个重写方法;

静态分派:静态重载多分派

  • 静态分派(《Thinking In Java》中称之为静态绑定(前期绑定)):
    • 所有依赖静态类型来定位方法执行版本(版本即哪一个方法)的分派动作,静态分派的最典型的应用就是方法重载;
  • 静态类型在编译期是可知的;
  • 1)基本类型(包装类型):
    • 以char为例,按照char>int>long>double>float>double>Character>Serializable>Object>...(变长参数,将其视为一个数组元素)
    • 变长参数的重载优先级最低;
    • (注意char到byte或short之间的转换时不安全的)
    • 基本类型与基本类型之间存在自动类型转换;
    • 基本类型到包装类型之间存在自动装箱;
    • java.lang.Serializable是java.lang.Character类实现的一个接口;
    • Character是绝对不会转型为Integer的,它只能安全地转型为它实现的接口或父类;Character还实现了另外一个接口java.lang.Comparable<Character>,如果同时出现两个参数分别为Serializable和 Comparable<Character>的重载方法,那它们在此时的优先级是一样的;编译器无法确定要自动转型为哪种类型,会提示“类型模糊”(Type Ambiguous),并拒绝编译;但是如果绕过Javac编译器,自己去构造出表达相同语义的字节码,将会发现这是能够通过Java虚拟机的类加载校验,而且能够被Java虚拟机正常执行的,但是会选择Serializable还是Comparable<Character>的重载方法则并不能事先确定,这是《Java虚拟机规范》所允许的;
    • 【注意】有一些在单个参数中能成立的自动转型,如char转型为int,在变长参数中是不成立的;
  • 2)引用类型:
    • 则需要根据继承关系进行匹配,注意只跟其编译时类型即静态类型相关;
    • 如果是重载方法之间的选择,则是使用静态类型

动态分派:动态重写单分派

  • 如果是父类与子类之间的重写方法的选择,则是使用动态类型
    • (如果有多个父类,那么接近上层的优先级越低)
  • 动态分派(《Thinking In Java》中称之为动态绑定(后期绑定)):
    • 在运行期根据实际类型确定执行版本的分派过程称为动态分派,这是重写的实际本质,在重写过程中并不是唯一的版本,而是选择更加合适的版本(如果有多个父类,那么接近上层的优先级越低);

多分派类型与单分派类型

  • 多分派类型:
    • 根据一个以上的宗量(方法的接受者与方法的参数统称为方法的宗量)进行方法的选择方法的分派类型;其中静态分派属于多分派类型;即Father father = new Son(); father.overloadMethod(param),中overloadMethod()方法的选择是要根据静态类型Father与方法的参数param共同确定的;
  • 单分派类型:
    • 动态分配属于单分派类型,即只会根据实际类型Son选择方法
  • 总结:
    • 静态多分派,动态单分派的语言

或许看完很抽象,所以应该结合例子看,例子如下!

例题

例题将包括5个书上的,和一个笔试题

例题一:重载方法匹配优先级(基本类型):

请分析如下程序的运行结果:

package org.fenixsoft.polymorphic;
public class Overload {public static void sayHello(Object arg) {System.out.println("hello Object");}public static void sayHello(int arg) {System.out.println("hello int");}public static void sayHello(long arg) {System.out.println("hello long");}public static void sayHello(Character arg) {System.out.println("hello Character");}public static void sayHello(char arg) {System.out.println("hello char");}public static void sayHello(char... arg) {System.out.println("hello char ...");}public static void sayHello(Serializable arg) {System.out.println("hello Serializable");}public static void main(String[] args) {sayHello('a');}
}

运行结果:

hello char

解题关键:

你只需要记住上面说的基本类型静态分派的顺序即可:

以char为例,按照char>int>long>double>float>double>Character>Serializable>Object>...(变长参数,将其视为一个数组元素)

例题二:重载方法匹配优先级(引用类型):

请分析如下程序的运行结果:

public class StaticDispatch {static abstract class Human {}static class Man extends Human {}static class Woman extends Human {}public void sayHello(Human guy) {System.out.println("hello,guy!");}public void sayHello(Man guy) {System.out.println("hello,gentleman!");}public void sayHello(Woman guy) {System.out.println("hello,lady!");}public static void main(String[] args) {Human man = new Man();Human woman = new Woman();StaticDispatch sr = new StaticDispatch();sr.sayHello(man);sr.sayHello(woman);}
}

运行结果:

hello,guy!
hello,guy!

解题关键:

  • Java语言是静态多分派,动态单分派的;
    • 如果是重载方法之间的选择,则是使用静态类型
    • 如果是父类与子类之间的重写方法的选择,则是使用动态类型
      • (如果有多个父类,那么接近上层的优先级越低)
    • 如A a = new B(); 会使用类型B去查找重写的方法,使用类型A去查找重载的方法;

例题三:动态分派

请分析如下程序的运行结果:

public class DynamicDispatch {static abstract class Human {protected abstract void sayHello();}static class Man extends Human {@Overrideprotected void sayHello() {System.out.println("man say hello");}}static class Woman extends Human {@Overrideprotected void sayHello() {System.out.println("woman say hello");}}public static void main(String[] args) {Human man = new Man();Human woman = new Woman();man.sayHello();woman.sayHello();man = new Woman();man.sayHello();}
}

运行结果:

man say hello
woman say hello
woman say hello

解题关键:

  • 在Java里面只有虚方法存在,字段永远不可能是虚的,换句话说,字段永远不参与多态,哪个类的方法访问某个名字的字段时,该名字指的就是这个类能看到的那个字段;当子类声明了与父类同名的字段时,虽然在子类的内存中两个字段都会存在,但是子类的字段会遮蔽父类的同名字段;

例题四:动态分派

请分析如下程序的运行结果:

public class FieldHasNoPolymorphic {static class Father {public int money = 1;public Father() {money = 2;showMeTheMoney();}public void showMeTheMoney() {System.out.println("I am Father, i have $" + money);}}static class Son extends Father {public int money = 3;public Son() {money = 4;showMeTheMoney();}public void showMeTheMoney() {System.out.println("I am Son, i have $" + money);}}public static void main(String[] args) {Father gay = new Son();System.out.println("This gay has $" + gay.money);}
}

运行结果:

I am Son, i have $0
I am Son, i have $4
This gay has $2

解题关键:

  • 输出两句都是“I am Son”,这是因为Son类在创建的时候,首先隐式调用了Father的构造函数,而Father构造函数中对showMeTheMoney()的调用是一次虚方法调用,实际执行的版本是Son::showMeTheMoney()方法,所以输出的是“I am Son”;
    • 如果是父类与子类之间的重写方法的选择,则是使用动态类型
      • (如果有多个父类,那么接近上层的优先级越低)
    • 如果你想简单的理解,那就记住上面的话,动态重写多分派,因为是重写,所以这里用动态分派,所以接近上层的优先级越低,所以这里调用的是Son类中重写的方法;
  • 而这时候虽然父类的money字段已经被初始化成2了,但Son::showMeTheMoney()方法中访问的却是子类的money字段,这时候结果自然还是0,因为它要到子类的构造函数执行时才会被初始化;
    • 这里可能有人会乱套,乱套不要怕,直接IDEA debug!
  • 走完父类的构造方法,那就回到子类中继续往下走,这个应该没啥问题,就正常的赋值,调用重写方法;
  • 至此,new Son() 结束;
  • main()的最后一句通过静态类型访问到了父类中的money,输出了2;

例题五:单分派和多分派:

请分析如下程序的运行结果:

public class Dispatch {static class QQ {}static class _360 {}public static class Father {public void hardChoice(QQ arg) {System.out.println("father choose qq");}public void hardChoice(_360 arg) {System.out.println("father choose 360");}}public static class Son extends Father {public void hardChoice(QQ arg) {System.out.println("son choose qq");}public void hardChoice(_360 arg) {System.out.println("son choose 360");}}public static void main(String[] args) {Father father = new Father();Father son = new Son();father.hardChoice(new _360());son.hardChoice(new QQ());}
}

运行结果:

father choose 360
son choose qq

解题关键:

  • 在Java语言中,方法的选择过程包括两个阶段:静态分派和动态分派;
  • 静态分派发生在编译期间,根据参数的静态类型来决定选择哪个重载方法;而动态分派发生在运行期间,根据对象的实际类型来决定调用哪个重写方法;
  • 在本例中,静态分派选择的目标方法签名是hardChoice(QQ)和hardChoice(_360),但实际执行的方法取决于运行时对象的实际类型;
  • 因此,father.hardChoice(new _360())调用了Father类中的hardChoice(_360)方法,而son.hardChoice(new QQ())调用了Son类中的hardChoice(QQ)方法;
  • 由于动态分派的目标方法只与接收者的实际类型有关,而与参数的类型无关,因此Java语言的动态分派属于单分派类型;

例题六:【用友笔试】

根据下面这个程序的内容,判断哪些描述是正确的:( )

public class Test {public static void main(String args[]) {String s = "tommy";Object o = s;sayHello(o); //语句1sayHello(s); //语句2}public static void sayHello(String to) {System.out.println(String.format("Hello, %s", to));}public static void sayHello(Object to) {System.out.println(String.format("Welcome, %s", to));}
}
  1. A. 这段程序有编译错误
  2. B. 语句1输出为:Hello, tommy
  3. C. 语句2输出为:Hello, tommy
  4. D. 语句1输出为:Welcome, tommy
  5. E. 语句2输出为:Welcome, tommy
  6. F. 根据选用的Java编译器不同,这段程序的输出可能不同

运行结果:

正确答案: C D 

解题关键:

相信懂了书里面5个较难例子的你,肯定做对啦,所以也就不讲啦!

ChatGPT的出现引发的思考

ChatGPT作为一个超强的AI,或许能取代一部分程序员,但是正所谓”智者千虑必有一失,愚者千虑必有一得“,在学习和生活中要不断思考,深挖才会有更多的价值!

并且现在ChatGPT已经能输出图片,并且也接入了一些聊天软件

可以看出,虽然ChatGPT能够根据文字描述生成大体符合要求的图片,但是一些细节问题仍有较大的发展空间,之前我还担心有了ChatGPT我的研究生方向:人脸超分辨率恢复与重建会不会变的没有意义,现在看来,会有意义,至少在我毕业之前仍会存在异议,从上图中可以看出,虽然ChatGPT能够生成大概的场景,但是对人脸五官的细节恢复十分差劲;

乐一下,让ChatGPT扮演服务端开发人员,看他自己对ChatGPT有什么看法:

参考文献

  • 《深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)周志明》
  • ChatGPT

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/5925.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用java对接chatgpt(含全部代码)

使用java对接chatgpt&#xff08;含全部代码&#xff09; 因为对vscode不熟悉&#xff0c;前段界面我也是在idea里写的&#xff0c;先看一下效果图是这样&#xff0c;比较简陋 我直接上代码&#xff0c;关于chatgpt前端的html&#xff0c;对了因为这个是我用之前写的匿名群聊改…

【开源免费】ChatGPT-Java版SDK重磅更新至1.0.10版,支持Tokens计算,快来一键接入!!!

简介 ChatGPT Java版SDK开源地址&#xff1a;github.com/Grt1228/cha… &#xff0c;目前收获将近1000个star。 有bug欢迎朋友们指出&#xff0c;互相学习&#xff0c;所有咨询全部免费。 最新版&#xff1a;1.0.10 <dependency><groupId>com.unfbx</groupId&…

面向Java开发者的ChatGPT提示词工程(1)

各位Java开发者们&#xff0c;欢迎来到万猫学社&#xff01;在这里&#xff0c;我将和大家分享ChatGPT提示词工程的系列文章&#xff0c;希望能够和大家一起学习和探讨提示词的最佳实践。 虽然互联网上已经有很多有关提示词的材料&#xff0c;比如那些“每个人都必须知道的30个…

JAVA 集成 chatGPT

1.文档地址&#xff1a; https://platform.openai.com/docs/introduction 下载demo&#xff1a;2. pom集成包 <dependency><groupId>com.theokanning.openai-gpt3-java</groupId><artifactId>client</artifactId><version>0.9.0</vers…

2023ChatGPT整理回答的Java高级工程师面试题

本文整理了一些 ChatGPT 回答的 java 面试题,希望能够帮助到更多的人! 死锁与活锁的区别,死锁与饥饿的区别? 死锁和活锁都是多线程并发编程中的问题,它们的区别主要在于线程是否能够继续执行。 死锁指的是两个或以上进程因竞争资源而造成的一种互相等待的现象。当多个线…

java集成chatGpt完整案例代码(效果和官网一样逐字输出)

要集成chatGpt参考我上一篇文章即可。但是&#xff0c;如果要实现官网一样的效果&#xff0c;逐字输出&#xff0c;难度就提升了不少了。经过在官网的研究发现它应该是采用了SSE技术&#xff0c;这是一种最新的HTTP交互技术。SSE(Server-Sent Events):通俗解释起来就是一种基于…

【程序源代码】ChatGPT Java Api

“ 关键字: “ChatGPT AI 人工智能" 01 ———— 【总体介绍】 ChatGPT Java Api 使用 maven <dependency><groupId>com.github.plexpt</groupId><artifactId>chatgpt</artifactId><version>1.1.2</version> </dependency…

体验使用 InsCode AI 创作助手 来帮我完成一篇博客

&#x1f947; 版权: 本文由【墨理学AI】原创首发、各位读者大大、敬请查阅、感谢三连 &#x1f389; 声明: 作为全网 AI 领域 干货最多的博主之一&#xff0c;❤️ 不负光阴不负卿 ❤️ 文章目录 InsCode AI 创作助手 它来啦回答不满意可以要求重新生成在输入 prompt 时&#…

厉害了!北大3位硕博生搞出ChatGPT版Excel!动动嘴就能自动处理表格……免费用!...

来源&#xff1a;量子位 做Excel表&#xff0c;真就动动嘴就够了&#xff01; 看&#xff0c;输入想要干的事&#xff1a;给学生成绩排个名吧。 简单敲个回车&#xff0c;表格唰一下就列好了&#xff01; 检查一遍也没错。 还能跨表格处理。 比如标记出两张不同表格中排名都在前…

「原驼」炸场:跑分达ChatGPT的99%,人类难以分辨!

源 | 量子位 大家好&#xff0c;这里是 NewBeeNLP。羊驼家族又出新品&#xff0c;直接炸场&#xff01;自动测试分数达到ChatGPT的99.3%&#xff0c;人类难以分辨两者的回答…… 这是开源大模型最新成果&#xff0c;来自羊驼家族的又一重磅成员——华盛顿大学原驼&#xff08;G…

《用ChatGPT自学的正确打开方式》

丰色 发自 凹非寺量子位 | 公众号 QbitAI 这两天&#xff0c;一个用ChatGPT进行自学的免费工具火了&#xff1a; 它叫AIbus&#xff0c;主界面是一块白板&#xff0c;只需写下你想探索的任何主题&#xff0c;比如“傅立叶变换”&#xff0c;它就会在几秒之内给出n个建议。 然后…

「实战」将多种AI工具整合到游戏开发工作流;AI应用推荐writeout;ControlNet新手实操流程图;ChatGPT复现之路 | ShowMeAI日报

&#x1f440;日报&周刊合集 | &#x1f3a1;生产力工具与行业应用大全 | &#x1f9e1; 点赞关注评论拜托啦&#xff01; &#x1f916; 『Notion AI 这波大赚』一个月内&#xff0c; AI 为 Notion 带来至少1000万美金ARR 作为最早一批接入 ChatGPT 的产品&#xff0c;Not…

从ChatGPT到Auto-GPT,自主人工智能真的要来了吗?

随着ChatGPT的持续爆火&#xff0c;人们在使用ChatGPT的时也发现了它的局限性&#xff0c;就是需要使用者自己来给GPT提示&#xff08;prompt&#xff09;。 如果你想感受ChatGPT强大&#xff0c;又没有OpenAI账号&#xff0c;可以关注《可立AI科技》这个微信公众号&#xff0c…

编辑部已成羊村,这几天幸亏有ChatGPT(doge)

梦晨 羿阁 发自 凹非寺量子位 | 公众号 QbitAI 坏事了&#xff0c;AI真的来抢饭碗了。 还是我的饭碗&#xff01; 这两天你们看的推送&#xff0c;有些标题是AI帮忙取的&#xff0c;有些文章甚至由AI完成了主要工作。 我呢&#xff1f;我不过是打打下手&#xff0c;加些过渡句&…

我用 ChatGPT 学设计模式之访问者模式

作者&#xff1a;明明如月学长&#xff0c; CSDN 博客专家&#xff0c;蚂蚁集团高级 Java 工程师&#xff0c;《性能优化方法论》作者、《解锁大厂思维&#xff1a;剖析《阿里巴巴Java开发手册》》、《再学经典&#xff1a;《EffectiveJava》独家解析》专栏作者。 热门文章推荐…

Spring Cloud Gateway路由到Amazon S3签名失败处理

Spring Cloud Gateway路由到Amazon S3签名失败处理 背景 最近在预研统一存储网关&#xff0c;想到就是使用Spring Cloud Gateway作为网关的入口&#xff0c;再反向代理到S3对象存储服务器。 软件版本 网关&#xff1a;Spring Cloud Gateway 3.1.2 s3对象存储&#xff1a;m…

基于java(springboot)和go-cqhttp实现QQ机器人

目录 yh-qqrobot机器人简介go-cqhttp搭建1.下载应用2.生成bat文件3. 初始化项目4. 配置5. 运行项目 yh-qqrobot搭建搭建后端1. 导入sql文件2. 配置文件3. 导入到idea 搭建前端 yh-qqrobot机器人简介 yh-qqrobot是一个基于若依框和go-cqhttp集成的系统&#xff0c;一开始我只是揣…

【基于Flink的城市交通实时监控平台】需求一:卡口车辆超速情况检测

案例需求&#xff1a; 从kafka的topic-car中读取卡口数据&#xff0c;将超速车辆写入mysql的select * from t_speeding_info表&#xff0c;当通过卡口的车速超过60就认定为超速 卡口数据格式&#xff1a; action_time long --摄像头拍摄时间戳&#xff0c;精确到秒, monitor…

chatgpt赋能python:Python下载工具:提高工作效率的不二之选

Python下载工具&#xff1a;提高工作效率的不二之选 作为一名有10年Python编程经验的工程师&#xff0c;我深知一款好用的下载工具对于我们的工作效率有多么重要。因此&#xff0c;在众多Python工具中&#xff0c;我多次选用了一些好用的下载工具&#xff0c;并且对它们进行了…

将 ChatGLM2-6B 部署成 OpenAI API 服务

将 ChatGLM2-6B 部署成 OpenAI API 服务 0. 背景1. FastChat 部署使用 ChatGLM2-6B1-1. 创建虚拟环境1-2. 克隆代码1-3. 安装依赖库1-4. 使用 UI 进行推理1-5. 使用 OpenAI API 方式进行推理 0. 背景 最近一直在使用 OpenAI 的 API 做一些学习和调研。使用 OpenAI 的 API&…