Java面试题

java类加载机制?

加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)、卸载(Unloading)等阶段,其中验证、准备、解析3阶段也可以称为连接(Lingking)

java类实例化过程?

创建内存空间、引用指该地址、再进行初始化

接口和抽象类有什么区别?

相同点:

  1. 都不能被实例化。
  2. 接口的实现类或抽象类的子类只有实现了接口或抽象类中方法才能实例化。

不同点:

  1. 接口只有定义没有方法实现。
  2. 一个类可以实现多个接口但只能继承一个抽象类。
  3. 接口强调功能实现而类强调所属关系。
  4. 接口成员变量必须赋初值不能修改,而且所有成员方法都是public、abstract的。抽象类成员变量可以在子类中重新定义也可以重新赋值。 

ArraryList和LinkList有什么区别?

ArrayList:底层结构是数组,查询快,增删慢。适用于需要对数据随机访问的时候。

LinkedList:底层结构是链表,查询慢,增删快。适用于需要对数据多次增删的时候。

ArraryList扩容的过程?

1.创建一个新的数组容量为之前的1.5倍

2.利用Arrary中的copyof方法把原数组内容复制到新数组

3.把新数据加进去

String、StringBuilder和StringBuffer有什么区别?

String是不可变字符串,而其他两个是可变字符串。

StringBuilder类中的方法没有使用同步锁,所以它的方法都是"线程"不安全,但是性能好。

StringBuffer类中的方法对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的,所以它的方法都是"线程"安全,但是性能不好。

final、finally、finalize有什么区别?

  • final:既是修饰符也是关键字。修饰的类无法继承,修饰的方法无法重写可以重载。
  • finally:一个关键字。在异常处理的时候不管异常抛出或者捕获都会执行,里面如果有return语句则会覆盖try或catch中的return。
  • finalize:是Object类中的protected方法,子类可以覆盖该方法实现资源清理工作。

怎么使用多线程的?使用场景?线程池原理?线程池初始化的参数和每个参数的含义?

使用多线程是为了把一个大任务分解为多个小任务执行,充分利用CPU性能。通过继承Thread类或者实现Runnable接口或Callable接口并重写 run 方法或call方法创建线程。

常用于web服务,tomcat,后台任务,异步处理等场景。

线程池原理:

  1. 判断线程池里的核心线程是否都在执行任务,如果不是(核心线程空闲或者还有核心线程没有被创建)则创建一个新的工作线程来执行任务。如果核心线程都在执行任务,则进入下个流程。

  2. 线程池判断工作队列是否已满,如果工作队列没有满,则将新提交的任务存储在这个工作队列里。如果工作队列满了,则进入下个流程。

  3. 判断线程池里的线程是否都处于工作状态,如果没有,则创建一个新的工作线程来执行任务。如果已经满了,则交给饱和策略来处理这个任务。

饱和策略:

当队列和线程池都满了,说明线程池处于饱和状态,那么必须对新提交的任务采用一种特殊的策略来进行处理。这个策略默认配置是AbortPolicy,表示无法处理新的任务而抛出异常。JAVA提供了4中策略:

  1. AbortPolicy:直接抛出异常

  2. CallerRunsPolicy:只用调用所在的线程运行任务

  3. DiscardOldestPolicy:丢弃队列里最近的一个任务,并执行当前任务。

  4. DiscardPolicy:不处理,丢弃掉。

一共七个参数,分别为:

  • corePoolSize:核心线程数,默认长期工作的线程。
  • maximumPoolSize:最大线程数,用来控制动态创建线程的数量。
  • keepAliveTime:空闲线程存活时间。
  • TimeUnit:时间单位。
  • BlockingQueue:线程池任务队列。
  • ThreadFactory:创建线程的工厂。
  • RejectedExecutionHandler:拒绝策略。

线程池执行任务发生异常?

