【Java基础知识1】Java入门详解

目录

一、Java发展简史

二、JDK、JRE、JVM

2.1 JDK

2.2 JRE

2.3 JVM

三、编程基础

3.1 常量与变量

1.常量

2.变量

3.2 数据类型

1.基本数据类型

2.引用数据类型

3.四类八种数据类型

4.数据类型转换

3.3 运算符

3.4 流程控制语句

1. 顺序结构

2. 选择结构

3. 循环结构

4. 跳转控制语句

3.5 方法

1.方法的声明

2.访问修饰符

3.静态方法

4.抽象方法

5.构造方法

6.方法的重载与重写

3.6 数组

1.数组定义

2.数组的声明

3.数组的初始化

4.数组的特点

5.数组的常见异常

6.数组的常见用法

7.多维数组

一、Java发展简史

  • 1991年,James Gosling(高司令)和他的团队在Sun Microsystems公司开始了一个名为“Green Project”的项目,旨在开发一种用于家庭电器的嵌入式系统编程语言。
  • 1995年,这个项目正式发布,语言被命名为Java,并随之推出了Java 1.0版本。
  • Java 1.0 (1995)
    • 推出了“Write Once, Run Anywhere”(一次编写,到处运行)的理念。
    • 包括了核心API和虚拟机(JVM),支持图形用户界面(GUI)和网络编程。
  • Java 1.1 (1997)
    • 增加了内部类、JavaBeans、RMI(远程方法调用)和JDBC(Java数据库连接)等特性。
    • 加强了安全性和性能。
  • Java 2(J2SE 1.2,1998)
    • 引入了Swing库,用于构建更丰富的图形界面。
    • 分离为三个版本:J2SE(标准版)、J2EE(企业版)、J2ME(微型版)。
  • Java 2(J2SE 1.3和1.4)
    • J2SE 1.3 (2000):提升了性能,加入了Java Sound API、RMI-IIOP等。
    • J2SE 1.4 (2002):引入了assertions、NIO(新的I/O库)和日志API。
  • Java 5(J2SE 5.0,2004)
    • 引入了大量新特性:泛型、增强for循环、自动装箱/拆箱、枚举类型、可变参数、注解等。
    • 将版本命名方式从J2SE改为Java SE。
  • Java 6(2006)
    • 增强了脚本语言支持(包括JavaScript),集成了Web服务的支持。
    • 提高了对桌面应用和Web应用的支持。
  • Java 7(2011)
    • 增加了新特性如Switch语句中使用字符串、try-with-resources语句、二进制字面量等。
    • 提高了对动态语言的支持。
  • Java 8(2014)
    • 引入了Lambda表达式和Stream API,极大地简化了集合操作和并行处理。
    • 增加了新的日期和时间API(java.time包)。
  • Java 9(2017)
    • 引入了模块化系统(Project Jigsaw),使得JDK更加模块化。
    • 提供了JShell(交互式命令行工具)。
  • Java 10(2018)
    • 引入了局部变量类型推断(var关键字)。
  • Java 11(2018)
    • 成为LTS(长期支持)版本。
    • 引入了一些新的API和特性,如新的字符串方法和HTTP客户端。
  • Java 12至Java 14
    • 增强了性能和安全性,引入了一些预览特性,如Switch表达式。
  • Java 15至Java 17
    • 增加了Sealed Classes、Records等特性。
    • Java 17成为LTS版本,提供长期支持。
  • 持续快速发布周期
    • 自Java 9以来,Java采用了每6个月发布一个新版本的快速发布周期。
    • 不同的版本带来了许多新的特性和改进,使得Java更加现代化和高效。

二、JDK、JRE、JVM

JDK:java development kit (Java开发工具)

JRE:java runtime environment (Java运行时环境)

JVM:Java Virtual Machine (Java虚拟机)

2.1 JDK

官方JDK下载地址: 点我跳转下载

JDK 包含了 JRE,同时还包含了编译 Java 源码的编译器 javac,以及其他的一些重要工具:

  • javap:class 类文件的最基础的反编译器;
  • jstack:用于打印 Java 线程栈踪迹的工具;
  • jconsole:用于监视 Java 程序的工具;
  • jhat:用于 Java 堆分析的工具
  • jar:用于打包 Java 程序的工具;
  • javadoc:用于生成 Java 文档的工具;

