1. JDK版本变迁和各版本新特性

JDK从1995年发布起至今已历经20多年,从JDK1.0升级到JDK21(September 19, 2023),本节先一起回顾一下JDK的版本变迁和各版本的新特性

版本变迁
  • 1995年5月23日,Java语言诞生;

  • 1996年1月,第一个JDK-JDK1.0诞生;

  • 1996年4月,10个最主要的操作系统供应商申明将在其产品中嵌入Java技术;

  • 1996年9月,约8.3万个网页应用了Java技术来制作;

  • 1997年2月18日JDK1.1发布

  • 1997年4月2日,JavaOne会议召开,参与者逾一万人,创当时全球同类会议纪录;

  • 1997年9月,JavaDeveloperConnection社区成员超过十万;

  • 1998年2月,JDK1.1被下载超过2,000,000次;

  • 1998年12月8日Java 2企业平台J2EE发布

  • 1999年6月,SUN公司发布Java三个版本:标准版(J2SE)、企业版(J2EE)和微型版(J2ME)

  • 2000年5月8日,JDK1.3发布

  • 2001年6月5日,Nokia宣布到2003年将出售1亿部支持Java的手机;

  • 2001年9月24日,J2EE1.3发布;

  • 2002年2月26日,J2SE1.4发布,此后Java的计算能力有了大幅提升

  • 2004年9月30日,J2SE1.5发布,成为Java语言发展史上的又一里程碑。为了表示该版本的重要性,J2SE1.5更名为Java SE 5.0;有诸多重大新特性;代号:Tiger(里程碑版本)

  • 2006年12月,SUN公司发布JDK6.0;代号: Mustang 此版本持续了5年之久才发布新版本,是最经典的版本。

  • 2009年12月,SUN公司发布Java EE 6;

  • 2010年11月,由于甲骨文对Java社区的不友善,因此Apache扬言将退出JCP;

  • 2011年7月28日,甲骨文发布Java SE 7;

  • 2014年3月18日,甲骨文发表Java SE 8。(重大版本 - LTS)

  • 2017年9月21日,JDK9发布。从JDK9开始固定为每半年一个版本,更新内容相应缩减。

  • 2018年3月21日,JDK10发布

  • 2018年9月25日,JDK11发布。(长期维护版本 - LTS)

  • 2019年3月19日,JDK12发布。
    2019年9月17日,JDK13发布。

  • 2020年3月17日,JDK14发布。
    2020年9月15日,JDK15发布。

  • 2021年3月16日,JDK16发布。

  • 2021年9月, JDK17发布。(长期维护版本 - LTS)

  • 2022年3月,JDK18发布。

  • 2022年9月,JDK19发布。

** 2023年3月,JDK20发布。*

  • 2023年9月,JDK21发布。(长期维护版本 - LTS)

  • 2024年3月,JDK22即将发布。
版本新特性

对重要版本的新特性做一下说明。

JDK1.2

改进集合框架,如新增HashMap替代旧的HashTable(常用)
开始提供JIT(Just In Time)编译器;

JDK1.3

Dynamic Proxy: 加入了JDK动态代理(常用)

JDK1.4

NIO: 在传统BIO的基础上引入了NIO(Non-Blocking IO)(常用)。

JDK5(2004-09)

里程碑版本,大部分人也是从该版本开始接触Java。引入了很多意义深远的特性,如下:
1)自动拆箱/装箱(Auto Inbox/Outbox)(常用)
2)枚举(Enum)(常用)
3)静态导入 (static import)
4)可变参数列表 (var args)(常用)
5)范型(Generic)(常用)
6)增强for循环(for-each)(常用)
7)注解(Annotation)(常用)
8)协变返回类型:实际返回类型可以是要求返回类型的一个子类
9)concurrent并发包(Doug leg)(常用)

JDK6(2006-12, LTS)

1)Compiler API,可以实现动态编译Java源文件,如jsp编译引擎就是动态的,修改后无需重启服务器
2)对脚本语言的支持:如js, ruby,groovy

注:因JDK6至JDK7中间间隔了足足5年,所以这个版本是个经典版本,很稳定,官方长期维护,使用了很长时间。

JDK7(2011-07, LTS)

JDK7版本从JDK6后5年才发布,原因是中间经历了Sun公司被收购。大体发布历程是:

2009 年 1 月, Sun 开始开发 JDK7 Milestone 1。
2009 年 11 月,Sun 在 Devoxx 2009 大会上宣布将闭包特性加入 JDK7,并将 JDK7 的发布日期推迟到 2010 年底。
2010 年 4 月,Oracle 收购 Sun。
2010 年 9 月,Mark Reinhold 在 JavaOne 大会上宣布 JDK7 将砍去 Lambda、Jigsaw 和部分 Coin 新特性并于 2011 年中发布,其余部分的新特性将于 2012 年底同 JDK8 一同发布。
2010 年 10 月,IBM 宣布加入 OpenJDK,将与 Oracle 合作共同开发 JDK。此后,Apple 和 SAP 也陆续加入 OpenJDK 社区。
2011 年 7 月 28 日,Oracle 正式发布 JDK7,并指定 OpenJDK7 为参考实现。

特性一:一组小的改进
1)Switch支持String(常用)
2)try … with … resource(常用)
3)范型类型自动推断(常用)
4)多重catch(常用)
5)数字可用下划线分割

特性二:G1垃圾回收器(Grabage-First Collector)(常用)
新出的垃圾回收器,用来替代Concurrent Mark-Sweep Collector(CMS)。目标是减少 Full GC 带来的暂停次数,增加吞吐量。

特性三:concurrent包改进(常用)
Doug Lea在此版本引入了轻量级的fork/join框架来支持多核多线程的并发计算。此外,实现了 Phaser 类,它类似于 CyclicBarrier 和 CountDownLatch 但更灵活。最后,ThreadLocalRandom 类提供了线程安全的伪随机数生成器。

特性四:IO与网络的更新
NIO2 主要包括了 3 个方面的改进:

  1. 新的文件系统 API 支持大量文件属性的访问、文件系统监控服务、平台相关的 API,如 DosFileAttributes 和 PosixFileAttributes 等,以及一个可插拔文件系统的 SPI。
  2. Socket 和文件的异步 IO。
  3. Socket channel 的功能完善,支持 binding、多播等。

特性五:JDBC更新(常用)
支持JDBC4.1和Rowset 1.1

JDK8(2014-03, LTS)

1)接口默认方法(常用)
即接口中可以声明一个非抽象的方法作为默认的实现,方法的返回类型前要加上“default”关键字
2)lambda表达式(常用)

3)函数式接口(常用)
指仅仅包含一个抽象方法的接口,需要标记@FunctionalInterface
4)使用 :: 来传递方法引用,是lambda的简写(常用)

5)Stream API(常用)

6)新的日期工具类(常用)

JDK9(2017-09)

1)模块化
即只加载应用运行需要的模块

2)改进的Java doc
生成的Java doc符合H5标准,支持API搜索

3)集合工厂方法,优化集合初始化(常用)

Set<Integer> ints = Set.of(1,2,3);
List<String> strings = List.of("first","second");

4)改进 Stream API

 IntStream.iterate(1, i -> i < 100, i -> i + 1).forEach(System.out::println);

5)支持私有接口方法

6)HTTP/2(常用, 是预览版)
新的方式处理HTTP调用,用于替换 HttpURLConnection,并提供对WebSocket和HTTP/2的支持

7)多版本兼容

JDK10(2018-03)

1)局部变量类型推断(常用)
即只能作为局部变量类型,方法参数,返回类型等不可以。常见示例:

var str = "ABC"; //根据推断为 字符串类型
var l = 10L;//根据10L 推断long 类型
var flag = true;//根据 true推断 boolean 类型
var flag1 = 1;//这里会推断boolean类型。0表示false 非0表示true
var list = new ArrayList<String>();  // 推断 ArrayList<String>
var stream = list.stream();          // 推断 Stream<String>

2)并行full gc的G1
通过并行Full GC, 改善G1的延迟。目前对G1的full GC的实现采用了单线程-清除-压缩算法。JDK10开始使用并行化-清除-压缩算法。

3)基于实验Java的JIT编译器
启用基于Java的JIT编译器Graal,它是JDK9中引入的Ahead-of-time(AOT)编译器的基础。

JDK11(2018-09, LTS)

1)增加一些实用API(常用)

