Java基础面试题大全 新地图开啦~,字节跳动开发面试经验

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip1024b (备注Java)
img

正文

就绪状态是进入运行状态的唯一入口,也就是线程想要进入运行状态状态执行,先得处于就绪状态

  1. 阻塞状态(Blocked):处于运状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入就绪状态才有机会被CPU选中再次执行.

根据阻塞状态产生的原因不同,阻塞状态又可以细分成三种:

等待阻塞:运行状态中的线程执行wait()方法,本线程进入到等待阻塞状态

同步阻塞:线程在获取synchronized同步锁失败(因为锁被其他线程占用),它会进入同步阻塞状态

其他阻塞:调用线程的sleep()或者join()或发出了I/O请求时,线程会进入到阻塞状态.当sleep()状态超时.join()等待线程终止或者超时或者I/O处理完毕时线程重新转入就绪状态

  1. 死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期

就绪 → 执行:为就绪线程分配CPU即可变为执行状态"

执行 → 就绪:正在执行的线程由于时间片用完被剥夺CPU暂停执行,就变为就绪状态

执行 → 阻塞:由于发生某事件,使正在执行的线程受阻,无法执行,则由执行变为阻塞

(例如线程正在访问临界资源,而资源正在被其他线程访问)

反之,如果获得了之前需要的资源,则由阻塞变为就绪状态,等待分配CPU再次执行

8.什么是线程池?线程池有什么优点?


我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题:

如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间。

所以我们在在Java中可以通过线程池来避免这些问题:

线程池:其实就是一个容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象的操作,无需反复创建线程而消耗过多资源。

合理利用线程池能够带来三个好处

  1. 降低资源消耗。减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。

  2. 提高响应速度。当任务到达时,任务可以不需要的等到线程创建就能立即执行。

  3. 提高线程的可管理性。可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)。

9. 你对Java内存分配了解多少?简单谈谈:


Java虚拟机管理的内存包括几个运行时数据内存:方法区、虚拟机栈、本地方法栈、堆、程序计数器,其中方法区和堆是由线程共享的数据区,其他几个是线程隔离的数据区

1. 程序计数器

程序计数器是一块较小的内存,他可以看做是当前线程所执行的行号指示器。字节码解释器工作的时候就是通过改变这个计数器的值来选取下一条需要执行的字节码的指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。如果线程正在执行的是一个Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是Native方法,这个计数器则为空。此内存区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemotyError情况的区域

2 Java虚拟机栈

虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧用于储存局部变量表、操作数栈、动态链接、方法出口等信息。每个方法从调用直至完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。

栈内存就是虚拟机栈,或者说是虚拟机栈中局部变量表的部分

局部变量表存放了编译期可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用(refrence)类型和returnAddress类型(指向了一条字节码指令的地址)

其中64位长度的long和double类型的数据会占用两个局部变量空间,其余的数据类型只占用1个。

Java虚拟机规范对这个区域规定了两种异常状况:如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常。如果虚拟机扩展时无法申请到足够的内存,就会抛出OutOfMemoryError异常

3 本地方法栈

本地方法栈和虚拟机栈发挥的作用是非常类似的,他们的区别是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则为虚拟机使用到的Native方法服务

本地方法栈区域也会抛出StackOverflowError和OutOfMemoryErroy异常

4 Java堆

堆是Java虚拟机所管理的内存中最大的一块。Java堆是被所有线程共享的一块内存区域,在虚拟机启动的时候创建,此内存区域的唯一目的是存放对象实例,几乎所有的对象实例都在这里分配内存。所有的对象实例和数组都在堆上分配

Java堆是垃圾收集器管理的主要区域。Java堆细分为新生代和老年代

不管怎样,划分的目的都是为了更好的回收内存,或者更快地分配内存

Java堆可以处于物理上不连续的内存空间中,只要逻辑上是连续的即可。如果在堆中没有完成实例分配,并且堆也无法再扩展时将会抛出OutOfMemoryError异常

5 方法区

方法区它用于储存已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据

除了Java堆一样不需要连续的内存和可以选择固定大小或者可扩展外,还可以选择不实现垃圾收集。这个区域的内存回收目标主要是针对常量池的回收和对类型的卸载

当方法区无法满足内存分配需求时,将抛出OutOfMemoryErroy异常

1.6 运行时常量池