2.2 JRE

JRE面向Java程序的使用者,而不是开发者,可以支撑Java程序的运行,包括JVM虚拟机(java.exe等)和基本的类库(rt.jar等)

2.3 JVM

JVM 是 Java Virtual Machine 的简称,意为 Java 虚拟机。JVM 主要通过分为以下 4 个部分,来执行 Java 程序:

  • 类加载器( ClassLoader )
  • 运行时数据区( Runtime Data Area )
  • 执行引擎( Execution Engine )
  • 本地库接口( Native Interface )

三、编程基础

3.1 常量与变量

在JVM的运转中,承载的是数据,而数据的一种变现形式就是“量”,量分为:常量与变量。

1.常量

所谓常量,即在作用域内保持不变的值,一般用final关键字进行修饰,通常分为全局常量、类内常量、局部常量。例如一年有四个季节、一年有12个月、一个星期有7天等。

常量分类

  • 字符串常量:凡是用双引号引起来的部分,都可以称之为字符串常量。(双引号中可跟多个字符)例如:"abc"、"Hello World"、"123"等;
  • 整形常量:数学中的整数,例如:100、200、0、-150;
  • 浮点数常量:数学中的小数,例如:2.5、-3.14、0.0;
  • 字符常量:凡是用单引号引起来的单个字符,都可以称之为字符常量。(单引号中只能有一个字符)例如:'A'、'b'、'9'、'中'等 ;
  • 布尔常量:只有true、false;
  • 空常量:null 代表没有任何数据。

2.变量

所谓变量,即在程序运行过程中可以改变的值,通常分为分为局部变量、成员变量和静态变量。比如年龄、身高、体重等。

变量注意事项

局部变量:

  • 局部变量声明在方法、构造方法或者语句块中;
  • 局部变量在方法、构造方法、或者语句块被执行的时候创建,执行完毕后销毁;
  • 访问修饰符不能用于局部变量;
  • 局部变量只在声明它的方法、构造方法或者语句块中可见;
  • 局部变量存储在栈;
  • 局部变量没有默认值,所以局部变量被声明后,必须经过初始化,才可以使用。

成员变量:

  • 成员变量声明在一个类中,但在方法、构造方法和语句块之外;
  • 成员变量在对象创建时创建,在对象被销毁时销毁;
  • 成员变量的值应该至少被一个方法、构造方法或者语句块引用,使得外部能够通过这些方式获取实例变量信息;
  • 访问修饰符可以修饰成员变量;
  • 成员变量存储在堆;
  • 成员变量对于类中的方法、构造方法或者语句块是可见的;一般情况下应该把成员变量设为私有。通过使用访问修饰符可以使成员变量对子类可见;成员变量具有默认值,数值型变量的默认值是0,布尔型变量的默认值是 false,引用类型变量的默认值是 null,变量的值可以在声明时指定,也可以在构造方法中指定。

静态变量:

  • 静态变量在类中以 static 关键字声明,且必须在方法、构造方法和语句块之外;
  • 一个类不管创建了多少个对象,该类仅有一份对应的静态变量;
  • 静态变量除了被声明为常量外很少使用;
  • 静态变量储存在静态存储区;
  • 静态变量在程序开始时创建,在程序结束时销毁;
  • 静态变量还可以在静态语句块中初始化。

3.2 数据类型

1.基本数据类型

  整数型   byte short int long

  浮点型   float double

  字符型   char

  布尔型   boolean

2.引用数据类型

  字符串、数组、类、接口、Lambda

3.四类八种数据类型

注意事项:

  • 1byte=8bite 1KB=1024byte 1MB=1024KB 1GB=1024MB
  • 字符串不是基本类型,而是引用类型;
  • 浮点型只是一个近似值,并非精确值;
  • 数据范围与字节不一定相关,例如float的数据范围比long更加广泛但float是四字节,long是八字节;
  • 浮点数默认类型是double,如果一定要使用float类型,需加后缀F;
  • 整数默认为int,如果一定要使用long类型,需要加上一个后缀L。

4.数据类型转换

当数据类型不一样时,将会发生数据类型转换

自动类型转换(隐式)

  1. 特点:代码不需要进行特殊处理,自动完成转换。

  2. 规则:数据范围从小到大。