1.调用线程池的excutor()方法执行任务,如果有异常,线程终止,等待垃圾回收,并在下一次执行任务时,创建新的线程。
2.调用submit()方法执行任务,如果有异常,作为结果返回,在结果Future调用get()方法时抛出,线程仍可复用。

有100个并发线程去银行取钱,其中几个线程出现问题怎么办?

  1. 使用线程同步机制,例如 synchronized 关键字或者 ReentrantLock 锁等,来保证线程安全。这样可以避免线程之间的冲突和数据竞争。

  2. 使用线程池来管理线程。线程池可以控制线程的数量和优先级,避免线程过多导致系统资源浪费。

  3. 引入异常处理机制,在线程中捕获并处理异常,避免线程因为异常而终止。

  4. 使用监控和日志系统来监控线程的状态和执行情况,便于发现和解决问题。

  5. 使用限流技术来限制并发线程的数量,避免线程过多造成系统资源紧张和性能问题。

  6. 对于出现问题的线程,可以使用线程中断机制来终止线程的执行。

  7. 对于需要高并发的业务场景,可以考虑使用分布式系统来提高系统的扩展性和可用性。

总之,处理并发线程问题需要综合运用多种技术和方法,对线程进行合理的管理和控制,保证线程的安全性和稳定性。

线程死锁的原因以及怎么解决?

1.互斥条件

2.互相占有且互相等待

3.不可抢占

4.循环且等待

解决:死锁一旦发生便很难人为干预,因此应该尽量规避它。而因为线程本身就是互斥的,所以因从其他三方面入手,如一次性申请所有资源避免占有且等待。在线程申请资源的时候如果申请不到边释放自己所占有资源来解决不可抢占问题。由于资源有线性顺序,因此通过序号从小到大申请便可以避免循环等待问题。

如何保证线程同时执行,依次执行以及有序交替执行?

用CountDownLatch保证同时执行,像赛跑一样所有线程准备好等信号一响全部开跑。

CylicBarrier保证依次执行,在每个线程执行完任务后,把信号量变成下个线程开始的信号量。

Semaphore保证交替执行,每次执行完变换成下个线程的信号量。

List、Set、Map的区别? 

主要区别为元素是否有序、是否允许元素重复。

List是有序且允许重复的。

Set除了TreeSet是可以有序的,其他都是无序且不允许重复的。

Map除了TreeMap是有序的,其他是无序的,元素的key值是唯一而value值允许重复。

HashMap怎么解决Hash冲突?

HashMap底层由数组、链表以及红黑树构成,由于底层有数组结构,而数组元素所在位置在算法中称为桶,通过pull方法往里面放数组时,HashMap会根据key的hash值去进行取模运算来决定放在哪个桶里,但是这样有一定几率会导致两个不同的key存到同一个位置,这就是hash冲突。因此,HashMap采用链式寻址的方式来解决,对于存在冲突的key,hashmap会把他组成一个单向链表,后面来的元素会以加到链表尾部的方式既尾插法,同时为了避免链表过长影响效率,当链表长度超过8会转为红黑树来提升性能。

重载和重写的区别?

重载:发生在同一个类中,方法名必须相同,参数类型、个数、顺序不同,方法返回 值和访问修饰符可以不同,发生在编译时

重写: 发生在父子类中,方法名,参数列表必须相同,返回值范围小于等于父类,抛出的异常范围小于等于父类, 访问修饰符范围大于等于父类;如果父类方法访问修饰符为 private 则子类就不能重写该方法。

堆和栈有什么区别?

相同:

  1. 都是属于Java内存的一种
  2. 系统都会自动去回收它,但是对于堆内存一般开发人员会自动回收它

不同:

  1. 堆内存用来存放由new创建的对象和数组。
  2. 栈内存用来存放方法或者局部变量等。
  3. 堆是先进先出,后进后出。
  4. 栈是后进先出,先进后出。

你对线程安全的理解?

多线程环境下保证线程安全,要保证对对象访问的原子性、有序性和多个线程之间的可见性。

