Java基础简要(基础、集合、正则、时间类、异常、Stream流、File类、IO流、多线程、数据结构、泛型)

一位等于1比特。比特(BIT)和位是同一个概念的不同表述,都是信息量的最小单位。1字节(byte)由8位组成。
在这里插入图片描述

1.介绍

  • JVM(Java Virtual Machine):Java虚拟机, 真正运行Java程序的地方
  • 核心类库:Java自己写好的程序,给程序员自己的程序调用的
  • JRE(Java Runtime Environment): Java的运行环境
  • JDK(Java Development Kit): Java开发工具包(包括上面所有)
    -

1.1 数据类型

1.1.1 基本数据类型

在这里插入图片描述

2 运算符

算数运算符、自增自减运算符、赋值运算符、关系运算符、逻辑运算符、三元运算符

2.1 逻辑运算符

  • 逻辑与 &,无论左边 true false,右边都要执行。
    短路与 &&,如果左边为 true,右边执行;如果左边为 false,右边不执行。
  • 逻辑或 |,无论左边 true false,右边都要执行。
    短路或 ||,如果左边为 false,右边执行;如果左边为 true,右边不执行。

2.2 运算符优先级

在这里插入图片描述

3 方法重载

同一个类中,方法名相同,参数不同的方法(个数不同、类型不同、顺序不同)
注意:识别方法之间是否是重载关系,只看方法名和参数,跟返回值无关。

4 流程控制语句

4.1 顺序结构

系统默认

4.2 分支结构

4.2.1 if 语句

if、else if、else
if 语句中只有一条语句时,大括号可省略

1.4.2.2 Switch 语句
switch(表达式){
	case1:
		语句体1;
		break;
	case2:
		语句体2;
		break;
	...
	default:
		语句体n;
		break;
}

表达式:(将要匹配的值) 取值为 byte、short、int、char,JDK5以后可以是 枚举 ,JDK7以后可以是 String
:case给出的值不允许重复;case后面的值只能是常量,不能是变量

4.3 循环语句

for、while、do…while

5 面向对象

5.1 面向对象三大特征

封装、继承、多态

5.1.1 继承

子类重写父类方法,需要保证方法声明完全一致(方法名,参数,返回值类型需要保持一致)
标识:@Override注解
注:

  • 父类中私有方法不能被重写
  • 子类重写父类方法时,访问权限必须大于等于父类
  • 接口可以多继承,类只能单继承

5.2 接口

抽象类和接口的对比:

  • 成员变量 :
    抽象类 : 可以定义变量, 也可以定义常量
    接口 : 只能定义常量

  • 成员方法
    抽象类 : 可以是定义具体方法, 也可以定义抽象方法
    接口 : 只能定义抽象方法

  • 构造方法
    抽象类 : 有
    接口 : 没有

5.2.1 新特性

5.2.1.1 JDK8的新特性

接口中可以定义有方法体的方法。(默认、静态)

5.2.1.1.1 默认方法

允许在接口中定义非抽象方法,但是需要使用关键字 default 修饰,这些方法就是默认方法
作用:解决接口升级的问题

接口中默认方法的定义格式:
格式:public default 返回值类型 方法名(参数列表) {}
范例:public default void show() {}

  • 默认方法不是抽象方法,所以不强制被重写 (但是可以被重写,重写的时候去掉default关键字)
  • public可以省略,default不能省略
  • 如果实现了多个接口,多个接口中存在相同的方法声明,子类就必须对该方法进行重写
5.2.1.1.2 静态方法

接口中允许定义 static 静态方法

接口中静态方法的定义格式:
格式:public static 返回值类型 方法名(参数列表) {}
范例:public static void show() {}

  • 静态方法只能通过接口名调用,不能通过实现类名或者对象名调用
  • public可以省略,static不能省略
5.2.1.2 JDK9的新特性

接口中可以定义私有方法。

5.3 final关键字

不能被重写、不能被继承、不能再次被赋值
final 修饰的引用类型的地址值不能发生改变,但是地址里面的内容是可以发生改变的

5.4 抽象

抽象方法:将共性的行为(方法)抽取到父类之后,发现该方法的实现逻辑无法在父类中给出具体明确,该方法就可以定义为抽象方法。
抽象类:如果一个类中存在抽象方法,那么该类就必须声明为抽象类

