JAVA-JDK1.8介绍

这篇具有很好参考价值的文章主要介绍了JAVA-JDK1.8介绍。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

        Java JDK 1.8-Java Development Kit的第8个主要版本。Java JDK 1.8是Java编程语言的一个重要版本,引入了一些新的功能和改进,同时也修复了几项bug。在本博客中,我将详细介绍Java JDK 1.8的一些主要特性和改进。

目录

1. Lambda表达式:

2. 函数式接口:

3. Stream API: 

4. 新的日期和时间API:

5. 默认方法:

6. 方法引用:

7. 并行流:

8. 重复注解:

总结


1. Lambda表达式:

   Lambda表达式是Java 8最重要的新特性之一。它允许我们以一种更简洁和功能强大的方式编写匿名函数。通过使用Lambda表达式,我们可以简化代码,提高可读性,并充分利用并行处理的优势。

Lambda表达式的语法如下:

(parameter1, parameter2, ...) -> { code }

其中,parameter1、parameter2等是Lambda表达式的参数,而code是Lambda表达式的主体部分。

Lambda表达式的使用

场景包括使用函数式接口、集合的流式处理等。

下面是一个简单的Lambda表达式的示例代码,以演示如何计算一个列表中所有数字的平均值:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

double average = numbers.stream()
                       .mapToDouble(num -> num)
                       .average()
                       .orElse(0);

System.out.println("平均值为: " + average);

在这个例子中,我们首先创建了一个包含整数的列表。然后使用`stream()`方法将列表转换为流。接着使用`mapToDouble()`方法将整数流映射为仅包含数字的Double流。然后使用`average()`方法计算数字流的平均值。最后使用`orElse()`方法在没有平均值的情况下返回0。最终输出计算得到的平均值。

Lambda表达式`num -> num`定义了一个匿名函数,它接收一个参数`num`表示列表中的每个元素,并返回该元素本身。在这个例子中,Lambda表达式用于将整数流转换为Double流。

通过使用Lambda表达式,我们可以将代码简化为几行,并且使代码更易于理解和维护。

Lambda表达式使得函数式编程在Java中变得更加便捷和实用。它在处理集合和并行处理等场景中具有重要的作用,能够提高代码的效率和可读性。

   

2. 函数式接口:

   在Java 8中,引入了函数式接口的概念。函数式接口是只有一个抽象方法的接口。通过使用函数式接口,我们可以更容易地创建Lambda表达式,并以更简洁的方式处理函数式编程。

Java中的函数式接口经常用作函数式编程的基础。它们可以接受Lambda表达式作为参数,或者将Lambda表达式作为返回值。

Java标准库中已经包含了一些内置的函数式接口,如PredicateConsumerSupplierFunction等。我们也可以自定义函数式接口,只需要使用@FunctionalInterface注解来确保接口只有一个抽象方法。

下面是一个示例代码,演示了如何使用函数式接口和Lambda表达式来定义和使用自己的函数式接口:

@FunctionalInterface
interface MyFunctionalInterface {
    void doSomething(int num);
}

public class Main {
    public static void main(String[] args) {
        // 使用Lambda表达式创建函数式接口的实例
        MyFunctionalInterface myFunction = (num) -> {
            System.out.println("参数为: " + num);
            System.out.println("执行原始操作");
        };

        // 调用函数式接口的抽象方法
        myFunction.doSomething(10);
    }
}

在这个例子中,我们首先定义了一个自定义的函数式接口MyFunctionalInterface,它有一个抽象方法doSomething,接收一个整数参数。

接下来,在Main类中,我们使用@FunctionalInterface注解来标记MyFunctionalInterface接口是一个函数式接口。

然后,我们使用Lambda表达式创建了一个函数式接口的实例myFunction。Lambda表达式(num) -> { ... }定义了一个匿名函数,接收一个整数参数,并在函数体中输出参数值和执行原始操作。

最后,我们调用函数式接口的抽象方法doSomething,并传递一个整数参数。