Java的同步锁和互斥锁?

同步锁:多个线程彼此合作通过一定逻辑顺序占有资源共同完成一个任务

互斥锁:在有限时间内只允许 一 个线程独占性的使用共享资源,而不允许其他线程使用防止访问冲突。

Java反射机制优缺点?

Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。反射被视为动态语言的关键。

优点:运行期类型的判断,动态加载类,提高代码灵活度。
缺点:性能瓶颈:反射相当于一系列解释操作,通知JVM要做的事情,性能比直接的java代码要慢很多。

JVM垃圾回收算法有哪些?

  1. 标记-清除算法
  2. 复制算法(Java堆中新生代的垃圾回收算法)
  3. 标记-压缩算法(或称为标记-整理算法,Java堆中老年代的垃圾回收算法)
  4. 分代收集算法

什么是OOM?

oom就是Out of Memory内存溢出,它是指需要的内存空间大于系统分配的内存空间。

什么是StackOverFlowError?

在jvm运行时的数据区域中有一个java虚拟机栈,当执行java方法时会进行压栈弹栈的操作。在栈中会保存局部变量,操作数栈,方法出口等等。jvm规定了栈的最大深度,当执行时栈的深度大于了规定的深度,就会抛出StackOverflowError错误

post和get请求的区别?

  1. get请求一般是去取获取数据而post用来提交数据。
  2. get请求的参数是可以直接看到的并且有长度限制,而post是无法直接看到且没长度限制。
  3. get请求可以被缓存而post不会缓存。
  4. get请求只能进行url编码,而post支持多种。

为什么使用spring框架?

  1. Spring无处不在。Spring受到全世界开发人员的信任。各个领域,各个企业都在广泛使用。
  2.  Spring灵活性强。Spring提供的扩展能力和启动的粘合第三方库的能力,可以使开发人员轻松构建几乎任何可以想象的应用程序。Spring框架的控制反转(IoC)能力,为广泛的功能集奠定了基础。
  3. Spring可以提高生产力。Spring Boot改变了Java编程的方式,从根本上简化了编程体验。Spring Cloud使微服务开发变得轻松。
  4. Spring快速。Spring可以快速启动,快速关闭并支持执行的优化。Spring项目也越来越多地支持反应式(非阻塞)编程模型,以提高效率。
  5. Spring注重安全。Spring代码提交者与安全专家合作,修补和测试所有报告的漏洞。Spring密切关注关联的第三方类库,并定期发布更新以帮助确保数据和应用程序尽可能安全。此外,Spring Security可以更轻松地与行业标准安全方案集成。
  6. Spring社区支持较好。Spring社区是一个庞大,全球化,多元的社区,涵盖了从初学者到经验丰富的职业人士的各个阶段需要内容,拥有带入新高度所需的支持和资源:快速入门,指南和教程,视频,聚会,支持等等。

SpringMVC 的流程?

  1. 用户发送请求给到前端控制器 DispatchServlet ;
  2. DispatchServlet 收到请求后,调用HandlerMapping 处理器映射器查找对应负责处理请求的 Handler;
  3. HandlerMapping 将找到的具体的处理器 Handler 生成处理器对象以及处理器拦截器(如果有则生成),一起返回给 DispatchServlet
  4. DispatchServlet调用HandlerAdapter 处理器适配器,请求执行具体的 Handler;
  5. HandlerAdapter 将具体 Handler 执行返回的模型和视图返回给到 DispatchServlet
  6. 此时 DispatchServlet 已经得到具体的 视图名称了,然后向 ViewResolver 发起请求,请求解析视图,返回已经解析好的视图对象;
  7. DispatchServlet 对视图进行渲染,将 model 与view 进行渲染;
  8. DispatchServlet 返回响应给到用户浏览器;

Springboot的核心注解是哪个?

