Java基础阶段的50个面试题及解析

1、Java语言的三大特性

1、封装

  • 概念:
    • 对类隐藏内部执行代码与数据细节,提供公开简单方式进行使用。
  • 分类:
    • 方法的封装就是将多行代码封装成方法,使用方法名进行标识使用;
    • 类的封装就是将属性与方法封装成类,为指定的类创建对象提供属性和行为。
    • ​现在的封装指的最多地是对属性的封装,使用private关键字对属性进行修饰使其只对当前类可见,提供公开的方法进行访问,大大地提高了系统的安全性。

2、继承

  • 概念:
    子类继承父类非私有的属性和方法,使得子类对象具有与父类相同的属性、相同的方法。
  • 作用:
    继承描述的是事物之间的所属关系,实现了代码的复用。

3、多态

  • 概念:
    一个父类不同的子类形态,根据不同的形态决定代码的调用与执行。
  • 发生条件:
    ①子类继承父类或实现类实现接口②方法重写③向上转型(声明父类变量保存子类对象)。

2、Java语言的主要特性

  • 简单性:Java的语法相较于C语言和C语言很接近,但代码量减少,使得大多数程序员很容易学习和使用Java。
  • 健壮性:检查机制,程序编译期间检测,报错。
    面向对象:是世界上第一个完全面向对象的语言。
  • 可移植性:基于JVM运行,在对应版本的JVM中都可以运行。
  • 多线程:同时执行多个不同功能的代码。
  • 分布式:程序功能分割执行,在不同的服务器中。
  • 安全性:Java通常被用在网络环境中,因此,Java提供了一个安全机制以防恶意代码的攻击。
  • 动态性:初始jdk只安装常用的基础功能,可以通过扩展的形式进行额外功能的添加。

3、JDK、JRE和JVM的关系

JDK:Java开发工具包,提供了编译、运行Java程序所需要的各种工具和标准,包括源代码以及公共jre并且包含开发环境的所有功能。
JRE:Java运行环境,为Java的运行提供了所需环境,用于解释执行Java的字节码文件。
JVM:Java虚拟机,是整个java实现跨平台的最核心的部分,保证程序的跨平台性,以及编译执行写好的java程序,是可运行Java字节码文件的虚拟计算机。
JDK、JRE和JVM三者是包含关系,使用JDK开发完成的java程序,交给JRE去运行,由JVM保证跨平台性。

4、&与&& 的区别

  • 1.&——位运算符、逻辑运算符
    &作为逻辑运算符时,&左右两端条件式有一个为假就会不成立,但是两端都会运行,比如(1+2)=4 &(1+2)=3;1+2=4即使为假也会去判断1+2=3是否成立。
  • 2.&&——逻辑运算符
    &&也叫做短路运算符,因为只要左端条件式为假直接不成立,不会去判断右端条件式。
  • 3.相同点
    &与&&都是与运算,当等式两边结果都为true时返回true,等式两边存在fasle时返回false。只要有一端为假,则语句不成立

5、哪句是编译失败的呢?为什么呢?

	byte b1=3,b2=4,b;
	b=b1+b2;
	b=3+4;

b=b1+b2;会编译失败

在进行赋值时虽然默认为int类型 但是如果数值在存储范围内不会出错

如果进行运算的是变量会获取对应地址存储的数据类型,进行运算后结果根据运算的类型进行转换,之后在进行赋值

6、if分支语句与三目运算符的区别

  • if分支语句是使用if关键字的特殊流程控制语句语法,三目运算符本质是运算符
  • 三目运算符会将结果返回,if语句不需要返回值
  • 在java源码中大量使用了三目运算符
  • 三目运算符书写的功能都可以使用if语句完成,但是反之可能要书写额外代码
  • 三目运算符运算结束后只能返回一个数据,if语句可以在代码块中对多个数据赋值
  • 三目运算符与if语句不成立的条件与代码块都不会执行
  • 三目运算符执行效率相比较if可能较低(如果三目运算符与if语句的结果都为常量时,三目运算符的效率高)

