Java面试八股文

本文详细列举了Java面试中涉及的基础语法、集合框架、事务、通信协议、异常处理、反射机制、JVM、多线程、JavaWeb、Redis、Mybatis、RabbitMQ等关键知识点,包括各种类、接口、方法的区别和应用场景,以及在并发、存储、通信等方面的设计和优化策略。通过对这些知识点的掌握,可以深入理解Java技术栈并应对面试挑战。
摘要由CSDN通过智能技术生成

基础语法

1 String 、StringBuilder 、StringBuffer 的区别?

1,String是只读字符串,引用的字符串内容是不能被改变的。

2,StringBuilder和StringBuffer表示的字符串对象可以直接被修改,StringBuilder单线程环境下使用,效率要比StringBuffer要高,StringBuffer加锁了,更加线程安全

2 equals() 与 == 的区别?

对于基本类型来说 一般使用==来比较值是否相等 equals不能用在基本类型 对象引用的话,equals()方法使用 == 来判断两个数据是否相等,如果我们自定义类时直接调用Object类中的equals()方法,判断地址值是否相同

3 是否可以继承String类? 为什么用final修饰?

不能,String是final修饰的类,不能被继承;
为了效率和安全
1.只有字符串是不可变的,字符串池才有可能实现
2.只有字符串是不可变的,所以多线程是安全的,同一个字符串实例可以被多个线程共享
3.因为字符串是不可变得,所以他在被创建的时候就已经被hashcode缓存了,不需要重新计算,使得字符串很适合做map中的键
4.如果字符串是可变的,会引起很严重的安全问题

4 什么是面向对象编程 ?

面向对象编程的基本思想就是利用类 方法 继承封装多态 等概念来进行程序设计,从现实世界中实际存在的事物(对象)出发来构造软件系统,尽可能的运用人类的自然思想进行程序设计

5 面向对象的三大特征

继承:子类继承父类可以实现代码的抽取和复用,单继承,多实现
封装:将事物的属性和行为抽取出来封装到类中
多态:父类的引用指向子类的实现 Animal a = new Dog(); 三个条件:继承 重写 向上转型

6 JDK,JRE,JVM

JDK是开发者工具包,包含jre和JVM
JER是开发环境,包含JVM和核心类库
JVM是虚拟机

7 java基本数据类型

整型 byte short int long
浮点型 float double
布尔型 boolean
字符型 char

8 什么是方法签名

方法名称和参数类型

9 java中的访问修饰符

private default protect public

10 final有什么用?和finally,finalize有什么区别?

final修饰的类不能被继承 final修饰的方法不能被重写 final修饰的变量为常量,不能被重新赋值
finally一般用在try-catch结构中,不管是否出现异常,finally后面的语句都会被执行
finalize 是Object类的方法 用在垃圾回收器中

11 this和super的区别

this指向的是自身的一个对象,代表对象本身,
super指向的是自己的一个超类对象,这个超类对象是最近的一个父类
this()调用的是本类的其他构造方法
super()调用的是父类的构造方法

12 break ,continue ,return 的区别及作用?

break 跳出当前循环 continue结束当前循环进入下一循环 return 结束整个方法

13 抽象类能被final修饰吗?

不能,final修饰的类不能被继承,而抽象类本身就是用来被继承的,相悖所以不能

14 static修饰的方法能调用非static修饰的变量和方法吗 ?

static修饰的方法只能调用静态方法和变量

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

因为生命周期不一致 局部变量保存在栈中 当方法结束后 非final修饰的变量会被销毁 而局部内部类对局部变量的引用仍然存在 调用局部变量的时候就会出错

16 重载(Overload)和重写(Override)的区别

重载:方法名称相同 参数类型不同 参数类型:参数数量 参数类型 参数顺序
重写:发生在父子类中 方法的名称参数必须相同 抛出的异常小于父类 访问修饰符大于等于父类

17 构造器(constructor)是否可被重写(override)

构造器不能被继承,所以不能被重写,但是可以被重载

18 Java中创建对象的方式有哪些