String str = "woshidage";
boolean isblank = str.isBlank();  //判断字符串是空白
boolean isempty = str.isEmpty();  //判断字符串是否为空
String  result1 = str.strip();    //首尾空白
String  result2 = str.stripTrailing();  //去除尾部空白
String  result3 = str.stripLeading();  //去除首部空白
String  copyStr = str.repeat(2);  //复制几遍字符串
long  lineCount = str.lines().count();  //行数统计

2)HttpClient增强(常用,已转换为正式版)
同时提供了同步调用和异步调用实现。JDK对http对调用支持已经足够强,以前apache提供的httpComponents基本可以去除了。

4)ZGC
JDK11最瞩目的特性,但目前是实验性质的。目标是GC暂停时间不会超过10ms,既能处理几百兆的小堆,也能处理几个T的大堆。

5)完全支持Linux容器(常用)
JDK10开始,JVM可以识别当前是否在容器中运行,能接受容器设置的内存限制和CPU限制。

JDK12(2019-03)
  1. Switch Expression
    传统使用switch的方式:

switch (day) {
	case MONDAY:
	case FRIDAY:
	case SUNDAY:
	System.out.println(6);
	break;
case TUESDAY:
	System.out.println(7);
	break;
case THURSDAY:
case SATURDAY:
	System.out.println(8);
	break;
case WEDNESDAY:
	System.out.println(9);
	break;
}

如今可简化为:

switch (day) {
case MONDAY, FRIDAY, SUNDAY -> System.out.println(6);
case TUESDAY -> System.out.println(7);
case THURSDAY, SATURDAY -> System.out.println(8);
case WEDNESDAY -> System.out.println(9);
}
JDK13(2019-09)
  1. 字符串拼接

JDK13前:

String html = "<html>\n" +
              "    <body>\n" +
              "        <p>Hello, world</p>\n" +
              "    </body>\n" +
              "</html>\n";

现在:

String html = """
              <html>
                  <body>
                      <p>Hello, world</p>
                  </body>
              </html>
              """;
  1. 重写实现旧版套接字API
    使用更简单、更现代的实现替换java.net.Socket和java.net.ServerSocket API使用的底层实现,易于维护和调试。新的实现很容易适应用户模式线程,也就是光纤。之前的底层实现可以追溯到jdk1.0,实现是遗留java和c代码的混合,维护和调试很痛苦,该实现使用线程堆栈作为I/O缓冲区,这种方式需要多次增加默认线程堆栈大小。
JDK14(2020-03)
  1. switch优化变为最终版
  2. gc相关
    1)删除CMS
    2)弃用 ParallelScavenge + SerialOld GC 的垃圾回收算法组合
    3)将 zgc 垃圾回收器移植到 macOS 和 windows 平台
  3. instanceof 扩展 (preview)
    传统instanceof使用方法:
     if (o instanceof String) {
        String s = (String)o;
        System.out.println(s.length);
    }
    

现在可以增强为:

     if (o instanceof String s) {
        System.out.println(s.length);
    }
  1. 有帮助的NullPointerException
    传统出现NullPointerException时的报错信息:
 Exception in thread "main" java.lang.NullPointerException
          at jdk14.NullTest.<init>(NullTest.java:16)
          at jdk14.Main.main(Main.java:15)

如果异常信息是链式调用时发生,如:a.b.c.d…, 此时很难直接定位NullPointerException发生在哪里。现在打印信息得到了增强:

Exception in thread "main" java.lang.NullPointerException:
    Cannot read field "c" because "a.b" is null
    at Prog.main(Prog.java:5)

