余声-个人博客


  • 首页

  • 分类

  • 归档

  • 标签

Stream

发表于 2024-09-10 | 更新于 2025-09-14 | 分类于 笔记
字数统计 | 阅读时长

Stream

Stream API的深入理解

Stream API是Java 8中引入的一个关键抽象概念,它允许你以声明性方式处理数据集合(包括数组等)。Stream通过一系列的操作(如筛选、转换、聚合等)来构建复杂的数据处理流水线。

特性及优点详解

  1. 无存储:Stream本身不存储数据,它只是数据源的一个视图。这意味着你可以对原始数据集合进行多次Stream操作,而不会改变原始数据。

  2. 为函数式编程而生:Stream API的设计符合函数式编程的范式,它鼓励使用不可变的数据和纯函数(即没有副作用的函数)。这使得代码更加简洁、易于理解和维护。

  3. 惰式执行:Stream上的操作是惰式执行的,这意味着只有在需要结果时才会执行操作。这有助于优化性能,因为它允许Stream API在可能的情况下延迟计算,直到真正需要结果为止。

  4. 可消费性:Stream只能被消费一次,一旦遍历过就会失效。这是为了保持流的不可变性,并防止在多个线程中同时修改流。

关键性操作

  • 流的创建:可以通过集合的stream()或parallelStream()方法、Stream.of()方法或Stream.Builder来创建流。

  • 中间操作:这些操作会返回一个新的流,并允许你进行链式调用。常见的中间操作包括filter()(筛选)、map()(转换)、flatMap()(扁平化映射)、sorted()(排序)、distinct()(去重)等。

  • 最终操作:这些操作会触发流的计算,并返回一个结果或副作用。常见的最终操作包括forEach()(遍历)、collect()(收集到集合)、reduce()(归约)、count()(计数)等。

示例分析

你给出的示例很好地展示了Stream API的使用场景。在这个示例中,你首先通过filter()筛选出非红色的球,然后通过map()将它们融化成随机的三角形,再通过另一个filter()筛选出非小的三角形,最后通过某种方式计算出剩余图形的周长。

这个示例展示了如何使用Stream API来构建一个复杂的数据处理流水线,并通过链式调用中间操作和最终操作来得到最终结果。

实际应用

Stream API在实际应用中非常有用,特别是在处理大型数据集时。它允许你以声明性方式编写代码,而不需要关心底层实现细节。此外,Stream API还支持并行处理,这使得它能够在多核处理器上更有效地利用计算资源。

总之,Stream API是Java 8中一个非常重要的特性,它极大地提高了Java程序员的生产力,并使得编写高效、简洁和易于维护的代码变得更加容易。

Stream

发表于 2024-09-10 | 更新于 2025-09-14 | 分类于 笔记
字数统计 | 阅读时长

Stream的并行流是如何实现的

Stream的并行流是如何实现的?

在Java中,Stream API提供了一种高效且声明式的方式来处理数据集合。并行流(parallel stream)是Stream API中的一个重要特性,它允许开发者利用多核处理器的并行处理能力来提高数据处理的效率。

  1. 获取并行流:

    • 使用Collection接口的parallelStream方法,或者通过Stream接口的parallel方法将顺序流转换为并行流。
  2. 底层实现:

    • 并行流底层使用了Java 7中引入的Fork/Join框架。
    • Fork/Join框架旨在将一个大任务分割(fork)成多个小任务,这些小任务可以并行执行,然后再将这些小任务的结果合并(join)成最终结果。
    • 这种分治策略非常适合处理可以递归分解的大规模计算任务。
  3. 执行方式:

    • 并行流通过并发运行的方式执行流的迭代及操作,从而充分利用多核处理器的性能。

ForkJoinPool和ThreadPoolExecutor的区别

