- 博客(128)
- 收藏
- 关注
原创 JVM(Java虚拟机)详解
但是当销毁引用a和b后,两个Test对象引用计数都-1,此时没有引用变量再指向两个Test对象,但两个对象其中的成员属性都互相引用,造成循环引用,此时引用计数器无法变成0,也就无法被垃圾回收。最大的好处是可以让程序员自定义的类不会把Java标准库中的类给覆盖了,因为即使写了一个类名为String,根据双亲委派模型,该类被加载首先会在rt.jar中查找,就找到了由BootStrapClassLoader来进行类加载,也就是仍然优先加载标准库的类而不是自己写的类。当计数器为0时,对象就会被垃圾回收。
2025-04-24 14:32:28
929
原创 Postman设置了Cookies但是请求不携带Cookie
使用Postman工具往往要向本地服务器发送请求携带Cookie便于测试接口,但是在Send下面的Cookies选项中设置域名127.0.0.1,并添加Cookie,发现发送的请求怎么都不会携带Cookie:通过Fiddler抓包发现并没有Cookie:这是由于Postman默认不会将Cookie发送给127.0.0.1(视为不安全域名)。
2025-04-23 21:38:11
601
原创 Linux部署Web程序
注意:部署前,需要在Linux环境中的MySQL进行建库建表,保证库和表和开发阶段用到的一模一样(在开发阶段,可以把数据库的建库和建表的语句写进sql文件,在Linux中使用mysql -u[数据库用户名] -p[数据库密码] < [数据库脚本].sql来执行。(1)首次使用,需要先修改可执行命令的可执行权限:cd apache-tomcat-8.5.47/bin、chmod +x *.sh(给所有.sh(Linux的可执行文件)后缀的命令加上可执行权限)。如果提示命令找不到,安装失败。
2025-04-23 15:21:50
980
原创 Linux常用命令
注意:如果同时指定两个以上的文件或目录,且最后的目的地是一个已经存在的目录,则它会把前面指定的所有文件或目录复制到此目录中。若同时指定多个文件或目录,而最后的目的地并非一个已存在的目录,则会出现错误信息。使用ps命令可以搭配其他命令一起使用,比如ps搭配grep,这里使用到|,是Linux的管道(把前一个命令的输出作为后一个命令的输入)。注意:在开发中还可能使用jps命令,jps类似linux的ps命令,不同的是ps是用来显示所有的进程,而jps只显示java相关的进程。既是一个命令,又是一个文本编辑器。
2025-04-22 14:43:00
829
原创 Servlet上传文件
注意:在服务器中上传的文件保存磁盘的时候,通常会出现重名的情况,因此往往把上传的文件名转化成唯一的字符串,在数据库保存唯一字符串和对应文件的路径,然后再把文件重命名为唯一的字符串写入指定上传路径中。这里boundary是边界的意思,表示使用后面这串字符来作为body中文件的分隔符。Cookie和Session。获取请求中给定name的文件。把提交的文件数据写入磁盘文件。
2025-04-21 20:37:30
957
原创 Cookie和Session
于是当用户第一次登录时,服务器校验完信息的正确性后,创建Session,并将该登录用户的信息存到Session中,最后将该Session存储到Redis中,读取时只需从Redis根据键Key来获取该用户信息。值Value是存储的信息。同时,Session通常存储在内存中,而在集群环境下,服务器通常部署在多台机器,因此,如果用户在服务器1实现的登录,但是服务器2的内存中并没有该用户登录的Session,那么如果用户的请求被负载均衡到服务器2上,服务器2就会发现用户未登录而重新让用户登录,这是不合理的情况。
2025-04-19 18:10:05
760
原创 Servlet
注意:返回给前端的响应如果有中文内容,就可能出现乱码,IDEA默认采用UTF-8编码,而浏览器默认采用和操作系统一样的编码,Windows采用GBK编码,因此编码解码方式不一样,就出现乱码了。这是Servlet中构造的响应的对象,在doXXX()方法中会构造空的HttpServletResponse对象,然后由doXXX()向该对象set一些参数和数据,最后Tomcat把该对象按照Http的格式转化成字符串并通过Socket发送给浏览器。要解析JSON格式的参数,就需要使用Jackson。
2025-04-18 10:33:55
740
原创 Tomcat与Servlet(2)
注意:doXXX方法是多态的体现,我们开发人员写的类继承HttpServlet类(有doXXX系列的方法,需要我们的自定义类重写),而HttpServlet类继承Servlet类,而在动态资源的访问中引用对象的类型是Servlet,因此相当于我们通过父类引用Servlet来调用子类的doXXX方法(父类引用指向子类对象)。Smart Tomcat在背后所做的工作就是让我们不用再打开Tomcat目录使用命令启动,可以在IDEA中点击自动启动Tomcat,并且自动部署运行我们的web程序。表示为当前服务起名。
2025-04-17 14:09:44
998
原创 fiddler开启后浏览器显示“您的连接不是私密连接”
HTTPS协议这个问题不会出现在http请求的场景。使用https协议时,由于https协议需要加密和证书来进行网站身份验证确保安全性,而fiddler是使用代理机制的抓包工具,因此开启fiddler服务后,https请求首先会发送给fiddler,但是要验证fiddler的证书可靠性,当fiddler的证书不符合判断安全规则,就会出现“您的连接不是私密连接”的问题。
2025-04-16 20:19:51
1161
原创 Tomcat与Servlet
包含了许多可执行程序,比如启动服务程序startup.bat和startup.sh,bat后缀是Windows的可执行程序,sh后缀是Linux的可执行程序,而Tomcat运行在JVM上,JVM已经实现了跨平台的特性,因此Tomcat的命令也是跨平台的多种格式。6.resp.getWriter()会获取到一个流对象,通过这个流对象就可以写入一些数据,写入的数据会被构造成一个HTTP响应的body部分,Tomcat会把整个响应转成字符串,通过socket写回给浏览器。如果没有红色,就说明依赖已经导入。
2025-04-16 15:55:09
1116
原创 HTTPS协议
客户端想要获得公钥,首先就要向服务器请求公钥内容,黑客入侵的中间设备截获请求,会伪造一对公钥public2和私钥private2,服务器发送的响应内容是公钥public1,黑客截获后把原服务器的公钥public1替换成伪造的公钥public2,此时客户端收到的公钥就是伪造的public2。,如果一样证书是真的,否则证书是假的。(3)客户端收到证书后,使用公钥public1对证书解密,并计算hash值来验证证书的真伪,如果是真的就构造对称密钥并用证书中的public2加密,把加密后的对称密钥发送给服务器。
2025-04-15 15:42:44
738
原创 构造HTTP请求
type表示请求的方法,包括http协议允许的多种;使用form表单构造GET请求,action是请求的地址,method是请求的方法,而input标签中name和输入的数据就构成了查询字符串query string,当点击提交时,GET请求就会发送到百度的服务器地址,然后默认返回百度搜索引擎的首页,使用Fiddler抓包,关键信息如下(即一个域名默认不允许通过ajax请求访问另一个域名的服务器(比如不允许搜狗在页面中的代码请求访问百度服务器),这是浏览器的默认行为,除非另一个域名的服务器允许跨域。
2025-04-14 19:33:29
1071
原创 HTTP协议
注意:登录流程,用Cookie存储用户的登录信息,当用户第一次登录时,返回的响应就会携带Set-Cookie让浏览器存储登录信息,下次用户访问该网站内的其他页面时,就会在携带Cookie一起发送给服务器,服务器判断该用户已经登录,就直接返回页面,防止用户登录一次后重复登录。HTTP协议是应用层的协议,基于传输层的TCP协议来传输,数据是文本类型的,因为HTTP协议已经有多版本了,HTTP1.0、HTTP1.1、HTTP2.0均为TCP,HTTP3基于UDP实现,为了便于说明,这里以HTTP1.1为例。
2025-04-12 16:28:07
727
原创 前端三件套—JavaScript的WebAPI(DOM+BOM)
通过querySelector和querySelectorAll即可实现标签对象的选择,从而操作标签的属性和内容等。事件三要素:事件源(哪个元素触发的)、事件类型(点击、选中等等)和事件处理程序(事件应该得到哪些结果返回给用户,回调函数)。事件就是用户操作页面的一系列行为,比如点击、选中等,当用户产生上述行为后,事件就会被JS捕获从而产生响应提供给用户反馈。js的内容不打算讲更多了,大概就这么些基础,后续的其他前端知识搭配项目一起学习会理解的更深。element.style.[属性名] = [属性值];
2025-04-11 14:23:37
1048
原创 前端三件套—JavaScript语法入门
其实,Java和JS的语法差异不是因为JS是弱类型引起的,而是因为JS是动态类型,Java是静态类型引起的。而强类型和弱类型描述的是语言变量类型的界限是否明确,即能否非常支持隐式类型转换,如果对隐式类型转换支持的很好,就是弱类型;还有一种object类型,与Java的对象不同,Java中的对象的类型就是类名,因此对象类型可能不同。DOM是页面文档对象模型(文档即html文档,对象是浏览器把html的标签和元素都称为对象,),是浏览器提供给JS操作页面的API。只有执行到初始化即=时,变量的类型才被确定。
2025-04-10 14:48:34
1005
原创 前端三件套—CSS入门
注意:border-radius可以同时设置四个角,使用四个length(空格分隔)或使用border-top-left-radius、border-top-right-radius、border-bottom-right-radius、border-bottom-left-radius。:background-size,取值两部分,宽度 高度,可以是数字、百分数,也可以是单词cover(扩展背景图片完全覆盖背景区域)或contain(扩展背景图片宽度高度完全覆盖内容区域(内容区域小于背景区域))。
2025-04-09 16:09:08
703
原创 前端三件套—HTML入门
内容自动根据浏览器宽度来决定排版,html内容首尾处的换行和空格均无效,在html中文字之间输入的多个空格只相当于一个空格,html中直接输入换行不会真的换行,而是相当于一个空格。其中html是head和body的父标签,而head和body是兄弟标签,title是head的子标签,很多写在body中的标签也是其子标签。HTML是前端页面的骨架,HTML代码是由标签构成,并且不需要编译,直接双击打开html文件,依靠浏览器即可运行。li标签是子标签,表示列表项,其中还能放其他标签,比如实现列表项的超链接。
2025-04-08 16:16:07
954
原创 网络编程—TCP/IP模型(数据链路层了解与知识补充)
采用以太网协议对IP数据包进行封装,添加首部(源MAC地址和目的MAC地址,使用ARP协议来进行IP和MAC地址映射)和尾部构造成以太网帧,并根据以太网帧数据载荷最大长度(MTU)来对IP数据包进行分片(标识、标志、片偏移),以太网帧在传播过程中会修改源MAC和目的MAC(分别对应传播过程的上一个节点和下一个节点)。,如果是第一次访问该域名,地址栏输入的域名主机不知道对应的IP,就会给DNS服务器发送请求,请求的内容是域名的IP是什么。DNS服务器返回响应,响应的内容是域名对应的IP。
2025-04-06 15:39:23
1142
原创 网络编程—TCP/IP模型(IP协议)
IP数据包转发过程可能经历多个路由器(上图进行了简化),每经过一个路由器,NAT机制就会将源IP改为自己的转发IP(WAN口出去的IP),同时记录下地址的映射(包是从哪来的),因此最终视频平台看到数据包的源IP并不是主机1的IP,而是上一条路由器的IP。观察下图的内网IP和外网IP,体会不同局域网的内网IP可以重复,相邻的局域网网络号不同(因为路由器把相邻的两个局域网连接起来),同一个局域网的网络号相同的含义。主机号为.0的IP,表示这个局域网的网络号,因此该IP不会分配给局域网的主机作为IP地址使用。
2025-04-06 15:11:14
1222
原创 网络编程—TCP/IP模型(TCP协议)
依次类推,以指数形式递增。发送端收到ACK后根据窗口大小字段调整自己的窗口,如果窗口大小是0,此时接收端缓冲区已经满了,因此发送端窗口大小为0不再发送数据,超过超时重传的时间时,发送端发送窗口探测报文段(没有数据载荷),接收端接收窗口探测报文段自动触发ACK发送,一旦接收端缓冲区有空间了会主动发送ACK报文段(窗口更新通知),进而下一步发送数据。如果发送方掉点,接收方长时间没有接收到数据,就会定期给发送方发送“心跳包”(发送方发送ping报文,接收方回复pong报文,具有周期性和检测对方是否存活的作用)。
2025-04-05 15:13:23
867
原创 网络编程—TCP/IP模型(UDP协议与自定义协议)
UDP校验和的计算没有采用著名的CRC算法(循环冗余校验和),而是把数据划分为多段16位的字(如果不足16位且为奇数位,就在末尾补形成偶数长度),把每个16位的字累加,溢出2字节(16位)的部分从16位的最低位进位,最后把得到的结果按位取反得到校验和。UDP协议的特点是无连接(不建立连接来传输数据)、不可靠(不知道数据是否发送过去)、面向数据报(发多少收多少,不能拆分为字节多次接收)、只有接收缓冲区没有发送缓冲区、大小受限(最长64kb)、全双工(同时发送和接收)。前两种方式组合,实现变长字节组合方式。
2025-04-05 14:44:47
1090
原创 网络编程—Socket套接字(TCP)
采用多线程方案,线程池实现一个线程为一个客户端服务(注意,当并发量很大时,线程池的线程数量很多,就会导致资源浪费调度困难等问题,此时需要采用NIO(非阻塞IO)的方式,这是一种I/O多路复用的技术,可以实现一个线程管理多个客户端)。也就是说ServerSocket的主要作用就是创建TCP服务器的全局连接监听,客户端作为连接发起方,因此直接创建Socket表示申请建立连接,而ServerSocket的accept()方法一旦监听到有客户端申请建立连接,就返回一个Socket用于建立服务器和客户端之间的连接。
2025-04-04 15:06:41
850
原创 网络编程—Socket套接字(UDP)
在服务器代码中,需要注意response.getBytes().length不等于response.length(),前一个方法获取的是字节长度,而后一个方法获取的是字符长度,当字符中有中文时,字节长度和字符长度并不相等,因此不能替换。基于UDP的Socket主要是DatagramSocket,用于发送和接收UDP数据报,作用和操作方式都类似文件(打开Socket文件(对应网卡),发送/接收数据报,关闭文件)。发送的数据保存在buf,offset是起始下标,length是数据长度,
2025-04-03 14:43:15
966
原创 网络编程—网络概念
如果信道是空闲的,设备就可以发送数据。物理层和数据链路层是物理设备和驱动程序的范畴,网络层和传输层是操作系统所负责的,应用层是应用程序所负责的,因此软件开发人员的主要工作就是在应用层进行网络编程。路由器相信大家都熟悉,有WAN口(一般蓝色,一个口)和LAN口(一般黄色,多个口),WAN口接入外部公网,LAN口实现局域网的主机互联。媒介访问控制协议,负责控制设备如何访问共享的通信介质(如以太网、无线电波等),确保在多台设备共享同一传输媒介时能够有效地进行数据传输,避免冲突、控制流量,并确保数据的有序传递。
2025-04-02 16:02:11
711
原创 文件读写与IO—应用案例
对于打开的文件需要及时关闭的情况,除了使用try-catch-finally语句,还有更简单的方式try with resources,这种方式会在try()中打开文件,读取结束后自动关闭文件,不用再显示调用关闭文件的代码。目录遍历的核心是递归遍历操作,文件系统结构是树形文件结构,因此可以采用DFS(深度优先遍历)来进行目录遍历。文件的复制操作主要是输入流和输出流的使用,注意不要在现有的文件系统测试,避免带来不必要的风险。注意:放入try()中的实例创建的类必须实现Closeable接口。
2025-04-01 15:55:21
929
原创 文件操作与IO—文件读写
因为实际中的程序多是服务器程序,即程序持续运行,如果打开文件不关闭,内存中进程对应的文件描述符表对应的文件描述符会一直存在,从而导致文件描述符表最终爆满。流(Stream)是一种数据的读写方式,读视为输入流,写视为输出流,批量读取数据时,这里的“批量”就是流,而java中数据的读写就是面向流的读写方式。PrintWriter类对标读文件时的Scanner类,也提供了更丰富地写文件的方法,比如println(),这是换行写入的方法。的为读写方式(以字符为单位的流)。在同一次打开的文件中多次写,是续写)。
2025-03-31 20:06:35
917
原创 文件操作与IO—File类
修饰符与类型属性含义依赖于系统的路径分隔符,String类型的表示依赖于系统的路径分隔符,char类型的表示构造方法含义创建File对象,依据父目录的File对象+子文件的字符串创建创建File对象,依据父目录的字符串+子文件的字符串创建创建File对象,依据文件路径字符串创建返回值方法名含义String返回父目录文件路径StringgetName()返回文件名StringgetPath()返回文件路径String返回绝对路径(把文件相对路径和工作路径拼接)
2025-03-31 19:53:58
883
原创 多线程—线程安全集合类与死锁
注意1:在Java 7时,ConcurrentHashMap的线程安全的实现是使用“分段锁”,即把若干哈希桶分为一个“段”,每个段共享一把锁,每个段的若干哈希桶的修改涉及锁竞争。对于扩容时的每一个操作,都参与元素移动的过程,即每次操作移动一小批元素(重新哈希),直到所有的元素都搬运完,旧的哈希表删除,完成扩容过程。线程需要同时持有两把锁才能进行任务的执行,但是由于一个线程持有一把锁,另一个线程持有另一把锁,两个线程都等待对方的另一把锁的释放,因此导致了线程相互阻塞等待对方的锁的死锁现象。
2025-03-30 23:22:41
727
原创 多线程—JUC(java.util.concurrent)
信号量Semaphore表示可用资源的数量,本质上是一个计数器,在信号量机制中有操作P和V(都是原子性的操作),P操作表示申请资源,因此P操作后资源数量-1;V操作表示释放资源,V操作后资源数量+1。但凡回答具体的数字都是错的,正确的做法是根据不同的程序设置不同数量,可以通过压测(性能测试)来控制不同线程数量,观察CPU占用率、内存占用率等等来确定合适的线程数量。如果把代码中的注释取消,即连续3次获取资源,此时可用资源的数量为0,再释放一次资源,此时可用资源的数量为1,再获取1次资源即可顺利执行。
2025-03-29 21:24:53
1096
原创 多线程—synchronized原理
锁分为细粒度(加锁范围小)和粗粒度(加锁范围大),当频繁使用细粒度锁加锁解锁时,JVM和编译器就会把多个细粒度锁优化成粗粒度锁,减少频繁的加锁解锁开销。,记录当前锁是哪个线程的,如果没有其他线程竞争锁,就不用真正的加锁,从而减少了加锁解锁的开销。3.synchronized的轻量级锁是自旋锁(基于CAS)实现,重量级锁是挂起等待锁(操作系统的mutex锁实现)。4.当锁竞争激烈时,此时自旋锁无法快速获得锁(就会一直浪费CPU资源),那就会升级为重量级锁。3.当偏向锁进入加锁状态时,也就是进入轻量级锁,
2025-03-29 21:10:38
735
原创 多线程—锁策略
操作4线程2判断value和oldValue不相同,因此不做任何操作,此时while条件成立,执行循环体一次,因此执行oldValue = value,此时线程2的oldValue值和value相同,再次执行条件判断CAS,会执行交换value=oldValue+1,因此value=2。如何解决:引入版本号,每一个数据都有对应的版本号,每一次修改版本号只会增加,CAS进行比较时如果发现数据一致,就比较版本号,只有版本号和数据都一样是才进行交换操作,否则就不进行任何操作(操作失败)。往往是纯用户态执行。
2025-03-25 17:28:57
960
原创 多线程—应用案例
),这种方式可读性强。这里注意synchronized的范围,如果只对wait和notify加锁(这是必须的),就会出现可能执行完queue.put()后,worker线程被调度下CPU,此时其他线程再添加任务到优先级阻塞队列中,其他线程执行的locker.notify()无事发生(因为worker线程还没来得及阻塞),当worker线程再次调度执行时,就会忽视刚刚新添加的任务直接进入阻塞状态,从而可能导致新添加的任务到时间并未执行。当队列空时,如果继续出队,就会阻塞,直到队列不空,则解除阻塞继续出队。
2025-03-23 15:23:06
626
原创 多线程—保证线程安全
比如,线程A(等待某些计算资源)、线程B(等待某些计算资源)和线程C竞争锁对象,线程A获得锁后发现自己需要的数据还没有,就执行结束释放锁,线程B竞争到锁也发现自己需要的数据还没有,也释放锁,线程A又抢到锁,这样循环往复,线程C长时间没有得到锁,出现线程饿死现象。当线程进入到synchronized修饰的代码块,如果其他线程还未获得锁,该线程就进行加锁,此时其他线程再想进入同一个锁对象修饰的代码块中,就会阻塞等待,直到加锁的代码块执行结束,线程解锁,此时其他线程再来竞争锁。计数器的值减为0时,锁才被释放。
2025-03-21 15:20:27
1045
原创 多线程—线程安全原理
问题在于,JVM底层和操作系统为了提高执行效率,可能会对指令集进行优化,比如Thread2一直读取判断数据,但是数据的值一直不变,为了提高效率,就不再从内存中load数据了(CPU从内存中访问数据的速度远远大于从寄存器中访问数据的速度),从而指令执行就被优化为上图的顺序,Thread2线程在Thread1线程修改数据后,仍然读取的是自己工作内存的未同步的副本数据,因此造成线程不安全问题。正是由于同步数据不一定及时,导致副本数据可能和内存中原数据的值不同,从而引起线程不安全。
2025-03-21 15:06:02
1068
原创 多线程—线程创建与状态
针对interrupt()的两种行为,多数情况需要搭配break和sleep使用,如果我们启动了一个线程,当线程此刻在执行比较重要的任务时,如果main线程发出中断命令,中断的本质是希望线程立即结束,但是我们不希望线程执行到一半就立即结束,此时线程可以结合sleep()和break来灵活应对,就如同上面的3种捕获异常后的处理方式。在上两幅图中,在线程界面,可以发现当前进程有关的线程,其中main线程就是main方法运行时自动启动的线程,而Thread-0线程就是我们在main方法中启动的Thread线程。
2025-03-19 17:48:47
648
原创 多线程—进程与线程
通过引入虚拟地址空间,每一个进程的虚拟地址空间相互独立,比如进程1的代码中访问到变量a,进程2的代码中也访问到变量a,但是这两个变量a的值不同,其在各自虚拟地址空间的地址相同,通过MMU(内存管理单元,通常集成在CPU上)来对虚拟地址进行映射,就可以访问到不同的所需数据,实现了进程的“隔离性”。由于并发编程往往会利用多线程,多个线程的执行需要多个CPU核心,因此当线程的数量高于CPU核心数,此时再增加线程的数量不会提高任务的执行速度,反而有可能拖累总任务,因为创建销毁线程也需要开销。程序即可执行文件,是。
2025-03-18 22:04:38
767
原创 访问者模式
Vistor:抽象访问者,为对象结构中每一个具体元素类ConcreteElement声明一个访问操作,从这个操作的名称或参数类型可以清楚知道需要访问的具体元素的类型,具体访问者需要实现这些操作方法,定义对这些元素的访问操作。在软件开发中,有时候需要处理集合对象结构,在该对象结构中存储了多个不同类型的对象信息,对同一对象结构中的元素的操作方式并不唯一,可能需要提供多种不同的处理方式,还有可能增加新的处理方式。类的职责更加清晰,有利于对象结构中元素对象的复用,相同的对象结构可以供多个不同的访问者访问。
2025-02-08 20:06:12
790
原创 模板方法模式
(1)AbstractClass:抽象类,定义了一系列基本操作(PrimitiveOperations),这些基本操作可以是具体的,也可以是抽象的,每一个基本操作对应算法的一个步骤,在其子类中可以重定义或实现这些步骤。同时,在抽象类中实现了一个模板方法(Template Method),用于定义一个算法的框架,模板方法不仅可以调用在抽象类中实现的基本方法,也可以调用在抽象类的子类中实现的基本方法,还可以调用其他对象中的方法。即一次性实现一个算法的不变部分,并将可变的行为留给子类来实现。
2025-02-08 20:04:16
816
原创 详解策略模式
换言之,这些具体算法类均有统一的接口,根据“里氏代换原则”和面向对象的多态性,客户端可以选择使用任何一个具体算法类,并只需要维持一个数据类型是抽象算法类的对象。ConcreteStrategy:具体策略类,它实现了在抽象策略类中声明的算法,在运行时,具体策略类将覆盖在环境类中定义的抽象策略类对象,使用一种具体的算法实现某个业务处理。(3)无法同时在客户端使用多个策略类,也就是说,在使用策略模式时,客户端每次只能使用一个策略类,不支持使用一个策略类完成部分功能后再使用另一个策略类来完成剩余功能的情况。
2025-02-08 20:02:40
978
原创 详解状态模式
Context:环境类,又称为上下文类,它是拥有多种状态的对象。State:抽象状态类,它用于定义一个接口以封装与环境类的一个特定状态相关的行为,在抽象状态类中声明了各种不同状态对应的方法,而在其子类中实现类这些方法,由于不同状态下对象的行为可能不同,因此在不同子类中方法的实现可能存在不同,相同的方法可以写在抽象状态类中。ConcreteState:具体状态类,它是抽象状态类的子类,每一个子类实现一个与环境类的一个状态相关的行为,每一个具体状态类对应环境的一个具体状态,不同的具体状态类其行为有所不同。
2025-02-08 20:00:09
770
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人