通过函数式接口和Lambda表达式,我们可以将一些通用的操作封装为一个函数式接口,然后通过传递不同的Lambda表达式来执行不同的操作。这种方式可以简化代码,提高代码的可读性和可维护性。

函数式接口在Java中是函数式编程的基础,它为我们提供了更便捷和灵活的方式来处理函数式编程的概念。

   

3. Stream API: 

  Stream API是Java 8引入的一个强大的功能,它提供了一种用于处理集合数据的流式操作的方式。Stream API允许我们以一种声明性的方式对数据进行操作,可以极大地简化代码,并提供了一些高效的并行处理能力

Java中的Stream是对集合(如List、Set、Map等)进行操作的一种抽象。它不是一种数据结构,而是对数据进行操作的工具。

Stream API提供了一系列的中间操作和终端操作。中间操作用于在流上进行一系列的转换和处理操作,而不会产生实际的结果。终端操作用于获取最终的结果,并结束对流的处理。

下面是一个示例代码,演示了如何使用Stream API对一组数字进行操作和处理:```java

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

double average = numbers.stream()
                       .filter(num -> num % 2 == 0)   // 筛选出偶数
                       .mapToDouble(num -> num * 2)   // 将偶数乘以2
                       .average()                     // 计算平均值
                       .orElse(0);                    // 如果没有平均值,则返回0

System.out.println("平均值为: " + average);

在这个例子中,我们首先创建了一个包含整数的列表。然后,使用`stream()`方法将列表转换为流对象。

接下来,我们使用`filter()`方法筛选出偶数。在Lambda表达式`(num -> num % 2 == 0)`中,我们判断一个数字是否为偶数。

然后,使用`mapToDouble()`方法将筛选出的偶数乘以2。在Lambda表达式`(num -> num * 2)`中,我们将每个偶数乘以2。

接着,使用`average()`方法计算所有乘以2后的偶数的平均值。

最后,使用`orElse()`方法在没有平均值的情况下返回0。

通过使用Stream API,我们可以通过一系列简洁的方法链式调用,对集合的数据进行筛选、转换和计算等操作。

Stream API提供了很多其他的操作方法,如`map()`、`reduce()`、`distinct()`、`limit()`等,可以根据具体需求进行使用。

另外,Stream API还提供了并行处理的能力,可以非常方便地利用多核处理器的优势来加速数据处理。

Stream API是Java 8中一个非常有用和强大的工具,它可以简化代码,提高可读性和可维护性,并提供高效的并行处理能力。

JAVA-Stream流详解:JAVA-Stream流详解_勤劳聪明的杰瑞的博客-CSDN博客

4. 新的日期和时间API:

  Java 8引入了新的日期和时间API(java.time包),用于替代过时的Date和Calendar类。新的日期和时间API提供了一种更简单、更流畅和更安全的方式来处理日期和时间,并提供了丰富的操作和功能。

新的日期和时间API包含了一些重要的类,如LocalDate、LocalTime、LocalDateTime、ZonedDateTime等,可以满足不同的日期和时间操作需求。

下面是一个示例代码,演示了如何使用新的日期和时间API操作和处理日期和时间:```java

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;

public class Main {
    public static void main(String[] args) {
        // 获取当前日期
        LocalDate currentDate = LocalDate.now();
        System.out.println("当前日期: " + currentDate);

        // 获取当前时间
        LocalTime currentTime = LocalTime.now();
        System.out.println("当前时间: " + currentTime);

        // 获取当前日期和时间
        LocalDateTime currentDateTime = LocalDateTime.now();
        System.out.println("当前日期和时间: " + currentDateTime);

        // 格式化日期和时间
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String formattedDateTime = currentDateTime.format(formatter);
        System.out.println("格式化后的日期和时间: " + formattedDateTime);

        // 解析字符串为日期和时间
        LocalDateTime parsedDateTime = LocalDateTime.parse(formattedDateTime, formatter);
        System.out.println("解析后的日期和时间: " + parsedDateTime);

        // 在特定时区进行日期和时间操作
        ZoneId timeZone = ZoneId.of("Asia/Shanghai");
        ZonedDateTime zonedDateTime = ZonedDateTime.of(currentDateTime, timeZone);
        System.out.println("特定时区的日期和时间: " + zonedDateTime);
    }
}