抽象方法的定义格式:
public abstract 返回值类型 方法名(参数列表);

抽象类的定义格式:
public abstract class 类名{}

  • 抽象类不能实例化
  • 抽象类存在构造方法
  • 抽象类中可以存在普通方法
  • 抽象类的子类
    • 要么重写抽象类中的所有抽象方法
    • 要么是抽象类

abstract 关键字的冲突:

  • final:被 abstract 修饰的方法,强制要求子类重写,被 final 修饰的方法子类不能重写
  • private:被 abstract 修饰的方法,强制要求子类重写,被 private 修饰的方法子类不能重写
  • static:被 static 修饰的方法可以类名调用,类名调用抽象方法没有意义

5.5 代码块

在Java类下,使用 { } 括起来的代码被称为代码块

  • 局部代码块
    位置:方法中定义
    作用:限定变量的生命周期,及早释放,提高内存利用率
  • 构造代码块
    位置:类中方法外定义
    特点:每次构造方法执行的时,都会执行该代码块中的代码,并且在构造方法执行前执行
    作用:将多个构造方法中相同的代码,抽取到构造代码块中,提高代码的复用性
  • 静态代码块
    位置:类中方法外定义
    特点:需要通过static关键字修饰,随着类的加载而加载,并且只执行一次
    作用:在类加载的时候做一些数据初始化的操作
  • 同步代码块

6 集合

6.1 单列集合

Collection接口
一次添加一个元素,单列集合.add(“元素”)
ArraysList、LinkedList、TreeSet、HashSet、LinkedHashSet

6.1.1 List接口

有序、有索引、可重复

6.1.1.1 ArrayList

ArrayList 长度可变原理:

  1. 当创建 ArrayList 集合容器的时候, 底层会存在一个长度为10个大小的空数组
  2. 扩容原数组 1.5 倍大小的新数组
  3. 将原数组数据,拷贝到新数组中
  4. 将新元素添加到新数组
6.1.1.2 LinkedList

LinkedList 底层基于双链表实现的,查询元素慢,增删首尾元素是非常快的
在这里插入图片描述

6.1.2 Set接口

无序、无索引、去重

6.1.2.1 TreeSet

作用 : 对集合中的元素进行排序操作 (底层红黑树实现)

6.1.2.1.1 自然排序
1.类实现 Comparable 接口
2.重写 compareTo 方法
3.根据方法的返回值, 来组织排序规则
   负数 : 左边走
   正数 : 右边走
   0  : 不存 

public class Student implements Comparable<Student>{
	@Override
	public int compareTo(Student o) {
		return this.age - o.age;
	}
}
TreeSet<Student> ts = new TreeSet<>();
ts.add(new Student("王五", 25));
ts.add(new Student("张三", 23));
ts.add(new Student("李四", 24));
6.1.2.1.2 比较器排序
1.TreeSet 的构造方法中, 传入 Compartor 接口的实现类对象
2.重写 compare 方法
3.根据方法的返回值, 来组织排序规则
   负数 : 左边走
   正数 : 右边走
   0  : 不存 

public class Student implements Comparable<Student>{
	@Override
	public int compareTo(Student o) {
		return this.age - o.age;
	}
}
TreeSet<Student> ts = new TreeSet<>();
ts.add(new Student("王五", 25));
ts.add(new Student("张三", 23));
ts.add(new Student("李四", 24));
6.1.2.2 HashSet

HashSet 集合底层采取哈希表存储数据
哈希表是一种对于增删改查数据性能都较好的结构

哈希表 :
JDK8版本之前 : 数组 + 链表
JDK8版本之后 : 数组 + 链表 + 红黑树

6.1.2.2.1 hashCode

哈希值:是JDK根据某种规则算出来的int类型的整数。
public int hashCode​():调用底层 C++ 代码计算出的一个随机数 (常被人称作地址值)
在这里插入图片描述
当添加对象的时候, 会先调用对象的hashCode方法计算出一个应该存入的索引位置, 查看该位置上是否存在元素:
不存在:直接存
存在:调用equals方法比较内容,false : 存,true : 不存
如果hashCode方法固定返回相同的值,数据都会挂在一个索引下面(如上图,hashCode方法return 1)

