关于面试-java面试题汇总

项目介绍

大部分情况,这是一场面试的开门题,面试官问这个问题,主要是考察你的概述能力和全局视野。有的人经常抱怨自己每天在堆业务,但没有成长。事实上,很多情况下确实在堆业务,但并不是没有成长的。并非做中间件或者技术架构才是成长,例如我们的需求分析能力,沟通协作能力,产品思维能力,抽象建模能力等都是一个非常重要的硬实力。

Java基础

1、List 和 Set 的区别

1:List:可重复,有序,数组或者链表存储

2:Set:不可重复,无序,使用map存储

2、HashSet 是如何保证不重复的

(1)如果hash码值(hashcode())相同,且equles判断相等,说明元素已经存在,不存;

(2)如果hash码值(hashcode())相同,且equles判断不相等,说明元素不存在,存;

3、HashMap 是线程安全的吗,为什么不是线程安全的(最好画图说明多线程环境下不安全)?

    1. 对象不能安全发布,构造过程逃逸; 

    2. 内存的可见性,内容不能及时发布;

    3. 操作不是原子的; 

    4. 读写不能同步;

    5. 存在死锁的可能性;

4、HashMap 的扩容过程

   HashMap的初始容量都是2的n次幂的形式存在的,而扩容也是2倍的原来的容量进行扩容

5、HashMap 1.7 与 1.8 的 区别,说明 1.8 做了哪些优化,如何优化的?

  (1) 1.7的jdk采用Entry数组来存储数据,但是entry是链表结构。在数据量大的情况下,put/get操作时间会略长。

  (2) 1.8的jdk采用node数组存储数据,node采用链表+红黑树结构,那么当数据存储在数组格子里,且这个格子key超过8个,会把链表转换为红黑树。那么根据红黑树的特性,在大数据量put/get会跟快。

6、HashMap实现原理 ?

    HashMap是基于hashing的原理,使用put(key, value)存储对象到HashMap中,使用get(key)从HashMap中获取对象。当我们给put()方法传递键和值时,我们先对键调用hashCode()方法,返回的hashCode用于找到bucket位置来储存Entry对象。

hashmap原理:

    操作put时,初始化好并查询链表长度是否需要扩容(扩容2倍),在根据key求hash值在计算它的下标做存储。 如果链表长度超过阈值,就会扩容成红黑树。

    操作get时,使用键的hashcode求取bucket位置,在找到节点并返回。

ConcurrentHashMap(安全):

          (1)JDK1.7里面,ConcurrentHashMap是用Segment和HashEntry实现的,每个Segment都是继承于Reentrantlock的,在对该segment进行操作时,获取锁,结束操作释放锁。

          (2)JDK1.8里面,没有用segment,而是用Node+CAS+synchronized实现的。

HashMap(不安全,存在死锁可能性):默认16,扩容是2倍,一个Entry数组,当发生hash冲突的时候,hashmap是采用链表的方式来解决的,在对应的数组位置存放链表的头结点。对链表而言,新加入的节点会从头结点加入。

(1) 1.7的jdk采用Entry数组来存储数据,但是entry是链表结构。在数据量大的情况下,put/get操作时间会略长。

(2) 1.8的jdk采用node数组存储数据,node采用链表+红黑树结构,那么当数据存储在数组格子里,且这个格子key超过8个,会把链表转换为红黑树。那么根据红黑树的特性,在大数据量put/get会跟快。

7、HashMap 的并发问题?

    HashMap在多线程put后可能导致get无限循环 。

    如果扩容前相邻的两个Entry在扩容后还是分配到相同的table位置上,就会出现死循环的BUG。

    解决方案:

        使用ConcurrentHashMap进行替代

8、Java反射

    java 获取反射常使用的三种方式:

        1.通过new对象实现反射机制

        2.通过路径实现反射机制

        3.通过类名实现反射机制

//方式一(通过建立对象)
Student stu = new Student();
Class classobj1 = stu.getClass();
System.out.println(classobj1.getName());
	
//方式二(所在通过路径-相对路径)
Class classobj2 = Class.forName("fanshe.Student");
System.out.println(classobj2.getName());
	