在这个例子中,我们首先使用`LocalDate.now()`方法获取当前日期。然后使用`LocalTime.now()`方法获取当前时间。接着使用`LocalDateTime.now()`方法获取当前日期和时间。

然后,我们使用`DateTimeFormatter`类创建一个日期和时间格式化对象,并使用`format()`方法将日期和时间按照指定的格式进行格式化。

接下来,我们使用`parse()`方法将格式化后的字符串解析为日期和时间对象。

最后,我们使用`ZoneId`类创建一个特定的时区对象,然后使用`ZonedDateTime`将日期和时间转换为特定时区的日期和时间。

新的日期和时间API提供了很多其他的操作方法,如计算日期差、增减日期、比较日期等。它还提供了更多的格式化选项,以满足不同的格式化需求。

通过使用新的日期和时间API,在处理日期和时间方面的代码可以变得更加优雅、可读性更高,并且更符合现代的日期和时间操作需求。

5. 默认方法:

  默认方法是Java 8引入的一种新特性,它允许接口中定义具有默认实现的方法。默认方法允许接口在不破坏现有实现的情况下,向接口添加新的方法。

默认方法被定义在接口中,使用关键字`default`来修饰方法,并提供方法的具体实现。实现该接口的类可以直接使用默认方法,也可以选择重写默认方法提供自定义实现。

下面是一个示例代码,演示了如何使用默认方法:```java

interface MyInterface {
    default void doSomething() {
        System.out.println("执行默认方法");
    }

    void doSomethingElse();
}

class MyClass implements MyInterface {
    @Override
    public void doSomethingElse() {
        System.out.println("执行自定义方法");
    }
}

public class Main {
    public static void main(String[] args) {
        MyClass myClass = new MyClass();
        myClass.doSomething();
        myClass.doSomethingElse();
    }
}

在这个例子中,我们首先定义了一个接口`MyInterface`,其中包含一个默认方法`doSomething()`和一个抽象方法`doSomethingElse()`。

接下来,我们定义了一个类`MyClass`,实现了`MyInterface`接口,并重写了抽象方法`doSomethingElse()`。

在主程序中,我们创建了`MyClass`的实例,并调用了默认方法`doSomething()`和重写的抽象方法`doSomethingElse()`。

在运行程序时,会执行默认方法和自定义方法的具体实现。

使用默认方法,允许我们向接口中添加新的方法,而不会破坏现有的实现类。这样在需要给接口添加新方法时,就不需要修改已存在的实现了。

需要注意的是,如果一个类实现了多个接口,而这些接口中存在同名的默认方法,那么实现类必须重写该方法来消除冲突。

默认方法是让接口具备一定的默认行为,以提供更好的灵活性和向后兼容性。它为接口的演化提供了更多的可能性。

6. 方法引用:

  方法引用是Java 8引入的一种简化Lambda表达式的方式。它允许直接引用已有的方法作为Lambda表达式的替代,以提高代码的简洁性和可读性。

方法引用可以看作是Lambda表达式的一种简写形式,它是对使用Lambda表达式调用特定方法的常见情况的一种简化语法。

在Java中,方法引用可以通过以下几种形式来表示:

1. 静态方法引用:`ClassName::staticMethodName`
2. 实例方法引用:`instance::instanceMethodName`
3. 对象方法引用:`ClassName::instanceMethodName`
4. 构造方法引用:`ClassName::new`

下面是示例代码,演示了各种方法引用的用法:```java

import java.util.Arrays;
import java.util.List;
import java.util.function.Function;