在这里插入图片描述

  1. 创建一个默认长度16的数组,数组名table
  2. 根据元素的哈希值跟数组的长度求余计算出应存入的位置
  3. 判断当前位置是否为null,如果是null直接存入
  4. 如果位置不为null,表示有元素,则调用equals方法比较
  5. 如果一样,则不存,如果不一样,则存入数组,
    • JDK 7新元素占老元素位置,指向老元素 (头插法)
    • JDK 8中新元素挂在老元素下面(尾插法)

在这里插入图片描述

  1. 创建 HashSet 集合, 内部会存在一个默认长度16,默认加载因为0.75的数组
  2. 调用集合的添加方法, 会拿着对象的hashCode方法计算出应存入的索引位置 ( 哈希值 % 数组长度)
  3. 判断索引位置元素是否是null:
    是 : 存入
    不是: 说明有元素, 调用equals方法比较内容,如果一样,则不存,如果不一样,则存入数组。
  4. 当数组存满到16*0.75=12时,就自动扩容,每次扩容原先的两倍
  5. 当链表挂载元素超过了8个 (阈值),检查数组长度:
    没有到达64, 扩容数组
    到达了64, 会转换为红黑树
6.1.2.3 LinkedHashSet

有序、不重复、无索引。
原理:底层数据结构是依然哈希表,只是每个元素又额外的多了一个双链表的机制记录存储的顺序。

6.1.3 单列集合小结

  1. 如果想要集合中的元素可重复
    用ArrayList集合,基于数组的。(用的最多)
  2. 如果想要集合中的元素可重复,而且当前的增删操作明显多于查询
    用LinkedList集合,基于链表的。
  3. 如果想对集合中的元素去重
    用HashSet集合,基于哈希表的。 (用的最多)
  4. 如果想对集合中的元素去重,而且保证存取顺序
    用LinkedHashSet集合,基于哈希表和双链表,效率低于HashSet。
  5. 如果想对集合中的元素进行排序
    用TreeSet集合,基于红黑树。后续也可以用List集合实现排序。

6.2 双列集合

Map接口
一次添加两个元素,双列集合.put(“元素key”,“元素value”)

双列集合的数据结构,都只针对于键有效,和值没有关系:
TreeMap : 键(红黑树)
HashMap : 键(哈希表)
LinkedHashMap : 键(哈希表 + 双向链表)
在这里插入图片描述

7 正则表达式

String telRegex = "编写规则";
"需要做校验的字符串".matches(telRegex));

字符类(默认匹配一个字符)

[abc]	        只能是a, b, 或c
[^abc]	        除了a, b, c之外的任何字符
[a-zA-Z]        a到z AZ,包括(范围)
[a-d[m-p]]	    a到d,或m通过p:([a-dm-p]联合)
[a-z&&[def]]	d, e,f(交集)
[a-z&&[^bc]]	a到z,除了b和c:([ad-z]减法)
[a-z&&[^m-p]]   a到z,除了m到p:([a-lq-z]减法)

预定义的字符类(默认匹配一个字符)

.	任何字符
\d	一个数字: [0-9]
\D	非数字: [^0-9]
\s	一个空白字符: [ \t\n\x0B\f\r]
\S	非空白字符: [^\s]
\w	[a-zA-Z_0-9] 英文、数字、下划线
\W	[^\w] 一个非单词字符

量词(配合匹配多个字符)

X?			X , 一次或根本不
X*			X,零次或多次 (任意次数)
X+			X , 一次或多次
X {n}		X,正好n次
X {n, }		X,至少n次
X {n,m}		X,至少n但不超过m次

8 时间类(jdk8)

8.1 日历类

LocalDate :代表本地日期(年、月、日、星期)
LocalTime :代表本地时间(时、分、秒、纳秒)
LocalDateTime :代表本地日期、时间(年、月、日、星期、时、分、秒、纳秒)

修改年月日时分秒相关的方法
LocalDateTime 、LocalDate 、LocalTime 都是不可变的, 下列方法返回的是一个新的对象
在这里插入图片描述

8.2 日期格式化类

DateTimeFormatter :用于时间的格式化和解析
在这里插入图片描述