1 使用new关键字
2 使用Class类的newInstance方法
3 使用Constructor类的newInstance方法
4 使用clone方法
5 使用反序列化

集合

1 ArrayList和LinkList的区别?

ArrayList查询速度快(不准确),尾部增删快,头部增删慢,随机访问速度快;LinkList头尾增删速度快,中间不高,性能远比arraylist差,不适合做查询;真想查询用hashMap

  1. 是否保证线程安全: ArrayList 和 LinkedList 都不保证线程安全;
  2. 底层数据结构: Arraylist 底层使用的是数组;LinkedList 底层使用的是双链表;
  3. 插入和删除是否受元素位置的影响:
    ArrayList 采用数组存储,所以插入和删除元素的时间复杂度受元素位置的影响。
    LinkedList 采用链表存储,所以插入,删除元素时间复杂度不受元素位置的影响。
  4. 是否支持快速随机访问 : LinkedList 不支持高效的随机元素访问,ArrayList 实现了RandmoAccess 接口,所以有随机访问功能
  5. 内存空间占用:
    ArrayList的空间浪费主要结尾会预留一定的容量空间
    LinkedList的空间花费则体现在它的每一个元素都需要消耗比ArrayList更多的空间
2 HashMap底层原理

JDK8以前:数组+双链表
JDK8以后:数组+双链表+红黑树

3 HashMap 的resize过程是什么样的?

采用hash表数据加链表的形式,1.8以后引入了红黑树的数据结构 ,初始化数组长度为16 ,当数组长度到0.75时扩容 , 链表长度大于8时转为红黑树 , 红黑树的长度小于6时转为链表结构数组中的元素容量超过了阙值的0.75就会触发扩容长度

4 HashMap你经常用在那个地方?
  1. 电子商务的应用中使用HashMap作为缓存。
  2. 金融领域出于性能的考虑非常多的运用HashMap和ConcurrentHashMap。
  3. controller层向前台返回数据可以用map封装数据
  4. mybatis中的map可以作为参数或者封装结果集
5 HashMap和Hashtable的区别?
  1. hashMap去掉了HashTable 的contains方法,但是加上了containsValue()和containsKey()方法。
  2. hashTable同步的,而HashMap是非同步的,效率上比hashTable要高。
  3. hashMap允许空键值,而hashTable不允许。
6 List、Map、Set三个接口,存取元素时,各有什么特点?

List 有序可重复
Set 无序不重复
Map 一般都是键值对key-value值,value可多值

7 HashSet是如何保证元素唯一性的呢?

通过元素的两个方法 hashcode和equals来完成的

8 TreeSet怎么对集合中的元素进行排序?

TreeSet底层数据结构是二叉树。

  1. 让元素自身具备比较性,需要元素对象实现Comparable接口,覆盖compareTo方法

  2. 让集合自身具备比较性,需要定义一个实现了Comparator接口的比较器,覆盖compare方法

9 map集合的两种取出方式?
  1. 通过map.keyset,先得到map集合的键,再根据键得到value值

  2. 通过map.entrySet直接得到键值对

10 Collection和Collections的区别?

Collection是集合类的上级接口,继承它的接口主要有set和list
Collections是工具类,有很多操作集合的方法

11 ConcurrentHashMap 的工作原理及代码实现

ConcurrentHashMap引入了分割(Segment)的概念,只对Map的一部分(Segment)进行上锁 , 这样 保证同步的时候,锁住的不是整个Map

12 HashCode的方法和作用

hashCode() 的作用是获取哈希码,也称为散列码;它实际上是返回一个int整数。这个哈希码的作 用是确定该对象在哈希表中的索引位置

不同的对象可能会有相同的hashcode , 在比较一个对象是否相等时 , 首先需要比较对象的hashcode是否相等, 其次要比较equal是否相等

因此,equals 方法被覆盖过,则 hashCode 方法也必须被覆盖 hashCode() 的默认行为是对堆上的对象产生独特值。如果没有重写 hashCode(),则该 class 的两个对象 无论如何都不会相等

13 什么是链表