强制类型转换(显式)

  1. 特点:代码需要进行特殊的格式处理,不能自动完成。

  2. 格式:范围小的类型 范围小的变量名 = (范围小的类型)范围大的数据。

注意事项:

  1. 强制类型转换一般不推荐使用,因为有可能发生精度损失、数据溢出;

  2. byte/short/char这三种数据类型都可以发生数学运算,例如+ - * /等;

  3. byte/short/char这三种数据类型在运算的时候,都会被首先提升称为int类型,然后再计算;

  4. Boolean类型不能发生数据转换。

public static void  main(String[]args){
        System.out.println(1024); // 这就是一个整数,默认是int类型
        System.out.println(3.14); // 这就是一个浮点数,默认是double类型

        // 左边是long类型, 右边是默认的int类型,左右不一样
        // 一个等号代表赋值,将右侧的int常量, 交给左侧的long变量进行存储
        // int --> long, 符合了数据范围从小到大的要求
        // 这行代码发生了自动类型转换。
        long num1 = 100;
        System.out.println(num1); // 100

        // 左边是double类型,右边是float类型,左右不一样
        // float --> double,符合从小到大的规则
        // 也发生了自动类型转换
        double num2 = 2.5F;
        System.out.println(num2); // 2.5

        // 左边是float类型,右边是long类型,左右不一样
        // long --> float,范围是float更大一些,符合从小到大的规则。
        // 也发生了自动类型转换
        float num3 = 30L;
        System.out.println(num3); // 30.0

        System.out.println("========");

        // 左边是int类型,右边是long类型,不一样
        // long --> int,不是从小到大
        // 不能发生自动转换!需要强制转换!
        // 格式:范围小的类型 范围小的变量名 = (范围小的类型)原本范围大的数据;
        int num = (int) 100L;
        System.out.println(num); // 100

        int num4 = (int)6000000000L;
        System.out.println(num4); // 结果不会是6000000000,结果为:1705032704,此时发生数据溢出

        // double --> int,强制类型转换
        int num5 = (int) 3.99;
        System.out.println(num5); //3,这并不是四舍五入,所有的小数位都会被舍弃掉

        char zif1 = 'A'; // 这是一个字符型变量,里面是大写字母A
        System.out.println(zif1 + 1); // 66, 也就是大写字母A被当作65处理。
        // 计算机的底层会用一个数字(二进制)来代表字符A,也就是65
        // 一旦char类型进行了数学运算,那么字符就会按照一定的规则翻译成为一个数字

        byte num6 = 40; // 注意!右侧的数值大小不能超过左侧的类型范围
        byte num7 = 50;
        // byte + byte --> int + int --> int
        int result1 = num6 + num7;
        System.out.println(result1); // 90

        short num8 = 60;
        // byte + short --> int + int --> int
        // int强制转换为short: 注意必须保证逻辑上真实大小本来就没有超过short范围,否则会发生数据溢出
        short result2 = (short) (num6 + num8);
        System.out.println(result2); // 100

    }

3.3 运算符

  1. 算术运算符: 基本的数学运算,加法、减法、乘法、除法和取模(取余)等;
    算数运算符包括:
    +加法运算,字符串连接运算
    -减法运算
    *乘法运算
    /除法运算
    %取模运算,两个数字相除取余数
    ++、--自增自减运算
  2. 关系运算符: 比较两个值的关系,如等于、不等于、大于、小于等;以布尔值(true 或 false)返回比较结果,用于条件判断;
  3. 逻辑运算符: 执行逻辑运算,如逻辑与、逻辑或和逻辑非等,以布尔值(true 或 false)返回比较结果,例如,&& 表示逻辑与,|| 表示逻辑或,! 表示逻辑非;
  4. 赋值运算符: 将值赋给变量,如 = 表示赋值运算,+= 表示加并赋值,a = 10,即将10赋值给变量a,A =  A+20可直接写成A += 20;
  5. 自增和自减运算符: 增加或减少变量的值,例如 ++ 表示自增,-- 表示自减;例:++num,num++
  6. 位运算符: 执行位级别的操作,如按位与、按位或、按位异或和位移操作等。位运算符通常用于整数数据类型。例如,& 表示按位与,| 表示按位或,<< 表示左移。
  7. 条件运算符(三元运算符): 
    格式:关系表达式?表达式1:表达式2;
    范例:a > b ? a : b;
  8. 实例关系运算符: 比较对象引用,如 instanceof 用于检查对象是否是特定类的实例。
  9. 类型转换运算符: 将值从一种数据类型转换为另一种数据类型,如强制类型转换。

