jvm
文章平均质量分 59
王佑辉
个人笔记,多谢指正,不喜勿喷
展开
-
【jvm】动态链接为什么需要常量池
在Java源文件被编译成字节码文件时,所有的变量和方法引用都作为符号引用保存在class文件的常量池中。通过存储符号引用而不是直接引用,可以减少内存的使用,并在需要时通过动态链接机制快速找到实际的方法或字段。这个过程中,JVM会根据常量池中的符号引用找到对应的直接引用(即内存中的实际地址),从而实现方法的调用和字段的访问。:由于动态链接是在运行时进行的,因此它允许程序在运行时动态地改变行为,提高了程序的灵活性和可扩展性。(如类和接口的完全限定名、字段的名称和描述符、方法的名称和描述符等)的一个区域。原创 2024-09-22 16:34:15 · 243 阅读 · 0 评论 -
【jvm】栈顶缓存技术
1.在基于栈式架构的虚拟机(如Java虚拟机)中,完成一项操作往往需要更多的入栈和出栈指令,这导致了更多的指令分派次数和内存读/写次数。2.当处理器执行指令时,如果需要使用栈顶元素,它可以直接从寄存器中获取,而无需访问内存,从而减少了访问延迟和提高了执行速度。4.栈顶缓存技术是一种有效的计算机体系结构优化技术,它通过减少内存读/写次数和降低访问延迟来提高指令的执行效率。:由于寄存器的数量有限,栈顶缓存技术可能无法缓存所有的栈顶元素,这在一定程度上限制了其性能提升的空间。2.是一种在计算机体系结构中用于。原创 2024-08-29 22:17:36 · 1011 阅读 · 0 评论 -
【jvm】局部变量表与GCRoots之间的关系
局部变量表的生命周期与对应的方法调用紧密相关。3.包括以下几种类型的引用:虚拟机栈(栈帧中的局部变量表)中引用的对象,方法区中的类静态属性引用的对象,常量引用的对象,本地方法栈中JNI(Java Native Interface)引用的对象。:当局部变量表中的变量引用了堆中的对象时,这些对象就被视为从GC Roots可达的,因此在垃圾收集过程中不会被回收。1.局部变量表与GC Roots的关系主要体现在:局部变量表中的引用是GC Roots的一个重要组成部分,它们决定了哪些对象在垃圾收集过程中是可达的。原创 2024-08-27 22:22:12 · 703 阅读 · 0 评论 -
【面试】jvm静态变量和局部变量对比
1.静态变量:随着类的加载而加载到JVM的方法区(静态区),当类被卸载时才会销毁。2.局部变量:存储在JVM的栈内存中,具体为栈帧中的局部变量表部分。1.在Java虚拟机(JVM)中,静态变量(类变量)和局部变量是两种不同类型的变量,它们在多个方面存在显著的区别。2.局部变量:定义在方法体内或方法参数中,属于方法或代码块。2.局部变量:每个线程的栈帧都是独立的,局部变量存储在栈帧的局部变量表中,因此不存在线程安全问题。1.静态变量:存储在JVM的方法区(静态区),这是一个所有线程共享的内存区域。原创 2024-08-26 22:40:20 · 745 阅读 · 0 评论 -
【jvm】局部变量表
局部变量表,也被称为。原创 2024-08-26 22:23:00 · 892 阅读 · 0 评论 -
【jvm】栈帧的内部结构
6.总的来说,JVM栈帧的内部结构是虚拟机进行方法调用和执行的基础,它通过局部变量表、操作数栈、动态链接、方法返回地址等部分,维系着方法执行过程中的各种数据信息。4.局部变量表中的变量只在当前方法调用中有效,方法执行结束后,随着方法栈帧的销毁,局部变量表也会随之销毁。5.在多线程环境下,每个线程都有自己的虚拟机栈,栈中存储的是各自的栈帧,它们之间互不影响。2.每个方法从调用到执行完成的过程,都对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。1.局部变量表是栈帧中非常重要的一部分,它主要用于。原创 2024-08-26 14:51:05 · 866 阅读 · 0 评论 -
【jvm】虚拟机栈是如何运行的
栈帧是方法执行时的内存模型,包含了方法执行所需的各种信息。1.入栈:当一个方法被调用时,会创建一个新的栈帧,并将其压入当前线程的虚拟机栈顶。1.虚拟机栈是Java程序运行时环境中的一个重要组成部分,它主要负责存储线程执行方法时的局部变量、操作数栈、动态链接、方法出口等信息。4.虚拟机栈的运行原理遵循了栈数据结构的基本特性——后进先出(LIFO),确保了方法调用的正确顺序和方法局部变量的有效管理。2.JVM虚拟机栈是Java程序运行时环境中的一个关键组件,它通过栈帧的入栈和出栈过程来支持方法的调用和执行。原创 2024-08-25 18:04:08 · 571 阅读 · 0 评论 -
【jvm】jvm方法和栈帧的关系
1.栈帧的创建:每当一个方法被调用时,JVM都会为该方法的执行创建一个新的栈帧(Frame),并将其压入Java虚拟机栈中。:在一条线程中,只有目前正在执行的那个方法的栈帧是活动的,这个栈帧被称为当前栈帧。当前栈帧对应的方法就是当前方法,定义这个方法的类就是当前类。3.JVM中的方法和栈帧之间存在着紧密的关系,栈帧是支持方法执行的重要数据结构,而方法的调用和执行过程则伴随着栈帧的创建、入栈、出栈等操作。:栈帧是线程私有的数据结构,每个线程都有自己的虚拟机栈,因此每个线程在执行方法时都会创建自己的栈帧。原创 2024-08-25 17:26:56 · 402 阅读 · 0 评论 -
【面试】jvm栈默认大小
2.这个默认值反映了早期JVM版本中对于线程栈内存管理的策略,以及当时计算机硬件资源的限制。1.随着JVM的演进和计算机硬件的发展,JVM栈的默认大小增加到了1MB。2.这一变化是为了适应更复杂的应用程序需求和更大的内存资源。1.JVM栈的默认大小通常是256KB。原创 2024-08-24 20:29:54 · 293 阅读 · 0 评论 -
【面试】jvm栈的大小通过什么参数设置?
9.对于需要处理大量递归调用或深层次嵌套调用的应用程序来说,合理设置线程堆栈大小是有必要的。8.在大多数情况下,除非有明确的性能问题或特定的需求,否则可能不需要手动设置这个参数。1.这个参数也用于设置每个线程的堆栈大小,但它与-Xss参数在功能上相似。6.在调整这个参数时,应该进行充分的测试,以确保应用程序的稳定性和性能。7.JVM在启动时会根据操作系统的默认值自动设置合适的线程堆栈大小。5.过大的堆栈大小则可能浪费系统资源,尤其是在多线程应用程序中。1.这是最常用的参数,用于直接设置每个线程的堆栈大小。原创 2024-08-24 15:42:51 · 382 阅读 · 0 评论 -
【jvm】虚拟机栈会oom吗
3.每个方法被调用时,Java虚拟机都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息,这个栈帧会被压入到虚拟机栈中,方法执行完成后,对应的栈帧会被弹出。2.这通常是由于虚拟机栈的容量被设置得太小,而应用又需要频繁地创建和销毁栈帧(例如,大量线程并发执行),导致虚拟机栈无法为新的栈帧分配足够的内存空间时,就会抛出OutOfMemoryError异常。5.默认情况下栈的大小是由JVM参数(如-Xss)来控制的,不同的操作系统和JVM实现可能会有不同的默认值。原创 2024-08-23 23:20:45 · 389 阅读 · 0 评论 -
【jvm】栈是否存在垃圾回收
1.JVM栈不会直接存在垃圾回收的问题。2.栈内存的管理是通过自动的压栈和出栈操作来实现的,与堆内存的垃圾回收机制不同。3.当方法执行完毕后,其对应的栈帧会自动销毁,局部变量占用的内存也随之释放。4.这种自动管理机制简化了内存管理的工作,并提高了程序的执行效率。原创 2024-08-21 21:18:29 · 350 阅读 · 0 评论 -
【jvm】如何理解栈管运行堆管存储
1.JVM通过栈来管理方法的执行和局部变量的生命周期,确保每个线程都有自己独立的执行环境。2.通过堆来管理对象实例和数组的存储,实现跨线程的数据共享和垃圾回收。3.这种设计使得Java程序既能够高效地执行方法调用和局部变量操作,又能够灵活地管理对象实例和数组的内存分配和释放。原创 2024-08-21 20:59:06 · 496 阅读 · 0 评论 -
【jvm】栈和堆的区别
1.堆:堆中的内存分配是动态的,适用于动态对象的存储。堆的大小可以动态地调整,由JVM自动管理,通常会根据当前应用的需求进行分配和释放。堆中的对象生命周期不受代码块的控制,直到没有任何引用指向该对象时,垃圾回收器才会将其回收。2.栈:栈的内存分配是连续的,适用于临时变量的存储。堆是一个大的内存池,用于存储所有的Java对象,包括实例变量和数组。每个线程都有自己的栈,用于存储该线程的方法调用和局部变量。因此,堆中的对象可以被所有线程访问,但这也需要进行线程安全的管理。的,每个线程都有自己的栈空间。原创 2024-08-21 16:09:44 · 580 阅读 · 0 评论 -
【jvm】PC寄存器为什么设定为线程私有?
如果PC寄存器不是线程私有的,那么为了保证线程之间的同步和互斥,就需要引入额外的同步机制(如锁)。通过将PC寄存器设定为线程私有,可以确保每个线程的执行状态不会被其他线程所干扰,从而保持并发执行的稳定性和可控性。:由于每个线程都有自己的PC寄存器,CPU在切换线程时只需要简单地读取和保存PC寄存器的值,就可以快速地恢复线程的执行状态,从而提高线程切换的效率。:如果多个线程共享同一个PC寄存器,那么当线程切换时,后一个线程的执行状态可能会覆盖前一个线程的执行状态,导致线程执行混乱。原创 2024-08-20 22:48:50 · 513 阅读 · 0 评论 -
【jvm】程序计数器的特征
1.JVM(Java虚拟机)中的程序计数器(Program Counter Register),简称PC寄存器,具有几个显著的特征,这些特征对于理解Java程序的执行流程和线程交互至关重要。这是因为它的内存分配是固定的,且不会随着程序的执行而动态增加。:与JVM中的其他内存区域(如堆、栈等)不同,程序计数器并不存储对象的引用或具体的数据,而仅仅是一个指示器,用于指示下一条指令的地址。:每当一个新的线程被创建时,JVM都会为其分配一个独立的程序计数器,并初始化为0(或某个特定的起始值)。原创 2024-08-20 22:16:30 · 496 阅读 · 0 评论 -
【jvm】程序计数器是如何计数的
程序计数器是当前线程正在执行的字节码的行号指示器,也可以看作是指向当前线程正在执行的字节码指令的指针。3.原创 2024-08-19 21:57:32 · 430 阅读 · 0 评论 -
【jvm】哪些内存结构与线程一一对应(线程私有)
1.线程私有意味着每个线程都拥有该内存结构的一个独立实例,这些实例之间互不干扰,保证线程之间的数据隔离和并发执行的安全性。3.虚拟机栈中存储的是栈帧(Stack Frame),每个栈帧对应着一次Java方法调用。2.本地方法栈也是线程私有的,用于执行Native方法(即使用非Java语言编写的方法)。1.它是线程私有的,可以看作是当前线程所执行的字节码的行号指示器。3.程序计数器是线程私有的,它的生命周期与线程的生命周期一致。2.它是线程私有的,生命周期与线程一致。(如果当前线程执行的是Java方法)或。原创 2024-08-19 21:33:00 · 478 阅读 · 0 评论 -
【jvm】直接引用
直接引用与虚拟机的内存布局紧密相关,不同的虚拟机实现可能会有不同的内存布局,因此同一个符号引用在不同的虚拟机实例上翻译出来的直接引用可能不同。2.是指向内存中实际存在的对象的引用,它与虚拟机的内存布局紧密相关,是JVM进行对象访问和操作的基础。1.在JVM的类加载过程中,当类被加载到内存中并初始化后,类中的符号引用会被解析为直接引用。(即被引用的),哪些是不可达的(即未被引用的),从而对不可达的对象进行回收。2.通过直接引用,JVM可以直接访问对象的属性和方法,执行对象的操作等。原创 2024-08-17 11:04:06 · 388 阅读 · 0 评论 -
【jvm】符号引用
1.符号引用通常包含:引用目标的类型(如类、方法、字段),引用目标的名称(如类名、方法名、字段名),引用目标的描述符(对于方法,包括参数类型和返回类型;2.在Java虚拟机规范中,符号引用的格式通常遵循“类或接口的全限定名 + ‘#’ + 成员名称 + 成员描述符”的规则。5.通过一组符号来描述所引用的目标,并在运行时由JVM解析为直接引用,以支持Java程序的动态加载和运行。2.符号引用与虚拟机的内存布局无关,引用的目标在解析之前并不一定要加载到内存中。来代替目标引用的一种引用方式。原创 2024-08-17 10:50:26 · 358 阅读 · 0 评论 -
【jvm】类加载分几步
这通常意味着从文件系统、网络或其他来源读取类的.class文件或其他格式的二进制表示。3.原创 2024-08-04 21:34:14 · 765 阅读 · 0 评论 -
【面试】class文件结构
2.class文件的总体结构:魔数、版本号、常量池、类的访问标识(标志、控制权限)、类名(类索引)、超类(父类索引)、接口(接口索引集合)、字段(字段表集合)、方法(方法表集合)、属性(属性表集合)。1.紧接着魔数的4个字节是Class文件的版本号,包括次版本号(Minor Version,占2个字节)和主版本号(Major Version,占2个字节)。2.版本号用于标识Class文件的兼容性,高版本的JDK能向下兼容以前版本的Class文件,但不能运行以后版本的Class文件。原创 2024-07-20 12:49:54 · 342 阅读 · 0 评论 -
【jvm】字符串常量池问题
3.如果常量池中已经包含了一个等于此String对象的字符串(使用equals(Object)方法确定),则返回代表池中这个字符串的String对象的引用。9. 19 new #4 : new一个String对象,对象的引用压入操作数栈。4. 7 new #4 :new一个String对象,对象的引用压入操作数栈。3.简化字符串比较:由于字符串常量池中的字符串是唯一的,可以使用==操作符来比较字符串的引用,从而简化比较操作。原创 2024-07-13 09:49:30 · 754 阅读 · 0 评论 -
【面试】基本数据类型的包装类缓存
(I)Ljava/lang/Integer 方法的描述符,该方法接受一个int类型的参数(由(I)表示)并返回一个java.lang.Integer类型的对象(由 (I)Ljava/lang/Integer;执行此指令时,JVM会从操作数栈顶部弹出一个int值(在这个例子中是10),将其作为参数调用java.lang.Integer.valueOf方法,并将返回的Integer对象推送到操作数栈的顶部。使用Boolean.TRUE和Boolean.FALSE时,得到的是缓存中的对象实例。原创 2024-06-23 20:15:35 · 597 阅读 · 0 评论 -
【面试】i++与++i的区别
3.该情况下,i++与++i没有区别,均是在原有的基础自增1,然后输出。原创 2024-06-23 18:20:51 · 1031 阅读 · 0 评论 -
【面试】什么是字节码指令
1.字节码指令是JVM能够理解和执行的基本指令。2.它由一个字节长度的操作码(Opcode)以及跟随其后的零至多个代表操作所需参数的操作数(Operands)构成。原创 2024-06-10 20:36:26 · 424 阅读 · 0 评论 -
【面试】哪些类型对应有Class的对象?
1.虽然类型变量和泛型类型在运行时会被擦除(type erasure),但它们在某些上下文中(如反射API)仍然有与之关联的 Class 对象或 Type 对象(后者是 Class 的超接口,用于表示更广泛的类型,包括泛型类型)。虽然基本类型本身没有直接的 Class 对象,但你可以使用它们的包装类来获取与它们相关的 Class 对象,或者使用 .TYPE 字段(对于包装类提供的静态字段)来获取与基本类型对应的 Class 对象。1.与类类似,每个定义的接口也有一个与之关联的 Class 对象。原创 2024-06-09 13:37:59 · 347 阅读 · 0 评论 -
【java】JVM前端编译器的局限性
1.前端编译器的主要功能是将Java源代码(.java)文件编译成字节码文件(.class文件),以供加载器进行类型加载。4.AOT编译器的使用也有一些限制,如需要为每个不同硬件和操作系统编译对应的发行包,且降低了Java链接过程的动态性。3.不直接涉及将字节码转换为可在硬件上直接运行的机器码过程,这是由JIT编译器在运行期间负责的。1.前端编译器的主要任务是将符合Java语法规范的Java代码转换为符合JVM规范的字节码文件。1.前端编译器在编译时是静态的,即它根据源代码的内容生成固定的字节码文件。原创 2024-06-09 11:17:19 · 425 阅读 · 0 评论 -
【面试】Java的前端编译器和后端编译器
4.在Java的编译过程中,前端编译器和后端编译器协同工作,共同将Java源代码转换为可执行的机器码。1.代码优化:在生成目标代码之前,对代码进行一系列的优化操作,以提高程序的执行效率和性能。1.在Java的编译过程中,编译器通常被划分为前端编译器和后端编译器,各自负责不同的任务。2.前端编译器主要负责源代码的词法分析、语法分析和语义检查,确保代码的语法正确性和准确性。3.语义检查:在语法分析的基础上,进行更深层次的检查,如类型检查、变量声明检查等。3.输出的目标代码是机器码,可以直接在硬件上执行。原创 2024-06-01 11:07:42 · 510 阅读 · 0 评论 -
【面试】生成class文件的编译器有哪些?
4.对于特定的开发环境和需求,可以考虑使用IDE自带的编译器(Eclipse编译器和Intelli IDEA编译器),以获得更多的特定功能和集成开发环境的优势。3.选择编译器时,一般建议使用官方发布的Oracle JDK或OpenJDK中的默认编译器(javac)进行Java编译。2.IntelliJ IDEA编译器同样可以将Java源代码编译为字节码文件,并提供了强大的代码分析和智能重构功能。2.这些编译器都能够将Java源代码编译为可在JVM上执行的字节码文件,是实现Java跨平台特性的关键。原创 2024-06-01 09:27:24 · 319 阅读 · 0 评论 -
【面试】class文件里面是什么?
2.用于描述类的方法,包括方法名、参数类型、返回类型、访问修饰符以及方法的字节码。class 文件是 Java 平台无关性的关键,因为它们包含了可以在任何支持 JVM 的硬件和操作系统上运行的字节码。1. .class 文件是 Java 编译器编译 Java 源代码文件(.java 文件)后生成的字节码文件。2.这是一个固定值(0xCAFEBABE),用于确定文件是否是一个有效的 Java 类文件。1.这些索引指向常量池中的条目,分别表示类的全限定名、父类的全限定名以及该类实现的接口列表。原创 2024-05-30 21:58:31 · 345 阅读 · 0 评论 -
【面试】字节码文件是跨平台的吗?
2.字节码文件是Java源代码经过Java编译器(javac)编译后生成的中间代码文件,这些包含了Java虚拟机(JVM)指令,而不是特定于某个硬件平台或操作系统的机器码。6.只要安装了相应版本的JVM,就可以在任何支持JVM的操作系统上运行Java字节码文件,而无需重新编译源代码。3.由于JVM是跨平台的,它能够在任何支持JVM的操作系统上执行字节码文件。5.这就是Java语言“一次编写,到处运行”的跨平台特性的基础。1.字节码文件(.class文件)是跨平台的。原创 2024-05-30 21:30:27 · 310 阅读 · 0 评论 -
【面试】什么是Java虚拟机
2.JVM是Java平台无关性的关键,它允许Java程序在任何支持JVM的硬件和操作系统上运行,从而实现“一次编写,到处运行”(Write Once, Run Anywhere)的跨平台特性。3.Java虚拟机是Java程序运行的核心环境,它负责加载、执行和管理Java程序,并提供了跨平台、内存管理、类加载、执行引擎、线程管理、安全性和性能调优等功能。1.Java虚拟机(Java Virtual Machine,简称JVM)是运行所有Java程序的抽象计算机,是Java语言的运行环境。原创 2024-05-30 21:02:10 · 394 阅读 · 0 评论 -
【面试】介绍一下HotSpot虚拟机
2.HotSpot虚拟机占据绝对的市场地位,从jdk1.3到现如今jdk14都是Oracle JDK和OpenJDK中默认的虚拟机。2.该虚拟机来源于Strongtalk虚拟机,而Strongtalk虚拟机中的技术又来源于为支持Self语言设计的Self虚拟机。1.HotSpot虚拟机是一款由Oracle JDK和OpenJDK广泛使用的Java虚拟机(JVM)。(JIT)技术,将常用的部分代码编译为本地(原生)代码,从而提高Java程序的执行性能。等特点,成为了Java领域广泛使用的虚拟机之一。原创 2024-05-30 20:49:04 · 765 阅读 · 0 评论 -
【面试】Java虚拟机的生命周期
可以使用-X系列的JVM参数来配置JVM的内存大小、垃圾回收策略等。3.在JVM终止时,也可以通过设置System.exit()的参数来返回一个状态码,以指示程序是正常退出还是由于某种错误而退出。(Garbage Collection)来自动管理内存,释放不再使用的对象占用的空间。2.如果应用程序请求了外部资源(如文件、数据库连接等),JVM会协调这些资源的访问。5.在终止前,JVM会执行一些清理工作,如关闭打开的文件、数据库连接等。1.Java虚拟机(JVM)的生命周期通常指的是JVM实例从。原创 2024-05-29 22:16:21 · 824 阅读 · 0 评论 -
【面试】谈谈常见的Java虚拟机有哪些
2.特点:GraalVM是一个高性能的运行时环境,支持多种语言,包括Java、JavaScript、Ruby、Python、R等。2.特点:也采用了即时编译技术,通过将字节码编译为本地机器码来提高程序的执行性能。2.特点:Exact VM是一个编译器和解释器混合执行的Java虚拟机,曾在Solaris平台上发布,但后来被其他虚拟机所取代。(Just-In-Time Compilation, JIT)的技术,将字节码实时编译为本地机器码,从而提高程序的执行效率。1.开发商:Oracle公司。原创 2024-05-29 21:19:43 · 448 阅读 · 0 评论 -
【面试】谈谈你对jvm的认识
1.JVM(Java Virtual Machine)是运行所有Java程序的抽象计算机,是Java语言的运行环境。2.它屏蔽了与具体操作系统平台相关的信息,使得Java程序只需生成在JVM上运行的目标代码(字节码),可以在多种平台上不加修改地运行。3.JVM包括一套字节码指令集、一组寄存器、一个栈、一个垃圾回收堆和一个存储方法域。原创 2024-05-29 21:06:25 · 659 阅读 · 0 评论 -
【面试】什么是Java堆内存溢出?
1.数据库连接、文件句柄等外部资源没有及时关闭,这些资源将会被JVM的垃圾回收器视为有效对象而无法回收,引发内存泄露。3.如果大量使用这样的集合类,并且没有及时清理其中的对象,这些对象将一直存在于堆内存中,导致内存泄露。1.应用程序中创建了大量对象,并且这些对象在短时间内无法被垃圾回收器回收,导致堆内存空间耗尽。2.由于长生命周期的对象持有短生命周期对象的引用,导致短生命周期对象无法被垃圾回收器回收。4.调整JVM的堆内存设置,根据应用程序的需求分配足够的内存空间。原创 2024-05-28 21:52:05 · 930 阅读 · 0 评论 -
【面试】JDK和JVM是什么关系?
3.JDK包含了JRE(Java Runtime Environment),即Java运行环境,以及编译Java源代码的编译器(javac)和其他工具(如javadoc、jdb等)。4.开发人员在开发java应用程序时,需要安装jdk,因为它包含了编写和编译java程序所需的所有内容。4.只要系统安装了JVM,就可以运行Java程序,而无需考虑该程序是在哪种操作系统或硬件平台上编写的。的,因为它将字节码转换成机器码的工作是在运行时动态完成的,而不是在编译时。,JVM的目标是提供一个跨平台的。原创 2024-05-28 21:26:30 · 648 阅读 · 0 评论 -
【面试】Oracle JDK和Open JDK什么关系?
1.Oracle JDK包含了闭源组件,并根据二进制代码许可协议获得许可。在没有商业许可的情况下,2019年1月之后发布的Oracle Java SE 8的公开更新将无法用于商业或生产用途。1.Oracle JDK包含一些特定于Oracle的商业特性或优化,这些特性可能不包含在Open JDK中。1.Oracle JDK是由Oracle公司基于Open JDK源代码开发的商业版本。2.Open JDK是完全开源的,采用了GPL协议,意味着可以自由使用和修改。Oracle JDK统一和稳定。原创 2024-05-28 20:57:30 · 468 阅读 · 0 评论