//方式三(通过类名)
Class classobj3 = Student.class;
System.out.println(classobj3.getName());

Java 并发

1、synchronized 的实现原理以及锁优化?

    synchronized 常见的三种用法如下:

        普通同步方法,锁是当前实例对象

        静态同步方法,锁是当前类的class对象

        同步方法块,锁是括号里面的对象



   synchronized的对象锁,其指针指向的是一个monitor对象(由C++实现)的起始地址。每个对象实例都会有一个 monitor。其中monitor可以与对象一起创建、销毁;亦或者当线程试图获取对象锁时自动生成。需要注意的是monitor不是Java特有的概念.

实现原理:

    每个对象有一个监视器锁(monitor)。当monitor被占用时就会处于锁定状态,线程执行monitorenter指令时尝试获取monitor的所有权,过程如下:

    如果monitor的进入数为0,则该线程进入monitor,然后将进入数设置为1,该线程即为monitor的所有者。

    如果线程已经占有该monitor,只是重新进入,则进入monitor的进入数加1。

    如果其他线程已经占用了monitor,则该线程进入阻塞状态,直到monitor的进入数为0,再重新尝试获取monitor的所有权。

2、volatile 的实现原理?

    1.保证共享变量可见性

        通俗来说就是,某个线程对一个volatile变量的修改,对于其它线程来说是可见的,即线程每次获取volatile变量的值都是最新的。

    2.禁止指令重排序

        volatile底层通过内存屏障实现禁止特定类型的处理器重排序

    原理:操作发送一个lock前缀的命令并写到系统内存,当其他线程来获取,效验这个lock,不对就重新获取值。(类似版本锁)

3、Java 的信号灯?

    Semaphore是Java1.5之后提供的一种同步工具,Semaphore可以维护访问自身线程个数,并提供了同步机制。使用Semaphore可以控制同时访问资源的线程个数,通过 acquire() 获取一个许可,如果没有就等待,而release() 释放一个许可。

4、synchronized 在静态方法和普通方法的区别?

    synchronized修饰不加static的方法,锁是加在单个对象上,不同的对象没有竞争关系;

    synchronized修饰加了static的方法,锁是加载类上,这个类所有的对象竞争一把锁。

5、怎么实现所有线程在等待某个事件的发生才会去执行?

    1.使用读写锁,刚开始主线程先获取写锁,然后所有子线程获取读锁,然后等事件发生时主线程释放写锁;

    2.使用CountDownLatch,初始值设为1,所有子线程调用await方法等待,等事件发生时调用countDown方法计数减为0;

6、CAS?CAS 有什么缺陷,如何解决?

    Cas是另一个无锁解决方案,更准确的是采用乐观锁技术,实现线程安全的问题。cas有三个操作数----内存对象(V)、预期原值(A)、新值(B)。

   CAS缺点这个方式也存在一定的问题:

            1、自循环时间长,开销大

            2、只能保证一个共享变量的原子操作

            3、ABA问题

7、synchronized 和 lock 有什么区别?

    1.Lock是一个接口,而synchronized是关键字。

    2.synchronized会自动释放锁,而Lock必须手动释放锁。

    3.Lock可以让等待锁的线程响应中断,而synchronized不会,线程会一直等待下去。

    4.通过Lock可以知道线程有没有拿到锁,而synchronized不能。

    5.synchronized能锁住类、方法和代码块,而Lock是块范围内的

8、final finally finalize

    final 表示最终的、不可改变的。用于修饰类、方法和变量。

    finally 异常处理的一部分,它只能用在try/catch语句中,表示希望finally语句块中的代码最后一定被执行(但是不一定会被执行)

    finalize()是在java.lang.Object里定义的,Object的finalize方法什么都不做,对象被回收时finalized方法会被调用。

    特殊情况下,可重写finalize方法,当对象被回收的时候释放一些资源。但注意,要调用super.finalize()。

9、强引用 、软引用、 弱引用、虚引用

      强引用: 是使用最普遍的引用。如果一个对象具有强引用,那垃圾回收器绝不会回收它。

      软引用: 如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;

      弱引用: 与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期 

      虚引用: 顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期

image.png