3.4 流程控制语句

在Java中,流程控制语句是用来控制程序中语句的执行顺序的。根据条件改变代码的执行流程,包括循环执行某段代码、根据条件选择性地执行某些代码块,以及按顺序执行代码。Java中的流程控制语句主要分为三大类:顺序结构、选择结构(也称为条件结构)和循环结构。

1. 顺序结构

顺序结构是最简单的流程控制结构,按照程序中语句的书写顺序,从上到下依次执行。

2. 选择结构

选择结构(条件结构)允许程序根据一个或多个条件来执行不同的代码块。Java中主要的选择结构语句有:

  • if 语句:如果条件为真(true),则执行if语句块中的代码。

  • if...else 语句:如果条件为真,则执行if语句块中的代码;如果条件为假(false),则执行else语句块中的代码。

  • if...else if...else 语句:这是if语句的扩展,允许在多个条件之间进行选择。
  • switch 语句:基于不同的case值选择执行不同的代码块。
  • switch (表达式) {
        case 1:
            语句体1;
            break;
        case 2:
            语句体2;
            break;
        ...
        default:
            语句体n+1;
            break;
    }

3. 循环结构

循环结构允许程序重复执行某段代码,直到满足特定的条件为止。Java中主要的循环结构语句有:

  • for 循环:在给定条件为真时,重复执行一段代码块。通常用于知道循环需要执行的确切次数时使用。
  • for (初始化语句;条件判断语句;条件控制语句) {
        循环体语句;
    }
  • while 循环:只要给定条件为真,就重复执行一段代码块。通常用于不确定循环需要执行多少次时使用。
  • while (条件判断语句) {
        循环体语句;
        条件控制语句;
    }
  • do...while 循环:至少执行一次代码块,然后只要给定条件为真,就继续重复执行。与while循环的主要区别在于,do...while循环至少会执行一次代码块,而while循环可能一次都不执行。
  • do {
        循环体语句;
        条件控制语句;
    }while(条件判断语句);

4. 跳转控制语句

  • 跳转控制语句(break)

    • 跳出循环,结束循环

  • 跳转控制语句(continue)

    • 跳过本次循环,继续下次循环

  • 注意: continue只能在循环中进行使用!

3.5 方法

方法,也称函数,如果想要重复一段或者多段代码块的使用,可以将这些代码封装成一个方法。

1.方法的声明

2.访问修饰符

3.静态方法

若方法的声明中加上了static关键字,那么这个方法就是静态方法。静态方法是属于类的,而不是属于类创建的对象或实例的,故在调用时无需通过对象实例。

注意事项:

  • 静态方法不能存在成员变量

  • 静态方法不能调用非静态方法

  • 静态方法可以调用静态方法

  • 非静态方法可以调用静态方法

4.抽象方法

若方法的声明中加上了abstract关键字,且没有方法体,那么这个方法就是抽象方法。抽象方法往往出现在抽象类和接口中。

注意事项:

  • 抽象类中不一定必须要有抽象方法,但是有抽象方法的类必须是抽象类
  • 若一个类继承了抽象类,则必须实现抽象类中的抽象方法
  • 抽象类不能被实例化
  • 抽象方法不能被声明为静态
  • 抽象方法不能用 private 修饰
  • 抽象方法不能用 final 修饰

5.构造方法

  1. 作用

    给对象的属性进行初始化

  2. 格式

    • 构造方法的方法名必须与类名相同

    • 构造方法没有返回类型,也不能定义为void

    • 没有具体的返回值

  3. 标准类组成

    • 为所有成员变量用private关键字修饰

    • 为每一个成员变量提供set、get方法

    • 提供一个无参构造

    • 提供一个有参构造

6.方法的重载与重写

1.重载

  • 重载就是在同一个类中,方法名称相同,但形参不同的方法。

  • 方法重载的规则:

    • 方法名称必须相同;

    • 参数列表必须不同(个数不同、类型不同、参数排列顺序不同);

    • 方法的返回值可以相同也可以不相同;

    • 仅返回类型不同不足以称为方法的重载。