它是方法区的一部分。Class文件中除了有关的版本、字段、方法、接口等描述信息外、还有一项信息是常量池,用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放

Java语言并不要求常量一定只有编译期才能产生,也就是可能将新的常量放入池中,这种特性被开发人员利用得比较多的便是String类的intern()方法

当常量池无法再申请到内存时会抛出OutOfMemoryError异常

10. 谈谈你对static的了解


static是Java中的一个关键字,可以用来修饰方法、变量、代码块、内部类,还可以使用静态导包

1.static方法

static方法一般称作静态方法,由于静态方法不依赖于任何对象就可以进行访问,因此对于静态方法来说,是没有this的,因为它不依附于任何对象,既然都没有对象,就谈不上this了。并且由于这个特性,在静态方法中不能访问类的非静态成员变量和非静态成员方法,因为非静态成员方法/变量都是必须依赖具体的对象才能够被调用。

注意:虽然在静态方法中不能访问非静态成员方法和非静态成员变量,但是在非静态成员方法中是可以访问静态成员方法/变量的。

2.static变量

static变量也称作静态变量,静态变量和非静态变量的区别是:静态变量被所有的对象所共享,在内存中只有一个副本【存放在方法区】,它当且仅当在类初次加载时会被初始化【加final和不加final的static变量初始化的位置不一样】。而非静态变量是对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响。

static成员变量的初始化顺序按照定义的顺序进行初始化。

3.static代码块

static关键字还有一个比较关键的作用就是用来形成静态代码块以优化程序性能,因为静态资源只会加载一次。static块可以置于类中的任何地方,类中可以有多个static块。在类初次被加载的时候,会按照static块的顺序来执行每个static块,并且只会执行一次。

初始化的顺序 静态代码块 > 构造代码块 > 构造函数

为什么说static块可以用来优化程序性能,是因为它的特性:只会在类加载的时候执行一次。

下面看个例子:

class Person{

private Date birthDate;

public Person(Date birthDate) {

this.birthDate = birthDate;

}

boolean isBornBoomer() {

Date startDate = Date.valueOf(“1946”);

Date endDate = Date.valueOf(“1964”);

return birthDate.compareTo(startDate)>=0 && birthDate.compareTo(endDate) < 0;

}

}

isBornBoomer是用来这个人是否是1946-1964年出生的,而每次isBornBoomer被调用的时候,都会生成startDate和birthDate两个对象,造成了空间浪费,如果改成这样效率会更好,其实就是利用了静态代码块在内存中值加载一次的机制:

class Person{

private Date birthDate;

private static Date startDate,endDate;

static{

startDate = Date.valueOf(“1946”);

endDate = Date.valueOf(“1964”);

}

public Person(Date birthDate) {

this.birthDate = birthDate;

}

boolean isBornBoomer() {

return birthDate.compareTo(startDate)>=0 && birthDate.compareTo(endDate) < 0;

}

}

因此,很多时候会将一些只需要进行一次的初始化操作都放在static代码块中进行。

4.静态内部类

在谈论静态内部之前,我们来谈谈,为何要用内部类?

定义在一个类内部的类叫内部类,包含内部类的类称为外部类。内部类可以声明public、protected、private等访问限制,可以声明为abstract的供其他内部类或外部类继承与扩展,或者声明为static、final的,也可以实现特定的接口。内部类有以下特点:

1.内部类一般只为其外部类使用【比如:hashmap集合中,内部类Entry<K,V>】

2.内部类提供了某种进入外部类的窗户,内部类存在外部类的引用,所以内部类可以直接访问外部类的属性

3.每个内部类都能独立地继承一个接口,而无论外部类是否已经继承了某个接口。因此,内部类使多重继承的解决方案变得更加完整。

静态内部类

定义静态内部类:在定义内部类的时候,可以在其前面加上一个权限修饰符static。此时这个内部类就变为了静态内部类。通常称为嵌套类,当内部类是static时,意味着:

  1. 要创建嵌套类的对象,并不需要其外围类的对象;

  2. 不能从嵌套类的对象中访问非静态的外围类对象(不能够从静态内部类的对象中访问外部类的非静态成员);

