自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+

小黑说Java

公众号:小黑说Java

  • 博客(42)
  • 收藏
  • 关注

原创 这篇分布式锁解读,能否算得上第二?

前言对多线程有所了解的朋友一般都会熟悉一个概念:锁。在多线程并发场景下,要保证在同一时刻只有一个线程可以操作某个业务、数据或者变量,通常需要使用加锁机制。比如synchronized或Lock等。而随着架构演进、业务发展,我们的应用往往都不是只部署在一台服务器上,而是使用分布式集群架构,同时存在多台相同的应用。比如某电商网站在进行商品销售时,因为商品的数量是有限的,每个用户购买一件商品,需要将商品的库存减1;但是我们想一下,在“双十一”这种火爆的活动时,可能会有大量的用户购买同一件商品,同时对该商

2022-03-08 09:23:41 709 4

原创 面试必看,多线程并发面试题合集

什么是java中的线程?线程可以理解为一个轻量化进程。是进程的最小部分,可以与进程的其他部分(线程)并发执行。什么是多线程?多线程是多个线程并发执行。Java支持多线程,因此它允许应用程序并发执行两个或多个任务。在java中创建线程的方法是什么?有两种方式创建线程:​ 继承Thread类​ 实现Runnable接口但是本质上最终都是创建Thread类。Thread和Runnable哪个更好?实现Runnable接口被认为是比继承Thread类更好的方法,原因如下:Java不支持多重继

2022-03-02 21:39:37 2128 6

原创 面试官让我设计个LRU缓存,结果...

小黑有个朋友最近去面试,过程中有问他一些缓存相关的问题。让他回答一下,设计一个LRU缓存,应该怎么实现我这个朋友呢,应该是没好好准备这块儿内容,反正是没咋答上来,于是。。。就让他回家等通知了。今天小黑就带大家来聊一聊LRU算法,并动手写一个LRU缓存。缓存淘汰策略是啥在我们平时开发中,经常会使用到缓存,比如一些热点商品,配置数据等,为了提高访问速度都会放到缓存中,但是,往往缓存的容量是有限的,我们不能将所有数据都放在缓存中,需要给缓存设定一个容量,当容量放满之后,要有新的数据放入缓存时,需要按照一

2022-03-02 20:01:15 1554 2

原创 Java 8 日期和时间 API看这篇就够了

前言在Java8中,不仅推出了Lambda表达式、streams流以及一些优化,对于日期和时间的处理也推出了全新的API。本文将带大家全面的了解新的日期和时间API的使用。LocalDateJava8中的Date/Time API都放在java.time包中;LocalDate表示一个只有年-月-日的日期对象,我们看一下如何来创建一个LocalDate对象:// 当前日期LocalDate now = LocalDate.now();// 2021-10-14LocalDate.of(202

2022-03-02 18:02:37 426

原创 单例模式没你想的那么简单

如果你自认为已经掌握懒汉式、饿汉式、DCL、IoDH、枚举等单例实现方式,可以直接看最后的打破单例。如果不是,建议你耐心从头看完。相信你看完本文能让你掌握Java中所有单例模式的设计方式。单例设计模式是GOF 23中设计模式中常见的设计模式之一,不论是在我们日常开发,还是一些第三方库中几乎都能见到单例模式。包括在面试时初中级的程序员基本都会被问到单例模式。单例模式的目的主要是为了保证在多线程场景下实例唯一的一种解决方案,实现起来还是比较简单的,但是实现方式各式各样,五花八门,今天小黑带大家梳理下单.

2022-03-02 18:00:59 92

原创 Typora+picGo+Gitee搭建个人图床

前言小黑在学习和工作中,经常需要进行写作,无论是记笔记,还是写博客,或者工作中需要编写接口文档或者技术文档。在这个过程中,我使用过很多工具,最开始使用word,但是需要花费很多的时间在格式调整和排版上;也使用过一些笔记软件,印象,有道,为知等一系列,但是都有一个问题,就是我如果笔记中有图片,那么我想把笔记内容再发到别的博客平台上时,需要单独对图片进行上传,然后在博客内容中替换,相当的耗费时间和精力。最后终于找到一个比较完美的搭配方案,就是使用Typora记录,然后再搭建一个图床,在图片插入到Typ