public class Main {
    public static void main(String[] args) {
        // 静态方法引用
        Function<Integer, String> convertToString = String::valueOf;
        String str = convertToString.apply(10);
        System.out.println("静态方法引用: " + str);

        // 实例方法引用
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
        names.forEach(System.out::println);

        // 对象方法引用
        MyClass myClass = new MyClass();
        Function<Integer, Boolean> isGreaterThan = myClass::isGreaterThanFive;
        System.out.println("对象方法引用: " + isGreaterThan.apply(10));

        // 构造方法引用
        Function<String, MyClass> createMyClassInstance = MyClass::new;
        MyClass instance = createMyClassInstance.apply("Hello");
        System.out.println("构造方法引用: " + instance.getMessage());
    }

    static class MyClass {
        private String message;

        public MyClass() {
            this.message = "Default Message";
        }

        public MyClass(String message) {
            this.message = message;
        }

        public boolean isGreaterThanFive(int num) {
            return num > 5;
        }

        public String getMessage() {
            return message;
        }
    }
}

在这个例子中,我们首先使用静态方法引用`String::valueOf`,将整数转换为字符串。

然后,使用实例方法引用`System.out::println`,将列表中的每个元素进行打印。

接着,创建了一个`MyClass`的实例,并使用对象方法引用`myClass::isGreaterThanFive`,将判断某个整数是否大于5的行为引用为方法。

最后,使用构造方法引用`MyClass::new`,创建了一个新的`MyClass`实例。

通过使用方法引用,我们可以将原本需要编写Lambda表达式的代码简化为更简洁的形式。方法引用允许我们直接引用已有的方法,提高了代码的可读性和可维护性。

7. 并行流:

并行流是Java 8引入的一种流式操作的方式,它可以充分利用多核处理器的性能,以并行的方式进行集合数据的处理操作。

在Java中,流(Stream)是对集合数据进行操作的一种抽象。通过调用集合的`parallelStream()`方法,可以将顺序流转换为并行流,从而实现并行处理。

并行流会将原始数据分割成多个小块,然后分配给不同的线程进行并行处理。这样可以在多核处理器上同时执行多个操作,从而提高处理效率。

下面是一个示例代码,演示了如何使用并行流进行并行处理:```java

import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        int[] numbers = {1, 2, 3, 4, 5};

        // 顺序流处理
        Arrays.stream(numbers)
              .forEach(num -> System.out.print(num + " "));
        System.out.println();

        // 并行流处理
        Arrays.stream(numbers)
              .parallel()
              .forEach(num -> System.out.print(num + " "));
        System.out.println();
    }
}

在这个例子中,我们首先创建一个整型数组`numbers`。

然后,通过调用`Arrays.stream()`方法将数组转换为顺序流,并使用`forEach()`方法依次打印数组中的元素。

接下来,通过在流上调用`parallel()`方法,将顺序流转换为并行流。然后再次调用`forEach()`方法打印数组中的元素。

通过对比顺序流和并行流的处理结果,我们可以看到并行流的处理顺序可能会发生变化,因为并行流会使用多个线程同时处理数据。

并行流适用于数据量较大且处理时间较长的情况。它可以将数据分成小块,利用多核处理器的优势,同时处理多个部分,提高处理效率。

需要注意的是,并行流的使用要谨慎。在某些情况下,并行流可能由于线程竞争和数据同步的需要而导致性能下降甚至出现错误的结果。因此,在使用并行流时应该进行适当的测试和评估。

通过使用并行流,可以更充分地利用多核处理器的性能,并提高集合数据的处理速度。这是一种高效且便捷的并行处理方式。

8. 重复注解:

重复注解是Java 8引入的一种新特性,它允许在单个元素上多次使用同一种注解。在之前的Java版本中,每个注解只能在一个元素上使用一次。

使用重复注解,可以简化在代码中使用相同注解的重复性操作。它可以使代码更加简洁、可读性更高,并提高代码的可维护性。

下面是一个示例代码,演示了如何使用重复注解:```java

import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
@interface Colors {
    Color[] value();
}

@Repeatable(Colors.class)
@Retention(RetentionPolicy.RUNTIME)
@interface Color {
    String value();
}

@Color("red")
@Color("green")
@Color("blue")
public class Main {
    public static void main(String[] args) {
        Color[] colors = Main.class.getAnnotationsByType(Color.class);
        for (Color color : colors) {
            System.out.println("颜色: " + color.value());
        }
    }
}