7、while循环与do…while循环的区别

  • 1、执行流程不同,while先执行条件表达式,do…while先执行循环体
  • 2、循环体执行次数不同,while循环可能一次都不执行,do…while至少执行一次
  • 3、使用场景不同

8、while循环与for循环的区别

  • 1、语法不同,使用不同的关键字实现循环功能
  • 2、初始化变量作用域不同(while循环创建的初始化变量在循环结束后也可以使用)
  • 3、内存占用区别(for循环内创建的变量在for循环结束后就会回收-》初始化与方法体中变量)
  • 4、使用场景不同
    • (1)如果在循环结束后仍然需要使用初始化变量使用while
    • (2)如果进行有限次数的循环使用for(存在固定次数)

9、override与overload的区别

overload:方法重载

  • 在一个类,方法名相同参数列表不同称发生了方法的重载,或多个方法互为重载
    • 参数列表不同:个数不同、类型不同、顺序不同

override:方法重写

  • 发生继承过程中,子类重写继承父类方法,称之为重写
    • 重写要求方法名、返回值类型和参数列表必须与被重写的方法一样,方法内部的代码块不同

两者的区别

  • 发生位置不同:重载一般发生在同一类中,重写发生在继承中
  • 书写语法不同:重载只需要方法名与参数列表就可以发生,重写返回值、方法名、参数列表必须与父类相同

10、this与super关键字的区别

this:当前类中方法声明的形参与成员变量相同时,使用this关键字标识成员变量
super:在继承过程中子类属性方法与父类属性方法相同时,使用super关键字标识父类属性与方法

  • this与super都可以调用构造方法
this(...)       ‐‐    本类的构造方法
super(...)      ‐‐    父类的构造方法

11、接口与抽象类的区别

语法区别: 抽象类使用abstract关键字修饰class 接口使用interface关键字创建
成员变量区别: 抽象类可以书写任意变量,接口中只能书写静态常量
成员方法区别: 抽象类中既可以书写实现方法也可以书写抽象方法,接口中只能拥有抽象方法
修饰符不同: 抽象类中修饰符与类的修饰符默认书写一致,接口中方法修饰符默认为public abstract
构造方法区别: 抽象类中可以书写构造方法,由子类调用进行赋值,接口中不能书写构造方法
关系区别: 类与类之间只存在单继承关系,类与接口存在多实现关系,接口与接口可以多继承

12、hash值相同的两个对象值一定相同吗

不一定,但是java中规定,如果两个对象值相同,那么hash值一定也相同
System.out.println("Aa".hashCode()); // 2112
System.out.println("BB".hashCode()); // 2112

13、为什么重写equals方法必须重写hashCode方法

java中规定,如果两个对象值相同,那么hash值一定也相同
如果equals方法返回true那么两个对象的hash值一定相同
反之不一定成立

14、equals与==的区别

  • equals是Object提供的方法,==是比较运算符
  • ==常用于比较基本数据类型中数值类型值是否相等,比较引用数据类型时,比较的是两个对象是否为同一个对象(物理地址是否相同)
  • equals是Object类提供的方法源码中使用的就是==,一般子类会重写equals方法进行内容的比较
  • ==既能比较基本数据类型也能比较引用数据类型,equalse只能比较引用类型(参数为Object,只能使用多态传入任意对象类型)

15、String、StringBuffer、StringBuilder区别

存储不同:

  • String:存储的是字符串常量不允许修改
  • StringBuffer、StringBuilder是拥有缓冲区存储,可以修改

返回值不同

  • String方法会返回一个新的字符串
  • StringBuffer、StringBuilder基本会返回自己修改后的本身

安全与效率不同

  • String:线程安全 占用资源
  • StringBuffer:线程安全 效率低
  • StringBuilder:线程不安全 效率高

使用场景不同:

  • 用于声明字符串并不进行频繁修改时使用String,否则应该使用StringBuffer、StringBuilder如果涉及到线程安全使用StringBuffer,只考虑效率使用StringBuilder

16、什么是包装类,什么是自动拆装箱