8.3 时间类

Instant :时间戳/时间线
ZoneId : 时区
ZonedDateTime : 带时区的时间
在这里插入图片描述

8.4 工具类

Period : 时间间隔(年,月,日)
Duration : 时间间隔(时、分、秒,纳秒)
ChronoUnit : 时间间隔 (所有单位)

9 异常

在这里插入图片描述

Error 严重级别问题
常见的 : 栈内存溢出 (StackOverflowError) 堆内存溢出 (OutOfMemoryError)

Exception:
RuntimeException 及其子类:运行时异常
除RuntimeException 之外所有的异常:编译时异常

运行时异常:
数组索引越界异常: ArrayIndexOutOfBoundsException
空指针异常 : NullPointerException
数学操作异常:ArithmeticException
类型转换异常:ClassCastException
数字转换异常: NumberFormatException

异常的默认处理流程
1.虚拟机会在出现异常的代码那里自动的创建一个异常对象:ArithmeticException
2.异常会从方法中出现的点这里抛出给调用者,调用者最终抛出给JVM虚拟机
3.虚拟机接收到异常对象后,先在控制台直接输出异常信息数据
4.终止 Java 程序的运行
5.后续代码没有机会执行了

10 Stream流

配合Lambda表达式,简化集合和数组操作
在这里插入图片描述
注:如果流对象已经被消费过,就不允许再次使用了

11 File类

在这里插入图片描述
File 对象可以定位文件和文件夹
File 封装的对象仅仅是一个路径名,这个路径可以是存在的,也可以是不存在的

在这里插入图片描述
在这里插入图片描述
:delete() 方法只能删除空文件夹,且不走回收站
在这里插入图片描述

  • 当调用者File表示的路径不存在时,返回null
  • 当调用者File表示的路径是文件时,返回null
  • 当调用者File表示的路径是一个空文件夹时,返回一个长度为0的数组
  • 当调用者File表示的路径是需要权限才能访问的文件夹时,返回null

12 IO流

input:输入(读取)
output:输出(写出)

12.1 IO 流体系结构

在这里插入图片描述

12.2 FileOutputStream 字节输出流

在这里插入图片描述
在这里插入图片描述
注:最后要关流释放资源

12.3 FileInputStream 字节输入流

在这里插入图片描述
注:
1.关联的文件不存在会抛出 FileNotFoundException 异常
2.文件夹的话会拒绝访问
在这里插入图片描述

12.4 字节缓冲流

字节缓冲流在源代码中内置了字节数组,可以提高读写效率。
: 缓冲流不具备读写功能, 它们只是对普通的流对象进行包装,真正和文件建立关联的, 还是普通的流对象
在这里插入图片描述
字节缓冲流读写过程:
在这里插入图片描述
没使用缓冲流
在这里插入图片描述

使用缓冲流
在这里插入图片描述

12.5 FileReader 字符输入流

用于读取纯文本文件,解决中文乱码问题
在这里插入图片描述

12.6 FileWriter 字符输出流

在这里插入图片描述
在这里插入图片描述
注:
1.字符输出流写出数据,需要调用flush或close方法,数据才会写出
2.Flush后可以继续写出,Close 后不能继续写出

字符流使用场景:读写纯文本文件
字节流使用场景:不是纯文本文件都用字节流

12.7 字符缓冲流

字节缓冲流在源代码中内置了字符数组,可以提高读写效率
BufferedReader、BufferedWriter
注: 缓冲流不具备读写功能, 它们只是对普通的流对象进行包装
在这里插入图片描述

12.8 转换流

InputStreamReader、OutputStreamWriter
作用:按照指定的字符编码读写操作、将字节流转换为字符流进行操作

为什么用转换流?直接new 需要的流不行吗?
因为有些流对象不是我们自己创建的,而是通过方法获取到的。
在这里插入图片描述

12.9 序列化流

在这里插入图片描述

public class Student implements Serializable {
  private static final long serialVersionUID = 1L;
  ...
}
  • 序列化流的作用是?
    可以在流中,以字节的形式直接读写对象
  • 序列化流我们用的是哪个类读取, 又是哪个类在写?
    ObjectInputStream、ObjectOutputStream
  • 调用的方法是?
    readObject() writeObject()
  • 类需要实现什么接口才可以序列化?
    Serializable接口
  • 实现接口后, 推荐多做一步操作, 这一步是 ?
    手动加入 serialVersionUID
  • transient 关键字的作用是?
    被 transient 修饰的成员变量不会被序列化

