最新【Java 基础语法】万字解析 Java 的 String 类,分布式技术面试大厂真题30讲

总结

我们总是喜欢瞻仰大厂的大神们,但实际上大神也不过凡人,与菜鸟程序员相比,也就多花了几分心思,如果你再不努力,差距也只会越来越大。

面试题多多少少对于你接下来所要做的事肯定有点帮助,但我更希望你能透过面试题去总结自己的不足,以提高自己核心技术竞争力。每一次面试经历都是对你技术的扫盲,面试后的复盘总结效果是极好的!

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

str1 = "Hello World" 其实是将 str1 这个引用指向了一个新的 String 对象,即上述代码的整个过程可以理解为这个图在这里插入图片描述

3.11 情况十一:


public static void func(String str1){

str1=“abc”

}

public static void main(String[] args){

String str = “Hello Java”;

func(str);

System.out.println(str == “Hello Java”);

}

结果其实还是:true,这是为啥呢?

这个其实和情况十是一种情形,虽然加了个函数,但函数里的形参的引用是指向实参引用的地址,然后将形参指向一个新的对象,对实参其实没有影响

介绍了这么多种情况我们再回顾下 == 和 equals 的用法吧!

3.12 == 和 equals


String 使用 == 比较并不是在比较字符串的内容,而是比较两个引用是否指向同一个对象(即引用值)

这两种有什么不同吗?

面向对象编程语言中,涉及到对象的比较有三种方式:比较身份(即比较引用值)、比较值、比较类型

一般编程语言中 == 是用来比较值的,但是 Java 中是用来比较身份的(不需要记,看内存的存储就行)

比较值我们好理解,那么这个身份什么意思呢?我们来看下面一张图在这里插入图片描述

诶对,大魔王现在去取快递,它的快递就放在那个红框框里。

我们可以把那个柜子的位置看看成“第二行,从左数第四个”或者是“第二行,从右数第第三个”,由于这两个位置都指向一个柜子,所以就表示身份相同,是我大魔王装快递的柜子

我们也可以在“第一行从左数第一个”柜子和“第一行从左数第二个“柜子都放入同样的物品,虽然它们不是同一个柜子,但是打开都是相同的物品,这就叫值相同,但是这

大家可以自细细感悟下,并且我们还能得到这样的结论:身份相同值一定相同,值相同身份不一定相同

因此比较字符串的时候,如果我们用 == 比较,可能明明它们的对象其实都是同一个字符串,但因为引用值的不同使结果出现错误。

故我们就要使用 equlas 去比较字符串,因为它是比较引用所指向的对象

注意:

当我们使用 equals 去比较字符串的时候,这样写代码要注意

String str1 = null;

String str2 = “abc”;

System.out.println(str1.equals(str2));

上述代码会抛出 java.lang.NullPointerException 异常,所以我们要注意 str1 的引用是非为空,故最好直接使用字面常量字符串的形式去比较,例如

String str1 = “abc”;

String str2 = “abc”;

System.out.println(“abc”.equals(str2));

4. 理解字符串不可变

===============================================================================

4.1 分析


字符串是一种不可变的对象,它的内容不可以改变

定义 String 类中的数组我们其实可以看到它是被 final 修饰的,无法修改

这是什么意思嘞,我们先看一段代码

String str = "hello ";

str += “java”;

str += “!!!”;

System.out.println(str);

结果是:"hello java!!!" ,就是你会感觉好像字符串被修改了对吧,就像是小时候的神奇宝贝进化一样,本来是小火龙,后来变成火恐龙,最好进化成喷火龙。始终都是这一只,但小火龙进化后,原本的小火龙就没有了

在这里插入图片描述

但是字符串是不会向上述那样,虽然最终输出的是:"hello java!!!",但是 "hello ""java""!!!" 这几个字符串都没有改变,还存在着。我们可以通过内存去理解一下在这里插入图片描述