基本类型对应的包装类(位于java.lang包中)
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
charCharacter
booleanBoolean
  • java中对于基本数据类型提供的对应引用类型类,书写对应包装类
  • 自动拆装箱就是在代码运行时,基本数据类型与对应包装类对象互相自动转换的过程

17、处理异常两种方式的区别

  • 抛出异常使用throws关键字,自行处理使用try…catch捕获和处理
  • 抛出异常时调用方处理,自行处理自己书写处理代码进行处理
  • 抛出异常书写在方法上,标识当期方法可能出现的异常,自行处理使用try将可能出现的异常代码包裹对于出现的异常使用catch进行匹配处理
  • 抛出异常会导致程序的停止运行,自行处理可能不会停止

18、final finally finalize()区别

final:java中的关键字,修饰符。

  • A).如果一个类被声明为final,就意味着它不能再派生出新的子类,不能作为父类被继承。因此,一个类不能同时被声明为abstract抽象类的和final的类。
  • B).如果将变量或者方法声明为final,可以保证它们在使用中不被改变.
    • 1)被声明为final的变量必须在声明时给定初值,而在以后的引用中只能读取,不可修改。
    • 2)被声明final的方法只能使用,不能重载。

finally:java的一种异常处理机制。

  • finally是对Java异常处理模型的最佳补充。finally结构使代码总会执行,而不管无异常发生。使用finally可以维护对象的内部状态,并可以清理非内存资源。特别是在关闭数据库连接这方面,如果程序员把数据库连接的close()方法放到finally中,就会大大降低程序出错的几率。

finalize:Java中的一个方法名。

  • Java技术使用finalize()方法在垃圾收集器将对象从内存中清除出去前,做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没被引用时对这个对象调用的。它是在Object类中定义的,因此所的类都继承了它。子类覆盖finalize()方法以整理系统资源或者执行其他清理工作。
  • finalize()方法是在垃圾收集器删除对象之前对这个对象调用的。

19、return执行后finally代码块是否还会执行

执行,finally代码块一定会执行无论是否在处理中使用return结束当前方法,也会在方法结束之前执行,除非在catch中调用System.exit(0)退出系统的执行

20、throw 与throws的区别

  • throw用在方法体内,根的是异常对象名;throws用在方法声明后面,跟的是异常类名
  • throw表示抛出异常,由方法体内的语句处理;throws表示抛出异常,由该方法的调用者来处理
  • throw执行throw约定抛出了某种异常;throws表示出现异常的一种可能性,并不一定会发生这些异常

21、for循环与增强for循环的区别

1、语法不同:

  • for循环语法中书写初始值、判断条件、迭代语句
  • 增强for循环中书写保存每次取出数据的变量声明以及遍历的数据

2、执行流程不同

  • for循环按照初始值、判断条件、迭代语句、循环体语句、判断语句 …执行
  • 增强for循环依次取出遍历容器中的数据赋值给临时变量之后使用

3、功能不同

  • for循环进行容器操作时,使用的是容器提供的方式进行获取并且可以进行修改
  • 增强for循环每次使用临时变量保存,不会修改容器中的数据

4、使用场景不同

  • for循环可以在执行时根据条件进行终止与操作
  • 增强for循环只能从头到尾遍历所有数据

22、ArrayList与LinkedList的区别

ArrayList:底层使用数组形式对数据进行存储

  • 查询修改快:数组可以直接通过索引获取对应位置数据
  • 添加删除慢: 在对首位或中间数据进行添加与删除操作时,需要将之后的数据向后或向前移动,随着数据的增大移动的次数也会增大,导致执行的效率降低

LinkedList:底层使用双向链表形式对数据进行存储

  • 查询修改慢:底层使用双向链表形式对数据进行存储,每一块只保存当前数据以及前后块地址,在进行查找时,如果查找的是非首末位块,需要依次向后查找
  • 添加删除快:链表每块保存数据添加与删除时只影响前后块位置的修改

23、在实际开发过程中经常使用ArrayList进行数据的存储

1、在数据量一定的情况下对ArrayList首位添加删除效率仍然比LinkedList对末位前一位的查找效率高
2、在实际开发中添加数据一般都是直接添加至末位,更多的时候是对数据的查找与修改