JDK15(2020-09)
  1. JEP 385 Deprecate RMI Activation for Removal
    RMI Activation被标记为Deprecate,将会在未来的版本中删除(JDK17)。RMI大家应该都清楚,RMI就是Remote Method Invocation,翻译成中文就是远程方法调用,是在JDK1.2中引入的。RMI为java提供了开发分布式系统的强大能力。而J2EE的规范EJB就是使用RMI来实现的bean的远程调用的。在RMI系统中,远程系统中存在很多分布式对象,如果这些分布式对象一直处于活动状态的话,将会占用很多宝贵的系统资源。于是RMI引入了一种lazy Activation的方式,这种方式就叫做延迟激活。对于现代应用程序来说,分布式系统大部分都是基于Web的,web服务器已经解决了穿越防火墙,过滤请求,身份验证和安全性的问题,并且也提供了很多延迟加载的技术。所以在现代应用程序中,RMI Activation已经很少被使用到了。并且在各种开源的代码库中,也基本上找不到RMI Activation的使用代码了。为了减少RMI Activation的维护成本,在JDK8中,RMI Activation被置为可选的。现在在JDK15中,终于可以废弃了。

  2. JEP 339 Edwards-Curve Digital Signature Algorithm (EdDSA)
    实现了EdDSA椭圆曲线签名算法。

  3. JEP 375 Pattern Matching for instanceof (second preview)
    该功能已经在JDK14初次引入,可看上文介绍

  4. JEP 384 Records (Second Preview)
    引入了Record类型,解决定义大量get/set方法的问题,可一定程度替代掉lomobok
    示例如下:

public record Address(
        String addressName,
        String city
) {}

public record CustUser(
        String firstName,
        String lastName,
        Address address,
        int age
) {}


Record和普通的类的区别就在于Record多了一个括号括起来的定义的字段。
Record类默认是final的,里面的字段默认是private final的。

可借助IDE的反编译功能,反编译字节码可得到Record类的实现:

public final class CustUser extends java.lang.Record {
    private final java.lang.String firstName;
    private final java.lang.String lastName;
    private final com.flydean.records.Address address;
    private final int age;

    public CustUser(java.lang.String firstName, java.lang.String lastName, com.flydean.records.Address address, int age) { /* compiled code */ }

    public java.lang.String toString() { /* compiled code */ }

    public final int hashCode() { /* compiled code */ }

    public final boolean equals(java.lang.Object o) { /* compiled code */ }

    public java.lang.String firstName() { /* compiled code */ }

    public java.lang.String lastName() { /* compiled code */ }

    public com.flydean.records.Address address() { /* compiled code */ }

    public int age() { /* compiled code */ }
}

可以看出Record类继承自Record类,属性默认private final,这意味着Record实例是immutable(不可变的), 且有一个默认的包含所有参数的构造方法,其他如toString(), hashCode(), equals()已得到了默认实现。

对于Record可以做一定限度的定制,如校验属性,定义新属性。

public record CustUserWithBody(
        String firstName,
        String lastName,
        Address address,
        int age
) {
    public String fullName(){
        return firstName + lastName;
    }

    public CustUserWithBody {
        if (age < 18) {
            throw new IllegalArgumentException( "年纪太小");
        }
    }
}

JDK16(2021-03)
  1. instanceof 增强确定为最终版本,该功能已经在JDK14初次引入,可看上文介绍。
  2. Records确定为最终版本,该功能同样也已经历了两代预览版,可看上文介绍。
  3. 387: 弹性Metaspace功能可将未使用的HotSpot虚拟机的Class Metadata(Metaspace)占用的内存更迅速的返回给操作系统,从而减少Metaspace的占用并简化Metaspace的代码以降低维护成本。
  4. 388: 将JDK移植到Windows/AArch64平台。
  5. 392: 提供用于打包独立的Java应用程序的jpackage工具。
JDK17(2021-09, LTS)

该版本是继JDK11之后3年新推出的长期支持版本。

  1. JDK 内部的强封装,除了sun.misc.Unsafe等关键的内部 API 外,用户将不再可能通过单个命令行选项来 relax 对内部元素的强封装,这在 JDK 9 到 JDK 16 中是可行的。该计划的目标包括提高 JDK 的安全性和可维护性,并鼓励开发人员从内部元素迁移到标准 API。
  2. 删除远程方法调用 (RMI) 激活机制,同时保留 RMI 的其余部分。RMI 激活机制已过时和废弃,在 JDK 15 中不推荐使用(可参考上文JDK15部分的描述)。
  3. 删除实验性 AOT 和 JIT 编译器,它们几乎没有使用,但需要大量维护工作。该计划要求维护 Java 级别的 JVM 编译器接口,以便开发人员可以继续使用外部构建的编译器版本进行 JIT 编译。
  4. 将 JDK 移植到 MacOS/AArch64 以响应 Apple 将其 Macintosh 计算机从 x64 转换到 AArch64 的计划(Apple M1处理器)。针对 MacOS/AArch64 的更改有可能破坏现有的 Linux/AArch64、Windows/AArch64 和 MacOS/x64 port,但这种风险可通过预集成测试来降低。
  5. 弃用 Applet API 以进行删除。这个 API 本质上是无关紧要的,因为所有 Web 浏览器供应商要么已经取消了对 Java 浏览器插件的支持,要么已经宣布了这样做的计划。Applet API 之前在 2017 年 9 月的 Java 9 中已被弃用,但并未删除。Applet API彻底被删除,最早java就是靠applet开始火的。
  6. 弃用 Security Manager,准备在未来版本中移除。追溯到 Java 1.0,Security Manager 一直是保护客户端 Java 代码的主要手段,很少用于保护服务器端代码。该提案的一个目标是评估是否需要新的 API 或机制来解决使用 Security Manager 的特定狭窄用例,例如阻塞System::exit。计划要求弃用 Security Manager 以与旧 Applet API 一起删除,该 API 也计划在 JDK 17 中弃用。