在这个例子中,我们首先定义了一个重复注解`Color`,它包含一个`value`属性用于表示颜色。

然后,我们使用`@Repeatable`注解将`Color`注解标记为可重复注解,指定了对应的容器注解`Colors`。

接着,我们在`Main`类上使用了多个`Color`注解,并分别为它们指定不同的颜色值。

在`Main`类的`main`方法中,我们使用`getAnnotationsByType()`方法获取`Color`注解的实例数组,并遍历输出每个注解的颜色值。

通过使用重复注解,我们可以方便地在同一个元素上使用多个相同类型的注解,而无需手动创建包含多个注解的容器。

需要注意的是,重复注解的使用必须遵循一定的规范,包括注解的元注解(如`@Repeatable`)和注解的定义方式。

重复注解是一项简化语法的特性,它使得编写重复性操作的代码更加简洁和直观。在某些场景下,使用重复注解可以提高代码的可读性和可维护性。

总结

1. Lambda表达式和函数式接口:Java 8引入了Lambda表达式,使得编写简洁、灵活的代码变得更容易。它们本质上是匿名函数,可以将函数作为参数传递,使得代码更加简洁和易读。此外,Java 8还提供了一些内置的函数式接口,如`Predicate`、`Consumer`、`Function`等,用于支持Lambda表达式的使用。

2. Stream API:Java 8引入了Stream API,提供了一种高效且便捷的处理集合数据的方式。Stream API可以支持串行和并行两种操作模式,能够在多核处理器上充分发挥性能优势。Stream API提供了丰富的中间操作和终端操作,可以对集合进行过滤、映射、排序、归约等操作。

3. 默认方法和静态方法:接口中引入了默认方法和静态方法的概念。默认方法允许为接口添加具体的方法实现,而不破坏现有的实现类。静态方法则允许在接口中定义静态方法,可以直接通过接口名称调用。

4. 方法引用和构造方法引用:方法引用是一种简化Lambda表达式的方式,允许直接引用已有的方法作为Lambda表达式的替代。它可以使代码更加简洁和可读。构造方法引用则允许引用类的构造方法,用于创建新的对象实例。

5. 日期和时间API:Java 8引入了新的日期和时间API(java.time包),替代了旧的Date和Calendar类。新的API提供了更好的日期和时间处理方式,并且提供了易于使用且线程安全的类。

6. 并行流:Java 8中的Stream API引入了并行流的概念,允许在多核处理器上同时处理多个数据项,提高处理效率。

7. 重复注解:Java 8允许同一个元素上使用多次相同的注解,通过重复注解可以简化代码,并提高代码的可读性和可维护性。

        总的来说,Java 8为开发人员带来了许多新特性和改进,使得Java语言更加现代化、灵活和易用。它通过引入Lambda表达式、Stream API、新的日期和时间API等功能,提供了更简洁、高效的编程方式,同时也提高了代码的可读性和可维护性。文章来源地址https://www.toymoban.com/news/detail-670934.html