10、ConcurrenHashMap 介绍?1.8 中为什么要用红黑树?

    ConcurrenHashMap 是当hash值相同的情况下(大于8),才会采用红黑树,利用红黑树的二分查找法进行定位。性能较高。

11、ThreadLocal原理,用的时候需要注意什么?

    ThreadLocal是并发场景下用来解决变量共享问题的类,它能使原本线程间共享的对象进行线程隔离,即一个对象只对一个线程可见。

    需要注意的是,threadlocal在多线程下并不是线程安全的。

12、如何检测死锁?怎么预防死锁?

    通过jvisualvm查看产生的死锁线程,一步步排查。 

    预防死锁可以设置加锁顺序,设置加锁时限等方法。

13、Java 内存模型?

    程序计数器

    堆

    栈

    方法区

14、线程池的种类,区别和使用场景?

    四种线程池:

        1. newCachedThreadPool(缓存)

        2. newFixedThreadPool(单线程)

        2. newScheduledThreadPool(定长)

        4.newSingleThreadExecutor(延迟)

Spring

1、BeanFactory 和 FactoryBean?

        BeanFactory只是个接口,负责生产和管理bean,它为其他具体的IOC容器提供了最基本的规范。

        FactoryBean是一个接口,当在IOC容器中的Bean实现了FactoryBean后,通过getBean获取到的Bean对象并不是FactoryBean的实现类对象,而是这个实现类中的getObject()方法返回的对象。

2、Spring IOC 的理解,其初始化过程?

    ioc即依赖注入,就是把某某托管给这个工厂去创建,并实现。

    初始化流程:

        1.Resource定位,读取xml获取对应加载类的路径获取主要注入的接口类。

        2.加载到spring的容器里。

        3.注册对应的接口类,并存到容器里。(map里)

3、BeanFactory 和 ApplicationContext?

    BeanFactory只是个接口,负责生产和管理bean,它为其他具体的IOC容器提供了最基本的规范。

    ApplicationContext是负责加载上下文或读取资源文件的类,或者通过他去实例化bean。

4、Spring Bean 的生命周期,如何被管理的?

    1.创建bean

    2.set方法注入

    3.调用init方法bean初始化

    4.执行初始化方法

    5.销毁

5、如果要你实现Spring AOP,请问怎么实现?

6、如果要你实现Spring IOC,你会注意哪些问题?

7、Spring 是如何管理事务的,事务管理机制?

    Spring事务管理模块主要包括3个接口:

        PlatformTransactionManager:事务管理器,主要用于平台相关的事务管理。

        TransactionDefinition:事务定义信息(隔离级别、传播、超时、只读)通过配置如何进行事务管理。

        TransactionStatus:事务具体运行状态——事务管理过程中,每个时间点事务的状态信息。

    主要通过这三个接口来实现aop切面,对事务做管理。

8、Spring 的不同事务传播行为有哪些,干什么用的?

   这里写图片描述

9、Spring 中用到了那些设计模式?

    工厂,单例,模型,原型,适配器,策略,装饰者。

Springboot

boot如何自动装配和启动流程是怎么样的?

  首先启动会先找到run方法,run方法会找到SpringBootApplication注解,里面包含三个注解,然后简单说一下每个注解的作用.

  1.SpringApplication.run 执行流程中有refreshContext(context),内部会解析我们的配置类上的标签,实现自动装配功能的注解@EnableAntoConfiguration

  2.会解析@EnableAntoConfiguration这个注解里面的@Import引入的配置类@AntoConfigurationImportSelector

  3.@AntoConfigurationImportSelector这个类中有方法SpringFactoriesLoder.loadFactoryNames(getStringFactoriesLoaderFactoryClass(),getBeanClasLoader());作用就是读取jarbao中的项目中的META-INF/spring.factories文件

  4.spring.factories 配置了要自动装配的 Configuration 类。

什么是 Spring Boot Stater ?

starter负责配置好与spring整合相关的配置和相关依赖(jar和jar版本),使用者无需关心框架整合带来的问题。

Netty

1、BIO、NIO和AIO

2、Netty 的各大组件

3、Netty的线程模型

4、TCP 粘包/拆包的原因及解决方法

5、了解哪几种序列化协议?包括使用场景和如何去选择