2022-03-02 17:54:56 514

原创 使用重试机制保证SpringBoot应用的稳定性

前言没有人能保证自己的系统不出错,同样,在调用第三方系统时,也不能保证能够100%的成功。往往会因为程序逻辑、网络中断、边界值等各种各样的问题导致服务失败。在不同的业务领域对于服务的错误率有着不同的要求,一些金融领域的系统一般要求服务的错误率为0.01%。那么为了保证很低的错误率,则需要通过一些专门的机制来完成。而最常见的方式就是在出现错误时通过重试来解决。场景比如,在购买保险的场景中,用户购买保险之前,需要根据用户的个人信息来查询产品的报价。在产品报价接口中,它调用了另一个服务查询客户信息

2022-03-02 09:32:07 502

原创 信息安全无小事,手把手教你日志脱敏

场景我们开发的程序迟早有一天都会上线到生产环境运行,但是没有人能保证自己的代码100%不出BUG(别抬扛,真没BUG是代码写的少)当我们线上出BUG之后,最常见的定位问题方法就是排查日志文件,所以我们一般都会在开发程序时,在适当的位置输出一些日志信息。并且有一些日志并不是只打印一些业务字段,可能会将整个对象输出到日志中。比如这样:log.info("客户信息:{}",JSON.toJSONString(customer));从代码的角度来说,不太严格的话,如果这个customer对象不是特别大的

2022-02-22 10:12:12 3955

原创 八张动图搞懂代理和反向代理

前言在分布式场景下,我们经常会听到“代理”、“反向代理”等这样的术语。如果你对它们的概念不是很清楚,那么可能会在具体场景下比较困惑。本期内容,主要跟大家介绍一下,代理和反向代理是什么?有什么区别?以及它们都有什么作用和使用案例。没有代理的请求过程在没有代理服务器时,客户端和服务器之间的请求和响应过程。代理服务器代理服务器是位于客户端和服务器之间的软件或硬件服务器。客户端连接到代理以请求真实服务器的连接。从本质上讲,代理服务器(又名转发代理)是一种软件或硬件,可以代表客户端促进从其他服务器请求

2022-02-22 10:08:50 695

原创 使用MyBatis拦截器后,摸鱼时间又长了。

场景在后端服务开发时,现在很流行的框架组合就是SSM(SpringBoot + Spring + MyBatis),在我们进行一些业务系统开发时,会有很多的业务数据表,而表中的信息从新插入开始,整个生命周期过程中可能会进行很多次的操作。比如,我们在某网站购买一件商品,会生成一条订单记录,在支付完金额后订单状态会变为已支付,等最后我们收到订单商品,这个订单状态会变成已完成等。假设我们的订单表t_order结果如下:当订单创建时,需要设置insert_by,insert_time,update_by,

2022-02-21 18:19:21 127

原创 神奇,同样执行1,000,000次循环的时间会不一样?

场景事情是这样的,我先来还原一下场景,有如下图中的一段代码,这段代码的逻辑很简单。先生成一个0-top范围的有序集合,比如top=100,那么就是生成[0,1,2,3,…99,100];如果shuffle=true,则将这个集合顺序打乱,相当于洗牌;然后遍历这个集合,统计出集合中数值小于top/2的数量,这个结果不管是否洗牌都是top的一半;记录循环开始和结束的时间,看看循环总共花费多少时间。按理说,不管这个集合有多大,都会执行top次的循环,每个循环里都要执行if判断,所以花费的时间不管

2022-02-21 11:40:17 192

原创 经典的线程同步问题:哲学家就餐

场景有五位沉默的哲学家围坐在一张圆桌旁,他们一生都在吃东西和思考。有五只筷子供他们使用,哲学家需要双手拿到一双筷子之后才能吃饭;吃完后会将筷子放下继续思考。那么现在有一个问题,我们需要想出一种方案,如何保证哲学家们可以交替吃饭和思考,而不会被饿死。上面这个问题是由Dijkstra提出的一个经典的线程同步问题。解决方案我们在开始想如何解决问题之前,可以先将这个场景通过代码还原,在程序中进行建模。每一只筷子可以看做是一个资源数据,都可以被它两边的哲学家尝试去获取,并且同一时间只能由其中一人持有,

