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虚拟机会选择子类的方法实现。
- 静态分派(Static Dispatch):
- 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));}
}
- A. 这段程序有编译错误
- B. 语句1输出为:Hello, tommy
- C. 语句2输出为:Hello, tommy
- D. 语句1输出为:Welcome, tommy
- E. 语句2输出为:Welcome, tommy
- F. 根据选用的Java编译器不同,这段程序的输出可能不同
运行结果:
正确答案: C D
解题关键:
相信懂了书里面5个较难例子的你,肯定做对啦,所以也就不讲啦!
ChatGPT的出现引发的思考
ChatGPT作为一个超强的AI,或许能取代一部分程序员,但是正所谓”智者千虑必有一失,愚者千虑必有一得“,在学习和生活中要不断思考,深挖才会有更多的价值!
并且现在ChatGPT已经能输出图片,并且也接入了一些聊天软件
可以看出,虽然ChatGPT能够根据文字描述生成大体符合要求的图片,但是一些细节问题仍有较大的发展空间,之前我还担心有了ChatGPT我的研究生方向:人脸超分辨率恢复与重建会不会变的没有意义,现在看来,会有意义,至少在我毕业之前仍会存在异议,从上图中可以看出,虽然ChatGPT能够生成大概的场景,但是对人脸五官的细节恢复十分差劲;
乐一下,让ChatGPT扮演服务端开发人员,看他自己对ChatGPT有什么看法:
参考文献
- 《深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)周志明》
- ChatGPT
相关文章:

ChatGPT似乎有的时候并不能搞懂Java的动态分派,你懂了吗?
目录 碎碎念 ChatGPT 中出现的问题 那么正确答案应该是什么呢? 分派的相关知识点总结: 分派是什么? 静态分派与动态分派: Java语言是静态多分派,动态单分派的; 静态分派:静态重载多分派…...

【C++初阶】vector的模拟实现
大家好我是沐曦希💕 文章目录一、前言二、无参构造&析构三、基础接口1.empty和clear2.size和capacity3.[]和iterator四、reserve和resize五、尾插尾删六、其他构造1.迭代器区间构造2.拷贝构造七、memcpy问题八、完整代码一、前言 在模拟实现容器时候࿰…...

微信小程序、小游戏的流量主一般可以赚多少钱?
本篇文章主要科普小程序、小游戏流量主一般赚钱的实际情况,通过在下长期运营的经验汇总而成。 日期:2023年2月26日 作者:任聪聪 小程序、小程序满1000用户后即可开通流量主,但实际上很多人并没有传说中的那种日赚几千的流量收入的…...

jni-Demo-基于linux(c++ java)
跑一个jni 的最简单的Demo需要提前准备 VsCode 编译器、win10下,vscode中集成linux操作系统、c编译器(gcc、g),java编译器(jdk1.8)参考:https://mangocool.com/1653030123842.htmlJniDemo类&…...

指针的进阶——(1)
本次讲解重点: 1、字符指针 2、数组指针 3、指针数组 4、数组传参和指针传参 5、函数指针 关于指针这个知识点的主题,我们在前面已经初级阶段已经对指针有了大致的理解和应用了。我们知道了指针的概念: 1、指针就是地址,但口…...

电商平台的促销活动如何抵御大流量的ddos攻击
每一次活动大促带来的迅猛流量,对技术人而言都是一次严峻考验。如果在活动期间遭受黑产恶意 DDoS 攻击,无疑是雪上加霜。电商的特性是业务常态下通常不会遭受大流量 DDoS 攻击,且对延迟敏感,因此只需要在活动期间按需使用 DDoS 防…...
代码随想录-48-104. 二叉树的最大深度
目录前言题目1.层序迭代思路2. 本题思路分析:3. 算法实现4. pop函数的算法复杂度5. 算法坑点前言 在本科毕设结束后,我开始刷卡哥的“代码随想录”,每天一节。自己的总结笔记均会放在“算法刷题-代码随想录”该专栏下。 代码随想录此题链接 …...