6、Netty的零拷贝实现

7、Netty的高性能表现在哪些方面

分布式相关

1、Dubbo的底层实现原理和机制

    Dubbo :是一个rpc框架,soa框架

    作为RPC:支持各种传输协议,如dubbo,hession,json,fastjson,底层采用mina,netty长连接进行传输!典型的provider和cusomer模式!

     作为SOA:具有服务治理功能,提供服务的注册和发现!用zookeeper实现注册中心!启动时候服务端会把所有接口注册到注册中心,并且订阅configurators,服务消费端订阅provide,configurators,routers,订阅变更时,zk会推送providers,configuators,routers,启动时注册长连接,进行通讯!proveider和provider启动后,后台启动定时器,发送统计数据到monitor!提供各种容错机制和负载均衡策略!!

    Dubbo的实现:

    Dubbo协议的Invoker转为Exporter发生在DubboProtocol类的export方法,它主要是打开socket侦听服务,并接收客户端发来的各种请求,通讯细节由Dubbo自己实现。

    dubbo原理:

        I.初始化过程

        2.解析服务

        3.暴露服务

        4.引用服务

    dubbo的泛化调用:泛化接口调用方式主要用于客户端没有 API 接口(泛化调用是指不需要依赖服务的二方包)及模型类元的情况,参数及返回值中的所有 POJO 均用 Map 表示,通常用于框架集成,API网关比如:实现一个通用的服务测试框架,可通过 GenericService 调用所有服务实现。泛化调用的方式可以有效减少平台型产品的二方包依赖,实现系统的轻量级运行。

2、描述一个服务从发布到被消费的详细过程

    首先先获取zk的配置信息,然后获取需要生产者暴露的url,然后调用registry.register方法将url注册到zookeeper上去,然后去消费者配置对应配置,根据端口和接口到注册中心找到生产者接口,然后去调用。

3、分布式系统怎么做服务治理

    服务治理解决方案:负载均衡,熔断降级限流,链路追踪,服务发现与配置中心,连接复用

    服务治理的痛点:超时配置,线程池配置,故障定位

4、幂等性的概念

    一个操作重复执行多次,其效果(不考虑操作时间)和只执行一次是一样的,那么这个操作就叫做是幂等

5、消息中间件如何解决消息丢失问题

    以rabbitmq为例:

        消息持久化:RabbitMQ 的消息默认存放在内存上面,如果不特别声明设置,消息不会持久化保存到硬盘上面的,如果节点重启或者意外crash掉,消息就会丢失。

        需要做到消息持久化,以下三个条件缺一不可。

            Exchange设置持久化

            Queue设置持久化 

            Message设置持久化    

        ack确认机制:就是消费端消费完成要通知服务端,服务端才把消息从内存删除。

    RabbitMQ消息丢失解决方案:

        第一步:设置创建queue设置为持久化(只会持久化queue元数据,但不会持久化queue中的数据);

        第二步:发送消息时,设置deliveryMode设置为2(此时queue中的数据也将被持久化);

        第三步:配合confirm机制使用(推荐使用异步监听机制,不推荐事务机制),当消息被持久化后才通知生产者ack;

    RabbitMQ消费者丢失数据场景:

        消费者接收到消息,但是还没操作,消费者自己挂了,但是rabbitmq以为该条消息已经被消费.

    消费者丢失数据解决方案:

        将autoAck关闭,在处理完消息后再手动提交ack;    

6、Dubbo的服务请求失败怎么处理

    重连或者配置超时请求

7、重连机制会不会造成错误

    如果在高性能请求的环境下,会导致服务雪崩。

8、对分布式事务的理解

    分布式事务就是指事务的参与者、支持事务的服务器分布于不同服务器节点上,要保证这些小操作要么全部成功,要么全部失败

9、如何实现负载均衡,有哪些算法可以实现?

    轮询法、随机法、源地址哈希法、加权轮询法、加权随机法、最小连接法

