java面试题总结(一)

持续更新中....................如有错误,欢迎评论指正!

1. &和&&的区别
 虽然二者都要求运算符左右两端的布尔值都是true整个表达式的值才是true。&&之所以称为短路运算是因为,如果&&左边的表达式的值是false,右边的表达式会被直接短路掉,不会进行运算。很多时候我们可能都需要用&&而不是&,例如在验证用户登录时判定用户名不是null而且不是空字符串,应当写为:username != null &&!username.equals(“”),二者的顺序不能交换,更不能用&运算符,因为第一个条件如果不成立,根本不能进行字符串的equals比较,否则会产生NullPointerException异常。注意:逻辑或运算符(|)和短路或运算符(||)的差别也是如此


2. Math.round(11.5) 等于多少?Math.round(-11.5)等于多少?
Math.round(11.5)的返回值是12,Math.round(-11.5)的返回值是-11。四舍五入的原理是在参数上加0.5然后进行下取整

3.switch 是否能作用在byte 上,是否能作用在long 上,是否能作用在String上?
expr可以是byte、short、char、int、enum、String类型,但是long类型不能

4.数组有没有length()方法?String有没有length()方法?

数组没有length()方法,有length 的属性。String 有length()方法。JavaScript中,获得字符串的长度是通过length属性得到的,这一点容易和Java混淆

5.是否可以继承String类?

String 类是final类,不可以被继承

6.隐式数据类型的装换

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

对于short s1 = 1; s1 = s1 + 1;由于1是int类型,因此s1+1运算结果也是int 型,需要强制转换类型才能赋值给short型

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

short s1 = 1; s1 += 1;可以正确编译,因为s1+= 1;相当于s1 = (short)(s1 + 1);其中有隐含的强制类型转换

7.两个对象值相同(x.equals(y) == true),但却可有不同的hash code,这句话对不对?

不对,如果两个对象x和y满足x.equals(y) == true,它们的哈希码(hash code)应当相同。

Java对于eqauls方法和hashCode方法是这样规定的:

(1)如果两个对象相同(equals方法返回true),那么它们的hashCode值一定要相同;

(2)如果两个对象的hashCode相同,它们并不一定相同

8. String和StringBuilder、StringBuffer的区别?

String 和 StringBuffer、StringBuilder 的区别在于 String 声明的是不可变的对象,每次操作都会生成新的 String 对象,然后将指针指向新的 String 对象,而 StringBuffer、StringBuilder 可以在原有对象的基础上进行操作,所以在经常改变字符串内容的情况下最好不要使用 String。

StringBuffer 和 StringBuilder 最大的区别在于,StringBuffer 是线程安全的,而 StringBuilder 是非线程安全的,但 StringBuilder 的性能却高于 StringBuffer,所以在单线程环境下推荐使用 StringBuilder,多线程环境下推荐使用 StringBuffer。

9. 重载(Overload)和重写(Override)的区别。重载的方法能否根据返回类型进行区分?

方法的重载和重写都是实现多态的方式,重载实现的是编译时的多态性,重写实现的是运行时的多态性。

重载发生在一个类中,同名的方法如果有不同的参数列表(参数类型 , 个数 , 顺序)不同则视为重载;与方法的返回值无关

重写发生在子类与父类之间,重写要求子类被重写方法与父类被重写方法有相同的返回类型,比父类被重写方法更好访问,不能比父类被重写方法声明更多的异常(里氏代换原则)

10. 抽象类(abstract class)和接口(interface)有什么异同?

抽象类和接口都不能够实例化,但可以定义抽象类和接口类型的引用。一个类如果继承了某个抽象类或者实现了某个接口都需要对其中的抽象方法全部进行实现,否则该类仍然需要被声明为抽象类。接口比抽象类更加抽象,可以看做是极端的抽象类 , 因为抽象类中可以定义构造器,可以有抽象方法和具体方法,而接口中不能定义构造器而且其中的方法全部都是抽象方法。抽象类中的成员可以是private、默认、protected、public的,而接口中的成员全都是public的。抽象类中可以定义成员变量,而接口中定义的成员变量实际上都是常量。有抽象方法的类必须被声明为抽象类,而抽象类未必要有抽象方法。