到了这里,关于JAVA-JDK1.8介绍的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Java学习】-Java JDK 1.8与17版本比较

    Java Development Kit(JDK)是Java编程语言的开发环境。它包含了Java编译器(javac)、Java虚拟机(JVM)以及其他必需的工具和库。本文将比较JDK 1.8和17两个版本,分析它们的发展历史和地位,并探讨它们之间的差异和优势。 JDK 1.8,也称为Java 8,于2014年发布。它是Java平台自2006年以

    2024年02月16日
    浏览(34)
  • IDEA报错:Error:Cannot determine path to ‘tools.jar‘ library for 17.0.2 (D:/Java/java-jdk/jdk-17.0.2)

    一、前言:由于发布了JDK17版本,有点好奇,想看看怎么样,结果在IDEA中报错了。报错信息:Error:Cannot determine path to \\\'tools.jar\\\' library for 17.0.2 (D:/Java/java-jdk/jdk-17.0.2)。图示如下:  二、报错原因: 我使用的是IDEA  2020.1.2版本,由于版本原因,IDEA  2020.1.2版本不支持JDK17,JDK版本

    2024年02月08日
    浏览(34)
  • WIN10 Java jdk 1.8安装教程

    由于今天换了新的办公室,有了新的电脑,所以要对机器安装一下JDK1.8的版本,于是顺便写一下教程。 点击下载链接进行下载 Java Downloads| Oracle 中国 (需要注册Oracle账户,如果没有或者不想的可以点击下方链接,我的阿里云盘里有) 链接: https://www.alipan.com/s/9z7D7UUMKuC https://www.

    2024年01月17日
    浏览(57)
  • IDEA,JDK是1.8,但Java版本只有21和17

    2023年11月26日,想创建一个springboot的项目,本地安装的是1.8,但是在使用Spring Initializr创建项目时,发现版本只有17和21。 在选择17版本的时候,会报错,而选择21版本时,可以继续创建 进入Springboot官网查看情况,发现在2023年11月24日,3.0以下的版本不再支持了。 第一个方案,

    2024年02月05日
    浏览(42)
  • 【Java系列】JDK 1.8 新特性之 Lambda表达式

    Lambda是一个匿名函数,我们可以将Lambda表达式理解为一段可以传递的代码(将代码像数据一样传递)。使用它可以写出简洁、灵活的代码。作为一种更紧凑的代码风格,使java语言表达能力得到提升。 结果: ​19:43:39.303 [main] INFO com.chen.test.JAVA8Features.Demo01 - 我是没有使用Lambda表

    2024年02月22日
    浏览(39)
  • Java入门 (超详细)JDK(1.8)下载与安装及环境变量的配置教程

    第一步:下载JDK_8 Oracle官网下载地址:https://www.oracle.com/java/technologies/javase/javase8u211-later-archive-downloads.html 进入官网JDK_8下载地址后在页面内向下浏览找到适合自己电脑操作系统的安装包下载。 注:官网下载需要注册账号,可以注册一下。不想要注册的小伙伴可以选择下载我

    2024年02月13日
    浏览(47)
  • 掌握Java JDK 1.8 API帮助文档中文版,事半功倍编程

    引言: Java是一门强大且广泛应用的编程语言,在开发过程中,准确地了解和使用Java标准库的API是非常重要的。JDK(Java Development Kit)是Java开发工具包,提供了丰富的API文档,其中包含了Java标准库中各种类和方法的详细说明。本文将为您介绍如何使用JDK 1.8 API帮助文档的中文

    2024年02月07日
    浏览(31)
  • 深度解析Java JDK 1.8中Stream流的源码实现:带你探寻数据流的奥秘

    1.1 什么是Stream流,以及它的主要特点和优势 什么是Stream流 ? jdk1.8 中引入的Stream流是一种用 函数式编程方式 操作集合的新特性,提供了一种更简洁、高效的方式来处理集合数据,可以将集合操作转换为一系列的流水线操作,实现更加优雅和功能强大的数据处理。 主要特点

    2024年03月16日
    浏览(49)
  • jdk 1.8环境下Tomcat 10报:Unrecognized option: --add-opens=java.base/java.lang=ALL-UNNAMEDError: Could no

    如标题,关闭时显示Unrecognized option: --add-opens=java.base/java.lang=ALL-UNNAMED Error: Could not create the Java Virtual Machine. Error: A fatal exception has occurred. Program will exit. 改安装Tomcat 9 就可以了。

    2024年01月17日
    浏览(35)
  • mac 安装java1.8

    1、下载jdk1.8 https://www.oracle.com/java/technologies/downloads/#java8-mac   2、 安装jdk1.8 一路默认,安装后的位置在这儿。 /Library/Java/JavaVirtualMachines/jdk-1.8.jdk  3、配置环境 打开终端,输入命令 添加以下配置。按i进行编辑,按esc退出编辑,按:wq保存并退出。 输入命令 4、检验 分别输入

    2024年02月09日
    浏览(25)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包