ForkJoinPool和ThreadPoolExecutor都是Java中用于管理线程和并行任务的工具,但它们在实现方式和适用场景上有所不同。

  1. 实现方式:

    • ForkJoinPool:基于工作窃取(Work-Stealing)算法实现的线程池。它适用于处理可以递归分解的大规模计算任务。每个线程都有自己的双端队列(deque)来存储任务,当某个线程的任务队列为空时,它会从其他线程的队列中窃取任务来执行。
    • ThreadPoolExecutor:基于任务队列和线程池的实现。它适用于处理不同类型的任务,包括计算密集型、IO密集型和混合型任务。ThreadPoolExecutor允许更灵活的任务调度和线程管理。
  2. 适用场景:

    • ForkJoinPool:更适合处理可以递归分解的大规模计算任务,如排序、归并、搜索等。
    • ThreadPoolExecutor:适用于更广泛的场景,包括异步执行、定时执行和周期性执行等。
  3. 性能:

    • ForkJoinPool通过工作窃取算法来减少线程之间的空闲时间,提高CPU利用率,但在任务划分不均衡时可能导致线程饥饿。
    • ThreadPoolExecutor的性能取决于任务类型、线程数量和任务队列的配置。

总结

Stream的并行流是Java中处理大规模数据集合的高效工具,它底层使用了Fork/Join框架来实现并行处理。而ForkJoinPool和ThreadPoolExecutor则是Java中用于管理线程和并行任务的两种不同实现方式,它们在实现方式、适用场景和性能上有所不同。开发者应根据具体的应用场景和需求选择合适的工具来优化程序的性能。

微服务教程笔记

发表于 2024-09-01 | 更新于 2025-09-14 | 分类于 java
字数统计 | 阅读时长

CouponType 枚举类

public static CouponType convert(String code) {
    return Stream.of(values())
    .filter(bean -> bean.code.equalsIgnoreCase(code))
    .findFirst()
    .orElse(UNKNOWN);
}
  • 使用Long表示金额,金额通常以分为单位,比如100代表100分,比使用Double转 BigDecimal 有效

  • JPA支持一对多、多对多的级联关系,但是过深的级联层级带来的DB层压力可能在洪峰流量下太大,所以尽量减少级联配置,用单表查询取代;如果一个查询需要join多张表,最好的做法是通过重构业务逻辑来简化DB查询的复杂度;

思考:java动态更新枚举类;

  • stream 根据门店分组计算每个门店下商品价格(key=shopId,value=门店商品总价)
    public Map<String,Long> getTotal(List products){
    Map<String, Long> collect = products.stream()
    .collect(Collectors.groupingBy(x -> x.getProductId(),
    Collectors.summingLong(x -> x.getPrice() * x.getCount()))
    );
    return collect;
    }

InnoDB引擎的4大特性?

发表于 2024-02-22 | 更新于 2025-09-14 | 分类于 面试
字数统计 | 阅读时长

👌InnoDB引擎的4大特性?

插入缓冲(insert buffer)

插入缓冲(Insert Buffer/Change Buffer):提升插入性能,change buffering是insert buffer的加强,insert buffer只针对insert有效,change buffering对insert、delete、update(delete+insert)、purge都有效

只对于非聚集索引(非唯一)的插入和更新有效,对于每一次的插入不是写到索引页中,而是先判断插入的非聚集索引页是否在缓冲池中,如果在则直接插入;若不在,则先放到Insert Buffer 中,再按照一定的频率进行合并操作,再写回disk。这样通常能将多个插入合并到一个操作中,目的还是为了减少随机IO带来性能损耗。

二次写(double write)

Doublewrite缓存是位于系统表空间的存储区域,用来缓存InnoDB的数据页从innodb buffer pool中flush之后并写入到数据文件之前,所以当操作系统或者数据库进程在数据页写磁盘的过程中崩溃,Innodb可以在doublewrite缓存中找到数据页的备份而用来执行crash恢复。数据页写入到doublewrite缓存的动作所需要的IO消耗要小于写入到数据文件的消耗,因为此写入操作会以一次大的连续块的方式写入

在应用(apply)重做日志前,用户需要一个页的副本,当写入失效发生时,先通过页的副本来还原该页,再进行重做,这就是double write。

自适应哈希索引(Adaptive Hash index)

Adaptive Hash index属性使得InnoDB更像是内存数据库。该属性通过innodb_adapitve_hash_index开启,也可以通过—skip-innodb_adaptive_hash_index参数关闭;

Innodb存储引擎会监控对表上二级索引的查找,如果发现某二级索引被频繁访问,二级索引成为热数据,建立哈希索引可以带来速度的提升

经常访问的二级索引数据会自动被生成到hash索引里面去(最近连续被访问三次的数据),自适应哈希索引通过缓冲池的B+树构造而来,因此建立的速度很快。哈希(hash)是一种非常快的等值查找方法,在一般情况下这种查找的时间复杂度为O(1),即一般仅需要一次查找就能定位数据。而B+树的查找次数,取决于B+树的高度,在生产环境中,B+树的高度一般3-4层,故需要3-4次的查询。