2.重写

  • 重写就是父类的方法与子类的方法相同(方法名和参数列表完全一致)。
  • 方法重写的规则:
    • 参数列表与被重写方法的参数列表必须完全相同;
    • 访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类的一个方法被声明为 public,那么在子类中重写该方法就不能声明为 protected;
    • 声明为 final 的方法不能被重写;
    • 声明为 static 的方法不能被重写,但是能够被再次声明;
    • 重写的方法能够抛出任何非强制异常,无论被重写的方法是否抛出异常。但是,重写的方法不能抛出新的强制性异常,或者比被重写方法声明的更广泛的强制性异常,反之则可以;
    • 构造方法不能被重写;
    • 如果不能继承一个类,则不能重写该类的方法。

3.6 数组

1.数组定义

  • 数组是相同类型数据的有序集合;

  • 数组描述的是相同类型的若干个数据,按照一定的先后次序排列组合而成;

  • 其中,每一个数据称作一个数组元素,每个数组元素可以通过一个下标(编号、标记)来访问它,下标是从 0 开始的,例:如果存 10 个数据,即下标为 0 ~ 9 。

2.数组的声明

首先必须声明数组变量,才能在程序中使用数组。

语法:

  • dataType[] arrayRefVar; //首选的方法
  • dataTypr arrayRefVar[]; //效果相同,但不建议

数组格式:

  • 数组类型[] 数组名 = new 数组类型[元素个数或数组长度];
int[] arr = new int[5];
 
arr[0] = 1;
 
arr[1] = 2;
  • 数组类型[]数组名 = new 数组类型[]{元素,元素,……};
int[] arr = new int[]{3,5,1,7};
 
int[] arr = {3,5,1,7};

3.数组的初始化

数组的三种初始化及区别

public static void main(String[] args) {  
    // 1.方式一  静态初始化
    int[] a = {1, 2, 3};	//正常的静态初始化
    Man[] mans = {new Man(1, 1), new Man(2, 2)};	//引入的静态初始化
    // 2.方式二  动态初始化
    int[] a = new int[3];
    a[0] = 1;	
    a[1] = 2;
    System.out.println(a[0]);	//1
    System.out.println(a[1]);	//2
    System.out.println(a[3]);	//0		未赋值则为 0		默认初始化
    // 3.方式三  默认初始化
    int[] a = new int[1];
    System.out.println(a[1]);	//0		未赋值则为 0
}  

区别:

静态初始化创建的同时赋值

动态初始化:包含默认初始化,未赋值的元素默认为 0

数组的默认初始化:数组是引用类型,它的元素相当于实例变量,因此数组一经分配空间,其中的每个元素也被按照实例变量同样的方式被隐式初始化(0)

4.数组的特点

  1. 数组一旦被创建,那么它的大小就是不可改变的;
  2. 同一数组内的元素必须是相同类型;
  3. 数组中的元素可以是任何数据类型,包括基本类型和引用类型
  4. 数组变量属于引用类型,数组本身就是对象,Java 中对象是在堆中的,因此数组无论保护原始类型还是其他对象类型,数组对象本身是在堆中的

5.数组的常见异常

  1. 数组角标越界异常,注:数组的角标从0开始。
    public static void main(String[] args) {
    int[] x = { 1, 2, 3 };
    System.out.println(x[3]);
    //java.lang.ArrayIndexOutOfBoundsException
    }
  2. 空指针异常
    public static void main(String[] args) {
    int[] x = { 1, 2, 3 };
    x = null;
    System.out.println(x[1]);
    // java.lang.NullPointerException
    }