@SpringBootApplication是 Spring Boot 的核心注解,主要组合包含了以下 3 个注解:

  • @SpringBootConfiguration:组合了 @Configuration 注解,实现配置文件的功能。
  • @EnableAutoConfiguration:打开自动配置的功能,也可以关闭某个自动配置的选项
  • @ComponentScan:Spring组件扫描。

Aop和ioc原理?

 ioc原理:

在传统的实现中,由程序内部代码来控制组件之间的关系。需要使用new关键字来实现两个组件之间关系的组合,这种实现方式会造成组件之间耦合。IOC很好地解决了该问题,它将实现组件间关系从程序内部提到外部容器,也就是说由容器在运行期将组件间的某种依赖关系动态注入组件中。

对象A依赖于对象B,当对象A需要用到对象B的时候,IOC容器就会立即创建一个对象B送给对象A。IoC容器就是一个对象制造工厂,需要什么,它会给提供,直接使用即可,而不用考虑所用的东西是如何制成的,也不用考虑最后是怎么被销毁的,这一切全部由IOC容器包办。

Aop原理:

面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

使用“横切”技术,AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处都基本相似。比如权限认证、日志、事务处理。Aop 的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。正如Avanade公司的高级方案构架师Adam Magee所说,AOP的核心思想就是“将应用程序中的商业逻辑同对其提供支持的通用服务进行分离。”

Springboot的启动方式有哪些?

  1. 打包用命令或者放到容器中运行
  2. 用 Maven/ Gradle 插件运行
  3. 直接执行 main 方法运行

Spring Boot 需要独立的容器运行吗?

不需要,内置了 Tomcat/ Jetty 等容器。

Mybatis的优点是什么?

  1. 与JDBC相比,减少了50%以上的代码量。 
  2. MyBatis是最简单的持久化框架,小巧并且简单易学。 
  3. MyBatis灵活,不会对应用程序或者数据库的现有设计强加任何影响,SQL写在XML里,从程序代码中彻底分离,降低耦合度,便于统一管理和优化,可重用。 
  4. 提供XML标签,支持编写动态SQL语句(XML中使用if, else)。  
  5. 提供映射标签,支持对象与数据库的ORM字段关系映射(在XML中配置映射关系,也可以使用注解)。
     

Mybatis的一级缓存和二级缓存?

  • 一级缓存是SqlSession级别的,通过同一个SqlSession查询的数据会被缓存,下次查询相同的数据,就会从缓存中直接获取,不会从数据库重新访问
  • 使一级缓存失效的四种情况:
  1. 不同的SqlSession对应不同的一级缓存  
  2. 同一个SqlSession但是查询条件不同
  3. 同一个SqlSession两次查询期间执行了任何一次增删改操作
  4. 同一个SqlSession两次查询期间手动清空了缓存
  • 二级缓存是SqlSessionFactory级别,通过同一个SqlSessionFactory创建的SqlSession查询的结果会被缓存;此后若再次执行相同的查询语句,结果就会从缓存中获取
  • 二级缓存开启的条件
  1. 在核心配置文件中,设置全局配置属性cacheEnabled="true",默认为true,不需要设置
  2. 在映射文件中设置标签<cache />
  3. 二级缓存必须在SqlSession关闭或提交之后有效
  4. 查询的数据所转换的实体类类型必须实现序列化的接口
  • 使二级缓存失效的情况:两次查询之间执行了任意的增删改,会使一级和二级缓存同时失效

Redis的垃圾回收机制?

  • 定时过期:设置过期时间的key都需要创建一个定时器,到期时间自动清除。
  • 惰性过期:每访问一个key,才进行判断key是否过期,过期则进行清除。
  • 定期过期:每隔一段时间扫描一定数量的key,并清除过期的。

Redis的缓存穿透和缓存雪崩?

  • 缓存穿透是指查询一个根本不存在的数据,缓存层和持久层都不会命中,请求都会压到数据库,从而压垮数据库。
  • 缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力。
  • 缓存雪崩是指缓存同一时间大面积的失效,所以,后面的请求都会落到数据库上,造成数据库短时间内承受大量请求而崩掉。