24、List集合与Set集合的区别

List接口,有序可重复

  • 常用实现类ArrayList、LinkedList,额外实现了通过索引操作的方法

Set接口,无序不可重复

  • 常用实现类HashSet,底层使用的map的方法,底层存储数据的结构为数组+链表(jdk8以后达到8之后转换为红黑树),set接口无索引操作,增强了对colleation接口的实现方法

25、HashMap与HashTable区别

  • hashMap是HashTable的替代
  • hashMap线程不安全,HashTable线程安全
  • hashMap的key可以使用null作为key
  • HashTable的key不允许为null作为key

26、Arraylist 与Vector 区别

  • 1)同步性:Vector 是线程安全的(同步),而ArrayList 是线程序不安全的;
  • 2)数据增长:当需要增长时,Vector 默认增长一倍,而ArrayList 却是一半。

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

  • List:以特定次序来持有元素,可有重复元素。
  • Set:无法拥有重复元素,内部排序。
  • Map:保存key-value 值,value 可多值,但Key值唯一。

28、字节流与字符流的区别

  • 字符流本质使用的就是字节流,只不过是根据当前编码进行字节流缓冲读取写入
  • 字节流通常读取文件(可以对任意文件进行操作)
  • 字符只能对文本文件进行操作(我们能看懂的)
  • 当需要对文件内容进行操作时使用字符流,如果进行文件复制使用字节流

29、什么是java 序列化,如何实现java 序列化?

序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化。可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间。序列化是为了解决在对对象流进行读写操作时所引发的问题;序列化的实现:将需要被序列化的类实现Serializable 接口,该接口没有需实现的方法,implements Serializable 只是为了标注该对象是可被序列化的,然后使用一个输出流(如FileOutputStream)来构造一个ObjectOutputStream(对象流)对象,接着,使用ObjectOutputStream 对象的writeObject(Object obj)方法就可以将参数为obj 的对象写出(即保存其状态),要恢复的话则用输入流。

30、GC 是什么? 为什么要有GC?

GC 是垃圾收集的意思(Gabage Collection),内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java 提供的GC 功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的,Java 语言没有提供释放已分配内存的显示操作方法。Java 程序员不用担心内存管理,因为垃圾收集器会自动进行管理。要请求垃圾收集,可以调用下面的方法之一:System.gc() 或Runtime.getRuntime().gc() 。

31、什么是泛型

用于声明时无法确定类型的替代,在使用时必须传入对应的类型进行转换,会自动将声明时类所有使用泛型的位置替换为指定的类型。

32、什么是不确定参数

在定义方法时,无法确定方法的参数有多少个,只能确定参数的类型,这个时候可以使用不确定参数进行书写,在调用方法时可以无限填入参数,会自动根据填入的参数创建数组在方法中使用。

33、简述递归的思想以及书写形式

在方法中不断调用本身,从而实现相应需求的过程称之为递归

书写

  • 1、明确每次执行的功能
  • 2、定义递归条件与边界
  • 3、调用自身方法

34、简述什么叫设计模式

设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。

35、单例模式

一个应用程序中,某个类的实例对象只有一个,你没有办法去new,因为构造器是被private修饰的,一般通过getInstance()的方法来获取它们的实例。getInstance()的返回值是一个对象的引用,并不是一个新的实例,所以不要错误的理解成多个对象。

36、工厂模式

工厂模式是一种经常被使用到的模式,根据工厂模式实现的类可以根据提供的数据生成一组类中某一个类的实例,通常这一组类有一个公共的抽象父类并且实现了相同的方法,但是这些方法针对不同的数据进行了不同的操作。首先需要定义一个基类,该类的子类通过不同的方法实现了基类中的方法。然后需要定义一个工厂类,工厂类可以根据条件生成不同的子类实例。当得到子类的实例后,开发人员可以调用基类中的方法而不必考虑到底返回的是哪一个子类的实例。

37、线程与进程的区别