12.10 打印流

打印流可以实现方便、高效的打印数据到文件中去,并且可以指定字符编码
write(97); 输出a
println(97); 输出97
在这里插入图片描述
在这里插入图片描述
两个流都具备自动刷出、自动换行的功能

12.11 Properties

其实就是一个Map集合,内部存在着两个方法,可以很方便的将集合中的键值对写入文件,也可以方便的从文件中读取。
常用于加载配置文件

12.11.1 作为集合的使用

在这里插入图片描述

12.11.2 和 IO 有关的方法

在这里插入图片描述

12.12 字符编码:

  • GBK: 英文字符占用1个字节、中文字符占用2个字节
  • Unicode:
    UTF-16编码规则:用2~4个字节保存
    UTF-32编码规则:固定使用四个字节保存
    UTF-8编码规则:用1~4个字节保存

12.13 编码和解码:

在这里插入图片描述

13 多线程

13.1 进程和线程

13.2 进程

进程 (Process) 是计算机中的程序关于某数据集合上的一次运行活动
是系统进行资源分配的基本单位
简单理解:程序的执行过程
1.独立性:每一个进程都有自己的空间,在没有经过进程本身允许的情况下,一个进程不可以直接访问其它的的进程空间
2.动态性:进程是动态产生,动态消亡的
3.并发性:任何进程都可以同其它进程一起并发执行

并行和并发
并行:在同一时刻,有多个指令在多个CPU上【同时】执行
并发:在同一时刻,有多个指令在单个CPU上【交替】执行
在这里插入图片描述

13.3 线程

进程可以同时执行多个任务,每个任务就是线程

多线程的意义:提高效率,可以同时处理多个任务

13.4 Java 开启线程的方式

在这里插入图片描述

13.5 线程相关方法