总体来说JDK17没有在语言层面有新的改进。

JDK18(2022-03)
  1. 特性一: 默认UTF-8字符编码
    之前版本JDK使用的字符编码跟OS相关,如中国大陆Windows11默认使用GBK。 如果JDK启动参数未配置 -Dfile.encoding=UTF-8,则默认会使用GBK编码,导致乱码。
    现在则默认就是UTF-8

  2. 特性二:简单的Web服务器
    JDK18中提供了一个新命令jwebserver, 运行这个命令可以启动一个简单的,最小化的静态web服务器,默认发布的是当前目录。

  3. 特性三:Javadoc中支持代码片段
    从JDK18开始,可以使用@snippet来生成注释,且可以高亮某个代码片段,如:

/**
 * 在 Java 18 之后可以使用新的方式
 * 下面的代码演示如何使用 {@code Optional.isPresent}:
 * {@snippet :
 * if (v.isPresent()) {
 *     System.out.println("v: " + v.get());
 * }
 * }
 *
 * 高亮显示 println
 *
 * {@snippet :
 * class HelloWorld {
 *     public static void main(String... args) {
 *         System.out.println("Hello World!");      // @highlight substring="println"
 *     }
 * }
 * }
 *
 */

效果如下:
在这里插入图片描述
4. 特性四: 使用方法句柄重新实现反射核心功能
JDK18改进了java.lang.reflect.Method, Constructor的实现逻辑,使得性能更佳。 不涉及到API的变动,只要升级到该版本,就能享受到更好的性能。

  1. 特性五: 互联网地址解析 SPI
    对于互联网地址解析 SPI,为主机地址和域名地址解析定义一个 SPI,以便 java.net.InetAddress 可以使用平台内置解析器以外的解析器。
InetAddress inetAddress = InetAddress.getByName("www.wdbyte.com");
System.out.println(inetAddress.getHostAddress());
// 输出
// 106.14.229.49
  1. 特性六: switch表达式增强
    示例:
static String formatterPatternSwitch(Object o) {
    return switch (o) {
        case Integer i -> String.format("int %d", i);
        case Long l    -> String.format("long %d", l);
        case Double d  -> String.format("double %f", d);
        case String s  -> String.format("String %s", s);
        default        -> o.toString();
    };
}

// switch可以和null进行结合判断
static void testFooBar(String s) {
    switch (s) {
        case null         -> System.out.println("Oops");
        case "Foo", "Bar" -> System.out.println("Great");
        default           -> System.out.println("Ok");
    }
}

// case可以加入表达式
static void testTriangle(Shape s) {
    switch (s) {
        case Triangle t && (t.calculateArea() > 100) ->
            System.out.println("Large triangle");
        default ->
            System.out.println("A shape, possibly a small triangle");
    }
}

JDK19(2022-09)

特性一: 虚拟线程(Virtual Threads)(preview)
这是JDK19最重要的新特性。

特性二:

JDK20(2023-03)
JDK21(2023-09)(LTS)

OpenJDK vs OracleJDK

市面上有各种jdk,最权威的是官方发布的oracle jdk,其他的还有adoptopenjdk, azul zulu jdk, Amazon Corretto, alibaba dragonwell, Temurin等。 oracle jdk 和Open jdk有什么区别?为什么又冒出各种各样的jdk? Oracle jdk从2019年之后需要商业收费,公司该如何选择?本节将对这些问题做一些澄清。