链表是可以将物理地址上不连续的数据连接起来,通过指针来对物理地址进行操作,实现增删改查 等功能。

链表大致分为单链表和双向链表

单链表:每个节点包含两部分,一部分存放数据变量的data,另一部分是指向下一节点的next指 针

双向链表:除了包含单链表的部分,还增加的pre前一个节点的指针

14 链表的优缺点

链表的优点

  1. 插入删除速度快(因为有next指针指向其下一个节点,通过改变指针的指向可以方便的增加 删除元素)
  2. 内存利用率高,不会浪费内存(可以使用内存中细小的不连续空间(大于node节点的大 小),并且在需要空间的时候才创建空间)
  3. 大小没有固定,拓展很灵活。

链表的缺点 : 不能随机查找,必须从第一个开始遍历,查找效率低

15 什么是红黑树

红黑树是一种含有红黑结点并能自平衡的二叉查找树。它必须满足下面性质:

  • 性质1:每个节点要么是黑色,要么是红色。
  • 性质2:根节点是黑色。
  • 性质3:每个叶子节点(NIL)是黑色。
  • 性质4:每个红色结点的两个子结点一定都是黑色。
  • 性质5:任意一结点到每个叶子结点的路径都包含数量相同的黑结点。
16 常用的集合类有哪些?

Map接口和Collection接口是所有集合框架的父接口:

Collection接口的子接口包括:Set接口和List接口
Map接口的实现类主要有:HashMap、TreeMap、Hashtable、ConcurrentHashMap以及 Properties等
Set接口的实现类主要有:HashSet、TreeSet、LinkedHashSet等
List接口的实现类主要有:ArrayList、LinkedList、Stack以及Vector等

17 哪些集合类是线程安全的?
  • Vector:就比Arraylist多了个 synchronized (线程安全),因为效率较低,现在已经不太建议使 用。
  • hashTable:就比hashMap多了个synchronized (线程安全),不建议使用。
  • ConcurrentHashMap:是Java5中支持高并发、高吞吐量的线程安全HashMap实现。
18 遍历一个 List 有哪些不同的方式?
  1. for 循环遍历,基于计数器。在集合外部维护一个计数器,然后依次读取每一个位置的元素, 当读取到最后一个元素后停止。
  2. 迭代器遍历,Iterator。Iterator 是面向对象的一个设计模式,目的是屏蔽不同数据集合的特点,统一遍历集合的接口。Java 在 Collections 中支持了 Iterator 模式。
  3. foreach 循环遍历。foreach 内部也是采用了 Iterator 的方式实现,使用时不需要显式声明 Iterator 或计数器。优点是代码简洁,不易出错;缺点是只能做简单的遍历,不能在遍历过 程中操作数据集合,例如删除、替换。
19 如何实现数组和 List 之间的转换?

数组转 List:使用 Arrays. asList(array) 进行转换。
List 转数组:使用 List 自带的 toArray() 方法。

数组转set : 使用构造函数 , 直接传入数组
new HashSet(arrays[])

20 如何把一个线程不安全的集合转化为线程安全集合?

向HashSet 中add ()元素时,判断元素是否存在的依据,不仅要比较hash值,同时还要结合 equles 方法比较。

HashSet 中的add ()方法会使用HashMap 的put()方法。HashMap 的 key 是唯一的在HashMap中如果K/V相同时,会用新的V覆盖掉旧的V,然后返回旧的V。所以不会重复

21 说一下 HashSet 的实现原理?

HashSet 是基于 HashMap 实现的,HashSet的值存放于HashMap的key上,HashMap的value统 一为present,因此 HashSet 的实现比较简单,相关 HashSet 的操作,基本上都是直接调用底层 HashMap 的相关方法来完成,HashSet 不允许重复的值。

22 HashSet如何检查重复?HashSet是如何保证数据不可重复的?

向HashSet 中add ()元素时,判断元素是否存在的依据,不仅要比较hash值,同时还要结合 equles 方法比较。

