Java编程语言学习与实践课件套装

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:这是一套全面覆盖Java编程语言基础知识到高级特性的教学资源。内容包含Java的发展历史、特点、应用领域;环境搭建;语法基础;面向对象编程核心概念如类与对象、继承、封装和多态;数组和字符串处理;异常处理;I/O流和NIO;集合框架和泛型;多线程编程与同步机制;反射、枚举与注解;设计模式;以及JVM原理等关键主题。这些PPT课件将帮助初学者逐步构建起对Java的全面理解和深入学习的基础。 java学习课件

1. Java基础与历史介绍

1.1 Java的起源与设计理念

Java语言自1995年由Sun Microsystems公司推出以来,迅速成为企业级应用开发的首选语言。它的设计理念是“一次编写,到处运行”,这得益于其独特的跨平台机制——Java虚拟机(JVM)。这种设计让Java具备了良好的可移植性和高效的内存管理。

1.2 Java的技术演进

随着互联网的快速发展,Java也在不断地演进。从Java SE(标准版)到Java EE(企业版)和Java ME(微型版),Java适应了不同的市场需求。特别是Java 8的重大更新,引入了Lambda表达式和Stream API,使得Java在函数式编程和并行处理方面迈出了重要的一步。

1.3 Java在行业中的应用

Java因其稳健性、高效性和跨平台特性,在全球的IT行业中得到了广泛应用。它不仅在Web应用、移动应用和企业级服务中占据主导地位,还被广泛应用于大数据处理、云计算等领域。Java的广泛社区支持和丰富的生态系统,使得Java开发者拥有强大的资源后盾。

Java的这些特点和优势使其成为初学者和专业开发者都不可忽视的编程语言。在后续的章节中,我们将深入了解Java的开发环境搭建、语法基础、面向对象编程以及高级特性,带领读者开启一段深入Java世界的旅程。

2. 开发环境搭建与配置

2.1 Java开发工具选择与安装

2.1.1 JDK的下载与安装

在开始编写Java程序之前,安装Java开发工具包(JDK)是不可或缺的一步。JDK是Java开发的核心组件,它包括Java运行环境(JRE)、Java虚拟机(JVM)以及Java程序设计的类库。

下载JDK

首先访问Oracle官网或者使用其他JDK发行版的官网,根据自己的操作系统选择合适的JDK版本进行下载。对于IT行业专业人员,推荐下载最新的JDK版本,以便利用最新的特性和性能优化。

安装JDK

安装过程通常非常直观。以Windows为例,在安装向导中选择合适的安装路径(推荐默认路径以避免不必要的问题),然后按步骤完成安装。如果是Linux或Mac用户,通常需要解压下载的tar.gz文件,并配置环境变量。

在安装完成之后,确认JDK是否安装成功。打开命令行工具,输入 java -version 应该能够看到已经安装的JDK版本信息。

2.1.2 IDE的选择与配置

集成开发环境(IDE)能够帮助开发者更高效地编写、编译和调试代码。选择一个合适的IDE对于提高开发效率至关重要。

选择IDE

主流的Java IDE有Eclipse, IntelliJ IDEA, NetBeans等。IntelliJ IDEA以其强大的智能代码辅助和丰富的插件支持,在IT行业中备受推崇。

配置IDE

  1. 打开IntelliJ IDEA。
  2. 选择 "Create New Project" 并选择适合Java的项目模板。
  3. 在接下来的步骤中,根据提示选择JDK路径。如果已经设置环境变量,可能IDE会自动检测到。如果没有,需要手动指定JDK的安装目录。
  4. 完成项目的创建,这时就可以开始编写Java代码了。

2.2 开发环境变量设置

2.2.1 PATH变量的作用与配置

PATH环境变量用于指定系统在何处查找可执行文件。在Java开发中,配置PATH变量可以方便我们在命令行中直接执行 java javac 命令。

设置PATH

在Windows系统中,可以通过右击“计算机”>“属性”>“高级系统设置”>“环境变量”来配置PATH。

  • 在"系统变量"区域找到"Path"变量,选择编辑。
  • 在变量值的末尾添加JDK的bin目录的路径,例如: ;C:\Program Files\Java\jdk-17.0.1\bin (注意要以分号 ; 开头)。
  • 保存并关闭环境变量设置窗口。