根本区别

  • 进程是操作系统资源分配的基本单位。
  • 线程是程序执行流的最小单元,是处理器任务调度和执行的基本单位。

内存分配不同

  • 同一进程的线程共享本进程的地址空间和资源。
  • 进程之间的地址空间和资源是相互独立的。

包含关系

  • 如果一个进程内有多个线程,则执行过程不是一条线的,而是多条线(线程)共同完成的;线程是进程的一部分,所以线程也被称为轻权进程或者轻量级进程

影响不同

  • 一个进程崩溃后,在保护模式下不会对其他进程产生影响。
  • 一个线程崩溃整个进程都死掉。所以多进程要比多线程健壮。

资源开销

  • 每个进程都有独立的代码和数据空间(程序上下文),程序之间的切换会有较大的开销。
  • 线程可以看做轻量级的进程,同一类线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器(PC),线程之间切换的开销小。

执行过程

  • 每个独立的进程有程序运行的入口、顺序执行序列和程序出口。
  • 线程不能独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制,两者均可并发执行。

38、创建多线程的方式

1、继承Thread类重写run方法
2、实现runnable接口重写run方法
3、使用callable与futrue接口创建线程
4、线程池创建

39、线程的生命周期

在这里插入图片描述

线程指在程序执行过程中,能够执行程序代码的一个执行单位,每个程序至少都有一个线程,也就是程序本身;Java 中的线程有四种状态分别是:运行、就绪、挂起、结束。

40、start方法与run方法的区别

书写的不同

  • run方法是线程执行时执行的具体方法
  • start方法是线程启动执行时的方法无需书写

线程生命周期转换不同

  • start方法是将线程由初始态转换为就绪态
  • run方法是将线程由就绪态转换为运行态

调用方不同

  • start方法由我们调用启动线程执行
  • run由计算机为线程分配运行资源之后自动调用

使用不同

  • start方法直接调用使用启动线程
  • run方法直接调用不会启动线程而是直接运行

41、wait()与 sleep()的区别

  • wait与sleep都可以使线程由运行态转化为阻塞态
  • wait由Object类提供所有的锁对象都可以使用,sleep由Thread类提供
  • wait方法会让当前获取对象锁的线程进入阻塞状态(必须获取锁对象)
  • sleep方法就是让当前线程进入阻塞状态
  • wait方法必须使用notify进行唤醒获取锁对象资源后继续执行
  • sleep方法在休眠时间到达后自动进入就绪态
  • wait方法执行后当前线程会释放锁对象
  • sleep方法不会释放锁对象

42、线程同步的方式

  • 同步代码块
    使用synchronized关键字将代码块中的代码进行同步,当多个线程执行相同代码时,会进行阻塞(等待其他线程执行结束后再执行)

  • 同步方法
    使用synchronized关键字修饰方法,当多个线程调用该方法时,同一时间只允许一个线程执行。

  • Lock锁
    在对应任务类创建锁对象,通过加锁lock()与释放锁方法unlock()对中间执行的代码进行能同步。

43、线程通信的原理

线程同步的基础上调用方法使线程按照指定的顺序执行

44、死锁的原理

两个线程或多个线程相互持有对方所需要的资源,导致线程都处于等待状态,无法往下执行,导致死锁。

45、简述synchronized 和java.util.concurrent.locks.Lock 的异同?

主要相同点:

  • Lock 能完成synchronized 所实现的所有功能。
    主要不同点:
  • Lock 有比synchronized 更精确的线程语义和更好的性能。
  • synchronized 会自动释放锁,而Lock 一定要求程序员手工释放,并且必须在finally 从句中释放。

46、TCP协议与UDP协议的区别

本质区别

  • TCP传输控制协议
  • UDP数据报协议

连接区别

  • TCP是通过三次握手后建立连接之后的数据传输
  • UDP无需连接直接发送数据

安全区别

  • TCP保证数据的准确性
  • UDP在传输过程中造成数据的丢失

数据传输的区别

  • TCP在连接中使用IO流的形式进行数据传输
  • UDP将数据分成等大的数据块进行传输