HashSet 中的add ()方法会使用HashMap 的put()方法。
HashMap 的 key 是唯一的在HashMap中如果K/V相同时,会用新的V覆盖掉旧的V,然后返回旧的V。所以不会重复

23 说一下HashMap的实现原理?

HashMap是基于哈希表的Map接口的非同步实现。此实现提供所有可选的映射 操作,并允许使用null值和null键。

HashMap实际上是一个“链表散列”的数据结构,即数组和链表的结合体。

HashMap 基于 Hash 算法实现的

  1. 当我们往HashMap中put元素时,利用key的hashCode重新hash计算出当前对象的元素在数组中的下标
  2. 存储时,如果出现hash值相同的key,此时有两种情况。
    • 如果key相同,则覆盖原始值;
    • 如果key不同(出现冲突),则将当前的key-value放入链表中
  3. 获取时,直接找到hash值对应的下标,在进一步判断key是否相同,从而找到对应值。
24 HashMap是如何解决hash冲突

核心就是使用了数组的存储方式,然后将冲突的key的对象放入链表中,一旦发现冲突就在链表中做进一步的对比。
需要注意Jdk 1.8中对HashMap的实现做了优化,当链表中的节点数据超过八个之后,该链表会转为红黑树来提高查询效率,数据长度低于6之后会退化为链表

25 为什么HashMap的初始长度是16 ?

因为长度太小很容易导致map扩容影响性能,如果分配的太大的话又会浪费资源,所以就使用16作为初始大小

减少hash碰撞
提高map查询效率
分配过小防止频繁扩容
分配过大浪费资源

26 HashMap 和 ConcurrentHashMap 的区别 ?

ConcurrentHashMap对整个桶数组进行了分割分段(Segment),然后在每一个分段上都用lock锁进行保护,
相对于HashTable的synchronized锁的粒度更精细了一些,并发性能更好,
而 HashMap没有锁机制,不是线程安全的。
HashMap的键值对允许有null,但是ConCurrentHashMap都不允许

27 什么是TreeMap ?

TreeMap 是一个有序的key-value集合,它是通过红黑树实现的。

TreeMap基于红黑树(Red-Black tree)实现。该映射根据其键的自然顺序进行排序,
或者根据 创建映射时提供的 Comparator 进行排序,具体取决于使用的构造方法。

28 comparable 和 comparator的区别?

comparable接口实际上是出自java.lang包,它有一个 compareTo(Object obj)方法用来排序
comparator接口实际上是出自 java.util 包,它有一个compare(Object obj1, Object obj2)方法用 来排序

29 如何实现对集合数据排序

使用Stream中的sorted方法
使用Collections中的sort方法
使用有序的集合 , 例如 : TreeSet , TreeMap

io流

1 io流体系介绍

四大家族(InputStream、OutputStream、Reader、Writer)
InputStream与OutputStream是所有字节型输入输出流的祖宗类
Reader与Writer是所有字节型输入输出流的祖宗类

2 Java的序列化

什么是序列化?
序列化是一种处理对象流的机制,序列化就是把对象转化为字节流,被传输的对象必须实现serializable接口。
什么是反序列化?
反序列化是序列化的逆过程,把字节流转化为对象

3 谈谈Java IO里面的常见类,字节流,字符流、接口、实现类、方法阻塞

输入流就是从外部文件输入到内存,输出流主要是从内存输出到文件

字符流中有抽象类InputStream和OutputStream,字节流的子类有
FileInputStream
FileOutputStream
BufferedOutputStream等。
字符流的子类有
BufferedReader
Writer

都实现了Closeable, Flushable, Appendable这些接口。程序中的输入输出都是以流的形式保存的,流中保存的实际上全都是字节文件

java中的阻塞式方法是指在程序调用改方法时,必须等待输入数据可用或者检测到输入结束或者抛出异常,否则程序会一直停留在该语句上,不会执行下面的语句。比如read()和readLine()方法

4 如何将字节流转化为字符流 ?

InputStreamReader 是字节流通向字符流的桥梁
BufferedReader in= new BufferedReader(new InputStreamReader(System.in));