innodb会监控对表上个索引页的查询。如果观察到建立哈希索引可以带来速度提升,则自动建立哈希索引,称之为自适应哈希索引(Adaptive Hash Index,AHI)。AHI有一个要求,就是对这个页的连续访问模式必须是一样的。

预读(read ahead)

InnoDB使用两种预读算法来提高I/O性能:线性预读(linear read-ahead)和随机预读(randomread-ahead)为了区分这两种预读的方式,我们可以把线性预读放到以extent为单位,而随机预读放到以extent中的page为单位。线性预读着眼于将下一个extent提前读取到buffer pool中,而随机预读着眼于将当前extent中的剩余的page提前读取到buffer pool中。

(1)线性预读(linear read-ahead)

方式有一个很重要的变量控制是否将下一个extent预读到buffer pool中,通过使用配置参数innodb_read_ahead_threshold,可以控制Innodb执行预读操作的时间。如果一个extent中的被顺序读取的page超过或者等于该参数变量时,Innodb将会异步的将下一个extent读取到buffer pool中,innodb_read_ahead_threshold可以设置为0-64的任何值,默认值为56,值越高,访问模式检查越严格例如,如果将值设置为48,则InnoDB只有在顺序访问当前extent中的48个pages时才触发线性预读请求,将下一个extent读到内存中。如果值为8,InnoDB触发异步预读,即使程序段中只有8页被顺序访问。你可以在MySQL配置文件中设置此参数的值,或者使用SET GLOBAL需要该SUPER权限的命令动态更改该参数。在没有该变量之前,当访问到extent的最后一个page的时候,Innodb会决定是否将下一个extent放入到buffer pool中。

(2)随机预读(randomread-ahead)

随机预读方式则是表示当同一个extent中的一些page在buffer pool中发现时,Innodb会将该extent中的剩余page一并读到buffer pool中,由于随机预读方式给Innodb code带来了一些不必要的复杂性,同时在性能也存在不稳定性,在5.5中已经将这种预读方式废弃。要启用此功能,请将配置变量设置innodb_random_read_ahead为ON。

MVCC解决的问题

发表于 2024-02-22 | 更新于 2025-09-14 | 分类于 面试
字数统计 | 阅读时长

👌MVCC解决了什么问题?

1.提高并发性

MVCC 允许多个事务同时执行读写操作,而无需互相阻塞或等待。这极大地提高了数据库的并发处理能力,特别是在高并发环境中。

2.减少锁争用

在传统的锁机制中,读写操作需要加锁,容易导致锁争用和死锁问题。MVCC 通过版本控制,使得读取操作不需要加锁,从而减少了锁争用的频率。

3.提供一致性视图

MVCC 为每个事务提供一个一致性的快照视图,使得事务在执行过程中看到的数据是固定的,不会受到其他并发事务的影响。这简化了应用程序的开发,因为开发者无需担心数据在事务执行过程中发生变化。

4.避免读写冲突

在 MVCC 中,读操作不会阻塞写操作,写操作也不会阻塞读操作。这避免了读写冲突,提高了系统的整体性能和响应速度。

5.减少死锁

由于读操作不需要加锁,MVCC 减少了死锁的可能性。死锁通常发生在多个事务互相等待资源释放的情况下,而 MVCC 的无锁读操作减少了这种情况发生的机会。

6.提高读性能

MVCC 提供了无锁的读操作,读操作直接读取数据的快照版本,不需要等待其他事务完成。这极大地提高了读操作的性能,尤其是在读操作频繁的场景下。

7.实现更高的隔离级别

MVCC 支持实现更高的隔离级别,如快照隔离(Snapshot Isolation),在这种隔离级别下,事务可以看到一个一致的快照视图,同时避免了脏读和不可重复读等问题。

假设有一个银行账户表accounts:

1
2
3
4
5
+----+--------+
| id | balance|
+----+--------+
| 1 | 1000 |
+----+--------+

场景 1:高并发读写

  • 事务 A:读取账户余额
  • 事务 B:更新账户余额