6.数组的常见用法

  1. 求最大值
    public static int getMax(int[] arr){
        //定义变量记录较大的值,初始化为数组中的任意一个元素。
        int max = arr[0];
        for(int x=1; x<arr.length; x++){
            if(arr[x]>max){
                max = arr[x];
            }
        }    
        return max;
    }
  2. 直接排序
    public static void selectSort(int[] arr){
        for(int x=0; x<arr.length-1; x++){
            for(int y=x+1; y<arr.length; y++){
            //为什么y的初始化值是 x+1?因为每一次比较,都用x角标上的元素和下一个元素进行比较。
                if(arr[x]>arr[y]){
                    int temp = arr[x];
                    arr[x] = arr[y];
                    arr[y] = temp;
                }
            }
        }
    }
  3. 冒泡排序
    public static void bubbleSort(int[] arr){
        for(int x=0; x<arr.length-1; x++){
            //-x:让每次参与比较的元减-1:避免角标越界。
            for(int y=0; y<arr.length-x-1; y++){
                if(arr[y]>arr[y+1]){
                    int temp = arr[y];
                    arr[y] = arr[y+1];
                    arr[y+1] = temp;
                }
            }
        }
    }
  4. 折半查找
    public static int halfSeach(int[] arr,int key){
        int min,mid,max;
        min = 0;
        max = arr.length-1;
        mid = (max+min)/2;
        while(arr[mid]!=key){
            if(key>arr[mid])
                min = mid + 1;
            else if(key<arr[mid])
                max = mid - 1;
            if(min>max)
                return -1;
            mid = (max+min)/2;
        }
        return mid;
    }
  5. 数组翻转
    public static void reverseArray(int[] arr){
        for(int start=0,end=arr.length-1; start<end; start++,end--){
            swap(arr,start,end);
        }
    }
    //对数组的元素进行位置的置换。
    public static void swap(int[] arr,int a,int b){
        int temp = arr[a];
        arr[a] = arr[b];
        arr[b] = temp;
    }

7.多维数组

多维数组可以看成是数组的数组。

二维数组:

语法:

int a[][] = new int[2][5]; 
int[][] a = {{1, 2}, {3, 4}, {5, 6}, {7, 8}, {9, 10}};

示例:

public static void main(String[] args) {
        int[][] array = {{1, 2}, {3, 4}, {5, 6}, {7, 8}, {9, 10}};
        //int array[][] = new int[2][5];    //相当于一个数组内嵌套了 2 层的数组
        /*
            //解析如下:
            a =
            {
                {1, 2}, //2 层嵌套的数组
                {3, 4},
                {5, 6},
                {7, 8},
                {9, 10},
            }
        */
        //打印指定元素的值
        System.out.println(array[0][0]);    //1
        System.out.println(array[0][1]);    //2
        System.out.println(array[1][1]);    //4
        System.out.println(array.length);   //5 5列
        System.out.println(array[0].length);    //2 2行
    }

上述二维数组 array 可以看成一个两行五列的数组

遍历二维数组:

public static void main(String[] args) {
        int[][] array = {{1, 2}, {3, 4}, {5, 6}, {7, 8}, {9, 10}};
        //遍历
        for (int i = 0; i < array.length; i++) {
            for (int j = 0; j < array[i].length; j++) {
                System.out.println(array[i][j]);
            }
        }
    }

三维数组:

语法:

int a[][][] = new int[][][];
int[][][] a = {{{1, 2}, {3, 4}}};

示例:

public static void main(String[] args) {
        int[][][] array = {{{1, 2}, {3, 4}},{{5, 6}, {7, 8}}, {{9, 10}, {11, 12}}};
        //int array[][][] = new int[2][2][3];    //相当于一个数组内嵌套了 3 层的数组
        /*
            //解析如下:
            a =
            {
            	{
            		{1, 2},
            		{3, 4},
            	},
            	{
            		{5, 6},
            		{7, 8},
            	},
            	{
            		{9, 10},
            		{11, 12},
            	},
                //3 层嵌套的数组
            }
        */
        //打印指定元素的值
        System.out.println(array[0][0][0]);    //1
        System.out.println(array[0][0][1]);    //2
        System.out.println(array[1][1][1]);    //8
        System.out.println(array.length);   //3 3组
        System.out.println(array[0].length);    //2 2列
        System.out.println(array[0][1].length); //2 2行
    }

上述三维数组 array 可以看成一个两行两列三组的数组

遍历三维数组:

public static void main(String[] args) {
        int[][][] array = {{{1, 2}, {3, 4}},{{5, 6}, {7, 8}}, {{9, 10}, {11, 12}}};
        //遍历
        for (int i = 0; i < array.length; i++) {
            for (int j = 0; j < array[i].length; j++) {
                for (int k = 0; k < array[i][j].length; k++) {
                    System.out.println(array[i][j][k]);
                }
            }
        }
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值