11. Java 中会存在内存泄漏吗,请简单描述。

理论上Java因为有垃圾回收机制(GC)不会存在内存泄露问题(这也是Java被广泛使用于服务器端编程的一个重要原因);然而在实际开发中,可能会存在无用但可达的对象,这些对象不能被GC回收,因此也会导致内存泄露的发生。例如hibernate的Session(一级缓存)中的对象属于持久态,垃圾回收器是不会回收这些对象的,然而这些对象中可能存在无用的垃圾对象,如果不及时关闭(close)或清空(flush)一级缓存就可能导致内存泄露

12. String s = new String(“xyz”);创建了几个字符串对象?

答:两个对象,一个是静态区的”xyz”,一个是用new创建在堆上的对象

13. Java 中的final关键字有哪些用法?

(1)修饰类:表示该类不能被继承;

(2)修饰方法:表示方法不能被重写;

(3)修饰变量:表示变量只能一次赋值以后值不能被修改(常量);

14. 程序的运行结果

class A {
 
    static {
        System.out.print("1");
    }
 
    public A() {
        System.out.print("2");
    }
}
 
class B extends A{
 
    static {
        System.out.print("a");
    }
 
    public B() {
        System.out.print("b");
    }
}
 
public class Hello {
 
    public static void main(String[] args) {
        A ab = new B();
        ab = new B();
    }
 
}

执行结果:1a2b2b。创建对象时构造器的调用顺序是:先初始化静态成员,然后调用父类构造器,再初始化非静态成员,最后调用自身构造器

15. 数据类型之间的转换:
将字符串转换为基本数据类型

调用基本数据类型对应的包装类中的方法parseXXX(String)或valueOf(String)即可返回相应基本类型;
将基本数据类型转换为字符串