在Linux或Mac系统中,通过在用户的 .bashrc .zshrc 文件中添加一行代码来配置PATH。

export PATH=$PATH:/path/to/jdk/bin

之后,重新加载配置文件或者重新登录终端,PATH变量即被更新。

2.2.2 CLASSPATH变量的配置

CLASSPATH变量用来指定Java虚拟机(JVM)查找类文件的路径。默认情况下,JVM会检查当前目录和Java标准库的路径。

设置CLASSPATH

在Windows系统中,通过命令行设置CLASSPATH:

set CLASSPATH=.;C:\path\to\your\classes;C:\path\to\your\libs\*

在Linux或Mac系统中,同样在终端中设置:

export CLASSPATH=.:$CLASSPATH:/path/to/your/classes:/path/to/your/libs/*

其中的点 . 代表当前目录,这样JVM也会在当前目录中查找类文件。

2.3 开发环境测试与问题诊断

2.3.1 基本命令行操作验证

设置好开发环境之后,接下来通过基本命令行操作来验证配置是否成功。

测试Java命令

打开命令行工具,输入 java -version 应该显示已安装的JDK版本。同样,输入 javac 则会显示编译器的使用帮助。

测试JDK安装

创建一个简单的HelloWorld.java文件:

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}

使用 javac HelloWorld.java 编译程序,然后使用 java HelloWorld 运行编译后的程序。如果看到 "Hello, World!" 的输出,说明环境配置成功。

2.3.2 IDE环境测试与调试

在IDE中进行环境测试和调试是最直观的方式,这可以帮助开发者在编写代码时发现并解决问题。

创建并运行项目

在IntelliJ IDEA中创建一个新的Java项目,编写简单的代码,并尝试运行。如果IDE能够顺利编译并执行程序,说明环境配置正确。

调试

调试是开发过程中不可或缺的一部分。在IntelliJ IDEA中,可以使用内置的调试工具:

  1. 在代码中设置断点(双击行号左侧的空白区域)。
  2. 点击 "Debug" 按钮启动调试模式。
  3. 当程序执行到断点时,IDE会暂停执行,并允许你查看当前的变量状态、执行单步调试等。

通过以上设置与测试,我们可以确保Java开发环境搭建与配置成功,为后续的开发工作打下坚实的基础。

3. Java语法基础教学

3.1 基本数据类型与运算符

3.1.1 数据类型的分类与使用

Java语言是一种静态类型语言,这意味着每个变量和表达式的类型在编译时都必须明确声明。Java定义了8种基本数据类型,分为四大类:整数类型、浮点类型、字符类型和布尔类型。这些类型的数据在内存中的占用空间和取值范围是固定且明确的。

  • 整数类型:byte、short、int、long
  • 浮点类型:float、double
  • 字符类型:char
  • 布尔类型:boolean

对于每种数据类型,都有对应的包装类,以便在需要对象的地方使用基本类型。这在处理集合类和泛型时尤其重要。

int myInt = 10;          // 整数类型
long myLong = 100L;      // 长整型,需要后缀L
float myFloat = 10.5f;   // 单精度浮点数,需要后缀f
double myDouble = 20.5;  // 双精度浮点数,默认类型
char myChar = 'A';       // 字符类型
boolean myBool = true;   // 布尔类型

上述代码展示了如何声明和初始化不同数据类型的变量。需要注意的是,某些类型的字面量表示需要特别的后缀,例如长整型的 L 和浮点数的 f d

3.1.2 运算符的种类与优先级

Java中的运算符用于对变量和值执行操作。运算符可以分为以下几类:

  • 算术运算符: + - * / % ++ --
  • 关系运算符: == != > < >= <=
  • 逻辑运算符: && || !
  • 位运算符: & | ^ ~ << >> >>>
  • 赋值运算符: =
  • 其他: instanceof , ?:

运算符的优先级是重要的,它决定了表达式中操作的执行顺序。例如,乘法和除法运算符在加法和减法之前执行。

int result = 1 + 2 * 3; // 结果为7, 不是9

在上面的例子中,乘法先于加法执行。若要改变执行顺序,可以使用括号。

int result = (1 + 2) * 3; // 结果为9

3.2 控制流程语句

3.2.1 条件语句详解

条件语句是根据条件表达式的真假来决定执行哪段代码。在Java中,主要的条件语句有 if else switch 等。

  • if 语句根据布尔表达式的真假来执行代码块。
  • else 语句可以和 if 连用,当 if 的条件不满足时执行其代码块。
  • switch 语句可以根据表达式的值来选择执行多个代码块中的一个。
if (condition) {
    // 条件为真时执行的代码
} else {
    // 条件为假时执行的代码
}

int number = 10;
switch (number) {
    case 10:
        // 当number为10时执行
        break;
    case 20:
        // 当number为20时执行
        break;
    default:
        // 当没有任何case匹配时执行
        break;
}

3.2.2 循环结构的使用与优化

循环语句允许重复执行一段代码直到满足某个条件。Java中的循环结构包括 for while do-while

  • for 循环在已知循环次数时使用。
  • while 循环在需要先检查条件是否满足再执行时使用。
  • do-while 循环至少执行一次循环体,之后再检查条件。
for (int i = 0; i < 10; i++) {
    // 循环10次
}

int count = 0;
while (count < 10) {
    // 当count小于10时执行
    count++;
}

int count = 0;
do {
    // 至少执行一次
    count++;
} while (count < 10);

循环优化通常涉及减少循环内部的计算量、避免不必要的对象创建以及确保循环能够尽可能快地终止。

3.3 函数的定义与调用

3.3.1 方法的声明与作用域

在Java中,函数通常被称为方法。方法是包含一系列语句的代码块,这些语句执行特定的任务,并可选择地返回值。

  • 方法的声明包括修饰符、返回类型、方法名、参数列表和可选的异常声明。
  • 方法的修饰符可以是访问级别( public , private , protected ),或者其他限定词(如 static , final , synchronized 等)。
  • 返回类型指的是方法执行完毕后所返回的数据类型。
  • 参数列表是一组用逗号分隔的参数声明。
public int add(int a, int b) {
    return a + b;
}

在上面的示例中, add 是一个公共方法,接受两个整型参数,返回它们的和。方法的作用域由其修饰符定义,这决定了它在哪里可以被访问。

3.3.2 参数传递与返回值处理

Java中的参数传递主要有两种类型:值传递和引用传递。

  • 基本类型(如 int , boolean 等)是值传递,传递的是实际值的副本。
  • 引用类型(如对象、数组和接口)是引用传递,传递的是引用的副本。
public void modify(int value) {
    value = 100; // 修改的是副本,不会影响实际的参数
}

public void modify(int[] array) {
    array[0] = 100; // 修改的是引用副本指向的实际对象
}

方法返回值的处理涉及到关键字 return return 语句可以返回一个值,并且一旦执行,将结束当前方法的执行。

public int triple(int value) {
    return value * 3;
}

在上例中,方法 triple 接受一个 int 类型的参数,并返回其三倍的值。返回值类型必须与方法声明中指定的返回类型一致。

通过理解并实践Java语法基础,读者可以掌握编程中最基本的概念,为以后学习更高级的编程技巧打下坚实的基础。

4. 类与对象核心概念

4.1 类的定义与对象的创建

4.1.1 类的属性与方法

在Java中,类是对象的蓝图或模板。它定义了一组属性(变量)和方法(函数),用于描述具有相同特征和行为的一组对象。理解类的概念是学习面向对象编程的基础。

属性 是类中定义的数据成员,它们表示对象的状态信息。属性可以包含基本数据类型(如int, float等)和引用数据类型(如String, 数组等)。

class Person {
    String name;  // String类型属性
    int age;      // int类型属性
    // 构造方法
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    // 方法
    public void introduce() {
        System.out.println("Hello, my name is " + name + " and I am " + age + " years old.");
    }
}

方法 是类中定义的行为,表示对象可以执行的操作。方法可以有返回类型,也可以没有(void类型)。方法可以接收参数,也可以不接收。

创建对象时,实际上是在堆内存中为新对象分配了空间,并根据类的定义初始化了属性。每个对象都有自己的属性副本,但所有对象共享同一个类的方法。

4.1.2 对象的生命周期与内存管理

对象的生命周期包括四个阶段:创建、使用、不可达、回收。

  • 创建 :使用 new 关键字创建对象。
  • 使用 :对象被赋给引用变量,可以通过变量访问对象。
  • 不可达 :当没有任何引用变量指向对象时,对象变为垃圾回收的候选。
  • 回收 :垃圾回收器(GC)释放不再被引用对象的内存。

Java虚拟机(JVM)通过垃圾回收机制自动管理对象的内存。开发者无需手动释放对象占用的内存,这大大简化了内存管理。

4.2 继承与多态性

4.2.1 继承的实现与特点

继承是面向对象编程的核心概念之一,允许新创建的类(子类)继承另一个类(父类)的属性和方法。这样,子类就可以在父类的基础上增加或覆盖属性和方法,从而扩展父类的功能。

在Java中,使用 extends 关键字实现继承。例如:

class Animal {
    public void eat() {
        System.out.println("This animal eats food.");
    }
}

class Dog extends Animal {
    @Override
    public void eat() {
        System.out.println("This dog eats meat.");
    }
}

public class TestInheritance {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.eat(); // 输出: This dog eats meat.
    }
}

多态性 是面向对象编程的另一个重要特性,指的是相同的行为作用于不同的对象,可以有不同的解释和不同的执行结果。

4.2.2 方法重载与重写的机制

方法重载 (Overloading)指的是在同一个类中可以创建多个同名方法,但参数列表必须不同(参数类型、个数或顺序不同)。方法重载提供了一种方法能够根据不同的参数执行不同的行为。

class MathUtils {
    public int add(int a, int b) {
        return a + b;
    }
    public double add(double a, double b) {
        return a + b;
    }
}

方法重写 (Overriding)则发生在子类和父类之间。子类可以重写父类的方法来提供特定的行为实现。

class Animal {
    public void makeSound() {
        System.out.println("Some sound.");
    }
}

class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("Bark!");
    }
}

重写时,子类方法签名必须与父类方法签名完全相同,并且访问修饰符的权限不能低于父类方法的权限。

4.3 访问控制与封装

4.3.1 四种访问修饰符的使用

Java提供了四种访问修饰符: public protected default (无修饰符)和 private 。它们用于控制类、方法和属性的访问级别:

  • public :可以在任何地方被访问。
  • protected :可以被同一个包内的类以及所有子类访问。
  • default (无修饰符):只能被同一个包内的类访问。
  • private :只能在同一个类内部访问。

访问控制符的选择依赖于我们希望封装的级别。通常,我们会将属性设置为 private ,并通过公共方法(getter和setter)提供访问和修改。

class Encapsulation {
    private String name;
    public void setName(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
}

4.3.2 设计原则与封装的作用

封装是面向对象编程的核心原则之一。它指的是将对象的状态隐藏在对象内部,并提供公共方法来访问和修改这些状态。封装的目的是隐藏内部实现细节,只向外界提供有限的接口。

封装有以下作用:

  1. 隐藏实现细节 :通过封装,类的实现细节对外部调用者透明,这样即使内部实现发生变化,也不会影响外部使用。
  2. 提供公共接口 :封装允许通过定义良好的公共接口控制外部对对象内部状态的访问。
  3. 提高安全性 :通过私有化属性和提供公共方法,可以限制对对象数据的随意访问和修改,保证数据的安全性。
class BankAccount {
    private double balance; // private属性,封装了数据

    public BankAccount(double initialBalance) {
        if (initialBalance > 0) {
            balance = initialBalance;
        }
    }

    public double getBalance() { // 提供公共接口访问私有属性
        return balance;
    }

    public void deposit(double amount) { // 修改私有属性
        if (amount > 0) {
            balance += amount;
        }
    }

    public boolean withdraw(double amount) {
        if (amount > balance) {
            return false;
        } else {
            balance -= amount;
            return true;
        }
    }
}

封装使得对象的操作更为安全、可靠,并且易于维护和扩展。通过封装,可以将复杂的实现细节隐藏起来,使得其他开发者在不了解内部实现的情况下,依然能够正常使用类的功能。

在以上内容中,我们通过代码块、表格和逻辑分析的方式深入探讨了类与对象的核心概念,以及继承、多态性和封装等面向对象编程的关键点。希望这些内容能够帮助IT行业的读者们加深对Java面向对象编程的理解,并在实际开发中应用这些知识。

5. 数组与字符串处理

数组与字符串是编程中最基础且重要的数据结构之一,它们在Java语言中扮演着核心的角色。在本章中,我们将深入探讨数组和字符串的内部工作机制,以及如何高效地使用这些结构来完成各种任务。

5.1 数组的声明与操作

5.1.1 一维与多维数组的创建

数组是一种用于存储固定大小且相同类型元素的数据结构。在Java中,数组一旦创建,其大小就不可改变。创建一维数组相对简单,只需指定数组类型以及数组中的元素个数:

int[] singleDimArray = new int[5];

对于多维数组,我们可以通过嵌套的方式来创建。例如,创建一个二维数组,可以视为“数组的数组”:

int[][] multiDimArray = new int[3][4];

这里创建了一个3行4列的二维数组。在Java中,可以创建任意维度的数组,但需要注意的是,高维度的数组并不会自动初始化,必须对每个维度进行初始化。

5.1.2 数组的遍历与排序算法

数组的遍历是程序中常见的操作,通常使用for循环或增强for循环来实现。例如,遍历前面创建的一维数组:

for (int i = 0; i < singleDimArray.length; i++) {
    System.out.println(singleDimArray[i]);
}

在处理数据时,数组排序是一个非常常见的需求。Java提供了Arrays类,其中包含了sort方法,可以用来排序数组:

import java.util.Arrays;

int[] numbers = {3, 1, 4, 1, 5, 9};
Arrays.sort(numbers);

排序后,numbers数组中的元素将会按照从小到大的顺序排列。尽管Java的Arrays类为我们提供了非常方便的排序方法,但在实际应用中,有时候需要根据特定的业务规则进行排序,这时就需要自定义比较器(Comparator)来实现。

5.2 字符串的不可变性与操作

5.2.1 字符串与字符数组的关系

在Java中,String对象是不可变的,这意味着一旦创建了一个String对象,其值就不能被改变。如果试图修改String对象的内容,实际上会生成一个新的String对象。

尽管String对象是不可变的,我们可以将其看作字符数组来处理。String类提供了大量有用的方法来进行字符串操作,例如:

String original = "Hello, World!";
char[] charArray = original.toCharArray();

这里, toCharArray() 方法将字符串转换成了一个字符数组。我们还可以利用这个字符数组通过遍历来访问每一个字符:

for (char c : charArray) {
    System.out.print(c + " ");
}

5.2.2 字符串处理类的使用

Java中的字符串处理功能非常强大,提供了String、StringBuffer和StringBuilder等类。String类的对象是不可变的,而StringBuffer和StringBuilder提供了一个可变的字符序列。

对于需要频繁修改字符串内容的场景,使用StringBuffer或StringBuilder会更加高效。例如,StringBuffer提供了一个append方法,可以用来在现有字符串末尾追加内容:

StringBuffer sb = new StringBuffer("Hello, ");
sb.append("World!");

经过追加操作后,sb中的内容将变为"Hello, World!"。由于StringBuffer是线程安全的,因此在多线程环境中使用时无需额外的同步处理,但是这也会带来性能上的开销。相比之下,StringBuilder不保证线程安全,但在单线程环境中它的性能更优。

总结

在本章中,我们介绍了数组与字符串的基础知识,并深入探讨了它们的操作方法。从一维与多维数组的创建和遍历,到字符串与字符数组的关系和字符串处理类的使用,每一步都为IT从业者提供了实际操作的指导和理论基础。掌握这些知识,是成为Java高级开发者必不可少的一步。接下来的章节将继续带领我们深入理解Java语言的更多高级特性,如异常处理机制。

6. 异常处理机制

异常处理是Java语言的一个重要特性,它能够使程序在发生错误时,能够进行适当的处理,而不是直接崩溃。这使得我们的程序更加健壮和可维护。本章节将详细介绍Java中的异常处理机制,并通过实践来深化理解。

6.1 异常类的层次结构

异常处理在Java中具有严格的层次结构,所有异常类都继承自Throwable类,其下有两个直接子类:Error和Exception。

6.1.1 异常与错误的区别

异常(Exception)是指那些非正常情况,但程序可以处理的情况。通常,异常是由用户操作不当或外部条件导致的,例如文件不存在、数据格式不正确等。而错误(Error)通常是虚拟机由于资源耗尽、不可恢复的情况等原因引起的,是程序无法处理的情况,例如OutOfMemoryError。

6.1.2 常用异常类的介绍

在Exception子类中,又分为受检异常(checked exceptions)和非受检异常(unchecked exceptions)两类。受检异常必须被显式处理,否则编译不通过;而非受检异常包括运行时异常(RuntimeException)和错误(Error)。

  • 运行时异常(RuntimeException) :如NullPointerException、ArrayIndexOutOfBoundsException等,通常发生在运行时,是程序员应该避免的错误。
  • 非运行时异常 :如IOException、SQLException等,需要程序显式捕获或声明抛出。

6.2 异常的捕获与处理

Java通过try-catch-finally语句来处理异常。try块中包含可能抛出异常的代码,catch块捕获并处理特定类型的异常,finally块无论是否捕获到异常都会执行。

6.2.1 try-catch-finally语句

try块中的代码如果发生异常,则会被catch块捕获。如果有多个catch块,则按照从上到下的顺序匹配异常类型,一旦匹配成功后,其他的catch块将不会被处理。

try {
    // 可能发生异常的代码
} catch (ExceptionType1 e) {
    // 处理ExceptionType1的异常
} catch (ExceptionType2 e) {
    // 处理ExceptionType2的异常
} finally {
    // 无论是否发生异常都会执行的代码
}

6.2.2 自定义异常类与异常链

在某些情况下,我们需要自定义异常类来更好地描述特定的异常情况。通过继承Exception或者RuntimeException类来创建自定义异常。

public class CustomException extends Exception {
    public CustomException(String message) {
        super(message);
    }
}

异常链是指在一个异常中包含另一个异常。这样做可以提供额外的上下文信息,帮助程序更好地理解和处理异常。

try {
    // 可能抛出InnerException的代码
} catch (InnerException e) {
    throw new OuterException("Outer message", e);
}

6.3 异常处理的最佳实践

异常处理是编写健壮代码不可或缺的部分,而遵循最佳实践则可以提升代码质量。

6.3.1 异常处理策略

异常处理策略应该清晰和一致。通常建议:

  • 使用合适的异常类型 :尽可能使用具体的异常类型而不是过于通用的异常。
  • 不要捕获了异常之后不进行任何处理 :至少要记录日志或者输出信息。
  • 避免使用空的catch块 :空的catch块会掩盖程序中本应处理的错误。

6.3.2 日志记录与异常堆栈跟踪

记录日志是调试程序和跟踪异常的有效方法。通过记录异常信息和堆栈跟踪,开发者可以更容易地定位和解决问题。

try {
    // 可能抛出异常的代码
} catch (Exception e) {
    // 记录异常信息和堆栈跟踪
    logger.error("异常发生", e);
    throw e; // 可以选择重新抛出异常
}

异常处理是Java程序设计的重要组成部分,它提供了程序在运行时控制错误和异常情况的能力。通过上述章节的理论知识和实践操作,读者应该能够理解异常处理机制,并能在自己的Java程序中合理地应用异常处理,编写出更加健壮的代码。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:这是一套全面覆盖Java编程语言基础知识到高级特性的教学资源。内容包含Java的发展历史、特点、应用领域;环境搭建;语法基础;面向对象编程核心概念如类与对象、继承、封装和多态;数组和字符串处理;异常处理;I/O流和NIO;集合框架和泛型;多线程编程与同步机制;反射、枚举与注解;设计模式;以及JVM原理等关键主题。这些PPT课件将帮助初学者逐步构建起对Java的全面理解和深入学习的基础。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值