2022-02-21 11:37:57 277

原创 2022年了,密码该如何保存都不会?

大家好呀,我是小黑。我们在开发应用时,只要涉及到用户,登录注册功能则是必不可少的。但是,并不是所有人都能做好登录注册功能。比如最基本的密码应该如何保存?应该用哪种加密方式对密码进行加密都不是很清楚。一旦出现数据库泄漏,密码外泄等问题,会对用户造成极大的损失。密码该如何保存?如果我们要在服务器中对用户进行身份验证,我们需要完成以下的步骤:获取到要登录用户的用户名和密码;根据用户名在数据库中查找到用户;比较用户提供的密码和数据库中的密码是否一致。那我们应该如何存储用户的密码呢?我们来看看都

2022-02-21 11:36:05 279

原创 淦~做一个短链接系统需要考虑这么多

我是小黑,一名在互联网“苟且”的程序员关注同名公众号【小黑说Java】,更多干货内容抢先送达,更有不定期抽奖送书活动。流水不争先,贵在滔滔不绝什么是短链接短链接顾名思义,就是一个比较短的链接(我好像说了个废话),我们平时看到的链接可能长这样:http://mp.weixin.qq.com/s?biz=MzU5MjY4MTM3MA==&mid=2247485162&idx=1&sn=00a7baa5284b8231c56507068378ccb2&chksm=f.

2022-01-05 19:33:01 266

原创 “低代码”是什么?程序员有可能会被取代吗

前言在当今世界,各个商业、互联网、企业之间的竞争异常激烈,各个中小企业都面临着数字化转型的挑战,为什么要数字化转型,因为数字化转型可以使企业变得更加敏捷,创新成本更低。但是数字化转型的道路具有一定的复杂性,需要有合格的开发人员能够快速准确地开发出符合复杂业务的应用程序和流程。而开发人员从0到1的开发系统,存在着一定的风险,因为这会有很长的交付时间,并且成本可能会非常高,而且对开发人员的专业程度有着高度的依赖性。大多数组织、企业都需要熟练、专业的开发人员,而按照二八定律,真正的熟练高级开发人员是比较短缺

2022-01-05 19:30:00 1211 1

原创 【设计模式系列】适配器模式

我是小黑,一名在互联网“苟且”的程序员关注同名公众号【小黑说Java】,更多干货内容抢先送达,更有不定期抽奖送书活动。流水不争先,贵在滔滔不绝前言我之前有专门写过一起单例设计模式的实现,最近准备专门整理一下常用的设计模式,分别都在什么场景下该如何使用。今天我们的主题是适配器模式,争取后面能将工作中常用的都写到,如果觉得对你有帮助,点个赞我会更有动力。适配器模式定义适配器设计模式是结构化设计模式之一,它的作用主要是让两个不兼容的接口可以一起工作。连接这些不相关接口的对象称为Adapter。.

2022-01-05 09:25:02 108

原创 【设计模式系列】通俗易懂的门面模式

我是小黑,一名在互联网“苟且”的程序员关注同名公众号【小黑说Java】,更多干货内容抢先送达,更有不定期抽奖送书活动。流水不争先,贵在滔滔不绝前言最近同事二狗子要装修房子,他装修之前呢,得先找个设计师设计,然后还需要找个水电工给新房子改水电,再然后,还得找泥瓦工,刷墙贴瓷砖之类的,这个过程中要招人,谈价钱,跟进度,二狗子一个写代码的程序员,他哪会这些呀,太麻烦了,要是有人能帮他干就好了。哎,这事儿好办呀,找个装修公司呀。有了装修公司,二狗子就只需要和装修公司谈好价钱,然后等房子装修就好,.

2022-01-05 09:23:07 227