缓存穿透解决方案:

  1. 对空值缓存:如果一个查询返回的数据为空(不管数据是否存在),我们仍然把这个空结果(null)进行缓存,设置空结果的过期时间会很短,最长不超过五分钟。
  2. 设置可访问的白名单:使用bitmaps;类型定义一个可以访问的名单,名单id作为bitmaps的偏移量,每次访问和bitmaps里面的id进行比较,如果访问id不在bitmaps里面,进行拦截,不允许访问
  3. 采用布隆过滤器:布隆过滤器(Bloom Filter)是由Howard Bloom在1970年提出的一种比较巧妙的概率型数据结构,它可以告诉你某种东西一定不存在或者可能存在。当布隆过滤器说,某种东西存在时,这种东西可能不存在;当布隆过滤器说,某种东西不存在时,那么这种东西一定不存在。 布隆过滤器相对于Set、Map 等数据结构来说,它可以更高效地插入和查询,并且占用空间更少,它也有缺点,就是判断某种东西是否存在时,可能会被误判。但是只要参数设置的合理,它的精确度也可以控制的相对精确,只会有小小的误判概率。

缓存击穿解决方案:

  1. 预先设置热门数据:在redis高峰访问前,把一些热门数据提前存入redis中,加大这些热门数据key的时长实时调整 现场监控哪些数据是热门数据,实时调整key的过期时长
  2. 使用分布式锁: 就是在缓存失效的时候(判断拿出来的值为空),不是立即去查数据库,先使用缓存工具的某些带成功操作返回值的操作。比如redis的setnx去set一个mutex key,当操作返回成功时(分布式锁),在查数据库,并回设缓存,最后删除mutex key当操作返回失败,证明有线程在查询数据库,当前线程睡眠一段时间在重试整个get缓存的方法

缓存雪崩解决方案:

  1. 构建多级缓存架构:nginx缓存+redis缓存+其他缓存(ehcache等)
  2. 使用锁或队列:使用锁或在队列的方式来保证不会有大量的线程对数据库进行读写,从而避免失效时大量的并发请求到底层存储系统上,不适用高并发情况
  3. 设置过期标志更新缓存:记录缓存数据是否过期(设置提前量),如果过期会触发通知另外的线程在后台去更新实际key的缓存
  4. 将缓存失效时间分散开:设置缓存过期时间时加上一个随机值,避免缓存在同一时间过期
     

MySQL数据库事务有什么用?

定义:一件事从开始到结束的过程

作用:保证数据的一致性、准确性以及有效性。

四大特性
1.原子性(atomicity):一个事务必须视为一个不可分割的最小工作单元,整个事务中的操作要么全部提交成功,要么全部失败回滚,对于一个事务来说,不可能只执行其中的一部分操作。

2.一致性(consistency):数据库总是从一个一致性的状态转换到另一个一致性的状态。

3.隔离性(isolation):一个事物所做的修改在最终提交以前,对其他事务是不可见的。

4.持久性(durability):一旦事务提交,则其所做的修改就会永久保存到数据库中。即便此时系统崩溃,修改的数据也不会丢失。

注意:

1.事务一旦提交结束,对数据库中数据的更改是永久性的。

2.事务只针对表记录操作(增删改)有效,对于库和表的操作无效。

索引有哪些种类和作用?

什么是索引:

  1. 索引是一种特殊的文件(InnoDB数据表上的索引是表空间的一个组成部分),它们包含着对数据表里所有记录的引用指针。
  2. 索引是一种数据结构。数据库索引,是数据库管理系统中一个排序的数据结构,以协助快速查询、更新数据库表中数据。索引的实现通常使用B树及其变种B+树。