OutputStreamWriter 是字符流通向字节流的桥梁
Writer out = new BufferedWriter(new OutputStreamWriter(System.out);

事务

1 说下事务的ACID

原子性(Atomicity): 原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。

一致性(Consistency): 事务前后数据的完整性必须保持一致。

隔离性(Isolation): 事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。

持久性(Durability): 持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响

2 事务有哪几种隔离级别呢?

读未提交(read uncommitted)
另一个事务修改了数据,但尚未提交,而本事务中的SELECT会读到这些未被提交的数据脏读

读已提交(read committed)RC
事务能够看到的数据都是其他事务已经提交的修改,也就是保证不会看到任何中间性状态,当然脏读也不会出现。

可重复读(repeatable read)RR
保证同一个事务中多次读取的数据是一致的,这是 MySQL InnoDB 引擎的默认隔离级别。

串行(serializable)
并发事务之间是串行化的,通常意味着读取需要获取共享读锁,
更新需要获取排他写锁,如果 SQL 使用 WHERE 语句,还会获取区间锁,是最高的隔离级别。

3 不考虑事务的隔离级别会有什么问题

并发事务可能造成:脏读、不可重复读和幻读等问题 ,
这些问题其实都是数据库读一致性问题,必须由数据库提供一定的事务隔离机制来解决

4 事务的并发?什么是脏读? 事务隔离级别,每个级别会引发什么问题,MySQL默认是哪个级别?

事务的并发问题

  • 脏读:脏读是指在一个事务处理过程中读取了另一个事务未提交的数据。
  • 不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果因此本事务先后两次读到的数据结果会不一致。
  • 幻读:可重复读的隔离级别解决了不可重复读的问题,保证了同一个事务里,查询的结果都是事务开始时的状态(一致性)。

MySQL默认的事务隔离级别为repeatable-read(可重复读)
MySQL 支持 4 中事务隔离级别.
事务的隔离级别要得到底层数据库引擎的支持, 而不是应用程序或者框架的支持.
隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大

可以优先考虑把数据库系统的隔离级别设为Read Committed,它能够避免脏读取,而且具有较好的并发性能。
尽管它会导致不可重复读、幻读这些并发问题,
在可能出现这类问题的个别场合,可以由应用程序采用悲观锁或乐观锁来控制。

通信协议

1 名词解释 IP协议 TCP协议 UDP
  • IP协议 分组交换协议 不可靠传输 一个数据包自动分成若干小的数据包然后通过网络进行传输
  • TCP协议 传输控制协议 可靠协议 建立再IP协议之上 先建立连接,然后才能传输数据,传输完成后断开连接 支持双向通信,双方可以同时传输和接收数据
  • UDP 数据报文协议 不面向连接,不可靠传输 传输效率高,通常用来传输视频等能容忍丢失部分数据的文件。
2 TCP与UDP比较

TCP:面向连接的协议 数据传输之前必然要建立连接
UDP: 每个数据报中都给出了完整的地址信息,无需要建立发送方和接收方的连接

TCP:传输数据大小限制 双方的socket就可以按统一的格式传输大的数据
UDP : UDP传输数据时是有大小限制的,每个被传输的数据报必须限定在64KB之内。

TCP : 可靠协议,确保完全正确发送数据
UDP: 不可靠的协议,发送方所发送的数据报并不一定以相同的次序到达接收方

3 Socket

网络上的两个程序通过一个双向的通讯连接实现数据的交换,这个双向链路的一端称为一个Socket。
Socket通常用来实现客户方和服务方的连接。一个Socket由一个IP地址和一个端口号唯一确定。
在Java环境下,Socket编程主要是指基于TCP/IP协议的网络编程。

异常

1 异常的处理

声明:其实就是程序中遇到异常时,自己不处理,交给其它程序处理 throw (在使用throw抛出异常代码的后面,不能书写任意代码。)
捕获:其实就是在程序中遇到异常时,不会交给其它程序处理,自己处理 try 、catch、finally(使用try…catch…finally结构,catch中抛出异常后面如果有其他语句,先执行finally语句再去执行catch中的其他语句)

2 定义异常处理时,什么时候定义try,什么时候定义throws呢?

功能内部如果出现异常,如果内部可以处理,就用try;
如果功能内部处理不了,就必须声明出来,让调用者处理。

3 请写出你最常见到的5个runtime exception。

NullPointerException(空指针异常)
ArrayIndexOutOfBoundsException(数组索引越界异常)
ClassCastException(类型转换异常)
ArithmeticException(数学计算异常)
NumberFormatException(数字格式化异常)

反射

1 什么是反射机制?反射机制优缺点

JAVA反射机制是在运行过程中,对于任意一个类,都可以知道这个类的所有属性和方法;
对于任意一个对象,都能够调用它的任意一个方法和属性,这种动态获取信息,动态调用的方法称为java反射机制
反射机制优缺点
缺点 : 性能差,比直接的java代码慢很多
优点 : 灵活性高,运行期类型的判断,动态加载类

2 反射机制的应用场景

我们平时的项目开发过程中,基本上很少会直接使用到反射机制,但这不能说明反射机制没有用,实际上有很多设计、开发都与反射机制有关,
例如模块化的开发,通过反射去调用对应的字节码;
动态代理设计模式也采用了反射机制,
还有我们日常使用的 Spring/SpringMVC / Mybatis 等框架也大 量使用到了反射机制

3 Java获取反射的三种方法

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

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

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

JDK1.8新特性

1 lambda表达式

Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。
使用 Lambda 表达式可以使代码变的更加简洁紧凑
是对函数式接口的另外一种重写形式
函数式接口(接口中只有一个抽象方法)

2 Optional

Optional类是Java8为了解决null值判断问题,借鉴google guava类库的Optional类而引入的一个同名Optional类,
使用Optional类可以避免显式的null值判断(null的防御性检查),避免null导致的NPE(NullPointerException)

JVM

1 JVM运行流程

首先通过编译器把 Java 代码转换成字节码文件,然后类加载器(ClassLoader)再把字节码加载到内存中,放在运行时数据区的方法区内,然后需要特定的命令解析器执行引擎 ,将字节码翻译成底层系统指令,再交由 CPU 去执行

2 说一下 JVM 运行时数据区

Java 虚拟机在执行 Java 程序的过程中会把它所管理的内存区域划分为若干个不同的数据区域。
这些区域都有各自的用途,以及创建和销毁的时间,
有些区域随着虚拟机进程的启动而存在,有些区域则是依赖线程的启动和结束而建立和销毁。
Java 虚拟机所管理的内存被划分为如下几个区域
方法区 虚拟机栈 本地方法栈 堆 程序计数器

  • 程序计数器(Program Counter Register):当前线程所执行的字节码的行号指示器,字节码解 析器的工作是通过改变这个计数器的值,来选取下一条需要执行的字节码指令,分支、循环、跳 转、异常处理、线程恢复等基础功能,都需要依赖这个计数器来完成; 为什么要线程计数器?因为线程是不具备记忆功能

  • Java 虚拟机栈(Java Virtual Machine Stacks):每个方法在执行的同时都会在Java 虚拟机栈中创 建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息; 栈帧就是Java虚拟机栈中的下一个单位

  • 本地方法栈(Native Method Stack):与虚拟机栈的作用是一样的,只不过虚拟机栈是服务 Java 方法的,而本地方法栈是为虚拟机调用 Native 方法服务的; Native 关键字修饰的方法是看不到的,Native 方法的源码大部分都是 C和C++ 的代码

  • Java 堆(Java Heap):Java 虚拟机中内存最大的一块,是被所有线程共享的,几乎所有的对象实 例都在这里分配内存;

  • 方法区(Methed Area):用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译后的 代码等数据。

3 说一说你对Java堆的理解 ?

java堆(Java Heap)是java虚拟机所管理的内存中最大的一块,是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例。

在Java虚拟机规范中的描述是:所有的对象实例以及数组都要在堆上分配。

java堆是垃圾收集器管理的主要区域,因此也被成为“GC堆”

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值