OpenJDK可理解为两个:源代码存储库和发行版本。

源代码存储库角度: 就源代码而言,只有一套Java源代码,存在OpenJDK项目中,地址是:https://github.com/openjdk/jdk。 这个项目由Oracle公司主导,还有很多大公司参与合作开发,如:IBM, Apple, Microsoft等。

发行版本角度: 各个公司基于同一套源码,加上一些自己的实用工具,为不同的平台(os:Linux, Mac, Windows; 架构:aarch64, x64)编译出二进制包,并附上授权声明,提供给大家下载使用。 各个不同的发行版本也会承诺如有版本更新也会及时释出新版本。

OracleJDK从9开始一样是基于OpenJDK,它额外的提供了一些闭源组件,以及商用license。可以理解为OracleJDK和OpenJDK源码几乎就一样,使用Oracle JDK需要付费,同时也能得到相应的服务: 客服支持,版本更新以及一些实用工具。

主流OpenJDK 发行版介绍

Temurin OpenJDK
原来是AdoptOpenJDK ,是2017年,一群Java用户组(JUG)成员、开发者和供应商(包括亚马逊、微软、Pivotal、Redhat等)建立了一个社区称作AdoptOpenJDK。他们提供免费、稳固的OpenJDK build,可用性与更新周期更长。甚至还有两个不同的Java虚拟机可供选择:HotSpot和OpenJ9。
目前它已归属于Eclipse 基金会,下载地址:https://adoptium.net/
该版本是大多数用户(无特殊功能要求)的最佳选择。

Oracle OpenJDK
oracle自己也基于OpenJDK编译了一套发行版,去除了商标,并且免费,但不承诺会及时更新。

Azul Zulu OpenJDK
官方称是世界上最大的OpenJDK商用提供商。它自家闭源的zing jvm在hotspot jvm的基础上进行了大量优化。zulu是Azul提供的开源版本,可自由使用,但不提供支持。 需要支持可选用商业版本:
在这里插入图片描述
商业版本分为两种:

  1. Azul Platform Core
    即之前的zulu enterprise/embedded版本

  2. Azul Platform Prime
    即之前的zing。它提供更优秀的性能。

zulu是本人比较喜欢的版本。下载地址:https://www.azul.com/downloads/?package=jdk

Microsoft OpenJDK
微软也发行了自己的openJDK版本,且不仅仅是Windows版本, macOS, Linux也有对应释出版本。果然Microsoft越来越开放了。 按微软的说法其Azure, SQL Server, Visual Studio Code, LinkedIn等都使用了java技术。
在这里插入图片描述
微软提供的软件质量肯定是妥妥的,用于生产都没什么问题,下载地址:https://www.microsoft.com/openjdk

Dragonwell OpenJDK
最后一个介绍一下阿里释出的发行版,命名为龙井。Alibaba Dragonwell 是一款免费的, 生产就绪型Open JDK 发行版,提供长期支持,包括性能增强和安全修复。阿里巴巴拥有最丰富的Java应用场景,覆盖电商,金融,物流等众多领域,世界上最大的Java用户之一。Alibaba Dragonwell作为Java应用的基石,支撑了阿里经济体内所有的Java业务。

阿里生产环境使用的OpenJDK,质量也是经的起考验,需要注意的是:

  1. Alibaba Dragonwell 会针对 Long Term Support(LTS) 提供 Java 8 和 Java 11两个版本
  2. Dragonwell随阿里云 VM 镜像发布,免费提供给阿里云客户使用;开发者也可以直接下载免费使用
  3. 阿里巴巴提供季度更新,Java8 更新至少到 2023 年 6月,Java11 更新至少到 2024 年 6月
  4. 目前仅支持Linux下的x64架构

下载地址:https://www.aliyun.com/product/dragonwell

用户JDK版本选择
  1. 有商业支持需求的选择Oracle JDK。 如果对性能方面有更高要求的选Azul Platform Prime, 即zing jvm。
  2. 免费用户无特殊要求的选Temurin OpenJDK即可。
  3. 有特殊架构需求的,如Mac m1(aarch64)有时释出版本受限,可选择zulu OpenJDK。
  • 7
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值