种类:

  • 唯一索引:不允许有俩行具有相同的值
  • 主键索引:为了保持数据库表与表之间的关系
  • 聚集索引:表中行的物理顺序与键值的逻辑(索引)顺序相同。
  • 非聚集索引:聚集索引和非聚集索引的根本区别是表记录的排列顺序和与索引的排列顺序是否一致
  • 复合索引:在创建索引时,并不是只能对一列进行创建索引,可以与主键一样,讲多个组合为索引
  • 全文索引: 全文索引为在字符串数据中进行复杂的词搜索提供有效支持

优点:

  • 可以大大加快数据的检索速度,这也是创建索引的最主要的原因。
  • 通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能。

缺点:

  • 时间方面:创建索引和维护索引要耗费时间,具体地,当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,会降低增/改/删的执行效率;
  • 空间方面:索引需要占物理空间。

内外连接有什么区别?

  1. 内连接(inner join):取出连接表中匹配到的数据,匹配不到的不保留
  2. 外连接(outer join):取出连接表中匹配到的数据,匹配不到的也会保留,其值为NULL

左外连接和右外连接的区别

  1. 左外连接,查询结果以左表为主,主表的数据会全部显示处理,从表根据连接条件没有匹配,查询结果从表数据都会以NULL展示
  2. 右外连接,查询结果以右表为主,主表的数据会全部显示处理,从表根据连接条件没有匹配,查询结果从表数据都会以NULL展示

数据库三大范式是什么?

第一范式(1NF):每个列都不可以再拆分。
第二范式(2NF):在第一范式的基础上,非主键列完全依赖于主键,而不能是依赖于主键的一部分。
第三范式(3NF):在第二范式的基础上,非主键列只依赖于主键,不依赖于其他非主键。

MySQL隔离级别是什么?

READ_UNCOMMITTED(读取未提交)
这是事务最低的隔离级别,它充许另外一个事务可以看到这个事务未提交的数据。解决第一类丢失更新的问题,但是会出现脏读、不可重复读、第二类丢失更新的问题,幻读。


READ_COMMITTED(读取已提交)
保证一个事务修改的数据提交后才能被另外一个事务读取,即另外一个事务不能读取该事务未提交的数据。解决第一类丢失更新和脏读的问题,但会出现不可重复读、第二类丢失更新的问题,幻读问题

REPEATABLE_READ(可重复读)
保证一个事务相同条件下前后两次获取的数据是一致的(注意是一个事务,可以理解为事务间的数据互不影响)解决第一类丢失更新,脏读、不可重复读、第二类丢失更新的问题,但会出幻读。

SERIALIZABLE(串行化)
事务串行执行,解决了脏读、不可重复读、幻读。但效率很差,所以实际中一般不用

默认可重读这个隔离级别。
 

Mysql怎么优化?

  1. 添加限制条件: 通过在查询语句中加入限制条件,减少需要扫描的数据量。

  2. 避免使用不必要的字段: 只选择需要的字段,减小需要扫描的数据量。

  3. 修改查询语句: 通过更换查询语句中的运算符或者函数,来优化查询速度。

  4. 分析SQL语句的执行计划: 通过分析SQL语句的执行计划,找出执行瓶颈并进行优化。

  5. 优化数据库结构: 通过调整数据库结构,提高查询性能。

  6. SQL优化。首先先判断什么样的SQL需要优化。可以在MySQL中开启慢查询,设置成例如SQL执行时长超过5秒就可以定为慢SQL,并记录到日志中。然后拿到慢SQL的执行记录和计划,通过explain关键字做分析。分析思路有例如SQL存在索引,判断是否执行了索引或者索引失效原因,若索引未失效则要考虑索引创建是否合理,以及是否遵循最左匹配原则等。

有哪些单例模式?

单例模式:某个类的实例在内存中只会创建一次。
单例模式有饿汉式单例模式、懒汉式单例模式和双检锁单例模式三种。

  • 饿汉式:线程安全,一开始就初始化
  • 懒汉式:非线程安全,延迟初始化
  • 双检锁:线程安全,延迟初始化


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值