JDK1.8特性之StringJoiner

JDK1.8中StringBuilder.append的正确使用与性能优化 字符串拼接是Java开发中的基础操作,其核心原理涉及JVM对字符串对象的处理机制。在JDK1.8环境下,编译器会对字符串连接操作进行自动优化,但开发者仍需理解StringBuilder的工作原理才能充分发挥其性能优势。StringBuilder通过可变字符数组实现高效拼接,相比直接使用+操作符能显著减少内存分配和垃圾回收压力,特别适合SQL拼接等高频字符串操作场景。在实际工程中,合理预分配容量、避免循环内重复创建对象等技巧可进一步提升性能。通过JMH基准测试可见,在长SQL和循环拼接场景下,正确使用Stri 阅读详情

StringBuilder、StringBuffer、String这三个的区别,很多文章都有在说。
这边也给大家做一个简要的概述

一:String、StringBuilder、StringBuffer

1:String

String类型是不可变对象,所以我们在每次对 String 类型进行改变的时候,其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象,不仅效率低下,而且大量浪费有限的内存空间,所以经常改变内容的字符串最好不要用 String 。
见源码:
在这里插入图片描述
final修饰符
修饰类:不能被继承,
修饰变量:表示该属性一旦被初始化便不可改变,这里不可改变的意思对基本类型来说是其值不可变,而对对象属性来说其引用不可再变。
修饰方法:说明这种方法提供的功能已经满足当前要求,不需要进行扩展,并且也不允许任何从此类继承的类来重写这种方法,但是继承仍然可以继承这个方法,也就是说可以直接使用。在声明类中,一个 final 方法只被实现一次。

2:StringBuffer

在使用 StringBuffer 类时,每次都会对 StringBuffer 对象本身进行操作,而不是生成新的对象,所以如果需要对字符串进行修改推荐使用 StringBuffer;线程安全

3:StringBuilder

StringBuilder是JDK1.5新增的,注意:不保证同步,该类的设计是用作在StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。如果可能,建议优先采用该类,因为在大多数实现中,它比 StringBuffer 要快。两者的方法基本相同。

4:StringBuffer和StringBuilder为什么可变

见String源码,我们发现
String对象的底层实际上是一个char[]数组:
如图一可见;
用final修饰的对象值可变,但是引用不变,即:value指向不可变,但是value[]数组的值可变,但因为有private关键字对其进行封装达到value[]数组值也不可变的目的

见StringBuffer源码
在这里插入图片描述
我们打开父类
在这里插入图片描述
可以清晰的看出StringBuffer的value[]没有被private final 修饰
那说明值是可以怎样的,可以被改变的哦。
我们接着看append方法是如何实现改变字符串的
在这里插入图片描述
然后进入super父类的方法
我们看看当前的源码
在这里插入图片描述
str.getChars()方法即是将str的所有字符拷贝到value[]的后面,返回的还是原来的value数组。
StringBuilder同理。
在这里插入图片描述

5:StringBuffer和StringBuilder区别

大家都知道StringBuffer是线程安全的,StringBuilder是非线程安全的

StringBuilder在 Java1.5 中被提出,它和 StringBuffer 之间的最大不同在于 StringBuilder 的方法不是线程安全的(不能同步访问)。
由于 StringBuilder 相较于 StringBuffer 有速度优势,多数情况下建议使用 StringBuilder 类。在应用程序要求线程安全的情况下,则必须使用 StringBuffer 类。

为什么StringBuffer是线程安全的呢?
见StringBuffer源码:
在这里插入图片描述
见StringBuilder源码:
在这里插入图片描述
是否出现了一个关键字synchronized,这个关键字大家都认识,这个关键字是为线程同步机制设定的;
这边大概举个例子,如果深究多线程的知识,自行学习
每一个类对象都对应了一把锁,当某个线程A调用类对象B中的synchronized方法C时,必须获得对象B的锁才能够执行C方法,否则线程A阻塞。一旦线程A开始执行C方法,将独占对象B的锁。使得其它需要调用B对象的C方法的线程阻塞。只有线程A执行完毕,释放锁后。那些阻塞线程才有机会重新调用C方法。这就是解决线程同步问题的锁机制。