因为不是动态的所以看起来没那么顺畅,首先是1号线,表示代码的第一行,代码的第二行就是加了一个 “java”,由于常量是不可以改变的,所以不可能直接加在原有的 “hello” 后面,就新开辟一个内存,将拼接的新的字符串存入,此时 str1 的地址应该变成 0x678。3号线也是和2号线一样的步骤。所以最后其实是开辟了五个内存。原有的字符串没有改变,而是增加了新的字符串

4.2 修改字符串方式(含反射简单介绍)


那么如果我们想要修改字符串该怎么办呢?

注意:

字符串是不可以修改的,我这里说的修改其实是得到和原字符串上进行改变的新的字符串,但原字符串是不会改变的,例如将字符串 str = "hello" 改成 str = "Hello"

方式一:借助原字符串,创建新的字符串

采用 substring 方法来提取字串

String str = “hello”;

str = “H” + str.substring(1);

System.out.println(str);

结果为:Hello,但是我们要知道

这样修改并没有改变原字符串,只是提取了它的字串,并进行了新的拼接

那么我就是想将字符串真正的改变而不是创建新的字符串有办法吗?有啊!这里需要用到反射

那什么是反射呢?

反射是 Java 类的一种自省的方式。通常情况下:类的内部细节有时候在类外是看不到的,但是通过反射就可以看到。

这其实就可以形象的理解为我们的行李箱接受安检的时候,行李箱通过检查的机器就可以直接看到行李箱内部的物品。在这里插入图片描述

因此如果我们可以拿到 String 内部的字符串将它直接修改,就 🆗。那么怎么做呢?

String str = “hello”;

// 拿到字节码对象

Class c = String.class;

// 获取 String 类的 value 字段

Field field = c.getDeclareField(“value”);

// 修改该字段的权限,使其访问属性为 true

field.setAccessible(true);

// 将 str 中的 value 属性获取到

char[] vals = (char[]) field.get(str);

// 将第一个字符修改成 ‘H’

vals[0] = ‘H’;

System.out.println(str);

结果为:“Hello”,并且是直接将原字符串修改

但是我们为什么要让 String 不可变呢?

  • 方便实现字符串常量池。如果可变那么对象池就需要考虑何时深拷贝字符串的问题
  • 不可变对象是线程安全的
  • 不可变对象更方便缓存 hash code,作为 key 时可以更高效的保存到 HashMap 中

5. 字符、字节、字符串

================================================================================

5.1 字符串与字符


之前我们就介绍到字符串内部含一个数组,即 String 应该可以和 char[] 相互转换

我搜集了下列方法

| No. | 方法名称 | 类型 | 描述 |

| — | — | — | — |

| 1 | public String(char value[]) | 构造 | 将字符数组中的所有内容变为字符串 |

| 2 | public String(char value[], int offset, int count) | 构造 | 将部分字符数组中的内容变为字符串,offset 为偏移量,从0开始 |

| 3 | public char charAt(int index) | 普通 | 取得指定索引的字符,索引从0开始 |

| 4 | public char[] toCharArray() | 普通 | 将字符串变为字符数组返回 |

接下来进行一一演示

示例一: 将字符数组中的所有内容变为字符串

char[] value = {‘a’, ‘b’, ‘c’, ‘d’, ‘e’};

String str = new String(value);

System.out.println(str);

结果为:abcde

示例二: 将部分字符数组中的内容变为字符串

char[] value = {‘a’, ‘b’, ‘c’, ‘d’, ‘e’};

String str = new String(value, 1, 3);

System.out.println(str);

结果为:bcd

示例三: 取得指定索引的字符,索引从0开始

String str = “abcde”;

char c = str.charAt(2);

System.out.println©;

结果为:c

示例四: 将字符串变为字符数组返回

String str = “abcde”;

char[] value = str.toCharArray();

System.out.println(Arrays.toString(value));

结果为:[a, b, c, d, e]

练习: 判断一个字符串是否都由数字组成

String str = “12213”;

char[] value = str.toCharArray();

for(int i=0; i<value.length; i++){

if(value[i]<‘0’ || value[i]>‘9’){

System.out.println(“不是都由字母组成”);

return;

}

}

System.out.println(“都是由字母组成”);

思路:

将字符串变为字符数组,然后判断每一位是否为数字