1. 将基本数据类型与空字符串(”")连接(+)即可获得其所对应的字符串;

2. 调用String 类中的valueOf()方法返回相应字符串

16. 如何实现字符串的反转及替换?

可以自己写实现也可以使用String或StringBuffer/StringBuilder中的方法 , 下面是使用的递归的方式实现字符串的反转

public static String reverse(String originStr) {
      if(originStr == null || originStr.length() <= 1) 
          return originStr;
      return reverse(originStr.substring(1)) + originStr.charAt(0);
  }

17. try{}里有一个return语句,那么紧跟在这个try后的finally{}里的代码会不会被执行,什么时候被执行,在return前还是后

会执行,在方法返回调用者前执行。在finally中改变返回值的做法是不好的,因为如果存在finally代码块,try中的return语句不会立马返回调用者,而是记录下返回值待finally代码块执行完毕之后再向调用者返回其值,然后如果在finally中修改了返回值,就会返回修改后的值

18.列出一些你常见的运行时异常?

- ArithmeticException(算术异常)
- ClassCastException (类转换异常)
- IllegalArgumentException (非法参数异常)
- IndexOutOfBoundsException (下标越界异常)
- NullPointerException (空指针异常)
- SecurityException (安全异常) 

19. List、Set、Map是否继承自Collection接口?

List、Set 是,Map 不是。Map是键值对映射容器,与List和Set有明显的区别,而Set存储的零散的元素且不允许有重复元素(数学中的集合也是如此),List是线性结构的容器,适用于按数值索引访问元素的情形。

20. Collection和Collections的区别?

Collection是一个接口,它是Set、List等容器的父接口;Collections是个一个工具类,提供了一系列的静态方法来辅助容器操作,这些方法包括对容器的搜索、排序、线程安全化等等。

21. List、Map、Set三个接口存取元素时,各有什么特点?

List以特定索引来存取元素,可以有重复元素。Set不能存放重复元素(用对象的equals()方法来区分元素是否重复)。Map保存键值对(key-value pair)映射,映射关系可以是一对一或多对一

22. final 在 java 中有什么作用?

  • final 修饰的类叫最终类,该类不能被继承。
  • final 修饰的方法不能被重写。
  • final 修饰的变量叫常量,常量必须初始化,初始化之后值就不能被修改
  • final 修饰形参 , 如果修饰的基本类型 , 那么值不能改变 , 如果修饰的是引用类型 , 那么引用的地址值不能改变 , 值可以改变

23. BIO、NIO、AIO 有什么区别?

  • BIO:Block IO 同步阻塞式 IO,就是我们平常使用的传统 IO,它的特点是模式简单使用方便,并发处理能力低。
  • NIO:New IO 同步非阻塞 IO,是传统 IO 的升级,客户端和服务器端通过 Channel(通道)通讯,实现了多路复用。
  • AIO:Asynchronous IO 是 NIO 的升级,也叫 NIO2,实现了异步非堵塞 IO ,异步 IO 的操作基于事件和回调机制。

24. HashMap 和 Hashtable 有什么区别?

  • hashMap去掉了HashTable 的contains方法,但是加上了containsValue()和containsKey()方法。

  • hashTable同步的,而HashMap是非同步的,效率上比hashTable要高。

  • hashMap允许空键值,而hashTable不允许

25. 说一下 HashMap 的实现原理?

HashMap概述: HashMap是基于哈希表的Map接口的非同步实现。此实现提供所有可选的映射操作,并允许使用null值和null键。此类不保证映射的顺序,特别是它不保证该顺序恒久不变。 

HashMap的数据结构: 在java编程语言中,最基本的结构就是两种,一个是数组,另外一个是模拟指针(引用),所有的数据结构都可以用这两个基本结构来构造的,HashMap也不例外。HashMap实际上是一个“链表散列”的数据结构,即数组和链表的结合体。

当我们往Hashmap中put元素时,首先根据key的hashcode重新计算hash值,根绝hash值得到这个元素在数组中的位置(下标),如果该数组在该位置上已经存放了其他元素,那么在这个位置上的元素将以链表的形式存放,新加入的放在链头,最先加入的放入链尾.如果数组中该位置没有元素,就直接将该元素放到数组的该位置上。

需要注意Jdk 1.8中对HashMap的实现做了优化,当链表中的节点数据超过八个之后,该链表会转为红黑树来提高查询效率,从原来的O(n)到O(logn)

26. 说一下 HashSet 的实现原理?

  • HashSet底层由HashMap实现

  • HashSet的值存放于HashMap的key上

  • HashMap的value统一为PRESENT

27. ArrayList 和 Vector 的区别是什么?

  • Vector是同步的,而ArrayList不是。然而,如果你寻求在迭代的时候对列表进行改变,你应该使用CopyOnWriteArrayList。 

  • ArrayList比Vector快,它因为有同步,不会过载。 

  • ArrayList更加通用,因为我们可以使用Collections工具类轻易地获取同步列表和只读列表。

28. Array 和 ArrayList 有何区别?

  • Array可以容纳基本类型和对象,而ArrayList只能容纳对象。 

  • Array是指定大小后不可变的,而ArrayList大小是可变的。 

  • Array没有提供ArrayList那么多功能,比如addAll、removeAll和iterator等

29. Iterator 和 ListIterator 有什么区别?

  • Iterator可用来遍历Set和List集合,但是ListIterator只能用来遍历List。 

  • Iterator对集合只能是前向遍历,ListIterator既可以前向也可以后向。 

  • ListIterator实现了Iterator接口,并包含其他的功能,比如:增加元素,替换元素,获取前一个和后一个元素的索引,等等

32. Iterator 怎么使用?有什么特点?

Java中的Iterator功能比较简单,并且只能单向移动:

(1) 使用方法iterator()要求容器返回一个Iterator。第一次调用Iterator的next()方法时,它返回序列的第一个元素。注意:iterator()方法是java.lang.Iterable接口,被Collection继承。

(2) 使用next()获得序列中的下一个元素。

(3) 使用hasNext()检查序列中是否还有元素。

(4) 使用remove()将迭代器新返回的元素删除。 

Iterator是Java迭代器最简单的实现,为List设计的ListIterator具有更多的功能,它可以从两个方向遍历List,也可以从List中插入和删除元素。

31. 如何实现数组和 List 之间的转换?

List转换成为数组:调用ArrayList的toArray方法。

数组转换成为List:调用Arrays的asList方法。

32. List集合

ArrayList : ArrayList是List接口的可变数组非同步实现,并允许包括null在内的所有元素

  1. 底层实现方式 : 底层使用数组实现
  2. 特点: 查找元素快:通过索引,增删元素慢
  3. 是否安全 :否
  4. 初始容量:10
  5. 扩容方式:每次1.5倍 奇数 +1

LinkedList : LinkedList是List接口的双向链表非同步实现,并允许包括null在内的所有元素

  1. 底层实现方式 : 底层是双向链表结构
  2. 特点: 增删元素快 , 查找元素慢
  3. 是否安全 :否
  4. 初始容量: 初始化的容量是一个header节点
  5. 扩容方式: 链表结构不用考虑扩容问题
  6. 链表的节点的指向操作: get操作是一个二分查找,判断节点index是小于链表长度/2还是大于,小于则从链表头遍历,大于则从链表尾部遍历

33. Set集合

hashSet : 

  1. HashSet初始化容量为16,容量因子为0.75,实际是它是一个hashmap实例 , 不保证set的迭代顺序,并允许使用null元素
  2. 底层结果是hashmap。
  3. 封装了hashmap的方法,不是key-value,只关注Key,内部实现默认value,保证了key不重复。
  4. 同hashmap。扩容也是2倍。

LinkedHashSet:

  1. 继承HashSet,初始化容量为16,容量因子为0.75
  2. 同LinkedHashMap。扩容也是2倍
  3. 封装LinkedHashMap方法,只关注key

34. Map 集合

hashMap : HashMap是基于哈希表的Map接口的非同步实现,允许使用null值和null键 , 但不保证映射的顺序

  1. 底层 : 底层是数组加单链表,1.8以后是当链表的长度超度8时,转换成数组加红黑树
  2. 初始容量: HashMap的初始化容量是16,容量因子是0.75
  3. 扩容机制 : 扩容后,数组大小为原来的 2 倍 , HashMap进行数组扩容需要重新计算扩容后每个元素在数组中的位置,很耗性能
  4. 插入新值的数据的方式 :
  5. 在插入新值的时候,如果当前的 size 已经达到了阈值,并且要插入的数组位置上已经有元素,那么就会触发扩容,扩容后,数组大小为原来的 2 倍。因为为双倍扩容,所有当把旧值分配到新的数组上时,会将原来 table[i] 中的链表的所有节点,分拆到新的数组的 newTable[i] 和 newTable[i + oldLength] 位置上,如原来 table[0] 处的链表中的所有元素会被分配到新数组中 newTable[0] 和 newTable[16] 这两个位置

hashTable : .Hashtable是基于哈希表的Map接口的同步实现,不允许使用null值和null键。synchronized是针对整张Hash表的,即每次锁住整张表让线程独占

  1. 底层数据结构 : 组中每一项是个单链表,即数组和链表的结合体
  2. 初始容量 : Hashtable的初始化容量是11,容量因子是0.75
  3. 扩容机制 : 调整Hashtable的长度,将长度变成原来的(2倍+1)
  4. 插入原理 ;
  5. Hashtable底层采用一个Entry[]数组来保存所有的key-value对,当需要存储一个Entry对象时,会根据key的hash算法来决定其在数组中的存储位置,在根据equals方法决定其在该数组位置上的链表中的存储位置;当需要取出一个Entry时,也会根据key的hash算法找到其在数组中的存储位置,再根据equals方法从该位置上的链表中取出该Entry

LinkedHashMap: LinkedHashMap继承于HashMap,它是非同步,允许使用null值和null键

  1. 初始容量 大小 : LinkedHashMap初始化容量为16,容量因子为0.75
  2. 扩容机制 : 扩容也是2倍
  3. 底层数据结构 : 底层使用哈希表与双向链表

ConcurrentHashMap

  1. 初始化长度: 初始化长度为16 , 扩容因子为0.75
  2. 扩容机制 : 2倍

 

 

35. 重载和重写的区别

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

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

36. 获取用键盘输入常用的两种方法

方法1:通过 Scanner

Scanner input = new Scanner(System.in);

String s = input.nextLine();

input.close();

方法2:通过 BufffferedReader

BufferedReader input = new BufferedReader(new InputStreamReader(System.in));

String s = input.readLine();

37、谈谈final, finally, finalize的区别

  1. final—修饰符(关键字)如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承。因此一个类不能既被声明为 abstract的,又被声明为final的。将变量或方法声明为final,可以保证它们在使用中不被改变。被声明为final的变量必须在声明时给定初值,而在以后的引用中只能读取,不可修改。被声明为final的方法也同样只能使用,不能重载
  2. finally—再异常处理时提供 finally 块来执行任何清除操作。如果抛出一个异常,那么相匹配的 catch 子句就会执行,然后控制就会进入 finally 块(如果有的话)finalize—方法名。Java 技术允许使用
  3. finalize() 方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的。它是在 Object 类中定义的,因此所有的类都继承了它。子类覆盖 finalize() 方法以整理系统资源或者执行其他清理工作。finalize() 方法是在垃圾收集器删除对象之前对这个对象调用的

38. 并行和并发有什么区别?

并行是指两个或者多个事件在同一时刻发生;而并发是指两个或多个事件在同一时间间隔发生。

并行是在不同实体上的多个事件,并发是在同一实体上的多个事件。

在一台处理器上“同时”处理多个任务,在多台处理器上同时处理多个任务。如hadoop分布式集群。

所以并发编程的目标是充分的利用处理器的每一个核,以达到最高的处理性能。

39. Thread类的sleep()方法和对象的wait()方法都可以让线程暂停执行,它们有什么区别?

sleep()方法(休眠)是线程类(Thread)的静态方法,调用此方法会让当前线程暂停执行指定的时间,将执行机会(CPU)让给其他线程,但是对象的锁依然保持,因此休眠时间结束后会自动恢复。wait()是Object类的方法,调用对象的wait()方法导致当前线程放弃对象的锁(线程暂停执行),进入对象的等待池(wait pool),只有调用对象的notify()方法(或notifyAll()方法)时才能唤醒等待池中的线程进入等锁池(lock pool),如果线程重新获得对象的锁就可以进入就绪状态。

40. 线程的sleep()方法和yield()方法有什么区别?
① sleep()方法给其他线程运行机会时不考虑线程的优先级,因此会给低优先级的线程以运行的机会;yield()方法只会给相同优先级或更高优先级的线程以运行的机会;
② 线程执行sleep()方法后转入阻塞(blocked)状态,而执行yield()方法后转入就绪(ready)状态;
③ sleep()方法声明抛出InterruptedException,而yield()方法没有声明任何异常;

④ sleep()方法比yield()方法(跟操作系统CPU调度相关)具有更好的可移植性

41. 当一个线程进入一个对象的synchronized方法A之后,其它线程是否可进入此对象的synchronized方法B?
答:不能。其它线程只能访问该对象的非同步方法,同步方法则不能进入。因为非静态方法上的synchronized修饰符要求执行方法时要获得对象的锁,如果已经进入A方法说明对象锁已经被取走,那么试图进入B方法的线程就只能在等锁池(注意不是等待池哦)中等待对象的锁。

42. 请说出与线程同步以及线程调度相关的方法。
- wait():使一个线程处于等待(阻塞)状态,并且释放所持有的对象的锁;
- sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要处理InterruptedException异常;
- notify():唤醒一个处于等待状态的线程,当然在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且与优先级无关;
- notityAll():唤醒所有处于等待状态的线程,该方法并不是将对象的锁给所有线程,而是让它们竞争,只有获得锁的线程才能进入就绪状态;

43. 编写多线程程序有几种实现方式?

1.一种是继承Thread类;

2.另一种是实现Runnable接口;

3.覆写Callable接口实现多线程(JDK1.5)    a.核心方法叫call()方法,有返回值 ;      b.有返回值 ;

4.通过Executor 的工具类可以创建三种类型的普通线程池 , 从线程池中获取线程

前两种都要通过重写run()方法来定义线程的行为,推荐使用后者,因为Java中的继承是单继承,一个类有一个父类,如果继承了Thread类就无法再继承其他类了,显然使用Runnable接口更为灵活 , ,2 和 3 相比 , call方法具有返回值 

44. 关于synchronized锁 和 lock 锁 的区别

1、 Lock是一个接口,属于JDK层面的实现;而synchronized属于Java语言的特性,其实现有JVM来控制(代码执行完毕,出现异常,wait时JVM会主动释放锁)。

2、 synchronized在发生异常时,会自动释放掉锁,故不会发生死锁现(此时的死锁一般是代码逻辑引起的);而Lock必须在finally中主动unlock锁,否则就会出现死锁。

3、 Lock能够响应中断,让等待状态的线程停止等待;而synchronized不行。

4、 通过Lock可以知道线程是否成功获得了锁,而synchronized不行。

5、 Lock提高了多线程下对读操作的效率。

45. 同步和异步的区别

如果系统中存在临界资源(资源数量少于竞争资源的线程数量的资源),例如正在写的数据以后可能被另一个线程读到,或者正在读的数据可能已经被另一个线程写过了,那么这些数据就必须进行同步存取(数据库操作中的排他锁就是最好的例子)。当应用程序在对象上调用了一个需要花费很长时间来执行的方法,并且不希望让程序等待方法的返回时,就应该使用异步编程,在很多情况下采用异步途径往往更有效率。事实上,所谓的同步就是指阻塞式操作,而异步就是非阻塞式操作。

46.线程6中种状态的转换

1.新建状态:在生成线程对象,并没有调用该对象的start方法,这是线程处于创建状态

2.就绪状态:Java线程中将就绪(ready)和运行中(running)两种状态笼统的称为“运行”。
线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取CPU的使用权,此时处于就绪状态(ready)。就绪状态的线程在获得CPU时间片后变为运行中状态(running)

3.限时等待状态:进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断)