嵌套类与普通的内部类还有一个区别:普通内部类的字段与方法,只能放在类的外部层次上,所以普通的内部类不能有static数据和static字段, 也不能包含嵌套类。但是在嵌套类里可以包含所有这些东西。也就是说,在非静态内部类中不可以声明静态成员,只有将某个内部类修饰为静态类,然后才能够在这 个类中定义静态的成员变量与成员方法。

另外,在创建静态内部类时不需要将静态内部类的实例绑定在外部类的实例上。普通非静态内部类的 对象是依附在外部类对象之中的,要在一个外部类中定义一个静态的内部类,不需要利用关键字new来创建内部类的实例。静态类和方法只属于类本身,并不属于 该类的对象,更不属于其他外部类的对象。

补充:内部类标识符

每个类会产生一个.class文件,文件名即为类名。同样,内部类也会产生这么一个.class文件,但是它的名称却不是内部类的类名,而是有着严格的限制:外围类的名字,加上$,再加上内部类名字。

5.静态导包

静态导包就是java包的静态导入,用import static代替import静态导入包是JDK1.5中的新特性。

一般我们导入一个类都用 import com……ClassName;

而静态导入是这样:import static com……ClassName.* ;

这里的多了个static,还有就是类名ClassName后面多了个.* ,意思是导入这个类里的静态方法。

当然,也可以只导入某个静态方法,只要把 .* 换成静态方法名就行了。

然后在这个类中,就可以直接用方法名调用静态方法,而不必用ClassName.方法名的方式来调用。

好处:这种方法的好处就是可以简化一些操作,例如打印操作System.out.println(…);

就可以将其写入一个静态方法print(…),在使用时直接print(…)就可以了。

但是这种方法建议在有很多重复调用的时候使用,如果仅有一到两次调用,不如直接写来的方便

在静态导入之前:

public class TestStatic {

public static void main(String[] args) {

System.out.println(Integer.MAX_VALUE);

System.out.println(Integer.toHexString(42));

}

}

在静态导入之后:

import static java.lang.System.out;

import static java.lang.Integer.*;

public class TestStaticImport {

public static void main(String[] args) {

out.println(MAX_VALUE);

out.println(toHexString(42));

}

}

让我们看一下使用静态导入特性的代码中将发生什么:

  1. 虽然该特性通常称为“静态导入”,但语法必须是import static,后面跟你想导入的static成员的完全限定名称,或者通配符。在本例中,我们在System类的out对象上进行静态导入。

  2. 在本例中,我们可能想使用java.lang.Integer类的几个static成员。该静态导入语句使用通配符来表达“我想在此类中的所有静态成员上进行静态导入”。

  3. 现在我们终于看到静态导入特性的好处!我们不必在System.out.println中键入System。太好了!另外,我们不必在Integer.MAX_VALUE中键入Integer。因此,在这行代码中,我们能够将快捷方式用于静态方法和一个常量。

  4. 最后,我们进行更多的快捷操作,这次针对Integer类的方法。

下面是使用静态导入的几条原则:

你必须说import static, 不能说static import。

提防含糊不清的命名static成员。例如,如果你对Integer类和Long类执行了静态导入,引用MAX_VALUE将导致一个编译器错误,因为Integer和Long都有一个MAX_VALUE常量,并且Java不会知道你在引用哪个MAX_VALUE。

你可以在static对象引用、常量(记住,它们是static 或final)和static方法上进行静态导入。

11.什么是方法?谈谈你对方法的理解


1.概念

方法其实是具有一定功能的代码块,我们可以把需要多次使用的功能提取成一个方法,这样多次使用的时候也不需要把这些重复的代码写多次造成代码的冗余。

2.格式

方法定义的格式:修饰符 返回值类型 方法名(参数列表){方法体}

方法签名:方法名(参数列表)

3.注意事项

注意:我们这里说的是返回值类型而不是返回值,如果一个方法有返回值,那么返回值类型必须设置为与返回值相同的类型,并且返回值需要使用return关键字来返回。

4.方法的重载:

在同一个类中出现方法名相同但参数列表不同方法的现象

注意:方法之间能否构成重载,取决于方法的参数个数与类型,与方法的参数名无关

我们可以通过方法名+参数列表的方式确定要调用的是哪个方法

方法的传值:基本类型传递的是实际值,引用类型传递的是地址

而且方法的参数属于形参,只是格式上需要定义,但是调用方法时起不到限制的作用

形参:定义方法的时候的参数列表

实参:使用方法的时候传入的数据