5.2 字符串与字节


字节常用于数据传输以及编码转换的处理,字符串 String 也能和字节数组 byte[] 相互转换

我搜集了下列方法

| No. | 方法名称 | 类型 | 描述 |

| — | — | — | — |

| 1 | public String(byte bytes[]) | 构造 | 将字节数组变成字符串 |

| 2 | public String(byte bytes[], int offset, int length) | 构造 | 将部分字节数组中的内容变为字符串 |

| 3 | public byte[] getBytes() | 普通 | 将字符串以字节数组的形式返回 |

| 4 | public byte[] getBytes(String charsetName)throws java.io.UnsupportedEncodingException | 普通 | 编码转换处理 |

接下来进行一一演示

示例一: 将字节数组变成字符串

byte[] bytes = {97, 98 ,99 ,100};

String str = new String(bytes);

System.out.println(str);

结果为:abcd

示例二: 将部分字节数组中的内容变为字符串

byte[] bytes = {97, 98 ,99 ,100};

String str = new String(bytes, 1, 2);

System.out.println(str);

结果为:bc

示例三: 将字符串以字节数组的形式返回

public static void main(String[] args) {

String str = “abcde”;

byte[] bytes = str.getBytes();

System.out.println(Arrays.toString(bytes));

}

结果为:[97, 98, 99, 100, 101]

示例四: 编码转换处理

public static void main(String[] args)throws java.io.UnsupportedEncodingException {

String str = “魔王”;

byte[] bytes = str.getBytes(“GBK”);

System.out.println(Arrays.toString(bytes));

}

结果为:[-60, -89, -51, -11]

如果我们将编码方式 “GBK” 改成 “utf-8”,则会有不同的结果

public static void main(String[] args)throws java.io.UnsupportedEncodingException {

String str = “魔王”;

byte[] bytes = str.getBytes(“utf-8”);

System.out.println(Arrays.toString(bytes));

}

结果为:[-23, -83, -108, -25, -114, -117]

注意:

细心的朋友在演示示例二的时候会发现,当我们只输了第二个参数时,String 被打了一个横线在这里插入图片描述

这是为什么呢?通过转到定义在这里插入图片描述

我们看到了 @Deprecated 这样的注解,这个表示这个方法已经被弃用了,这在我们今天介绍 String 的构造方法那张图里面就有这个方法,也被表明被弃用

5.3 字节数组和字符数组使用场景


对于字节数组:

byte[] 是把 String 按照一个字节一个字节的方式处理,适合用在网络传输数据存储针对二进制数据操作的场景

对于字符数组:

char [] 是把 String 按照一个字符一个字符的方式处理,适合用在对文本数据操作尤其是包含中文的时候

那啥又是文本数据和二进制数据呢?其实可以这样记忆