原创 【设计模式系列】用代理模式避免rm -rf /*

我是小黑,一名在互联网“苟且”的程序员关注同名公众号【小黑说Java】,更多干货内容抢先送达,更有不定期抽奖送书活动。流水不争先,贵在滔滔不绝前言也许你没有操作过Linux,但是一定听说过rm -rf /* 的传说,这个命令会将系统中所有的文件删除,直接导致操作系统无法使用,只能重装系统,如果在生产环境执行基本上是灾难。这里放一张图那么实际管理过程中,肯定不会让开发人员具备能执行这么高权限的账号,只有运维人员或者运维老大才有这样的权限。今天我们就用设计模式中的来讲一讲,操作系统是如何实现对于.

2022-01-04 09:28:52 120

原创 Redis分布式锁存在的问题

在很多场景中,我们为了保证数据的最终一致性,需要很多的技术方案来支持,比如分布式事务、分布式锁等。

2022-01-03 19:31:32 2326

原创 Java8中Optional实践

不管是一名小白程序员还是有三五年工作的CRUD BOY,或者是资深的高级Java工程师,在我们日常开发中,由于null的存在,经常会遇到NullPointerException,而我们为了避免该异常的产生,往往需要对于使用到的对象进行一些非空判断,最开始我们都会使用if…else来进行处理,比如下面的代码:Person person = getPer.

2021-12-31 12:29:14 353 1

原创 Spring依赖注入的优雅方案

在这篇文章中,我将向您展示如何使用Project Lombok作为Spring框架依赖性注入的最佳实践。前言Spring框架本身有各种不同的方式来执行依赖项的注入。灵活的选择是Spring框架的强项。然而,并非所有依赖注入方式都被认为是最佳实践。依赖注入接下来我们通过一些代码示例,来分别实现Spring的多种依赖注入的方式。首先我们有一个MyServ.

2021-12-30 12:06:40 271

原创 Java 8的日期和时间 API

在Java8中,不仅推出了Lambda表达式、streams流以及一些优化,对于日期和时间的处理也推出了全新的API。本文将带大家全面的了解新的日期和时间API的使用。LocalDateJava8中的Date/Time API都放在java.time包中;LocalDate表示一个只有年-月-日的日期对象,我们看一下如何来创建一个LocalDat.

2021-12-30 12:04:26 195

原创 Java中的HTTP客户端工具对比

HTTP(超文本传输协议)是一种应用层协议,用于客户端和服务端进行通信,按照标准格式如JSON、XML等进行网络数据的传输,通常也作为应用程序之间以RESTAPI形式进行通信的常用协议。在Java应用中需要调用其他应用提供的HTTP服务API时,通常需要使用一些HTTP客户端组件。而可选择的HTTP客户端有很多,本期内容主要介绍在Java应用程序中.

2021-12-29 15:11:14 3766

原创 Java中的SOLID原则

Robert C. Martin提出了5条面向对象的设计原则,并将其缩写为SOLID。这个首字母缩写词的每一个字母都在谈论Java中的原则。当以一种组合的方式使用所有的SOLID原则时,就会更容易开发出易于管理的软件。Robert C. Martin,世界级编程大师,设计模式和敏捷开发先驱,敏捷联盟首任主席,C++ Report前主编。20世纪70.

2021-12-29 15:10:39 1110

原创 Guava cache缓存实践

在我们日常开发中,如果某些数据会频繁的进行读取,并且很少会做修改,我们一般会对这些数据进行缓存,来提高读取的速度。使用缓存之所以能提高性能,是因为读取的速度比从磁盘或数据库中读取的速度更高。但是使用缓存并不是全部都是好处,因为存放缓存数据的空间一般都是CPU内存,或者Redis等,它们的空间更宝贵,是典型的空间换时间,所以需要放到缓存中的数据应该是.

2021-12-28 09:25:55 378

原创 常见的限流算法

在高并发环境下,为了保证系统的稳定,通常会用到限流、降级、熔断等手段,来保证系统的稳定可用。限流顾名思义就是限制服务处理的流量,其实熔断、降级本质上也是限流的一种,都是阻断了请求流量,本篇文章重点介绍常见的限流算法。为什么限流为什么需要限流呢?这个问题比较好理解,就是请求服务的流量过大,会导致服务崩溃,为了避免这种情况的发生,所以要对流量进行限制。在.

2021-12-27 17:49:43 282

原创 单例模式的N种实现方式

如果你自认为已经掌握懒汉式、饿汉式、DCL、IoDH、枚举等单例实现方式,可以直接看最后的打破单例。如果不是,建议你耐心从头看完。相信你看完本文能让你掌握Java中所有单例模式的设计方式。单例设计模式是GOF 23中设计模式中常见的设计模式之一,不论是在我们日常开发,还是一些第三方库中几乎都能见到单例模式。包括在面试时初中级的程序员基本都会被问到单.

2021-12-27 10:55:41 1915

原创 Guava Retryer实现接口重试

小黑在开发中遇到个问题,我负责的模块需要调用某个三方服务接口查询信息,查询结果直接影响后续业务逻辑的处理;这个接口偶尔会因网络问题出现超时,导致我的业务逻辑无法继续处理;这个问题该如何解决呢?,小黑首先想到的就是重试嘛,如果失败了就再调用一次。问题来了,如果又失败了呢?接着重试嘛。我们循环处理,比如循环5次,全失败则任务服务不可用,结束调用。如.

2021-12-26 16:50:27 464

原创 ForkJoin看这篇就够了!

大家好,我是小黑,一个在互联网苟且偷生的农民工。在JDK1.7中引入了一种新的Fork/Join线程池,它可以将一个大的任务拆分成多个小的任务并行执行并汇总执行结果。Fork/Join采用的是分而治之的基本思想,分而治之就是将一个复杂的任务,按照规定的阈值划分成多个简单的小任务,然后将这些小任务的结果再进行汇总返回,得到最终的任务。分治法分治法是计算机领域常用的算法中的其中一个,主要思想就是将将一个规模为N的问题,分解成K个规模较小的子问题,这些子问题相互独立且与原问题性质相同;求解出子问题的解

2021-09-17 13:14:02 1507

原创 并发编程之:异步调用获取返回值

大家好,我是小黑,一个在互联网苟且偷生的农民工。Runnable在创建线程时,可以通过new Thread(Runnable)方式,将任务代码封装在Runnable的run()方法中,将Runnable作为任务提交给Thread,或者使用线程池的execute(Runnable)方法处理。public class RunnableDemo { public static void main(String[] args) { ExecutorService executorSer

2021-09-16 08:13:37 2814

原创 面试官:谈谈BlockingQueue

大家好,我是小黑,一个在互联网苟且偷生的农民工。队列学过数据结构的同学应该都知道,队列是数据结构中一种特殊的线性表结构,和平时使用的List,Set这些数据结构相比有点特殊,它的特殊之处在于它只允许在队列的头部(Head)进行删除操作,在尾部(Tail)进行插入操作,这种方式的队列我们称之为先进先出队列(FIFO)。在JDK1.5中推出了队列这一数据结构的具体实现,接口Queue是对于队列的定义,并有一些列具有特殊功能的队列实现。在Queue接口中定义了队列的如下方法:其中add(E)并非Qu

2021-09-09 21:57:55 314

原创 并发编程之:线程池(二)

大家好,我是小黑,一个在互联网苟且偷生的农民工。本期带来线程池的第二期内容,如果对线程池的基本概念还不是很清楚,可以先看我上一篇文章。面试官:谈谈你对线程池的理解本期内容会从以下几个方面解析线程池的具体实现:线程池状态线程池初始化如何执行任务钩子方法等待队列和排队策略自定义拒绝策略线程池关闭动态调整容量合理配置容量线程池状态ThreadPoolExecutor中定义了如下几种线程池状态:RUNNING :运行状态,该线程池可以接受新任务和处理排队任务SHUTDOWN:

2021-09-07 20:45:23 302

原创 并发编程之:JUC并发控制工具

大家好,我是小黑,一个在互联网苟且偷生的农民工。在上一期我们讲了Thread.join()方法和CountDownLatch,这两者都可以做到等待一个线程执行完毕之后当前线程继续执行,并且CountDownLatch要更优秀,能满足同时等待多个线程执行,我们通过查看源码知道CountDownLatch是通过AQS实现的。那么在java.util.concurrent包中除了像CountDownLatch这样的并发控制工具外,还有哪些呢?今天带大家一起来看一看。CountDownLatch等待一个或

2021-09-07 19:49:04 122

原创 并发编程之:CountDownLatch

大家好,我是小黑,一个在互联网苟且偷生的农民工。先问大家一个问题,在主线程中创建多个线程,在这多个线程被启动之后,主线程需要等子线程执行完之后才能接着执行自己的代码,应该怎么实现呢?Thread.join()看过我 并发编程之:线程 的朋友应该知道怎么做,在Thread类中有一个方法join(),这个方法是一个阻塞方法,当前线程会等待调动join()方法的线程死亡之后再继续执行。我们通过代码来看看执行结果。public class JoinDemo { public static voi

2021-09-06 13:04:23 163

原创 并发编程之:AQS源码解析

并发编程之:AQS源码解析大家好,我是小黑,一个在互联网苟且偷生的农民工。在Java并发编程中,经常会用到锁,除了Synchronized这个JDK关键字以外,还有Lock接口下面的各种锁实现,如重入锁ReentrantLock,还有读写锁ReadWriteLock等,他们在实现锁的过程中都是依赖与AQS来完成核心的加解锁逻辑的。那么AQS具体是什么呢?提供一个框架,用于实现依赖**先进先出(FIFO)**等待队列的阻塞锁和相关同步器(信号量,事件等)。 该类被设计为大多数类型的同步器的有用依据,这

2021-09-04 20:21:39 291

原创 并发编程之:线程池(一)

大家好,我是小黑,一个在互联网苟且偷生的农民工。池化线程池是在计算机开发中常见的一种池化技术,是为了提高资源的利用率,将一些资源重复利用,避免重复的构建来提高效率。类似字符串常量池,数据库连接池,HttpClient连接池等,都是用的池化技术。线程池在没有线程池概念之前,我们要使用线程必须先通过创建一个Thread类来完成线程的构建,并调用start()方法开启,在线程执行完会将线程销毁,而线程资源是很宝贵的,创建和销毁线程会造成资源的浪费。而线程池是将创建的线程存储到一个池中,在需要使用时从池中去

2021-09-03 23:04:12 195

原创 并发编程之:Lock

大家好,我是小黑,一个在互联网苟且偷生的农民工。在之前的文章中,为了保证在并发情况下多线程共享数据的线程安全,我们会使用synchronized关键字来修饰方法或者代码块,以及在生产者消费者模式中同样使用synchronized来保证生产者和消费者对于缓冲区的原子操作。synchronized的缺点那么synchronized这么厉害,到底有没有什么缺点呢?主要有以下几个方面:使用synchronized加锁的代码块或者方法,在线程获取锁时,会一直试图获取直到获取成功,不能中断。加锁的条件只能在

2021-09-02 19:12:04 183

原创 并发编程之:Atomic

并发编程之:Atomic大家好,我是小黑,一个在互联网苟且偷生的农民工。在开始讲今天的内容之前,先问一个问题,使用int类型做加减操作是不是线程安全的呢?比如 i++ ,++i,i=i+1这样的操作在并发情况下是否会有问题?我们通过运行代码来看一下。public class AtomicDemo { public static void main(String[] args) throws InterruptedException { Data data = new Data

2021-09-01 13:07:29 271

原创 并发编程之:ThreadLocal

大家好,我是小黑,一个在互联网苟且偷生的农民工。从前上一期 并发编程之:synchronized 我们学到要保证在并发情况下对于共享资源的安全访问,就需要用到锁。但是,加锁通常情况下会让运行效率降低,那有什么办法可以彻底避免对共享资源的竞争,同时又可以不影响效率呢?答案就是小黑今天要和大家讲的ThreadLocal。ThreadLocal是什么?该类提供了线程局部 (thread-local) 变量。这些变量不同于它们的普通对应物,因为访问某个变量(通过其 get 或 set 方法)的每个线程都有

2021-08-31 13:36:32 171

原创 并发编程之:synchronized

大家好,我是小黑,一个在互联网苟且偷生的农民工。之前的文章中跟大家分享了关于Java中线程的一些概念和基本的使用方法,比如如何在Java中启动一个线程,生产者消费者模式等,以及如果要保证并发情况下多线程共享数据的访问安全,操作的原子性,使用到了synchronized关键字。今天主要和大家聊一聊synchronized关键字的用法和底层的原理。为什么要用synchronized相信大家对于这个问题一定都有自己的答案,这里我还是要啰嗦一下,我们来看下面这段车站售票的代码:/** * 车站开两个窗口同

2021-08-30 12:48:16 172

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除