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从入门到放弃》 👦个人简介:一名双非编程菜鸟,在这里分享自己的编程学习笔记,欢迎大家的指正与点赞,谢谢! 类和对…...

Xshell远程连接Kali(默认 | 私钥)Note版
前言:xshell远程连接,私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...
关于 WASM:1. WASM 基础原理
一、WASM 简介 1.1 WebAssembly 是什么? WebAssembly(WASM) 是一种能在现代浏览器中高效运行的二进制指令格式,它不是传统的编程语言,而是一种 低级字节码格式,可由高级语言(如 C、C、Rust&am…...
MySQL账号权限管理指南:安全创建账户与精细授权技巧
在MySQL数据库管理中,合理创建用户账号并分配精确权限是保障数据安全的核心环节。直接使用root账号进行所有操作不仅危险且难以审计操作行为。今天我们来全面解析MySQL账号创建与权限分配的专业方法。 一、为何需要创建独立账号? 最小权限原则…...

基于Springboot+Vue的办公管理系统
角色: 管理员、员工 技术: 后端: SpringBoot, Vue2, MySQL, Mybatis-Plus 前端: Vue2, Element-UI, Axios, Echarts, Vue-Router 核心功能: 该办公管理系统是一个综合性的企业内部管理平台,旨在提升企业运营效率和员工管理水…...

MacOS下Homebrew国内镜像加速指南(2025最新国内镜像加速)
macos brew国内镜像加速方法 brew install 加速formula.jws.json下载慢加速 🍺 最新版brew安装慢到怀疑人生?别怕,教你轻松起飞! 最近Homebrew更新至最新版,每次执行 brew 命令时都会自动从官方地址 https://formulae.…...

Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement
Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement 1. LAB环境2. L2公告策略2.1 部署Death Star2.2 访问服务2.3 部署L2公告策略2.4 服务宣告 3. 可视化 ARP 流量3.1 部署新服务3.2 准备可视化3.3 再次请求 4. 自动IPAM4.1 IPAM Pool4.2 …...
Spring Security 认证流程——补充
一、认证流程概述 Spring Security 的认证流程基于 过滤器链(Filter Chain),核心组件包括 UsernamePasswordAuthenticationFilter、AuthenticationManager、UserDetailsService 等。整个流程可分为以下步骤: 用户提交登录请求拦…...

阿里云Ubuntu 22.04 64位搭建Flask流程(亲测)
cd /home 进入home盘 安装虚拟环境: 1、安装virtualenv pip install virtualenv 2.创建新的虚拟环境: virtualenv myenv 3、激活虚拟环境(激活环境可以在当前环境下安装包) source myenv/bin/activate 此时,终端…...

Qt的学习(一)
1.什么是Qt Qt特指用来进行桌面应用开发(电脑上写的程序)涉及到的一套技术Qt无法开发网页前端,也不能开发移动应用。 客户端开发的重要任务:编写和用户交互的界面。一般来说和用户交互的界面,有两种典型风格&…...

车载诊断架构 --- ZEVonUDS(J1979-3)简介第一篇
我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 做到欲望极简,了解自己的真实欲望,不受外在潮流的影响,不盲从,不跟风。把自己的精力全部用在自己。一是去掉多余,凡事找规律,基础是诚信;二是…...