10、Zookeeper的用途,选举的原理是什么?

    zk的用途:1.命名服务 2.配置管理 3.集群管理 4.分布式锁 

    选举原理:当leader崩溃或者leader失去大多数的follower,这时候zk进入恢复模式,恢复模式需要重新选举出一个新的leader,让所有的Server都恢复到一个正确的状态。

                    1.选举线程由当前Server发起选举的线程担任,其主要功能是对投票结果进行统计,并选出推荐的Server;

                    2.选举线程首先向所有Server发起一次询问(包括自己);

                    3.举线程收到回复后,验证是否是自己发起的询问(验证zxid是否一致),然后获取对方的id(myid),并存储到当前询问对象列表中,最后获取对方提议的leader相关信息(id,zxid),并将这些信息存储到当次选举的投票记录表中;

                     4. 收到所有Server回复以后,就计算出zxid最大的那个Server,并将这个Server相关信息设置成下一次要投票的Server;

                     5.线程将当前zxid最大的Server设置为当前Server要推荐的Leader,如果此时获胜的Server获得n/2 + 1的Server票数, 设置当前推荐的leader为获胜的Server,将根据获胜的Server相关信息设置自己的状态,否则,继续这个过程,直到leader被选举出来。

11、数据的垂直拆分水平拆分。

    垂直拆分:把一个拥有很多列的表拆分为多个表,原则根据使用度的区分,根据业务区分,根据复杂类型区分

    水平拆分:指按照业务对系统进行划分 。

12、zookeeper原理和适用场景

    zookeeper基本原理:树形层次结构,树中的节点称为 Znode, 每个 Znode 存储的数据有小于 1m 的大小限制。zookeeper 对 Znode 提供了几种类型:临时 Znode、持久 Znode、顺序 node 等几种类型,用于不同的一致性需求。在 Znode 发生变化时,通过“观察”(watch)机制可以让客户端得到通知。可以针对 Zookeeper 服务的“操作”来设置观察,该服务的其他操作可以触发观察。Zookeeper 服务的“操作”包括一些对 Znode 添加修改获取操作。

    zookeeper适用场景:可以用作集群管理,服务名统一管理,配置管理等。

13、zookeeper watch机制

    Znode发生变化(Znode本身的增加,删除,修改,以及子Znode的变化)可以通过Watch机制通知到客户端

14、redis/zk节点宕机如何处理

        redis根据哨兵机制处理。

        zk根据心跳机制检测做轮询重新选举。

15、分布式集群下如何做到唯一序列号

    数据库id,uuid,雪花算法等方式去生成唯一序列号

16、如何做一个分布式锁

    可以使用redis来实现,当有一个商品下单,生成key签名,并把对应商品采用redis提供的锁做锁定,并设置时限,如果超出时间其他线程可下单。

17.b和b+树的区别

    b树:

    b+树:

    区别:主要是存储的内容不一样,b树只存单一数据,b+可以存储hash集合等。检索查询的方式不一样,b是一层层遍历,b+顺序排列相连。

缓存