在传统的锁机制下,事务 A 和事务 B 可能会互相阻塞。然而在 MVCC 中:

  1. 事务 A 开始,读取balance = 1000。
  2. 事务 B 开始,更新balance为 1200。
  3. 事务 A 继续读取,仍然看到balance = 1000。
  4. 事务 B 提交后,新的事务可以看到balance = 1200。

这种情况下,事务 A 和事务 B 可以并发执行,互不影响。

场景 2:避免读写冲突

  • 事务 C:读取账户余额
  • 事务 D:更新账户余额

在 MVCC 中:

  1. 事务 C 开始,读取balance = 1000。
  2. 事务 D 开始,更新balance为 1500。
  3. 事务 D 提交后,新的事务可以看到balance = 1500。
  4. 事务 C 继续读取,仍然看到balance = 1000。

MVCC,读写并发,读写不冲突(读不加锁,读写不冲突)

dependencyManagement与dependencies的区别

发表于 2022-07-31 | 更新于 2025-09-14 | 分类于 java
字数统计 | 阅读时长
  • dependencyManagement
    • 用于父类的管理,一般写在顶层父类的pom.xml中
    • 只是做声明依赖,不做具体引入,只有在子项目中使用到是才会实现依赖
    • 子类声明了version,就用子类自己的,否则都继承父类的version和scope
  • dependencies
    • 默认被子类全部继承

日期类

发表于 2022-07-31 | 更新于 2025-09-14 | 分类于 java
字数统计 | 阅读时长
1
2
3
4
5
6
7
8
9
10
System.out.println(new Date());
System.out.println(new Date().getTime());
System.out.println(new DateTime());
System.out.println(new LocalDate());
Mon May 30 11:18:29 CST 2022
1653880709973
2022-05-30 11:18:29
2022-05-30
Mysql数据库存储日期dateTime(年月日时分秒)
Mysql数据库存储日期date(年月日)

Date获取7天后的日期

发表于 2022-07-31 | 更新于 2025-09-14 | 分类于 java
字数统计 | 阅读时长
1
2
3
4
5
6
7
1、 DateUtils.addDays();
2、 private static Date getAfterDay(Date date, int diff) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date == null ? new Date() : date);
calendar.add(Calendar.DATE, diff);
return calendar.getTime();
}

SpringSecurity+ oauth2实现同账号多端同时登录

发表于 2022-07-31 | 更新于 2025-09-14 | 分类于 java
字数统计 | 阅读时长

SpringSecurity+ oauth2实现同账号多端同时登录

参考链接:https://blog.csdn.net/m0_67391377/article/details/126509478
单点登录:https://mp.weixin.qq.com/s/DGFFPl93kZxS5G_DSFTBDA
多端登录:https://blog.csdn.net/zhourenfei17/article/details/88826911

shiro中的Realm如何使用

参考链接:https://blog.csdn.net/m0_54849873/article/details/124345270

shiro域(安全数据源)

shiro从Realm获取安全的数据(例如用户,角色,权限等)
SecurityManager需要进行身份验证就必须从Realm中获取到一个合法的用户身份,从而比较用户身份是否合法,同时在SecurityManager获取身份的同时Realm也需要维护一套用户身份用来判断用户是否能执行某项操作

cookie和session的区别

发表于 2022-07-31 | 更新于 2025-09-14 | 分类于 java
字数统计 | 阅读时长

cookie 和 session 的区别

localstorage 和cookie 的区别

  • 都可以用来做本地存储,实现数据的持久化,区别如下
    • localstroage存储的内容会多一点,5M;cookie存储的只有4k;
    • 有效时间不一样;cookie 的有效时间可以自行设置,local可以一直生效;
    • 请求时cookie可以被携带,同源的cookie信息会自动作为请求头的一部分发给服务端;local不会,一直存储在浏览器端

localstroage 和sessionstroage 的区别

  • 都是前端的本地存储(保存在客户端,不与服务器进行交互通信,存储数据的大小一样,只能存储字符串类型的数据)
    • 生命周期不同,local是永久的,除非主动删除;session的生命周期仅在当前会话下有效,在同源的窗口中始终存在的数据(只要浏览器的窗口没有关闭,即使刷新页面或者进入同源的另一个页面数据依旧存在,但在关闭浏览器窗口就会被销毁)

session 和sessionStroage 的区别

  • session主要的作用是维持会话状态的key,sessionStroage则是存储会话期间的数据