数据量的区别

  • TCP在安全的连接中无需考虑大小
  • UDP如果数据过大,数据包增大,丢失的概率也增大

使用场景不同

  • TCP用于安全通信与数据的安全传输,数据的上传
  • UDP用于数据的发送,适用于直播,视频

47、接口的默认方法与接口的静态方法的区别

默认方法:

  • 使用 default 修饰,不可省略。
  • Java8 允许在接口中增加默认方法,默认方法在实现类中可以不去实现它。
  • 如果接口中有默认方法,实现类将默认继承这个默认方法,当然如果有需要的话可以在实现类中覆盖抽象方法
  • 默认方法的使用方式:用实现类的实例来直接点出这个默认方法。而当被覆盖后,接口中的默认方法调用为:接口名.super.默认方法。

静态方法:

  • 使用 static 修饰,供接口直接调用。
  • 只能使用接口名调用,不可以通过实现类的类名或者实现类的对象调用。
  • 静态方法属于接口本身,不被实现类所继承。

48、创建对象时类的加载顺序

先加载父类,执行父类静态代码块,父类静态变量与方法,父类成员变量与方法,创建父类对象

加载子类,执行子类静态代码块,子类静态变量与方法,子类成员变量与方法,创建子类对象

49、常用类加载器有哪些

BootstrapClassLoader

  • 引导类加载器, 用来加载 Java 的核心库,是用原生代码来实现的,
  • 并不继承自 java.lang.ClassLoader。它负责将jre/lib下面的核心类库.

PlatformClassLoader

  • 平台类加载器可以看到所有平台类 ,平台类包括由平台类加载器或其祖先定义的Java SE平台API,其实现类和JDK特定的运行时类

SystemClassLoader

  • 它也被称为应用程序类加载器(ApplicationClassLoader) ,与平台类加载器不同。 系统类加载器通常用于定义应用程序类路径,模块路径和JDK特定工具上的类

UserClassLoader

  • 自定义类加载器

50、XML解析方式以及其优缺点

sax解析

  • sax:Simple API for XML。边读取边解析,采用的是事件回调的方式,书写好用于处理响应事件的方法,进行解析,当进行读取事触发相应事件执行对应方法
  • 优点
    • 进行解析是无需加载全部文档,可以边读取边解析
    • 基于事件回调进行响应的解析,只有触发相应事件时才会回调相应方法
    • 可以解析数据量大于内存的数据
  • 缺点
    • 需要自己维护响应事件的回调方法,随文档的复杂度难度递增
    • 单向解析,不会进行反向查询,只能从头解析

dom解析

  • dom:domDocument Object Model。dom解析方式基于数据的节点层次结构进行解析,dom解析方式类可以理解为内嵌了处理器,在进行加载时使用已经提供的方式进行数据的解析,并以一定的层次结构进行保存,提供相应的方法可以直接进行数据的获取
  • 优点
    • 底层以数据节点的形式进行存储数据,提供相应的方法快速获取
    • 可以对某一标签直接进行访问
  • 缺点
    • 需要加载整个文件,消耗内存,不能处理大于内存的数据
    • 无论是否需要都会加载整个数据

jdom解析

  • jdom:Java-based Document Object Model。基于java规范开发的dom方式解析xml数据,主要是基于javaAPI与集合修改了原本的nodeList存储节点的形式,与dom原有的API。
  • 优点:
    • 将数据存储使用集合的形式存储
    • 简化API的使用
  • 缺点:
    • 没有良好的灵活性
    • 性能较差

dom4j解析

  • DOM4J是一个非常非常优秀的Java XML API,具有性能优异、功能强大和极端易用使用的特点,同时它也是一个开放源代码的软件。如今你可以看到越来越多的Java软件都在使用DOM4J来读写XML,为解决jdom简化API导致的灵活性问题,dom4j在其基础上添加了大量的API功能代码。
  • 优点:
    • 提供了大量的API应用于各种形式的使用
  • 缺点:
    • API太过繁琐,如果只是进行简单的解析,不需要使用
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

璃尔 °

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

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

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

打赏作者

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

抵扣说明:

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

余额充值