4.无限等待状态:该状态不同于WAITING,它可以在指定的时间后自行返回

5.阻塞状态:线程正在运行的时候,被暂停,通常是为了等待某个时间的发生(比如说某项资源就绪)之后再继续运行。sleep,suspend,wait等方法都可以导致线程阻塞

6.消亡状态:如果一个线程的run方法执行结束或者调用stop方法后,该线程就会死亡。对于已经死亡的线程,无法再使用start方法令其进入就绪 

47.守护线程和用户线程

用户线程:非守护线程包括常规的用户线程或诸如用于处理GUI事件的事件调度线程,Java虚拟机在它所有非守护线程已经离开后自动离开

守护线程:守护线程则是用来服务用户线程的,比如说GC线程。如果没有其他用户线程在运行,那么就没有可服务对象,也就没有理由继续下去

用户线程即运行在前台的线程,而守护线程是运行在后台的线程。 守护线程作用是为其他前台线程的运行提供便利服务,而且仅在普通、非守护线程仍然运行时才需要,比如垃圾回收线程就是一个守护线程。当VM检测仅剩一个守护线程,而用户线程都已经退出运行时,VM就会退出,因为没有如果没有了被守护这,也就没有继续运行程序的必要了。如果有非守护线程仍然存活,VM就不会退出。守护线程并非只有虚拟机内部提供,用户在编写程序时也可以自己设置守护线程。用户可以用Thread的setDaemon(true)方法设置当前线程为守护线程
 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值