ftp问题

发表于 2022-07-31 | 更新于 2025-09-14 | 分类于 ERROR
字数统计 | 阅读时长
  • 问题 :FTP上传storefile一直返回false的解决,报500
    https://blog.csdn.net/LiHuiJUNMate/article/details/124257181
    https://blog.csdn.net/weixin_44901564/article/details/108062627

  • 553 550
    http://www.zzvips.com/article/226409.html+用户权限问题

javacv学习笔记

发表于 2022-07-31 | 更新于 2025-09-14 | 分类于 JavaCV
字数统计 | 阅读时长

java版opencv之Javacv各种场景使用案例

————————————————
版权声明:本文为CSDN博主「jwolf2」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_39506978/article/details/133251234

java opencv 基本操作6

https://blog.csdn.net/kan_Feng/article/details/126456760

js运行进制的梳理

发表于 2022-07-31 | 更新于 2025-09-14 | 分类于 前端
字数统计 | 阅读时长

参考连接:https://mp.weixin.qq.com/s/0tLxTybwJ7NCLBPtQClXoA

js运行进制的梳理

进程与线程

  • 两者区别
    • 简单来讲,能看到的就是进程,例如:资源管理器中的进程列表;看不到的就是线程;
    • 进程是cpu资源分配的最小单元(系统会给他分配资源,能拥有资源和独立运行的最小单位);
    • 线程是cpu调度的最小单位(线程是建立在进程的基础上的一次程序运行单位);

浏览器是多线程的,它包括哪些进程

  • Browser线程:浏览器的主线程,只有一个
  • 第三方的插件进程:每个类型的插件对应一个进程,使用时才会创建
  • GPU进程(最多一个,用于3D绘制等)
  • 浏览器渲染进程(浏览器内核) Renderer进程,每个tab页面一个进程:用于页面渲染、脚本执行、事件处理

为什么浏览器是多线程的

如果是单线程的,某个tab页面崩溃或者插件崩溃,就会影响到整个的浏览器

浏览器内核(渲染进程)多线程的

  • GUI渲染线程(渲染页面,解析html、css)
  • js引擎线程(js内核,处理js脚本程序,一个tab页面只有一个js线程来运行js程序)
  • GUI渲染线程和js线程是互斥的
  • 事件触发归属于浏览器,用于控制事件循环;js是单线程,事件队列中的任务都是排队等待js引擎处理
  • 定时触发器线程
  • 异步http请求线程

Browser进程和浏览器内核(Renderer进程)的通信过程

  • B进程收到用户请求,需要获取页面内容,随后将该任务通过RendererHost接口传递给Renderer进程;
    Renderer接口收到信息后,交给渲染线程(加载网页开始渲染网页,可能会使用到Brwerer进程获取资源或者GPU进程来帮助渲染-可能会有js线程操作DOM-最后Renderer进程将结果传递给Browser进程),Browser进程收到结果并绘制出来

浏览器内核线程之间的关系

  • GUI渲染线程和js引擎线程互斥
    • js是可以操作DOM的,如果在修改这个元素属性的同时渲染界面,那渲染线程前后获取的元素数据就不一样了;
  • js阻塞页面加载
    • 避免js执行实践过长,这样会造成页面的渲染不连贯,导致渲染加载阻塞,用户体验不佳
  • WebWorker,js的多线程?

Spring Joinpoint类注解

发表于 2022-07-31 | 更新于 2025-09-14 | 分类于 java
字数统计 | 阅读时长

Spring Joinpoint类注解

joinpoint是AOP 的连接点(一个连接点代表一个被代理的方法)
    静态连接点就是被代理的方法本身,可以直接通过getStaticPart方法调用,动态连接点就是对静态方法之外的增强方法;
    动态连接点从静态连接点的拦截器上获取静态部分,并进行加强,形成动态连接点;
    proceed() 方法得作用是:转到链的下一个拦截器上;
    getStaticPart() 方法的作用是:返回连接点的静态部分;静态部分是一个拥有连接器链的对象;(这个静态方法都要被谁拦截使用,可以通过该方法返回)