看的懂得就是文本数据(例如 .java 文件),看不懂的就是二进制数据(例如 .class 文件

6. 字符串常见操作

==============================================================================

6.1 字符串比较


上述介绍到 equals 可以比较字符串是否相等,并且是区分大小写的。而除了它,String 类还有其他比较字符串的方法

我搜集了下列方法

| NO. | 方法名称 | 类型 | 描述 |

| — | — | — | — |

| 1 | public boolean equals(Object anObject) | 普通 | 区分大小写的比较 |

| 2 | public boolean equalsIgnoreCase(String anotherString) | 普通 | 不区分大小写的比较 |

| 3 | public int compareTo(String anotherString) | 普通 | 比较两个字符串大小关系 |

接下来进行一一演示

示例一: 区分大小写的比较

String str1 = “hello”;

String str2 = new String(“Hello”);

System.out.println(str1.equals(str2));

结果为:false

示例二: 不区分大小写的比较

String str1 = “hello”;

String str2 = new String(“Hello”);

System.out.println(str1.equalsIgnoreCase(str2));

结果为:true

示例三: 比较两个字符串大小关系

String str1 = “hello”;

String str2 = new String(“Hello”);

System.out.println(str1.compareTo(str2));

结果为:32,这个结果是怎么来的呢?

字符串的大小比较,其实是“字典序”的比较,将两个字符串从第一个字母开始,一一比较,如果相等就比较下一个,如果不等就停止比较,结果返回的是较大的字母减去较小字母的差值

6.2 字符串查找


我们做算法题经常碰到某个字符串中是否存在一个指定的内容,而 String 类中就有专门的查找方法

我搜集了下列方法

| No. | 方法名称 | 类型 | 描述 |

| — | — | — | — |

| 1 | public boolean contains(CharSequence s) | 普通 | 判断一个字符串是否存在 |

| 2 | public int indexOf(String str) | 普通 | 从头开始查找指定字符串的位置,查到了返回位置的开始索引,查不到返回-1 |

| 3 | public int indexOf(String str, int fromIndex) | 普通 | 从指定位置开始查找子字符串位置 |

| 4 | public int lastIndexOf(String str) | 普通 | 由后向前查找子字符串位置 |

| 5 | public int lastIndexOf(String str, int fromIndex) | 普通 | 从指定位置由后向前查找 |

| 6 | public boolean startsWith(String prefix) | 普通 | 判断是否以指定字符串开头 |

| 7 | public boolean startsWith(String prefix, int toffset) | 普通 | 从指定位置开始判断是否以指定字符串开头 |

| 8 | public boolean endWith(String suffix) | 普通 | 判断是否以指定字符串结尾 |

接下来进行一一演示

示例一: 判断一个字符串是否存在

String str = “helloworld”;

System.out.println(str.contains(“hello”));

结果为:true

示例二: 从头开始查找指定字符串的位置,查到了返回位置的开始索引,查不到返回-1

String str = “helloworld”;

System.out.println(str.indexOf(“world”));

结果为:5

示例三: 从指定位置开始查找子字符串位置

String str = “helloworldhelloworld”;

System.out.println(str.indexOf(“world”, 6));

结果为:15

示例四: 由后向前查找子字符串位置

String str = “helloworld”;

System.out.println(str.lastIndexOf(“world”));

结果为:5

示例五: 从指定位置由后向前查找

String str = “helloworldhelloworld”;

System.out.println(str.indexOf(“world”, 6));

结果为:15

示例六: 判断是否以指定字符串开头

String str = “helloworld”;

System.out.println(str.startsWith(“hello”));

结果为:true

示例七: 从指定位置开始判断是否以指定字符串开头

String str = “helloworld”;

System.out.println(str.startsWith(“hello”, 2));

结果为:false

示例八: 判断是否以指定字符串结尾

String str = “helloworld”;

System.out.println(str.endsWith(“world”));

结果为:true

6.3 字符串替换


String 类中也有方法将一个指定的新字符串替换掉已有的字符串数据

我搜集了下列方法

| No. | 方法名称 | 类型 | 描述 |

| — | — | — | — |

| 1 | public String replaceAll(String regex, String replacement) | 普通 | 替换所有的指定内容 |

| 2 | public String replaceFirst(String regex, String replacement) | 普通 | 替换首个内容 |

接下来进行一一演示

示例一: 替换所有的指定内容

String str = “helloworld”;

System.out.println(str.replaceAll(“world”, “java”));

结果为:“hellojava”

示例二: 替换首个内容

String str = “helloworld”;

System.out.println(str.replaceFirst(“l”, “-”));

结果为:he-loworld

注意:

由于字符串是不可变对象,替换不修改当前字符串,而是产生一个新的字符串

6.4 字符串拆分


String 类中也有方法将一个完整的字符串按照指定的分隔符划分为若干子字符串

我搜集了下列方法

| No. | 方法名称 | 类型 | 描述 |

| — | — | — | — |

| 1 | public String[] split(String regex) | 普通 | 将字符串全部拆分 |

| 2 | public String[] split(String regex, int limit) | 普通 | 将字符串部分拆分,该数组长度就是 limit 极限 |

接下来进行一一演示

示例一: 将字符串全部拆分

String str = “hello world hello java”;

String[] result = str.split(" ");

for(String s : result){

System.out.println(s);

}

结果为:

hello

world

hello

java

示例二: 将字符串部分拆分,该数组长度就是 limit 极限

String str = “hello world hello java”;

String[] result = str.split(" ", 2);

for(String s : result){

System.out.println(s);

}

结果为:

hello

world hello java

其中第二个参数指最多分的组数,这个代码的参数是2,所以最多分两组

示例三: 拆分 IP 地址

String str = “192.168.1.1”;

String[] strings = str.split(“.”);

for(String s: strings){

System.out.println(s);

}

但是这个代码输出不了结果,如果大家不信可以上机试试。那怎样写才是对的呢?看下面代码

String str = “192.168.1.1”;

String[] strings = str.split(“\.”);

for(String s: strings){

System.out.println(s);

}

此时结果就是:

192

168

1

1

这是由于在分割字符中,如果是以字符 “|”、“*”、“+” 分隔,分割时都得加上转义字符 " \ ",而这里之所以要加两个,是因为通过第一个 " \ ",先将第二个 " \ " 变成了转义符号

示例四: 一个代码中有多个分隔符要进行多次拆分

String str = “java string-split#test”;

String[] strings = str.split(" |-|#");

for(String s: strings){

System.out.println(s);

}

结果为:

java

string

split

test

是不是很方便,如果一个字符串中有多个分隔符并要对他们都要进行分割,可以用 “|” 作为连字符

示例五: 多次分割

String str = “name=zhangsan&age=18”;

String[] strings = str.split(“&”);

for(String s: strings){

String[] tmp = s.split(“=”);

for(String ss: tmp) {

System.out.println(ss);

}

}

结果为:

name

zhangsan

age

18

注意:

  • 字符串 “|”、“*”、“+” 作为分割符时,参数前要加转义字符 " \ ",但是要写成 " \ \ ",因为第一个斜杠是为了将第二个斜杠变成转义字符
  • 如果一个字符串中有多个分隔符需要被分割,可以将这些分隔符用 “|” 号连接,写到参数里面

6.5 字符串截取


上面稍微介绍过了 substring 方法,它是用来截取字符串的。它的参数不仅可以只有一个,我们来了解下

| No. | 方法名称 | 类型 | 描述 |

| — | — | — | — |

| 1 | public String substring(int beginIndex) | 普通 | 从指定索引截取到结尾 |

| 2 | public String substring(int beginIndex, int endIndex) | 普通 | 截取部分内容 |

接下来进行一一演示

示例一: 从指定索引截取到结尾

String str1 = “helloworld”;

String str2 = str1.substring(5);

System.out.println(str2);

结果为:“world”

示例二: 截取部分内容

String str1 = “helloworld”;

String str2 = str1.substring(2,5);

System.out.println(str2);

结果为:“llo”

注意:

截取部分内容,参数其实是一个左闭右开的区间,意思就是不包含 endIndex 位置的字符

6.6 其他操作


除了上述的一些操作字符串的方法,其实还有很多其他的方法,下面我就列举了几个

| No. | 方法 | 类型 | 描述 |

| — | — | — | — |

| 1 | public String trim() | 普通 | 去掉字符串中的左右空格,保留中间空格 |

| 2 | public String toUpperCase() | 普通 | 字符串转大写 |

| 3 | public String toLowerCase() | 普通 | 字符串转小写 |

| 4 | public native String intern() | 普通 | 字符串入池操作 |

| 5 | public String concat(String str) | 普通 | 字符串连接,等同于 “+” |

| 6 | public int length() | 普通 | 取得字符串长度 |

| 7 | public boolean isEmpty() | 普通 | 判断字符串是否为空(空不是 null,而是长度为0) |

这里的方法就不一一展示示例了,如果大家能够把上述字符串的方法都记得的话,那么去做一些题目那真的可以说是更加轻松了。并且字符串的方法不止这些,大家可以去 Java 的 api 中去查看学习

在这里插入图片描述

7. StringBuffer 和 StringBuilder

===================================================================================================

7.1 了解 StringBuffer 和 StringBuilder


StringBuffer 和 StringBuilder 是什么呢?遇到没学过的我们可以借助 api 查看一下

在这里插入图片描述

在这里插入图片描述

从上面两张图中我们可以获取到关于 StringBuffer 和 StringBuilder 的几个知识点

  • StringBuffer 和 StringBuilder 都是类
  • 两者都在 java.lang 包中,即不用手动导包
  • 两者都继承了这三个接口:SerializableAppendableCharSequence
  • 两者都继承了 Object 类

此时大家应该对这两个类应该都有印象了,我们通过分析到这两个类和 String 类一样都继承了 CharSequence 接口,而这个接口描述的是一系列的字符集会,故我们可以理解,StringBuffer 和 StringBuilder 和 String 类一样都是和字符串相关的

7.2 StringBuffer、StringBuilder 和 String 的区别


那么字符串既然有了 String 类,为什么还要有这两个类呢?

通常来讲 String 的操作比较简单,但是由于 String 的不可更改特性,为了方便字符串的修改,则提供 StringBuffer 和 StringBuilder类

由于 StringBuffer 和 StringBuilder 大部分功能相似,下面则只用 StringBuffer与 String 进行比较找出区别,之后再将这两者进行比较

区别一:

我们知道 String 类可以采用直接赋值和构造两者方法。但是 StringBuffer 只可以采用构造法,如

StringBuffer sb = new StringBuffer(“hello”);

最后

看完上述知识点如果你深感Java基础不够扎实,或者刷题刷的不够、知识不全面

小编专门为你量身定制了一套<Java一线大厂高岗面试题解析合集:JAVA基础-中级-高级面试+SSM框架+分布式+性能调优+微服务+并发编程+网络+设计模式+数据结构与算法>

image

针对知识面不够,也莫慌!还有一整套的<Java核心进阶手册>,可以瞬间查漏补缺

image

全都是一丢一丢的收集整理纯手打出来的

更有纯手绘的各大知识体系大纲,可供梳理:Java筑基、MySQL、Redis、并发编程、Spring、分布式高性能架构知识、微服务架构知识、开源框架知识点等等的xmind手绘图~

image

image

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

都是类

  • 两者都在 java.lang 包中,即不用手动导包
  • 两者都继承了这三个接口:SerializableAppendableCharSequence
  • 两者都继承了 Object 类

此时大家应该对这两个类应该都有印象了,我们通过分析到这两个类和 String 类一样都继承了 CharSequence 接口,而这个接口描述的是一系列的字符集会,故我们可以理解,StringBuffer 和 StringBuilder 和 String 类一样都是和字符串相关的

7.2 StringBuffer、StringBuilder 和 String 的区别


那么字符串既然有了 String 类,为什么还要有这两个类呢?

通常来讲 String 的操作比较简单,但是由于 String 的不可更改特性,为了方便字符串的修改,则提供 StringBuffer 和 StringBuilder类

由于 StringBuffer 和 StringBuilder 大部分功能相似,下面则只用 StringBuffer与 String 进行比较找出区别,之后再将这两者进行比较

区别一:

我们知道 String 类可以采用直接赋值和构造两者方法。但是 StringBuffer 只可以采用构造法,如

StringBuffer sb = new StringBuffer(“hello”);

最后

看完上述知识点如果你深感Java基础不够扎实,或者刷题刷的不够、知识不全面

小编专门为你量身定制了一套<Java一线大厂高岗面试题解析合集:JAVA基础-中级-高级面试+SSM框架+分布式+性能调优+微服务+并发编程+网络+设计模式+数据结构与算法>

[外链图片转存中…(img-aBYOJfSz-1715653185195)]

针对知识面不够,也莫慌!还有一整套的<Java核心进阶手册>,可以瞬间查漏补缺

[外链图片转存中…(img-uQz015nY-1715653185195)]

全都是一丢一丢的收集整理纯手打出来的

更有纯手绘的各大知识体系大纲,可供梳理:Java筑基、MySQL、Redis、并发编程、Spring、分布式高性能架构知识、微服务架构知识、开源框架知识点等等的xmind手绘图~

[外链图片转存中…(img-4sGiby6K-1715653185196)]

[外链图片转存中…(img-Ib03hywS-1715653185196)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值