![](https://img-blog.csdnimg.cn/20201014180756925.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
Java
文章平均质量分 64
Dylanioucn
想写一首关于世界的诗,以编程的方式~
展开
-
【二叉树前/先序DLR中序LDR后序LRD遍历及镜像翻转,so esay~】
二叉树的遍历方式,根据遍历根节点的顺序不同,分为三种:前序(先序)遍历(DLR)、中序遍历(LDR)、后序遍历(LRD);镜像反转【将二叉树的每个左右子树互换】原创 2022-04-17 21:42:16 · 1569 阅读 · 0 评论 -
逆序打印字符串的三种思路(StringBuilder.reverse()方法/从后往前倒序访问字符数组/前后交换字符数组元素)
逆序打印字符串的三种思路(StringBuilder.reverse()方法/从后往前倒序访问字符数组/前后交换字符数组元素)原创 2022-04-12 12:38:11 · 1355 阅读 · 0 评论 -
【每日一练及解题思路V2】给定一个字符串,找出其中不含重复字符的最长子串的长度
从左到右遍历字符串的每个字符,找到每个字符所能组成的不包含重复字符的子串,然后比较这些子串的长度,取其中最大的那一个即是所要找的不含重复字符的最长子串。原创 2022-04-09 12:56:10 · 1083 阅读 · 0 评论 -
【每日一练及解题思路V1】给定一个字符串,找出其中不含重复字符的最长子串的长度
给定一个字符串,找出其中不含重复字符的最长子串的长度原创 2022-04-08 16:27:43 · 1176 阅读 · 0 评论 -
Oracle java官网关于可重入读写锁ReentrantReadWriteLock的解析
Oracle java官网关于可重入读写锁ReentrantReadWriteLock的解析1.[原文链接](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/ReentrantReadWriteLock.html)2.与ReadWriteLock的关系3.这个类有以下特性:1).Acquisition order(获取顺序)2).Reentrancy(可重入性)3).Lock downgrading(锁降级)4).In原创 2022-04-08 12:22:30 · 1107 阅读 · 0 评论 -
Oracle Java官网关于不可变对象的解析
Oracle Java官网关于不可变对象的解析一、Immutable Objects(不可变对象)1. 原文url2. 原文翻译二、A Synchronized Class Example(一个同步类的例子)1. 原文url2.原文代码3. 原文翻译三、A Strategy for Defining Immutable Objects(定义不可变对象的策略)1.原文url2.原文翻译3.原文代码一、Immutable Objects(不可变对象)1. 原文url https://docs.oracle原创 2022-04-07 22:17:35 · 701 阅读 · 0 评论 -
Oracle Java官网关于生产者消费者的示例解析
通过模拟现实生活中一边生产一遍消费的场景,来说明:通过给方法加锁、轮询条件是否满足、以及适时地协调线程间通信(wait/nofity)的方式,可以确保多线程间能够以一种正确且高效的方式访问共享资源原创 2022-04-07 12:22:26 · 2414 阅读 · 2 评论 -
synchronized与lock在原理、用法、是否阻塞、是否可响应中断、是否有超时机制、是否公平、是否支持并发读、可重入等方面的对比分析
synchronized与lock在原理、用法、是否阻塞、是否可响应中断、是否有超时机制、是否公平、是否支持并发取、可重入等方面的对比分析原创 2022-04-04 11:49:12 · 1624 阅读 · 1 评论 -
13行代码实现两个线程交替打印1-100内的整数(不加锁、递加取余判断),欢迎来挑战~
13行代码实现两个线程交替打印1-100内的整数,核心代码如下: private static int step = 0; public static void task(int max,int remainder){ while(step<=max) { if(step%2==remainder) System.out.println(Thread.currentThread().getName() + step++);原创 2022-01-14 21:03:22 · 230 阅读 · 0 评论 -
如何玩转序列化 反序列化 Serializable transient serialVersionUID
一、⭐⭐⭐什么是序列化和反序列化????????????序列化:通过IO字节流的方式,将jvm内存中的Java对象转换为另外一种格式持久存储下来(记录到文件里、存储到数据库里、上传到网络,本文采用的是记录到文件里);反序列化:通过IO字节流的方式,将被持久化的特定格式的Java对象反序列化还原出来。二、⭐⭐⭐序列化和反序列化的使用要点????????????1. 序列哈反序列化要先实现 Serializable 接口;2. transient不参与序列化 ;3. static修饰的属性不参与序列原创 2021-04-24 18:29:45 · 2015 阅读 · 0 评论 -
让星星⭐月亮告诉你,Thread.join底层源码到底是如何实现插队功能的?(synchronized+while(isAlive)+wait(0))
⭐⭐⭐解析Thread.join底层源码,分析如何保证调用它的线程实现插队功能????????????1、Thread.join方法加了synchronized关键字,为了和后面的wait(0)搭配使用;2、使用while循环检测调用join方法的插队线程是否还在运行,若还在运行,就调用wait(0)方法,假装释放锁后去排队了,其实时间参数传入的是0,也就是没去排队,还会继续循环执行这套逻辑;3、直到调用join的插队线程执行完毕die了,才会从循环中跳出,这时才算插队结束,才会回到被插队的线程中继续原创 2021-04-11 23:18:57 · 184 阅读 · 0 评论 -
线程交替执行的几种方法(递加求余判断/环形链表步进/LockSupport/synchronized/ReentrantLock/CountDownLatch/循环屏障/信号量)
线程交替执行的几种方法(累加求余判断/环形链表步进/LockSupport/synchronized关键字/ReentrantLock可重入锁/CountDownLatch倒计时门闩/CyclicBarrier循环屏障/Semaphore信号量)原创 2021-04-11 22:58:29 · 860 阅读 · 2 评论 -
让星星⭐月亮告诉你,为啥就只加了一个static就让程序连最简单的+1操作都不会了?究竟实例变量和静态变量之间藏着什么秘密?
零、前情提要????????????实例变量(也称成员变量),在类的实例对象被创建时,会先按照实例变量的先后顺序被赋初始默认值,然后再按照实例赋值语句先后的顺序进行实例变量的赋值操作,最后执行构造方法。静态变量(也称类变量),在类初始化的时候,会先按照静态变量的先后顺序被赋初始默认值,然后再按照静态赋值语句先后的顺序进行静态变量的赋值操作。这里还搞不大清楚没关系,让我们来演示推敲一番:一、⭐⭐⭐实例变量版本演示代码????????????class InstanceObj{ public st原创 2021-04-07 18:08:42 · 106 阅读 · 0 评论 -
如何配置eclipse的JVM运行参数-Xms10m -Xmx10m
一、⭐⭐⭐使用场景????????????当想测试一些需要触发垃圾回收的场景时,可以通过配置eclipse的jvm运行参数的方式,限定内存的大小,从而达到效果二、⭐⭐⭐配置步骤????????????1、右键你的项目工程2、点击Run AS3、点击Run Configurations…4、点击Java Application5、选择要调试运行的类6、点击Arguments这个tab页7、在VM arguments里添加要配置的jvm参数8、点击Apply9、点击Run三、⭐⭐⭐步骤截原创 2021-04-06 19:24:52 · 3045 阅读 · 0 评论 -
让星星⭐月亮告诉你,强软弱虚引用类型对象在内存足够和内存不足的情况下,面对System.gc()时,被回收情况如何?
一、⭐⭐⭐工具????????????Eclipse+JDK1.8注:测试前需配置eclipse的JVM运行参数:-Xmx10m -Xms10m(如何配置eclipse的JVM运行参数),只分配10M的内存。因为会使用创建指定大小字节数组的方式,来触发内存临界值(10M),进而观察内存足够和不足两种场景下不同引用类型的具体表现。二、⭐⭐⭐概念????????????1 强引用类型强引用类型的对象无特定类型,硬气!宁折不弯,即便在内存不足报OutOfMemmoryError(OOM)的情况下,也不肯原创 2021-04-06 19:06:28 · 419 阅读 · 2 评论 -
使用完全注解的方式进行AOP功能实现(@Aspect+@Configuration+@EnableAspectJAutoProxy+@ComponentScan)
1、简单介绍如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP,如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换.2、注解说明@Configuration//用于定义配置类,可替换xml配置文件@EnableAspectJAutoProxy(proxyTargetClass=true) //开启AspectJ 自动代理模式,如果不填proxyTargetClass=true,默认为false(代表即便你配置了@EnableAsp原创 2021-04-05 13:04:32 · 1216 阅读 · 6 评论 -
让星星月亮告诉你,通过反射创建类的实例对象,并通过Unsafe theUnsafe来修改实例对象的私有的String类型的成员属性的值
首先,了解一些Unsafe这个类,这个类可以直接进行内存级别的相关操作(如分配释放内存、修改指定内存地址的值等),这里主要介绍的是用它的theUnsafe私有成员属性来修改指定内存位置的值。流程如下:一、 获取Unsafe theUnsafe属性1、 通过反射获取Unsafe.class的theUnsafe属性(可以用它来进行内存操作,这里主要是用它来修改指定内存位置的值)2、 将属性访问权限放开因为该属性是私有属性,本来外部是无法直接访问的,如果不把属性访问权限放开,则无法获取属性,在执行f.g原创 2021-04-04 19:01:46 · 417 阅读 · 2 评论 -
让星星⭐月亮告诉你,eclipse java连接mysql8.0遇到的JDK版本驱动时间相关报错及解决方法
驱动相关报错:Loading class com.mysql.jdbc.Driver'. This is deprecated. The new driver class iscom.mysql.cj.jdbc.Driver’. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.解决方法:应该用com.mysql.cj.jdb原创 2021-03-25 22:48:52 · 249 阅读 · 2 评论 -
让星星⭐月亮告诉你,(饿汉式3种【直接实例化\枚举\静态代码块】+懒汉式5种【从普通到DCL演进4种、静态内部类】)单例模式详解
一、概述:单例模式:某个类在整个系统种只能有一个实例对象可被获取和使用的代码模式,提供一个全局唯一的类的实例对象给外部调用,例如:代表jvm运行环境的Runtime类。要点如下:1、保证类只有唯一一个实例对象:则要求存储该实例对象的是一个静态变量;2、保证只能在该类的内部创建实例对象,其他地方不允许创建:则要求该类的构造器私有化;3、保证外部能访问获取到这个唯一的实例对象:1)直接暴露public2)提供静态变量的get方法。4、根据创建对象时机的不同,分饿汉式和懒汉式:1)饿汉式:还没等原创 2021-03-25 22:37:34 · 177 阅读 · 1 评论 -
让星星⭐月亮告诉你,(示例实战)当我们在说递归和迭代时,到底在说什么? 算法编程题:有n步台阶,一次只能上1步或2步,共有多少种走法?
编程题:有n步台阶,一次只能上1步或2步,共有多少种走法?1.递归 recursion 自己调自己,注意方法出口,频繁入栈出栈比较耗时,可能会导致栈溢出2.迭代 iteration 比较高效推导过程:n=1 [1] f(1)=1n=2 [1,1] [2] f(2)=2n=3 [1,1,1] [1,2] [2,1] f(3)=3n=4 [1,1,1,1] [1,1,2] [1,2,1] [2,1,1] [2,2] f(4)=5n=5 [1,1,1,1,1] [1,1,1,2] [1,1,2,1原创 2021-03-25 22:28:29 · 82 阅读 · 0 评论 -
让星星⭐月亮告诉你,(示例实战)enum枚举类九大特性详解
枚举类:1、Java枚举是一个特殊的类,一般表示一组常量,比如一年的四个季节,一年的12个月份,一星期的7天,方向有东西南北等;2、Java枚举类用enum关键字来定义,各个常量使用逗号,来分割;3、每个枚举都是通过Class在内部实现的,且所有的枚举值都是public static final的。比如:enum Color{RED,GREEN,BLUE}以上枚举转化为在类内部实现:class Color{public static final Color RED = new Color(原创 2021-03-25 22:25:14 · 106 阅读 · 0 评论 -
让星星⭐月亮告诉你,(讲解+示例实战)方法参数的传递机制(值传递及地址传递)以及String类的对象的不可变性
1、方法参数的传递机制①形参是基本数据类型:传递数据值②形参是引用数据类型:✦传递地址值;✦特殊类型:String、包装类对象的不可变性。2、String、包装类的对象的不可变性示例代码如下,执行结果应该是:jvm.Person@15db974200hjysetNameclass Person{ String name; Person(){ System.out.println(this); } public void setName(){ this.name = "原创 2021-03-25 22:22:53 · 103 阅读 · 0 评论 -
(加深理解)类初始化及实例对象初始化顺序
1、类初始化过程①一个类要创建实例需要先加载并初始化该类 ✦main方法所在类需要先加载和初始化②一个子类要初始化需要先初始化父类③一个类初始化就是执行<cinit>()方法 ✦<cinit>()方法由静态类变量显示赋值代码和静态代码组成 ✦静态类变量显示赋值代码和静态代码从上到下顺序执行 ✦<cinit>()方法只执行一次 ✦静态代码块只有在被第一次调用的时候才执行,且只执行一次2、实例初始化过程①实例初始化就是执行&l...原创 2021-03-25 22:14:41 · 350 阅读 · 0 评论 -
让星星⭐月亮告诉你,(局部变量表、操作数栈)当我们在执行i=i++及i++时,底层到底在执行什么?
遇到一个比较有意思的题目,看上去很简单,实际运行起来却不是那么回事了。会发现i=i++和i++两者运行结果居然不一样!主要是没理解清楚java方法执行时,局部变量和操作数栈的分配运行机制,这就分享给大家分析过程:public class AutoIncrement { public static void main(String[] args) { int i = 0; i++;//相当于i=i+1; /* 步骤说明: 1、将局部变量i的值0 load到操作数栈 局部变量 i原创 2021-03-25 22:10:52 · 146 阅读 · 0 评论 -
让星星⭐月亮告诉你,本地验证webservice接口demo项目(包含客户端服务端,支持请求参数为字符串返回结果为xml、请求参数为xml、请求被服务端屏蔽的接口三种场景)
1.背景:有些第三方客户可能对外提供的是webservice接口,而非Restful风格http接口。在无法连到第三方客户的环境里进行实地验证的情况下,为了尽可能地减少上线部署时的风险,最好能先在本地对接口进行充分的验证。故编写了这个可以在本地验证webservice接口的demo项目,以便在对接webservice接口时进行本地验证调试。此demo里包含***请求参数为字符串返回结果为xml***、请求参数为xml、***请求被服务端屏蔽的接口***三个案例演示。此demo包含服务端、客户端及公共工原创 2021-02-05 22:03:17 · 254 阅读 · 4 评论 -
让星星⭐月亮告诉你,Java二叉查找树的基本实现
二叉树可分为满二叉树、完全二叉树、平衡二叉树(二叉查找树)、最优二叉树(哈夫曼树),此篇代码实现的是二叉查找树(左右子树深度之差的绝对值不超过1待实现)。package unittest;import java.util.Arrays;class Person implements Comparable<Person>{ private String name; private int age; Person(String name,int age){ this.name =翻译 2020-07-29 14:27:07 · 121 阅读 · 0 评论 -
让星星⭐月亮告诉你,Java之ThreadLocal
package unittest.jdk8newfeature;class Message{String info;public String getInfo() {return info;}public void setInfo(String info) {this.info = info;}}class Channel{private final static ThreadLocal THREADLOCAL = new ThreadLocal();public static vo翻译 2020-07-28 21:24:26 · 133 阅读 · 0 评论 -
让星星⭐月亮告诉你,HashMap中红黑树TreeNode的split方法源码解读
PS:由于文档是我在本地编写好之后再复制过来的,有些文本格式没能完整的体现,故提供下述图片,供大家阅览,以便有更好的阅读体验:HashMap中红黑树TreeNode的split方法源码解读分析HashMap$TreeNode(既是树又是链表)的split方法的源码,会发现主要分两部分操作:数据从旧数组转移到新数组上来時,旧数组上的数据会根据(e.hash & oldCap) 是否等于0,重新rehash计算其在新数组上的索引位置,分成2类:① 等于0时,则将该树链表头节点放到新数组时原创 2020-06-20 15:04:30 · 1296 阅读 · 2 评论 -
让星星⭐月亮告诉你,HashMap中保证红黑树根节点一定是对应链表头节点moveRootToFront()方法源码解读
红黑树根节点若不为其对应链表的头节点,则按照下述步骤的处理,将根节点向前移动到头节点:将根节点从所在链表中删除,即链表的删除操作:修改根节点的前后节点的指向即可,即将根节点的上一节点的下一节点设置为根节点的下一节点,将根节点的下一节点的上一节点设置为根节点的上一节点。将根节点所在链表的头节点位置的值设置为根节点;将现有头节点的上一个节点设置为根节点,将根节点的下一个节点设置为现有头节点,将根节点的上一个节点设置为null.具体源码如下:/**HashMap$TreeNode的moveRootT原创 2020-06-09 23:45:42 · 432 阅读 · 0 评论 -
HashMap扩容时的rehash方法中(e.hash & oldCap) == 0算法推导
HashMap在扩容时,需要先创建一个新数组,然后再将旧数组中的数据转移到新数组上来此时,旧数组上的数据就会根据(e.hash & oldCap) 是否等于0这个算法,被很巧妙地分为2类:① 等于0时,则将该头节点放到新数组时的索引位置等于其在旧数组时的索引位置,记未低位区链表lo开头-low;② 不等于0时,则将该头节点放到新数组时的索引位置等于其在旧数组时的索引位置再加上旧数组长度,记为高位区链表hi开头high.具体,详见下述的算法推导解析:算法:(e.hash & old原创 2020-06-08 15:50:53 · 10212 阅读 · 33 评论 -
让星星⭐月亮告诉你,HashMap在put数据时是如何找到要存放的位置的?
初印象:初识HashMap时,知道HashMap是用来存放Key-Value这样的键值对的,也知道HashMap的底层数据结构是:数组+链表+红黑树,且数组长度为2的x次幂。疑问:那么往HashMap中添加键值对时,是什么决定了键值对的存放位置呢?即存放位置是如何计算出来的呢?相同的疑问可能还会以下面的问题描述方式提出来:其他描述方式:1.向HashMap中put数据时,数据是如何找到HashMap中Node<K,V>[] table数组的对应索引下标位置的?2.HashMap在put&原创 2020-06-03 23:26:33 · 2125 阅读 · 0 评论 -
让星星⭐月亮告诉你,HashMap的resize()即扩容方法源码解读(已重新完善,如有不足之处,欢迎指正~)
分析HashMap的resize()即扩容方法的源码,会发现主要分两部分操作:为创建新数组初始化新数组容量和新数组扩容阈值;创建新数组后,需将旧数组数据转移到新数组上来具体,详见下述的源码解析:/**HashMap的resize()方法*//** * Initializes or doubles table size. If null, allocates in * accord with initial capacity target held in field thr原创 2020-06-02 23:57:16 · 229 阅读 · 4 评论 -
让星星⭐月亮告诉你,对Java总体认知(摘抄自《深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)》)
Java概述:Java不仅仅是一门编程语言,它还是一个由一系列计算机软件和规范组成的技术体系,该技术体系提供了完整的软件开发和跨平台部署的支持环境,并广泛应用于嵌入式系统、移动终端、企业服务器、大型机等多种场合。时至今日,Java已经吸引超过600多万的软件开发者,这是全球最大的软件开发团队。而且使用Java的设备数量已经超过了45亿部。其中有8亿多台个人计算机、21亿部移动电话和其他手持设备,35亿个智能卡、以及大量机顶盒、导航系统和其他设备。Java优点:Java之所以能收到如此广泛的认可,不仅仅翻译 2020-06-01 22:32:36 · 146 阅读 · 0 评论 -
让星星⭐月亮告诉你,HashMap的put方法源码解析及其中两种会触发扩容的场景(足够详尽,有问题欢迎指正~)
分析HashMap的put方法的源码后发现,HashMap的扩容方法在两个场景下会被调用:初始化HashMap的链表数组时,会被调用,用来初始化链表数组的初始容量为16,以及初始化链表数组的阈值为初始容量16*负载因子0.75=12;当put到HashMap存储的元素个数超过阈值时,会被调用,用来将链表数组的容量和阈值都扩大为原来的2倍。具体,详见下述的源码解析:/*HashMap的put方法,实际上调用的是putVal方法/public V put(K key, V value) {原创 2020-06-01 16:53:21 · 267 阅读 · 0 评论 -
让星星⭐月亮告诉你,Java冒泡排序及其时间复杂度计算
@author Dylaniou2020-05-28 21:21冒泡排序算法:第一轮冒泡排序:第一次拿数组的第1位和第2位进行比较,若第1位大于第2位,则将两者的值交换,再继续拿交换后的第1位与第3位进行比较,若第1位大于第3位,则将两者的值交换,然后再继续拿交换后的第1位与后续位进行比较,直到第1位与后续所有位置都比较完毕,最后会发现第一轮冒泡排序的最终结果是把最小值放到了第1位;第二轮冒泡排序:因为第一轮已经把最小值放到了第1位,则第二轮应该从第2位开始第一次拿数组的第2.原创 2020-05-28 23:11:18 · 1278 阅读 · 0 评论 -
让星星⭐月亮告诉你,LinkedList和ArrayList底层数据结构及方法源码说明
一、LinkedList(同时实现了List接口和Deque implements Queue接口)1.LinkedList底层数据结构是一个双向链表(每个节点除了本身元素外,还包含了要指向的前一个节点Node prev和后一个节点Node next),双向链表还记录了头节点Node first和尾节点Node last.2.链表的数据结构在逻辑上是连续的,但是在物理空间上是不连续的(因此,索引下标和头元素存放的物理内存地址是不相关的,所以不能根据索引下标直接获取到元素,需要循环遍历);3.Linke原创 2020-05-21 20:57:55 · 928 阅读 · 0 评论 -
让星星⭐月亮告诉你,2的n次幂与二进制位全为1之间的联系,为啥只差一个1
现象:2^3 = 8 = (1+2+4) +1 =(20+21+2^2)+1 即23-1=(20+21+22)2^4 = 16 = (1+2+4+8) +1 =(20+21+22+23)+1 即24-1=(20+21+22+2^3)观察上述现象,可以发现2^n次幂等于2的0次幂到2的(n-1)次幂的所有值相加后再加1.而2的0次幂到2的(n-1)次幂是连续的,对应到二进制的位里面,就全是连续的1111*111啦,在HashMap中计算数组下标时,就利用到了这一特性:数组长度为2^n(通过HashMa原创 2020-05-21 11:21:44 · 989 阅读 · 0 评论 -
让星星⭐月亮告诉你,HashMap之tableSizeFor(int cap)方法原理详解(分2的n次幂和非2的n次幂两种情况讨论)
方法说明:HashMap的tableSizeFor(int cap)方法,可以返回一个大于或等于给定cap值的2的n次幂的数值. /** * Returns a power of two size for the given target capacity. */ static final int tableSizeFor(int cap) { int n = cap - 1; //第一点:这里减1,是为了保证本身已经是2的n次幂的情形下(2^3原创 2020-05-21 11:08:47 · 455 阅读 · 0 评论 -
让星星⭐月亮告诉你,HashMap底层数据结构及其增put删remove查get方法的代码实现原理
1.HashMap底层数据结构是数组+链表(jdk1.7头插法<扩容时链表逆序可能会导致环形链表的问题出现> jdk1.8尾插法)+红黑树(jdk1.8).2.HashMap中数组的容量默认为16,负载因子默认为0.75,当数组的0-15个下标里有160.75=12个被使用时,且HashMap中存储的元素总个数大于64时,则发生扩容操作,数组的容量扩大为原来的2n.3.负载因子代表数组中存储数据密度的大小:负载因子越大,数组单位容量内存储的数据越多,不同元素之间(key不同,但计算得到的数组原创 2020-05-21 09:20:03 · 345 阅读 · 0 评论 -
让星星⭐月亮告诉你,LinkedList和ArrayList(指定位置/头尾增加删除)
代码执行结论:/*现象:LinkedList在指定位置采用add(index,data)方式增加数据时,位置越靠前耗时越少,越靠后耗时越多(而ArrayList采用add(index,data)方式的耗时跟位置关系不大);原因:虽说LinkedList底层属于链表数据结构,不需要开辟一块连续的内存地址空间,逻辑上连续即可,在新增、插入和删除操作上占优势(只需要修改节点的前后指向即可,不需要移动数据);但是因为LinkedList在插入时需要移动指针到指定节点, 才能开始插入,一旦要插入的位置比较远,原创 2020-05-08 18:08:28 · 3222 阅读 · 2 评论