【Vue3源码】第六章 computed的实现
【Vue3源码】第六章 computed的实现 上一章节我们实现了 ref 及其它配套的isRef、unRef 和 proxyRefs API。这一章开始实现computed计算属性。 认识computed 接受一个 getter 函数,返回一个只读的响应式 ref 对象。该 ref 通过 .value 暴露 getter 函数的返回值。…...
Java基础之注解
3.注解 3.1概述【理解】 概述 对我们的程序进行标注和解释 注解和注释的区别 注释: 给程序员看的注解: 给编译器看的 使用注解进行配置配置的优势 代码更加简洁,方便 3.2自定义注解【理解】 格式 public interface 注解名称 { public 属性类型 属性名() default 默认值…...
三、线性表
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 前言 提示:这里可以添加本文要记录的大概内容: 自学JAVA数据结构笔记,跟学视频为:黑马程序员Java数据结构与java算法全套教程…...
C++统计方形
统计方形 内存限制:256 MB 时间限制:1 S 题目描述 有一个n*m方格的棋盘,求其方格包含多少正方形、长方形(此处长方形不包含正方形) 输入格式 输入存在多组测试数据。每组测试数据输入两个整数n,m,数字不超…...

Tina_Linux配网开发指南
OpenRemoved_Tina_Linux_配网_开发指南 1 概述 1.1 编写目的 介绍Allwinner 平台上基于wifimanager-v2.0 的WiFi 配网方式,包括softap(WiFi ap 模式热点配网),soundwave(声波配网),BLE(蓝牙低功耗配网)。 1.2 适用范围 • allwinner 软件平台tina v5.0 版本及以…...

高频面试题|RabbitMQ如何防止消息的重复消费?
一. 前言最近有很多小伙伴开始找工作,在面试时,面试官经常会问我们这样一个题目:RabbitMQ如何防止重复消费?有很多小伙伴这个时候都在想,消息怎么还会重复消费呢???.......所以他们在面试后就跑来问壹哥,针对这个比…...

黑盒测试用例设计方法-边界值分析法
目录 一、边界值定义 二、边界值的考虑 三、边界值的优化 四、边界值的设计用例的步骤 五、案例 六、边界值的类型 一、边界值定义 边界值分析法就是对输入或输出的边界值进行测试的一种黑盒测试方法。通常边界值分析法是作为对等价类划分法的补充,这种情况下…...

项目风险管理中不可忽视的5个关键点
1、风险意识非常重要 项目经理必须要有风险意识,并不是项目计划做好就万事大吉,而是需要对项目风险进行预判,时刻保持风险意识,及时发现和处理项目风险。 项目风险管理关键:风险意识 2、建立组织风险资产库 寻…...

Linux->进程地址空间
目录 前言: 1. 程序地址空间回顾 2. 进程空间是什么 3. 进程地址空间与内存 4. 进程地址空间和内存的关联 5. 为什么要有进程地址空间 前言: 我们在平时学习的过程当中总是听到栈、堆、代码段等等储存空间,但是这些东西到底是什么&…...

【奶奶看了也不会】AI绘画 Mac安装stable-diffusion-webui绘制AI妹子保姆级教程
1.作品图 2.准备工作 目前网上能搜到的stable-diffusion-webui的安装教程都是Window和Mac M1芯片的,而对于因特尔芯片的文章少之又少,这就导致我们还在用老Intel 芯片的Mac本,看着别人生成美女图片只能眼馋。所以小卷这周末折腾了一天&#…...

基于stm32电梯管理系统设计
基于stm32电梯管理系统设计这里记录一下以前自己做的嵌入式课程设计,报告中的图片和文字太多了,全部一个一个把搬过来太麻烦了,需要完整文本和代码自行q我963160156,也可在微信公众号 *高级嵌入式软件* 里回复 *电梯* 查看完整版文章摘要关键…...

Spring中的FactoryBean 和 BeanFactory、BeanPostProcessor 和BeanFactoryPostProcessor解析
文章目录FactoryBean 和 BeanFactory后置处理器BeanPostProcessor 和 BeanFactoryPostProcessorBeanPostProcessorBeanFactoryPostProcessorFactoryBean 和 BeanFactory BeanFactory接⼝是容器的顶级接⼝,定义了容器的⼀些基础⾏为,负责⽣产和管理Bean的…...

【C++从入门到放弃】类和对象(上)
🧑💻作者: 情话0.0 📝专栏:《C从入门到放弃》 👦个人简介:一名双非编程菜鸟,在这里分享自己的编程学习笔记,欢迎大家的指正与点赞,谢谢! 类和对…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...
OpenLayers 可视化之热力图
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 热力图(Heatmap)又叫热点图,是一种通过特殊高亮显示事物密度分布、变化趋势的数据可视化技术。采用颜色的深浅来显示…...

【OSG学习笔记】Day 18: 碰撞检测与物理交互
物理引擎(Physics Engine) 物理引擎 是一种通过计算机模拟物理规律(如力学、碰撞、重力、流体动力学等)的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互,广泛应用于 游戏开发、动画制作、虚…...

简易版抽奖活动的设计技术方案
1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...

visual studio 2022更改主题为深色
visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中,选择 环境 -> 常规 ,将其中的颜色主题改成深色 点击确定,更改完成...

【机器视觉】单目测距——运动结构恢复
ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛…...
MVC 数据库
MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...

C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...

ElasticSearch搜索引擎之倒排索引及其底层算法
文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...