面试——Java基础篇

面试🤺🤺🤺<持续更新>

  • 🗡️JAVA
    • ⚔️ Java基础篇
    • ⚔️ I/O、泛型、反射、异常篇
    • ⚔️ Java容器篇
    • ⚔️ JUC
    • ⚔️ JVM
    • ⚔️ 新特性
    • ⚔️ 补充点

⚔️ Java基础篇


前言

通过本文,你将了解如下内容:

  • 🕐 Java语言的概念、常识与基本语法
  • 🕑 Java语言数据类型
  • 🕒 面向对象基础
  • 🕓 Java语言常用类拥有那些方法
  • 穿插在文章内的补充知识点(希望也能看看,说不定有不一样的收获❤️❤️❤️)`

提示:以下是本篇文章正文内容

一、🕐 Java语言的概念、常识与基本语法

1、Java语言的概念、常识

1)Java语言特性?

易用性
健壮性(Java语言的强类型机制、异常处理、垃圾的自动收集等)
安全性
面向对象
跨平台性
支持多线程编程(Java语言诞生本身就是为简化网络编程设计)
支持网络编程(多线程机制使应用程序在同一时间并行执行多项任)
编译与解释共存

2)为什么Java语言易学?

Java语法与C和C++相似,继承了C++的面向对象核心,它摒弃了C++难懂的指针、多继承、运算符重载等概念;新增了垃圾回收机制对内存进行自动管理,简化操作。

3)Java语言平台无关性

Java程序在编写完成后,会通过javac工具编译成.class文件(只能被虚拟机解释),通过java工具启动虚拟机(不同操作系统对应的虚拟机),执行字节码文件,不同操作系统虚拟机将字节码文件解释成对应操作系统能够理解的机器代码。从而实现一次编译,多处运行

4)JVM vs JDK vs JRE

JVM(Java Virtual Machine):Java虚拟机;
JRE(Java Runtime Environment):Java运行环境;核心类库主要是java.lang包,其包括基本数据类型、基础数学函数、异常、线程、字符串处理类,系统缺省时加载这个类。
JDK(Java Development Kit):Java开发工具;
在这里插入图片描述

5)为什么说Java语言“编译与解释共存”?

编译型语言:编程效率低,但运行速度快;如C、C++、GO、Rust等
解释型语言:编程效率高,但运行速度慢;如python、javaScript、Php等

即时编译(JIT,just in time)技术:将程序编译成字节码文件,执行时直译字节码文件运行;诞生Java、LLVM等

6)什么是字节码文件?采用字节码的优势是什么?

字节码以.class为文件后缀的二进制文件,它不面向任何处理器,只面向虚拟机;
Java通过字节码一定程度上解决了解释型语言的执行效率低的问题,同时又保留了解释型语言可移植的特点

7)Java语言属于什么类型语言?

Java属于静态类型语言,在后面发展中加入了动态特性
补充点
静态类型语言:指在编译时变量的数据类型即可确定的语言
动态类型语言:指在运行期间才去做数据类型检查
强类型定义:强制数据类型定义的语言
弱类型定义语言:数据类型可以被忽略的语言
https://www.php.cn/java/base/465416.html
图片来源于https://www.php.cn/java/base/465416.html

8)Java语言与C++的区别?

  • 共同点
    – 面向对象语言,支持封装、继承与多态
  • 不同点
    – Java语言抛弃指针,拒接直接访问内存,增加了安全性;
    – Java语言抛弃多继承,因为命名存在歧义,编译过程中不能确定;
    – Java语言引入GC垃圾回收机制去管理释放无用内存;
    – Java语言抛弃操作符重载、保留了方法重载;

2、Java语言基本语法

编码


1)Java语言采用何种编码方案?有何特点?

Java语言采用Unicode编码标准,Unicode(标准码),它为每个字符制订了一个唯一的数值,因此在任
何的语言,平台,程序都可以放心的使用

注释


2)Java语言有哪几种注释?

单行注释: // 注释
多行注释: /* 注释*/
文档注释:/** 注释*/

访问权限修饰符


3)Java语言的权限修饰符有哪些?区别?

权限符当前类同包子类不同包
public
protected×
default(默认,即缺省,不使用任何关键字)××
private×××

运算符


4)&(|)与&&(||)区别?

&(|)运算符有两种用法:(1)按位与(或);(2)逻辑与(或)。
&&(||)运算符是短路与运算。&&(||)左边的表达式的值是false(true),右边的表达式会被直接短路掉,不会进行运算

5)自增自减运算符

自增运算符怕(++)和自减运算符(- -):可放在变量前面和后面,放前面(b = ++a)表示先进行a+1操作,然后将结果赋值给b;放后面(b = a++)表示先进行赋值操作将a给b,在进行a+1操作。这两种a的结果一样,但b的结果不一致。- -操作同理
补充点
i++是原子操作吗?
不是原子操作
原子操作:一个操作是不可中断的,要么全部执行成功要么全部执行失败
主内存:分配给java虚拟机进程的内存(计算机物理内存一部分)的一部分
工作内存(working memory):cpu的寄存器和高速缓存的抽象描述
i++需要执行三次指令:

  • 第一次:工作内存去将主内存中的i读取到cpu寄存器
  • 第二次:寄存器中的i自增1
  • 第三次:将i写回内存
    在这里插入图片描述

关键字


6)Java语言关键字有哪些?

分类关键字
访问控制privateprotectedpublic
类,方法和变量修饰符abstractclassextendsfinalimplementsinterfacenative
newstaticstrictfpsynchronizedtransientvolatileenum
程序控制breakcontinuereturndowhileifelse
forinstanceofswitchcasedefaultassert
错误处理trycatchthrowthrowsfinally
包相关importpackage
基本类型booleanbytechardoublefloatintlong
short
变量引用superthisvoid
保留字gotoconst

7)Java语言有没有goto?Java语言是怎么跳出多重循环?

goto 是 Java 中的保留字,在目前版本的 Java 中没有使用

// 在外面的循环语句前定义一个标号,然后在里层循环体的代码中使
// 用带有标号的break 语句,即可跳出外层循环
public static void main(String[] args) {
	ok:for (int i = 0; i < 10; i++) {
		for (int j = 0; j < 10; j++) {
			if (j == 5) {
				break ok;
			}
		}
	}
}

8)final、finalize、finally区别?

final是关键字,修饰变量时,变量在第一次赋值后不可再进行赋值操作;修饰常量时,与static连用;修饰方法时,方法不可被重写;修饰类时,类不可被继承,不可与abstract连用,否则无意义。
finalize是方法,Object类中的方法,常用于垃圾回收最后一次确认是否回收。
finally是关键字,作用在try-catch代码块中,该代码块中代码一定会被执行,常用于关闭资源

9)static关键字应用场景

修饰变量、修饰常量、修饰方法、修饰类、修饰代码块

流程控制


10)break、continue、return的区别及作用?

continue :指跳出当前的这一次循环,继续下一次循环;
break :指跳出整个循环体,继续执行循环下面的语句;
return:用于跳出所在方法,结束该方法的运行;

11)switch是否能作用在byte上?是否能作用在String上?是否能作用在Long上?

switch(expr)中expr在java5之前允许byte、short、char、int
java5后允许enum
java7后允许String
Long类型暂不支持


二、🕑 Java语言数据类型

1、数据类型有哪些?

基本类型:
在这里插入图片描述
引用类型:数组、类、接口

2、字符型常量与字符串常量区别?

形式 : 字符常量是单引号引起的一个字符,字符串常量是双引号引起的 0 个或若干个字符;
含义 : 字符常量相当于一个整型值( ASCII 值),可以参加表达式运算; 字符串常量代表一个地址值(该字符串在内存中存放位置);
占内存大小 : 字符常量只占 2 个字节; 字符串常量占若干个字节。

3、float f = 3.4是否正确?

不正确。3.4 是双精度数,将双精度型(double)赋值给浮点型(float)属于下转型(down-casting,
也称为窄化)会造成精度损失,因此需要强制类型转换float f =(float)3.4; 或者写成 float f =3.4F

4、short s1 = 1; s1 = s1 + 1;有错吗?s1 += 1;有错吗?

对于 short s1 = 1; s1 = s1 + 1;由于 1 是 int 类型,因此 s1+1 运算结果也是 int型,需要强制转换类型才
能赋值给 short 型;
而 short s1 = 1; s1 += 1;可以正确编译,因为 s1+= 1;相当于 s1 = (short(s1 + 1);其中有隐含的强制类型
转换

5、基本类型与包装类型区别?

成员变量包装类型不赋值就是 null ,而基本类型有默认值且不是 null。
包装类型可用于泛型,而基本类型不可以。
基本数据类型的局部变量存放在 Java 虚拟机栈中的局部变量表中,基本数据类型的成员变量(未被 static 修饰 )存放在 Java 虚拟机的堆中。包装类型属于对象类型,我们知道几乎所有对象实例都存在于堆中。
相比于对象类型, 基本数据类型占用的空间非常小。

6、包装类型缓存机制?

Java 基本数据类型的包装类型的大部分都用到了缓存机制来提升性能。
Byte,Short,Integer,Long 这 4 种包装类默认创建了数值 [-128,127] 的相应类型的缓存数据,Character 创建了数值在 [0,127] 范围的缓存数据,Boolean 直接返回 True or False
float与double类型,没有缓存机制

7、自动拆箱装箱机制了解吗?

装箱:将基本类型用它们对应的引用类型包装起来;
拆箱:将包装类型转换为基本数据类型
装箱其实就是调用了 包装类的valueOf()方法,拆箱其实就是调用了 xxxValue()方法


三、🕒 面向对象基础

1、面向对象与面向过程区别?

面向过程:
优点:性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗资源;比如单片机、嵌入式
开发、Linux/Unix等一般采用面向过程开发,性能是最重要的因素。
缺点:没有面向对象易维护、易复用、易扩展


面向对象:
优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系
统,使系统更加灵活、更加易于维护
缺点:性能比面向过程低


面向过程是具体化的,流程化的,解决一个问题,你需要一步一步的分析,一步一步的实现。
面向对象是模型化的,你只需抽象出一个类,这是一个封闭的盒子,在这里你拥有数据也拥有解决问题
的方法。需要什么功能直接使用就可以了,不必去一步一步的实现,至于这个功能是如何实现的,管我
们什么事?我们会用就可以了。
面向对象的底层其实还是面向过程,把面向过程抽象成类,然后封装,方便我们使用的就是面向对象

面向对象三大特征


2、面向对象特征有哪些?

封装、继承、多态

3、什么是多态机制?Java语言怎样实现多态?

不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用
调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选
择多个运行状态,这就是多态性。
多态分为编译时多态和运行时多态。其中编辑时多态是静态的,主要是指方法的重载,它是根据参数列
表的不同来区分不同的函数,通过编辑之后会变成两个不同的函数,在运行时谈不上多态。而运行时多
态是动态的,它是通过动态绑定来实现的,也就是我们所说的多态性。


Java实现多态有三个必要条件:继承、重写、向上转型

4、面向对象五大原则

单一职责原则SRP(Single Responsibility Principle):类的功能要单一
开放封闭原则OCP(Open-Close Principle):一个模块对于拓展是开放的,对于修改是封闭的
里式替换原则LSP(the Liskov Substitution Principle LSP):子类可以替换父类出现在父类能够出现的任何地方
依赖倒置原则DIP(the Dependency Inversion Principle DIP):高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象。抽象不应该依赖于具体实现,具体实现应该依赖于抽象
接口分离原则ISP(the Interface Segregation Principle ISP):设计时采用多个与特定客户类有关的接口比采用一个通用的接口要好

构造器


5、构造器作用?类没有说明构造器,程序会正常执行吗?

构造器作用主要是完成对象的初始化工作
如果一个类没有声明构造方法,也可以执行!因为一个类即使没有声明构造方法也会有默认的不带参数的构造方法。如果我们自己添加了类的构造方法(无论是否有参),Java 就不会再添加默认的无参数的构造方法

6、构造器能否被override?

构造器不能被继承,因此不能被重写,但可以被重载

7、调用子类构造器之前,会先调用父类无参构造器,其目的是什么?

帮助子类做初始化工作

8、构造器方法特性?

方法名与类名一致
无返回值
类加载时自动调用

变量与方法


9、静态变量普通变量区别?

静态变量被所有的对象所共享,在内存中
只有一个副本,它当且仅当在类初次加载时会被初始化。而非静态变量是对象所拥有的,在创建对象的
时候被初始化,存在多个副本,各个对象拥有的副本互不影响。

10、静态变量实例变量区别?

静态变量: 静态变量不属于任何实例对象,属于类,在内存中只会有一份,在类的加载过程中,JVM只为静态变量分配一次内存空间。
实例变量: 每次创建对象都会为每个对象分配成员变量内存空间,实例变量是属于实例对象的,在内
存中,创建几次对象,就有几份成员变量。

11、静态方法实例方法区别?

在外部调用静态方法时,可以使用"类名.方法名"的方式,也可以使用"对象名.方法名"的方式。而实
例方法只有后面这种方式。也就是说,调用静态方法可以无需创建对象。
静态方法在访问本类的成员时,只允许访问静态成员(即静态成员变量和静态方法),而不允许访
问实例成员变量和实例方法;实例方法则无此限制

12、什么是方法返回值?返回值作用是什么?

方法的返回值是指我们获取到的某个方法体中的代码执行后产生的结果!(前提是该方法可能产生结
果)。返回值的作用:接收出结果,使得它可以用于其他的操作!

内部类


13、什么是内部类?

将一个类的定义放在另外一个类的定义内部,这就是内部类。内部类本身就是类的一个
属性,与其他属性定义方式一致

14、内部类有哪些?优点?应用场景?

  • 成员内部类:定义在类内部,成员位置上的非静态类,就是成员内部类
public class Outer {
	private static int radius = 1;
	private int count =2;
	class Inner {
		public void visit() {
		}
	}
}
  • 局部内部类:定义在方法中的内部类,就是局部内部类
public class Outer {
	private static int radius = 1;
	private int count =2;
	public void visit() {
		class Inner {
		
		}
	}
}
  • 匿名内部类:匿名内部类就是没有名字的内部类
public class Outer {
	private void test(final int i) {
		new Service() {
			public void method() {
				
			}
		}.method();
	}
}
  • 静态内部类:定义在类内部的静态类,就是静态内部类
public class Outer {
	private static int radius = 1;
	static class StaticInner {
		public void visit() {
		}
	}
}

15、局部内部类和匿名内部类访问局部变量的时候,为什么变量必须要加上final?

类访与局部变量生命周期不一样,没有被final修饰的局部变量在调用完后会被销毁,而局部内部类对局部变量的引用依然存在,当调用局部内部类时就会报错

重写与重载


16、重载与重写的区别?重载方法能不能根据返回类型进行区分?

方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译时的多态性,而后者实现的是运行
时的多态性。

  • 重载:发生在同一个类中,方法名相同参数列表不同(参数类型不同、个数不同、顺序不同),与方法
    返回值和访问修饰符无关,即重载的方法不能根据返回类型进行区分
  • 重写:发生在父子类中,方法名、参数列表必须相同,返回值小于等于父类,抛出的异常小于等于父
    类,访问修饰符大于等于父类(里氏代换原则);如果父类方法访问修饰符为private则子类中就不是重

equals


17、==与equals区别?

  • ==:基本数据类型== 比较的是值,引用数据类型 == 比较的是内存地址
  • equals:类没有覆盖 equals() 方法情况下, equals() 等价于通过“==”比较这两个对象;类覆盖了 equals() 方法情况下。一般比较两个对象的内容;若它们的内容相等,则返回 true (即,认为这两个对象相等)

18、hashCode与equals?

  • 如果两个对象的hashCode 值相等,那这两个对象不一定相等(哈希碰撞)
  • 如果两个对象的hashCode 值相等并且equals()方法也返回 true,我们才认为这两个对象相等
  • 如果两个对象的hashCode 值不相等,我们就可以直接认为这两个对象不相等

19、对象相等与指向它们的引用相等,两者有什么不同?

对象的相等:比的是内存中存放的内容是否相等而
引用相等:比较的是他们指向的内存地址是否相等

值传递


20、将一个对象当作参数传递给一个方法后,此方法可改变这个对象的属性,并返回变化后的结果,这里是值传递还是引用传递?

是值传递。Java 语言的方法调用只支持参数的值传递。当一个对象实例作为一个参数被传递到方法中
时,参数的值就是对该对象的引用。对象的属性可以在被调用过程中被改变,但对对象引用的改变是不
会影响到调用者的

21、为什么java只有值传递?

方法得到的是所有参数值的一个拷贝

22、值传递与引用传递的区别?

值传递:指的是在方法调用时,传递的参数是按值的拷贝传递,传递的是值的拷贝,也就是说传递后就
互不相关了
引用传递:指的是在方法调用时,传递的参数是按引用进行传递,其实传递的引用的地址,也就是变量
所对应的内存空间的地址。传递的是值的引用,也就是说传递前和传递后都指向同一个引用(也就是同
一个内存空间)

类与接口


23、接口与抽象类有什么共同点和区别?

相同点

  • 接口和抽象类都不能实例化
  • 都位于继承的顶端,用于被其他实现或继承
  • 都包含抽象方法,其子类都必须覆写这些抽象方法

不同点

参数抽象类接口
声明抽象类使用abstract关键字声明接口使用interface关键字声明
实现子类使用extends关键字来继承抽象类。如果子类不是抽象类的话,它需要提供抽象类中所有声明的方法的实现子类使用implements关键字来实现接口。它需要提供接口中所有声明的方法的实现
构造器抽象类可以有构造器接口不能有构造器
访问修饰符抽象类中的方法可以是任意访问修饰符接口方法默认修饰符是public。并且不允许定义为 private 或者protected
多继承一个类最多只能继承一个抽象类一个类可以实现多个接口
字段声明抽象类的字段声明可以是任意的接口的字段默认都是 static 和 final的

24、类加载顺序?触发类加载有哪些情况?

加载静态成员/代码块
加载非静态成员/代码块
调用构造方法

调用静态成员时,会加载该类及其父类;子类调用父类静态成员只会加载父类。
第一次 new 对象的时候 加载(第二次再 new 同一个类时,不需再加载)
加载子类会先加载父类(覆盖父类方法时所抛出的异常不能超过父类定义的范围)

拷贝


25、深拷贝与浅拷贝区别?什么是引用拷贝?

  • 浅拷贝会在堆上创建一个新的对象(区别于引用拷贝的一点),不过,如果原对象内部的属性是引用类型的话,浅拷贝会直接复制内部对象的引用地址,也就是说拷贝对象和原对象共用同一个内部对象
  • 深拷贝会完全复制整个对象,包括这个对象所包含的内部对象
  • 引用拷贝就是两个不同的引用指向同一个对象
    在这里插入图片描述

四、🕓 Java语言常用包(类)拥有那些类(方法)

1、JDK中常用包有哪些?

java.lang:系统基础类
java.io:与输入输出有关
java.nio:io包plus版,提高了性能
java.net:与网络有关
java.util:辅助包,如集合类
java.sql:与数据库操作有关

Math


2、Math.round(0.5)等于多少?Math.round(-0.5)等于多少?

四舍五入的原理是在参数上加0.5 然后进行下取整
Math.round(0.5)等于1;Math.round(-0.5)等于0;

Object


Object

native修饰符:

  • 官方文档显示:“A native method is a Java method whose implementation is provided by non-java code.”
  • “native方法是一种Java方法,其实现由非Java代码提供”。所有底层可能是C++编写的方法
/**
 * native 方法,用于返回当前运行时对象的 Class 对象,使用了 final 关键字修饰,故不允许子类重写。
 */
public final native Class<?> getClass()
/**
 * native 方法,用于返回对象的哈希码,主要使用在哈希表中,比如 JDK 中的HashMap。
 */
public native int hashCode()
/**
 * 用于比较 2 个对象的内存地址是否相等,String 类对该方法进行了重写以用于比较字符串的值是否相等。
 */
public boolean equals(Object obj)
/**
 * naitive 方法,用于创建并返回当前对象的一份拷贝。
 */
protected native Object clone() throws CloneNotSupportedException
/**
 * 返回类的名字实例的哈希码的 16 进制的字符串。建议 Object 所有的子类都重写这个方法。
 */
public String toString()
/**
 * native 方法,并且不能重写。唤醒一个在此对象监视器上等待的线程(监视器相当于就是锁的概念)。如果有多个线程在等待只会任意唤醒一个。
 */
public final native void notify()
/**
 * native 方法,并且不能重写。跟 notify 一样,唯一的区别就是会唤醒在此对象监视器上等待的所有线程,而不是一个线程。
 */
public final native void notifyAll()
/**
 * native方法,并且不能重写。暂停线程的执行。注意:sleep 方法没有释放锁,而 wait 方法释放了锁 ,timeout 是等待时间。
 */
public final native void wait(long timeout) throws InterruptedException
/**
 * 多了 nanos 参数,这个参数表示额外时间(以毫微秒为单位,范围是 0-999999)。 所以超时的时间还需要加上 nanos 毫秒。。
 */
public final void wait(long timeout, int nanos) throws InterruptedException
/**
 * 跟之前的2个wait方法一样,只不过该方法一直等待,没有超时时间这个概念
 */
public final void wait() throws InterruptedException
/**
 * 实例被垃圾回收器回收的时候触发的操作
 */
protected void finalize() throws Throwable { }

String


String

1、String、StringBuffer、StringBuilder 的区别?

操作少量的数据: 适用 String
单线程操作字符串缓冲区下操作大量数据: 适用 StringBuilder
多线程操作字符串缓冲区下操作大量数据: 适用 StringBuffer

StringStringBufferStringBuilder
可变性不可变可变可变
线程安全是常量,线程安全方法加了synchronized,线程安全线程不安全
性能每次创建新的字符串较慢比StringBuffer快10%~15%

2、String 为什么是不可变的?

  • 保存字符串的数组被 final 修饰且为私有的,并且String 类没有提供/暴露修改这个字符串的方法;
  • String 类被 final 修饰导致其不能被继承,进而避免了子类破坏 String 不可变

3、字符串拼接用“+” 还是 StringBuilder?

  • 字符串对象通过“+”的字符串拼接方式,实际上是通过 StringBuilder 调用 append() 方法实现的,拼接完成之后调用 toString() 得到一个 String 对象
  • 如果循环内使用“+”进行字符串的拼接的话,存在比较明显的缺陷:编译器不会创建单个 StringBuilder 以复用,会导致创建过多的 StringBuilder 对象
String str1 = "str";
String str2 = "ing";
String str3 = "str" + "ing";// 被编译器优化成String str3 = "string";
String str4 = str1 + str2; // String str4 = new StringBuilder().append(str1).append(str2).toString();
String str5 = "string";
System.out.println(str3 == str4);//false
System.out.println(str3 == str5);//true
System.out.println(str4 == str5);//false
// 如果Str1与str2加上final,String str4 = str1 + str2;编译器便可以确认值
// System.out.println(str3 == str4);//true

4、String#equals() 和 Object#equals() 有何区别?

String 中的 equals 方法是被重写过的,比较的是 String 字符串的值是否相等。 Object 的 equals 方法是比较的对象的内存地址

5、字符串常量池的作用了解吗?

字符串常量池 是 JVM 为了提升性能和减少内存消耗针对字符串(String 类)专门开辟的一块区域,主要目的是为了避免字符串的重复创建

6、intern 方法有什么作用?

  • 如果字符串常量池中保存了对应的字符串对象的引用,就直接返回该引用。
  • 如果字符串常量池中没有保存了对应的字符串对象的引用,那就在常量池中创建一个指向该字符串对象的引用并返回

总结

————————————— ———
参考资料:

  • guide哥.【JavaGuide】. 面试指北. JAVA,.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蓝桉未与

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值