重载的意义:

是为了方便外界对方法进行调用,什么样的参数程序都可以找到对应的方法来执行,体现的是程序的灵活性

5.方法的重写:

子类继承父类以后,如果子类对父类的功能不满意,可以重写父类的方法

但是重写的时候需要注意如下的规则:两同两小一大

一大:子类方法的修饰符范围 >= 父类方法的修饰符范围–指的是访问控制符

两同:方法名相同,参数列表相同

两小: 子类方法的返回值类型 <= 父类方法的返回值类型【这个大小是继承关系,不是值的大小】

子类方法抛出的异常类型 <= 父类方法抛出的异常类型【这个还没学,不用管】

注意:如果父类方法的返回值类型是void,子类保持一致即可

注意:子类不可以重写父类的私有方法,还是因为不可见

重写的意义:是在不修改源码的前提下,进行功能的修改和拓展

(OCP原则:面向修改关闭,面向拓展开放)

6.方法的递归:

递归:在方法中调用自己本身

注意递归次数过多时,会出现栈溢出异常

== 练习题 : 求数字阶乘(递归解法版)==

需求:接收用户输入的数字,计算该数字的阶乘结果

已知:负数不可以有阶乘,0的阶乘结果是1,

5 ! = 5 x 4 x 3 x 2 x 1

package cn.cxy.design;

//需求:求用户输入数字的阶乘结果

//f(int n)–用来求阶乘

//规律:

//f(n)= n*f(n-1)

//f(5)= 54321 = 5*f(4)

//f(4)= 4321 = 4f(3)

//f(3)= 321 = 3*f(2)

//f(2)= 21 = 2f(1)

//f(1)= 1

//

//5!=54321=120

//4!=432*1

//3!=321

//2!=2*1

//1!=1

public class TestRecursion {

public static void main(String[] args) {

int result = f(15);//调用f()用来求阶乘

System.out.println(result);

}

/*递归的两要素 1.总结规律 2.最简问题/

public static int f(int n) {

if(n == 1) {//最简问题

return 1;

}else {//其他情况 n*f(n-1)

//递归:再方法内部自己调用自己

return n*f(n-1);

}

}

}

在这里插入图片描述

== 练习题 : 递归求目录总大小==

需求:递归求目录的总大小 D:\ready,步骤分析如下:

1.列出文件夹中的所有资源–listFiles()–>File[]

2.判断,当前资源是文件还是文件夹–文件夹大小为0,文件大小需要累加

–是文件,求文件的字节量大小length(),累加就行

–是文件夹,继续列出文件夹下的所有资源–listFiles()–>File[]

–判断,是文件,求文件的字节量大小length(),累加就行

–判断,是文件夹,再一次列出文件夹下的所有资源

–…重复操作

也就是说,规律就是:只要是文件夹,就需要重复步骤1 2

package cn.cxy.file;

import java.io.File;

/*本类用来递归求目录总大小/

public class FileSumRecursion {

public static void main(String[] args) {

//1.指定要求哪个目录的总大小

/**注意:此处指定的目录必须是真实存在的

  • 如果传一个不存在的文件夹会报错,如果是传了一个空文件夹,大小为0*/

File file = new File(“D:\ready”);

//2.调用size()求目录大小

long total = size(file);

//3.接收结果并打印

System.out.println(“文件夹的总大小为:”+total);

}