当看到这个,一说到安全,那大家第一反应,那我就直接用StringBuffer就好了,多线程比StringBuilder安全,如果有多线程需要对同一个字符串缓冲区进行操作的时候,StringBuffer的确是首选。
这样是不是表明StringBuilder和String是不安全咯,String不可变的,线程对于堆中的一个String对象只能读取,不能修改。

注意:看源码我们发现StringBuilder是1.5出来的,说白点前身就是StringBuffer,不考虑线程安全,StringBuilder比StringBuffer效率高,StringBuilder应该是首选。另外,JVM运行程序主要的时间耗费是在创建对象和回收对象上。

6:String,StringBuffer,StringBuilder效率

接着我们看看String那要不要用
可以这样说,某些特别情况下, String 对象的字符串拼接其实是被 JVM 解释成了 StringBuffer 对象的拼接,所以某些时候 String 对象的速度并不会比 StringBuffer 对象慢,而特别是以下的字符串对象生成中, String 效率是远要比 StringBuffer 快的:

如同下面的情况
String str = “this”+“is”+“a”+“java”;
StringBuffer stringBuffer = new StringBuffer(“this”).append(“is”),append(“a”).append("java);

你会发现,生成str对象会很快,而stringBuffer却不快,因为JVM会自动解析str为
String str = “this”+“is”+“a”+“java”;
String str = “this is a java”;
注意:慢的是对象,就是来自另外的String对象,如下
String str1 = “this”;
String str2 = “is”;
String str3 = “a”;
String str4 = “java”;
这种情况JVM 会正常的按照原来的方式去做。

正常情况下,StringBuffer比String快。
因为StringBuffer有字符串缓冲区的概念。

7:总结三者区别

描述是否可变是否线程安全多线程或单线程操作字符串
StringString的值是不可变的,那每次对String的操作都会生成新的String对象,效率低下,且浪费大量优先的内存空间不可变
StringBufferStringBuffer是可变的,由于大量的方法用synchronized修饰,属于线程安全,任何对它指向的字符串的操作都不会产生新的对象。可变是多线程
StringBuilderStringBuilder是1.5引入的,非线程安全的,效率比StringBuffer高。任何对它指向的字符串的操作都不会产生新的对象。可变是单线程

如果我们在编译阶段能确定的字符串常量,完全没有必要创建String或StringBuffer、StringBuilder对象。可以直接的使用字符串常量的"+“连接操作效率最高。
StringBuffer对象的append效率要远远高于String对象的”+"连接操作。

大致了解了三者区别,具体涉及到class文件,这边没有多做概述,我们现在看看为什么有了StringBuilder,StringBuffer,JDK1.8引入了StringJoiner。

二:StringJoiner

我们经常拼接字符串,考虑线程安全我们就用StringBuffer,非线程安全我们就用StringBuilder。

现在JDK1.8拼接神器StringJoiner来了。
先上个例子:

StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(hi);
stringBuilder.append(",");
stringBuilder.append("python");
stringBuilder.append(",");
stringBuilder.append("i am java");
System.out.println(stringBuilder.toString());

重复拼接的逗号(,),看起来是不是很傻瓜式的样子,我们看看StringJoiner是如何做的。

StringJoiner stringJoiner = new StringJoiner(",");
 stringJoiner.add("hi");
 stringJoiner.add("python");
 stringJoiner.add("i am java");
  System.out.println(stringJoiner.toString());

我们直接见源码
首先观看构造方法
在这里插入图片描述
默认提供了两种构造方法,一个是需要传分隔符的,一个是需要传分隔符,前缀,后缀,我们清楚看到
this.emptyValue = this.prefix + this.suffix;
emptyValue 默认是前缀+后缀组成。

先解释下成员变量
prefix:拼接后的字符串前缀
delimiter:拼接时的字符串分隔符
suffix:拼接后的字符串后缀
value:拼接后的值
emptyValue:空值的情况,value为 null 时返回

看看它给我们提供了哪些可以公共调用的方法,
setEmptyValue 设置空值
在这里插入图片描述
toString 主要用于转换String
在这里插入图片描述
add 用于添加字符串
在这里插入图片描述
merge 从另外一个StringJoiner进行合并
在这里插入图片描述
length 长度
在这里插入图片描述
上面我们用到了add方法
见源码
在这里插入图片描述
在这里插入图片描述
StringBuilder,可以清晰的看到,底层还是根据StringBuilder进行封装的,看看多了一个prefix没有,首先它会先添加一个前缀。然后分隔符,字符串

看返回对象仍是StringJoiner,所以后面我们有需求,仍然可以用流式处理。

我们刚才模拟了分隔符,现在我们加上前后缀作为例子看看

StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("[“);
stringBuilder.append(hi);
stringBuilder.append(",");
stringBuilder.append("python");
stringBuilder.append(",");
stringBuilder.append("i am java");
stringBuilder.append("]“);

System.out.println(stringBuilder.toString());// [hi,python,i am java]


StringJoiner stringJoiner = new StringJoiner(",","[","]");// 参数一分隔符,参数二前缀,参数三后缀
 stringJoiner.add("hi");
 stringJoiner.add("python");
 stringJoiner.add("i am java");
  System.out.println(stringJoiner.toString());// [hi,python,i am java]

代码是不是很优雅

空值如何处理
// 构造方法1
 StringJoiner stringJoiner = new StringJoiner(",");
  System.out.println(stringJoiner.toString());
// 构造方法2
StringJoiner stringJoiner = new StringJoiner(",", "[", "]");

输出指定字符串
可以通过setEmptyValue 
 StringJoiner stringJoiner = new StringJoiner(",", "[", "]");
    stringJoiner.setEmptyValue("gaci");
    System.out.println(stringJoiner.toString());// gaci

三:String.join()

String.join() 主要针对 StringJoiner 又封装了一层的 API,也是Java1.8特性,可以传入动态参数或者迭代器。
见源码:
在这里插入图片描述
提供了两个方法:
动态参数
在这里插入图片描述
迭代器
在这里插入图片描述
仔细阅读之后,此API只能用于简单的拼接,不能添加前后缀以及空值处理。
System.out.println(String.join(",",“hi”,“python”,“i am java”));
在这里插入图片描述
的确方便了更多
使用拼间多个相同的分隔符时,使用 StringJoiner,简单处理使用 String.join() 也能完成;针对不同的场景使用不同的 API,这才是最佳最优雅的处理方式。

五:流式处理StringBuilder和StringJoiner

StringBuilder流式处理


final List<String> langs = Arrays.asList("java", "python", "php");

final String collectJoin = langs.stream().collect(Collectors.joining(", "));

StringBuilder:
final String collectBuilder =
    langs.stream().collect(Collector.of(StringBuilder::new,
        (stringBuilder, str) -> stringBuilder.append(str).append(", "),
        StringBuilder::append,
        StringBuilder::toString));

格式化输出:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4);
String num = numbers.stream()
    .map(i -> i.toString())
    .collect(Collectors.joining(", "))

StringJoiner是一种收集器,没有实现Collector接口。可以传递定界符,前缀和后缀之外,还可以使用StringJoiner调用Collectors.joining(CharSequence)从Stream创建格式化的输出。
当使用并行流时,这很有用,因为我们在某些时候,将需要并行处理的批处理,StringJoiner就发生了。

JDK 1.8(Java 8)新特性详解 Java 8(JDK 1.8)是Java发展史上的重要里程碑版本,发布于2014年3月。该版本引入了一系列革命性特性,主要包括:Lambda表达式和函数式接口支持函数式编程;方法引用简化代码;Stream API提供强大的流式数据处理能力;Optional类优雅处理空值;接口支持默认和静态方法;全新的java.time日期时间API;CompletableFuture改进异步编程;集合框架增强(如HashMap红黑树优化);新增Base64支持、Nashorn JavaScript引擎等。这些特性不仅提升了 阅读详情

相关推荐

在没有信用卡的情况下怎么申请谷歌云(Google Cloud)?

这笔额度足够用来跑一台云服务器、部署小型网站,甚至可以尝试 AI、机器学习等项目。但问题来了——想要拿到这 300 美元,你必须先通过支付方式验证。默认选项就是绑定一张国际信用卡(Visa、MasterCard 之类),然而不少人没有信用卡,或者信用卡无法支持国际支付,结果就卡在注册第一步。很多人会疑惑:既然是送额度,为什么还要绑卡?原因其实很简单:谷歌需要确认你是真实用户,而不是批量注册薅羊毛;通过支付验证,后续如果你用完 300 美元额度,可以直接进行付费使用;

m0_74824483的博客 5653

String、StringBuilder、StringBuffer 和 StringJoiner

在 Java 中,String、StringBuilder、StringBuffer 和 StringJoiner都是字符串操作类,用于处理字符串数据,它们有不同的特点和应用场景。StringBuilder:StringBuilder 是 Java 中的另一个类,它可以用于对字符串进行动态操作,即可在原始字符串对象的基础上直接修改字符串内容,而不是创建新的字符串对象。

记录java学习日常~ 930

core_analyzer分析c++程序内存占用

环境:centos; 进程:单进程多线程c++程序; 问题:1. 分析系统内存占用; 2. 分析ptmalloc内存空洞(bins上的空闲chunk的大小); 包括:1. 占用了很大内存的c++进程; 2. gcore(在进程不core dump的情况下生成core文件); 3. core_analyzer(分析gcor...

weixin_41644391的博客 4811

Java8的StringJoiner

Java StringJoiner的工具类

qq_37158147的博客 1334

OS实验xv6 6.S081 开坑

OS实验xv6 6.S081 开坑 终于把xv6 2019 6.S081做完了,网络部分没有写,因为有计网实验了。怎么说呢,xv6的坑有点多,能做完多亏了:和我同学ljj交流,参考RedemptionC老哥的博客(他写的非常详细,遗憾的是,他好像没有写mmap),再者就是参考这位老哥的做法(没有源码,写得不是特别详细,不过有借鉴作用,mmap就是借鉴了他的思想)……废话不多说了,直接开始。 实验指导 首推RedemptionC的博客 这位老哥的个人博客 xv6 6.S081官网(后面的实验都要参考官网

不定期更新系统使用、编程小技巧,哔哩哔哩账号:https://space.bilibili.com/399455629,欢迎关注 4493

解决屏幕不亮难题:慷智SerDes DE信号极性配置避坑指南

本文深入探讨了基于慷智AIM95x系列SerDes芯片的嵌入式显示系统开发中,因DE信号极性配置不匹配导致屏幕不亮的典型故障。文章详细解析了DE信号的核心作用与极性定义,提供了慷智SerDes芯片中DE极性寄存器的具体配置方法与调试记录,并给出了从隔离问题、对比时序到波形验证的系统性排查流程,帮助工程师快速定位并解决此类隐蔽问题。

weixin_29185493的博客 140

Java的StringJoiner

这段代码展示了如何使用 Java 的流(Streams)和以便将一个字符串列表连接成一个格式化的字符串。具体来说,它将水果名称列表转换为一个用逗号分隔的字符串,并在字符串的开头和结尾添加方括号。是一个非常实用的工具类,简化了字符串拼接的过程,特别是在需要添加分隔符、前缀和后缀时。它使得代码更清晰、可读,并提高了处理字符串的灵活性。

2302_81034736的博客 918

C语言编写Picard迭代和牛顿迭代法

为了完成学校计算方法的作业,花了两个多星期将所有实验报告编写出来,看到同桌找代码的辛苦,优快云也没有这类代码,我只是一时兴起,想分享我写的代码与大家共飨,有错误还请多多指正,代码都不难,也是为了让优快云帮我保存下,我辛辛苦苦做出来的,倘若能给别人带来一丝一毫的帮助,我都万分荣幸。 1:什么是Picard迭代 先弄一个满足f(x) = 0的函数将其转化为x= 正在上传… 重新上传 取消 ...

mohenxiang的博客 4699

java.util.StringJoiner类介绍

类是 Java 8 中引入的一个实用工具,用于将多个字符串连接成一个字符串,其灵感来自于其他编程语言中的类似工具。类提供了一种简单而灵活的方式来处理字符串的拼接操作。类不是线程安全的,如果有多个线程同时访问一个。类可以处理空值,你可以选择是否忽略空值。:你可以指定连接字符串时要使用的分隔符。:你可以指定连接字符串的前缀和后缀。实例,可能会导致不确定的结果。

qq_27390023的博客 373

HCIP-Cloud Service DevOps Engineer V2.0 华为认证云服务 DevOps高级工程师 章节测试题+结课测试题(模拟考试题)汇总

本文为HCIP-Cloud Service DevOps Engineer V2.0 华为认证云服务DevOps高级工程师 在线课程中所有章节测试以及结课测试(HCIP-Cloud Service DevOps Engineer模拟考试)习题和答案

gaogao0305的博客 2266

基于STM32、HAL库的MICRF112YMM-TR 无线收发器驱动程序设计

内部集成了 VCO、PLL、PA、LNA、混频器、滤波器等射频功能单元,极大减少了外部元件数量,降低了设计和布线难度。: 具有多种工作模式(睡眠、待机、接收、发射),待机电流极低,非常适合电池供电的物联网(IoT)设备。是 Microchip 公司生产的一款高性能、低功耗的单片 UHF ASK/FSK 收发器芯片。: 支持 ASK (幅移键控) 和 FSK (频移键控) 调制,适应不同应用需求。// 可以添加其他配置参数,如中心频率、数据速率等。智能家居(安防、遥控、传感)远程钥匙进入系统 (RKE)

corlin6688的博客 415

关于 Java 字符串拼接的几种方式以及性能比较

一、字符串拼接 字符串拼接是我们在Java代码中比较经常要做的事情,就是把多个字符串拼接到一起。 我们都知道,String 是 Java 中一个不可变的类,所以他一旦被实例化就无法被修改。 不可变类的实例一旦创建,其成员变量的值就不能被修改。这样设计有很多好处,比如可以缓存 hashcode、使用更加便利以及更加安全等。 但是,既然字符串是不可变的,那么字符串拼接又是怎么回事呢? 1...

游戏建模零基础入门教程 4862

14、微电网控制方法与建模分析

本文详细探讨了微电网的控制方法与建模分析,包括逆变器的小信号状态空间模型、网络模型、负载模型及其组合形成的完整微电网模型。通过对系统特征值和灵敏度因子的分析,揭示了不同模式与系统参数之间的关系。文章还提出了多个研究问题,如岛式系统控制器设计、风力发电控制、并网变换器控制等,为微电网的稳定性分析和优化控制提供了理论支持和实践方向。

elastic6hunter的博客 123

jdk1.8 新特性 StringJoiner的使用

StringJoiner是1.8版本的新加String辅助类 用StringBulider做分隔很繁琐 可以使用StringJoiner 使用StringBulider StringBuilder sb = new StringBulider(); IntStream.range(1,10).forEach(i->{ sb.append(i+""); if(i<10) sb.append(","); }) 这样的操作相对繁琐 使用StringJoiner StringJoiner sj = n

nanZhaiXiaoLang的博客 399

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

Java技巧 - 字符串拼接

【代码】Java技巧 - 字符串拼接。

子笙的博客 532

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

JAVA8新特性之StringJoiner

平时我们进行字符串拼接时,最常用的就是StringBuilder和StringBuffer了,但是在JDK 1.8+中,引入了一个字符串拼接神器:StringJoiner。

追寻心的步伐 499

JDK1.8新特性简单介绍与理解(上)

今天是大年初六了,明天就该开始2021年的coding之旅了,趁着过年放假的时候,我想着先整理一下Java的新特性,现在来说,我们在工作中用的最普遍的就是Java8了,因为从9开始就是收费版本了,但是我们学习的Java内容可能已经有点老了,一些新特性我们没有接触到,所以我就想着简单的介绍一下Java8的新特性,本人也是刚刚学习到的内容。 1.接口 在新版本下,接口中可以定义普通方法与静态方法。 我们在子类中调用 2.编码与解码 当我们需要一定安全性的时候,我们在进行保存的时候需要使用Base64进行编码

虚心学习,和气编码 459

StringJoiner学习和使用

StringJoiner学习和使用

泡^泡 412

JDK8字符串拼接的正确姿势

1. 对列表中的元素进行拼接 以前,对一个列表中的字符串进行拼接时,常见的代码如示例1所示: 代码示例1 List<String> ids = ImmutableList.of("1", "2", "3"); StringBuilder sb = new StringBuilder(); for (String id : ids...

dhu86380的博客 1258

JDK8——StringJoiner类和String的join方法

JAVA8——StringJoiner类 介绍 StringJoiner是Java8新出的一个类,用于构造由分隔符分隔的字符序列,并可选择性地从提供的前缀开始和以提供的后缀结尾。省的我们开发人员再次通过StringBuffer或者StingBuilder拼接。 StringJoiner sj = new StringJoiner(":", "[", "]"); sj.add("George").add("Sally").add("Fred"); String desiredString = sj.

这个人很懒,什么都没有留下。 564

jdk8中字符串拼接神器:StringJoiner

jdk8中字符串拼接神器:StringJoiner,取代使用StringBuffer类,可以添加前缀和后缀,使代码更简洁

dylan的博客 1136

【Java】StringJoiner

StringJoiner跟StringBuilder一样,也可以看成是一个容器,创建之后里面的内容是可变的。作用:提高字符串的操作效率,而且代码编写特别简洁,但是目前市场上很少有人用。因为它是从JDK8才出现的。他们之前一直在用用熟了就懒得改了。1、String:表示字符串的类,定义了很多操作字符串的方法2、StringBuilder:一个可变的操作字符串的容器。它可以帮助我们快速的去操作字符串。我们一般会用它的两个功能:拼接字符串、将容器里面的内容进行反转。

qq_39921135的博客 1044

JAVA基础 —— StringBuilder和StringJoiner

StringBuilder 以及StringJoiner 的概述、构造方法以及成员方法

hdakj22的博客 1411

Java知识【StringBuilder和StringJoiner】

StringBuilder和StringJoiner,字符串面试知识

日常学习总结 865

【从零开始学Java | 第四篇】StringBuilder与StringJoiner

本文介绍了Java中用于高效字符串拼接的StringBuilder和StringJoiner类。StringBuilder作为可变字符串容器,通过append()方法实现高效拼接,避免String不可变性带来的性能问题,支持链式调用和字符串反转等功能。StringJoiner则专为带分隔符的字符串拼接设计,可指定间隔符和首尾符号,简化如CSV或JSON数组格式的拼接操作。两者都能显著提升字符串处理效率,其中StringBuilder适用于循环拼接场景,StringJoiner更适合格式化拼接需求。

iting_0924的博客 505

java基础学习 day35(StringJoiner的用法,String和这两个扩展的区别)

StringJoiner概述 StringJoiner跟StringBuilder一样,也可以看成是一个容器,创建之后里面的内容是可变的。 作用:可以指定间隔符号,开始符号,结束符号,提高代码的编写效率。 出现时间:JDK8开始 StringBuilder的构造方法 public StringJoiner(“间隔符号”) //创建一个StringJoiner对象,指定拼接时的间隔符号 StringJoiner sj = new StringJoiner(“—”); sj.add(“1”).a

丿罗小黑的博客 1113
上一篇: Nacos(第一篇)_Springboot2.x+Nacos配置管理中心
下一篇: Java+CountDownLatch多任务处理优化
BugRoot
博客等级 码龄9年 9粉丝 50原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值