ReflectiveMethodInvocation类是joinpoint的实现类

    至此,proceed()方法解析完毕。我们来总结一下。
    首先要明确的一点就是一个连接点代表着一个对象里的一个方法。一个对象里的多个方法,就是多个连接点。每个连接点对象中,都存着一个拦截器链,proceed方法就是遍历拦截器链,如果和连接点所代表的方法一致,则执行MethodInterceptor的invoke方法,进行方法的代理,如果拦截器和代理方法不匹配,则进入下一个拦截器。直到都不匹配,则执行原始方法。

    代理对象的所有方法,都会形成一个连接点对象;

    由此可知,我们定义的方法,最终会封装为相应的MethodInterceptor对象,在连接点的proceed中被调用;而在连接点的拦截器中,已经封装好了连接点所代理方法MethodInterceptor;连接点直接使用拦截器进行方法的调用;

综合所述,连接点就是AOP中的最小单元,连接点里存放了代理对象的目标类,目标方法,方法拦截器;进行代理的时候,调用拦截器MethodInterceptor的加强方法,执行代理方法;

参考链接:https://blog.csdn.net/qq1309664161/article/details/120159606

Shiro之@RequiresPermissions注解原理详解

原理:使用了AOP进行了增强,来判断当前用户是否有该权限标识;
从proceed()方法进来,然后发送请求,进入断点,加强链上的AopAllianceAnnotationsAuthorizingMethodInterceptor元素就是加强@RequiresPermissions而生成的元素,该类实现了MethodInterceptor 接口,其中invoke方法就是对原对象方法的增强,进入方法,执行到了assertAuthorized()方法,调用其中的getMethodInterceptors()方法获取注解,若有则调用相应的注解Handler去处理相应的逻辑(就是调用Realm中定义的权限获取方法);
这样就对注解@RequiresPermissions的方法进行了增强

参考链接:https://blog.csdn.net/qq1309664161/article/details/123181245

springcloud中feign调用时token丢失问题

发表于 2022-07-31 | 更新于 2025-09-14 | 分类于 SpringCloud
字数统计 | 阅读时长
  • https://blog.csdn.net/weixin_39267497/article/details/119213250

Bean的拷贝

发表于 2022-07-31 | 更新于 2025-09-14 | 分类于 java
字数统计 | 阅读时长

bean 的拷贝

  • BeanUtils.copyProperties 基于反射实现,使用的浅拷贝,对于属性和方法要求较高,坑多,建议不使用;
  • 可以使用简单的get和set方法,如果属性过多,可以使用Mapstruct
  • Mapstruct 是在编译期期间就生成的bean属性复制的代码,不用在运行期间使用反射或者字节码技术,具有很高的性能;需要写一个接口ConvertMapper 和@Mapper注解实现;

报错

发表于 2022-07-31 | 更新于 2025-09-14 | 分类于 ERROR
字数统计 | 阅读时长

报错:Failed to start bean ‘documentationPluginsBootstrapper‘; nested exception is java.lang.NullPointe

  • 解决:https://blog.csdn.net/hadues/article/details/123753888

报错:springboot/cloud项目接口调用返回结果从json变为xml原因

  • 解决:https://blog.csdn.net/hmq1350167649/article/details/122615247

报错:java.net.SocketException: Software caused connection abort: recv failed

  • 解决:https://www.cnblogs.com/zhaochunhua/p/3593357.html

文件

发表于 2022-07-31 | 更新于 2025-09-14 | 分类于 java
字数统计 | 阅读时长
  • ftp实现文件上传下载
    FtpClient的方法:https://blog.csdn.net/weixin_43651188/article/details/100665484

问题总结

发表于 2022-07-31 | 更新于 2025-09-14 | 分类于 ERROR
字数统计 | 阅读时长

1.跨域问题 Cross-Origin Read Blocking (CORB) blocked cross-origin response
https://blog.csdn.net/Gemini_Kanon/article/details/114025078
2.跨域的请求在服务端会不会真正执行?
https://blog.csdn.net/qq_41720396/article/details/124702736
3.nginx实现跨域的原理:就是把前端项目和后端项目放在一个域中
https://blog.csdn.net/weixin_39860280/article/details/111647823
4.new File()会不会在本地创建文件(File类是对文件系统的映射,并不是硬盘上真实的文件)
https://blog.csdn.net/weixin_33994429/article/details/94455128

<i class="fa fa-angle-left"></i>1…1112

239 日志
22 分类
30 标签
GitHub
© 2025 javayun
由 Hexo 强力驱动
主题 - NexT.Gemini