private static long size(File file) {

//1.列出文件夹中的所有资源–listFiles()–>File[]

File[] fs = file.listFiles();

//2.遍历数组,获取每file对象

//2.1定义变量,记录总和

long sum = 0;

for(int i = 0;i < fs.length ; i++) {

//2.2通过下标操作当前遍历到的资源

File f = fs[i];

//2.3判断,当前资源是文件还是文件夹–文件夹大小为0,文件大小需要累加

if(f.isFile()) {

//–是文件,求文件的字节量大小length(),累加就行

sum += f.length();//相当于:sum = sum + f.length();

}else if(f.isDirectory()) {

//–是文件夹,继续列出文件夹下的所有资源,1 2步骤–listFiles()–>File[]

/*方法的递归,递归现象,就是在方法的内部调用方法自身/

sum += size(f);

}

}

return sum;//把sum记录的值返回调用位置

}

}

练习题 : 递归删除文件夹

需求:递归删除文件夹 D:\ready\a

1.列出文件夹下的所有资源listFiles()

2.判断,当前资源是文件还是文件夹

–判断,是文件,直接删除delete()

–判断,是文件夹,继续重复操作1 2

具体思路可以分为这么几步:

1.首先,我们需要指定一个根目录作为要删除的对象

2.列出文件夹下的所有资源listFiles(),并进行遍历

3.判断当前的资源,如果是文件,直接删除;如果是文件夹,则执行步骤2

4.将文件夹中的内容删除完毕后,删除文件夹本身

package cn.tedu.file;

import java.io.File;

/*本类用于递归删除目录/

public class TestFileDeleteRecursion {

public static void main(String[] args) {

//1.指定要删除的目录

/**为了更好的测试,注意指定的目录是已存在的目录,但是,千万不要删盘符!!!*/

/我们也有一些没有权限的文件夹,那个是无法访问且不能删除的哦/

File file = new File(“D:\ready\a”);

//2.调用删除目录的方法

boolean result = del(file);

//3.打印删除的结果

System.out.println(“删除的结果为:”+result);

}

public static boolean del(File file) {//完成的同学不是很多,抓紧时间写,写完截图发群里哈,这首歌结束我们继续

//1.列出文件夹下的所有资源

File[] fs = file.listFiles();

//2.循环遍历拿到的所有资源

for (int i = 0; i < fs.length; i++) {

//2.1获取本次循环遍历到的file对象

File f = fs[i];

//3.判断,当前资源是文件还是文件夹

if(f.isFile()) {

f.delete();//是文件,直接删除

System.out.println(file.getName()+“文件删除成功!”);

}else if(f.isDirectory()) {

//是文件夹,需要继续进行步骤1 2 ,出现了重复调用的情况

//递归,在方法的内部调用自己

del(f);

}

}

//位置:在for循环执行之外删除文件夹

file.delete();//空文件夹直接删除

System.out.println(file.getName()+“文件夹删除成功!”);

return true;

}

}

12.内部类有哪些种类?又有哪些使用场景?


  1. 定义在一个类中或者方法中的类称为内部类。

  2. 内部类可以分为以下四类:

  3. 成员内部类【这里是非静态的】

这是最普通的内部类,它定义在一个类的内部中,就如同一个类里的成员变量一样。

成员内部类可以无条件的访问外部类的成员属性和成员方法(包括 private 和 static 类型的成员)

最后总结我的面试经验

2021年的金三银四一眨眼就到了,对于很多人来说是跳槽的好机会,大厂面试远没有我们想的那么困难,摆好心态,做好准备,你也可以的。

另外,面试中遇到不会的问题不妨尝试讲讲自己的思路,因为有些问题不是考察我们的编程能力,而是逻辑思维表达能力;最后平时要进行自我分析与评价,做好职业规划,不断摸索,提高自己的编程能力和抽象思维能力。

BAT面试经验

实战系列:Spring全家桶+Redis等

其他相关的电子书:源码+调优

面试真题:

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  1. 内部类可以分为以下四类:

  2. 成员内部类【这里是非静态的】

这是最普通的内部类,它定义在一个类的内部中,就如同一个类里的成员变量一样。

成员内部类可以无条件的访问外部类的成员属性和成员方法(包括 private 和 static 类型的成员)

最后总结我的面试经验

2021年的金三银四一眨眼就到了,对于很多人来说是跳槽的好机会,大厂面试远没有我们想的那么困难,摆好心态,做好准备,你也可以的。

另外,面试中遇到不会的问题不妨尝试讲讲自己的思路,因为有些问题不是考察我们的编程能力,而是逻辑思维表达能力;最后平时要进行自我分析与评价,做好职业规划,不断摸索,提高自己的编程能力和抽象思维能力。

[外链图片转存中…(img-iQpdcEl6-1713620295128)]

BAT面试经验

实战系列:Spring全家桶+Redis等

[外链图片转存中…(img-HRidQYni-1713620295129)]

其他相关的电子书:源码+调优

[外链图片转存中…(img-IvF6OWfQ-1713620295129)]

面试真题:

[外链图片转存中…(img-DtoP5AfJ-1713620295130)]

[外链图片转存中…(img-tK9VIYFh-1713620295130)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
[外链图片转存中…(img-0WfYsK4u-1713620295131)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值