1、Redis有过哪些数据,以及Redis底层怎么实现

    五种类型:(string)字符串对象,(list)列表对象,(hash)哈希对象,(set)集合对象,(zset)有序集合对象

      底层实现:

        1.String的底层实现:string原理

        底层字符串特性?

             1).二进制安全(体现在len这个字段上)

             2).避免频繁的内存分配,进行内存得预分配(体现在上面扩容过程)

             3).兼容c语言函数库(其实底层都会加\0占一个字节作为字符串结尾)

        

        2.哈希底层的实现:数组 + 链表(采用头插法解决冲突,不会像java语言的map一样转化为红黑树),redis会把kay、value封装成一个dictEntry的结构体(dictEntry的key为string类型,value是一个指针,指向一个redisObject对象(不像java语言一样把hashmap的key、value的具体值封装在一起))

              redis为什么要把value封装成一个redisObject对象?

              因为redis支持value的值有多种不同的数据类型

        3.list底层实现:底层是链表,有两个list,一个是ziplist,字面意是压缩列表,另一个是quicklist,字面意是快速列表,在redis中直接使用的是quicklist

        4.set底层实现: Set是一个特殊的value为空的Hash。

        5.zset底层实现:Zset底层是一种跳表SkipList数据结构(跳表在原有的有序链表上面增加了多级索引,通过索引来实现快速查找,实质就是一种可以进行二分查找的

2、Redis缓存穿透,缓存雪崩

缓存穿透问题

现象:用户大量并发请求的数据(key)对应的数据在redis和数据库中都不存在,导致尽管数据不存在但还是每次都会进行查DB。

为什么key对应数据在缓存和db中不存在还会每次都进行DB查询呢?因为很多开发同学写的代码写的逻辑都是先从redis缓存中查一把,如果缓存中为空则从DB中查,如果DB中查到的数据不为空则设置到缓存并返回给接口。那么问题来了,如果从DB中查询的数据为空呢??

解决方案:

从DB中查询出来数据为空,也进行空数据的缓存,避免DB数据为空也每次都进行数据库查询;

使用布隆过滤器,但是会增加一定的复杂度及存在一定的误判率;

缓存雪崩问题

现象:大量key同一时间点失效,同时又有大量请求打进来,导致流量直接打在DB上,造成DB不可用。

解决方案:

设置key永不失效(热点数据);

设置key缓存失效时候尽可能错开;

使用多级缓存机制,比如同时使用redsi和memcache缓存,请求->redis->memcache->db;

3、如何使用Redis来实现分布式锁

4、Redis的并发竞争问题如何解决

5、Redis持久化的几种方式,优缺点是什么,怎么实现的

6、Redis的缓存失效策略

7、Redis集群,高可用,原理

8、Redis缓存分片

9、Redis的数据淘汰策略

JVM

1、详细jvm内存模型

2、讲讲什么情况下回出现内存溢出,内存泄漏?

3、说说Java线程栈

4、JVM 年轻代到年老代的晋升过程的判断条件是什么呢?

5、JVM 出现 fullGC 很频繁,怎么去线上排查问题?

6、类加载为什么要使用双亲委派模式,有没有什么场景是打破了这个模式?

7、类的实例化顺序

8、JVM垃圾回收机制,何时触发MinorGC等操作

9、JVM 中一次完整的 GC 流程(从 ygc 到 fgc)是怎样的

10、各种回收器,各自优缺点,重点CMS、G1 11、各种回收算法

12、OOM错误,stackoverflow错误,permgen space错误

1)put的时候导致的多线程数据不一致。

这个问题比较好想象,比如有两个线程A和B,首先A希望插入一个key-value对到HashMap中,首先计算记录所要落到的桶的索引坐标,然后获取到该桶里面的链表头结点,此时线程A的时间片用完了,而此时线程B被调度得以执行,和线程A一样执行,只不过线程B成功将记录插到了桶里面,假设线程A插入的记录计算出来的桶索引和线程B要插入的记录计算出来的桶索引是一样的,那么当线程B成功插入之后,线程A再次被调度运行时,它依然持有过期的链表头但是它对此一无所知,以至于它认为它应该这样做,如此一来就覆盖了线程B插入的记录,这样线程B插入的记录就凭空消失了,造成了数据不一致的行为。

2)另外一个比较明显的线程不安全的问题是HashMap的get操作可能因为resize而引起死循环(cpu100%)

java

1.基础(集合,io流)-----》进阶:多线程包,JVM,设计模式

2.spring(ioc和aop)-----》进阶:事务,分布式事务

3.中间件(zookeeper,redis,activemq)集群-----》落地:缓存穿透,雪崩

4.RPC框架(dubbo,Cloud)----》问题:dubbo和cloud的区别

5.接口(http,webservice)

数据库

1.mysql,oracle(特性与区别)

2.acid原理

3.数据库4种隔离级别

4.数据库优化(执行计划解析,索引的场景,索引碎片的处理)

5.分区分表

流程图、甘特图、燃尽图

项目风险时间控制

懂点技术

然后让下面人 乐意 跟你干

前端

1.html

2.css

3.js

4.es6,webpack

5.vue,react

如果技术点的话,有:

1.前后加密双重效验实现机制

2.单点登录实现原理和几种方式

3.跨域怎么实现互通手段和几种方式

4.nio,bio的区别和机制

5.消息中间件的原理,举例你用的几项

6.sql优化和执行计划的技巧使用过么

7.java并发编程的有几个类,并举例几个常见的并发设计模式

参考:面试宝典

https://gitee.com/MrString/study

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值