![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/0ab189d5771844f49c609a74bf427699.png
优先级: 1 ~ 10 默认为5

线程的调度方式:
抢占式调度(随机)
非抢占式调度(轮流使用)

13.6 线程安全和同步

安全问题出现的条件:多线程环境、有共享数据、有多条语句操作共享数据
同步技术:将多条语句操作共享数据的代码给锁起来,让任意时刻只能有一个线程可以执行
同步代码块、同步方法、Lock锁

13.6.1 同步代码块

synchronized(锁对象) {
	多条语句操作共享数据的代码
}

注:
1.锁对象可以是任意对象,但是需要保证多条线程的锁对象,是同一把锁
2.同步可以解决多线程的数据安全问题,但是也会降低程序的运行效率

13.6.2 同步方法

public synchronized void method() {
	多条语句操作共享数据的代码
}

方法分为静态和非静态,静态方法的锁对象是字节码对象,非静态方法的锁对象是 this

13.6.2 Lock 锁

lock.lock();
...
lock.unlock();

Lock 是接口,无法直接创建对象
在这里插入图片描述

13.6.3 死锁

由于两个或者多个线程互相持有对方所需要的资源,导致这些线程处于等待状态,无法前往执行

13.6.4 等待唤醒机制

在这里插入图片描述
注:需要使用锁对象调用,wait() 方法在等待的使用会释放锁对象

使用 ReentrantLock 实现同步,并获取 Condition 对象
在这里插入图片描述

13.7 生产者消费者模式

为了解耦生产者和消费者的关系,通常会采用共享的数据区域 (缓冲区),就像是一个仓库
生产者生产数据之后直接放置在共享数据区中,并不需要关心消费者的行为
消费者只需要从共享数据区中去获取数据,并不需要关心生产者的行为

13.8 线程生命周期

线程被创建并启动以后,它并不是一启动就进入了执行状态,也不是一直处于执行状态。
Java 中的线程状态被定义在了 java.lang.Thread.State 枚举类
在这里插入图片描述
在这里插入图片描述

13.9 线程池

当程序中需要创建大量生存期很短暂的线程时,频繁的创建和销毁线程,就会严重浪费系统资源。
将线程对象交给线程池维护,可以降低系统成本 ,从而提升程序的性能。
在这里插入图片描述

线程池不建议使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,规避资源耗尽的风险。
说明:Executors 返回的线程池对象的弊端如下:

  1. FixedThreadPool和SingleThreadPool
    允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。
  2. CachedThreadPool :
    允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。

Executors 中提供静态方法来创建线程池
在这里插入图片描述

自定义线程池ThreadPoolExecutor 类
在这里插入图片描述
参数1:核心线程数量 (正式员工),不能小于0
参数2:最大线程数量 (正式员工 + 临时工),不能小于等于0, 最大数量 >= 核心线程数量
参数3:空闲时间,不能小于0
参数4:时间单位
参数5:任务队列 (指定排队人数),不能为null
参数6:线程对象任务工厂,不能为null
参数7:拒绝策略,不能为null

拒绝策略:
在这里插入图片描述

  • 临时线程什么时候创建?
    线程任务数 > 核心线程数 + 任务队列的数量
  • 什么时候会开启拒绝策略
    线程任务数 > 最大线程数 + 任务队列的数量

15 数据结构

数据结构是计算机底层存储、组织数据的方式,是指数据相互之间是以什么方式排列在一起的
通常情况下,精心选择的数据结构可以带来更高的运行或者存储效率

常见的数据结构:栈、队列、数组、链表、二叉树、二叉查找树、平衡二叉树、红黑树、哈希表

15.1 栈、队列

在这里插入图片描述

15.2 数组

查询速度快:查询数据通过地址值和索引定位,查询任意数据耗时相同
增、删效率低:新增或删除数据的时候,都有可能大批量的移动数组中其他的元素

15.3 链表

在这里插入图片描述
链表中的结点是独立的对象,在内存中是不连续的,每个结点包含数据值和下一个结点的地址。
链表查询慢,无论查询哪个数据都要从头开始找。
链表增删相对

在这里插入图片描述

15.4 小结

栈:后进先出,先进后出。
队列:先进先出,后进后出。
数组:内存连续区域,查询快,增删慢。
链表:元素是游离的,查询慢,首尾操作极快。

15.5 树

在这里插入图片描述
在这里插入图片描述

15.5.1 二叉查找树

二叉查找树,又称二叉排序树或者二叉搜索树

每一个节点上最多有两个子节点
任意节点左子树上的值都小于当前节点
任意节点右子树上的值都大于当前节点

15.5.2 红黑树

15.5.2.1 介绍

红黑树是一种自平衡的二叉查找树,是计算机科学中用到的一种数据结构。
是一种特殊的二叉查找树,红黑树的每一个节点上都有存储位表示节点的颜色
每一个节点可以是红或者黑;红黑树不是高度平衡的,它的平衡是通过"红黑规则"进行实现的

15.5.2.2 平衡二叉树和红黑树区别
  • 平衡二叉树:
    高度平衡,当左右子树高度差超过1时,通过旋转保持平衡。
  • 红黑树:
    是一个二叉查找树,高度不平衡,特有的红黑规则。
15.5.2.3 红黑规则
  • 每一个节点是红色的,或者是黑色的
  • 根节点必须是黑色
  • 如果一个节点没有子节点或者父节点,则该节点相应的指针属性值为Nil,这些Nil视为叶节点,每个叶节点(Nil)是黑色的
  • 如果某一个节点是红色,那么它的子节点必须是黑色(不能出现两个红色节点相连的情况)
  • 对每一个节点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点
    在这里插入图片描述

添加节点规则:
红黑树在添加节点的时候,添加的节点默认是红色的
在这里插入图片描述

16 泛型

JDK5引入的, 可以在编译阶段约束操作的数据类型, 并进行检查

16.1 泛型类

创建对象的时候确定具体类型

16.2 泛型方法

非静态方法:
public class ArrayList<E> {
    public boolean add(E e) {
    }
}

静态方法
public static<T> void printArray(T[] array){
}

16.3 泛型接口

类实现接口的时候,直接确定类型
延续接口的泛型,等创建对象的时候再确定

16.4 泛型通配符

? (任意类型)
? extends E (只能接收 E 或者是 E 的子类)
? super E (只能接收 E 或者是 E 的父类)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值