---
aliases: []
tags:
- PL
- java
- jdk
- Eclipse
- dbeaver
created: 2023-01-30 11:19:11
modified: 2026-03-23 18:23:04
---
# Java 笔记
---
## 目录
* [JDK](#java_jdk)
* [Open JDK](#OpenJDK)
* [JRE](#java_jre)
* [JVM](#java_jvm)
* [IDE](#java_ide)
* [Java相关的配置](#java_config)
* [SDKMan](#java_sdkman)
* [IO 相关](#java_io)
* [函数编程相关](#java_functaional)
---
## JDK
不同的版本有不同的 JDK,不同厂商也有不同的 JDK。而非 [Oracle](https://www.oracle.com/) 的 JDK 均源于「OpenJDK」。
### OpenJDK
> [!info] 关于 OpenJDK
> OpenJDK 是由 **OpenJDK Community 、Oracle、IBM** 领导,连同 Alibaba,Amazon,Ampere,Azul,BellSoft,Canonical,Fujitsu,Google,Huawei,Intel,Java Community,JetBrains,London Java Community,Microsoft,Red Hat,SAP,SouJava,SUSE,Tencent,Twitter ,VMWare 等第三方共同开发、维护的 Java SE 开源参考实现。
[OpenJDK](https://openjdk.org) 与 Oracke JDK 区别:
* Oracle JDK 只发布二进行版本;OpeanJDK 只发源码
* Oracle JDK 包含了 OpenJDK 少量没有的功能
* 从 Java SE7 开始往后的版本,所有 JDK 都源于 OpenJDK。所以从某种意义上讲,Oracle JDK 也是 OpenJDK 的一个发生版。
* Oracle JDK 持有 Java 商标;其他 OpenJDK 不能使用 Java 商标。
* 授权不同:OpeanJDK 允许免费商用,而 Oracle JDK 只能个人研究使用,商用收费(从 JDK8u211 这版本开始)
广义上的「OpenJDK」指的是非 Oracle JDK 之外所有厂商源于 OpenJDK 源码自行定制编译发布的 OpenJDK 发行版。
狭义上的「OpenJDK」专指 **Oracle OpenJDK**,所以 OpenJDK 官网指向可下载的二进制文件其实是 Oracle OpenJDK 地址,它其实就是 Oracle 版的 OpenJDK 发行版。也就是说,Oracle 除了原有的 JDK 版,还有一个 OpenJDK 版本 -- 情况跟 RHEL 与 CenterOS 关系一样。
发行版的 OpenJDK 大部分都是可以 **免费商用** 的,商用付费的代表是 Oracle JDK 和 IBM、RedHat 的 OpenJDK。
而不同的厂商会根据 OpenJDK 源自行定制编译自己的二进制发行版本。下面就介绍几个:
#### Oracle OpenJDK
上面已经说了,**狭义** 上的 OpenJDK 就是指「Oracle's OpeanJDK」。
官网:[https://openjdk.org](https://openjdk.org)。
各大版本:
* [OpenJDK 11](https://jdk.java.net/java-se-ri/11)
* [OpenJDK 17](https://jdk.java.net/java-se-ri/17)
#### Eclipse Temurin
[Adopt JDK](https://adoptium.net) 原来是 OpenJDK 中社区 JDK 中比较重要的一个发行版。后来 **AdoptOpenJDK** 加入到了 [Eclipse](https://www.eclipse.org/org/) 基金会旗下的 [Adoptium](https://adoptium.net) 工作组(「Adoptium Working Group」),后更名为「Temurin JDK」。[Temurin](https://adoptium.net/temurin/) 是「Adoptium」其中一个项目(Project),专门提供生产环境的 JRE 或 JDK 及相关技术。
官网也从 [https://adoptopenjdk.net](https://adoptopenjdk.net) 迁移到 [https://adoptium.net](https://adoptium.net)。
Temurin JDK 清华镜像:[https://mirror.tuna.tsinghua.edu.cn/Adoptium/](https://mirror.tuna.tsinghua.edu.cn/Adoptium/)
大部分 Open JDK 都能使用 [SDKMan](#SDKMan) 安装。
#### 微软 OpenJDK
没想到吧,微软也有发 OpenJDK。
> [!inof] 微软与 [Eclipse](#Eclipse%20相关)
>
> 2021 年 8 月,微软宣布将成为 Eclipse 基金会的战略成员,并且加入其董事会。
>
> 早在 2016 年,微软就以解决方案成员的身份加入了 Eclipse 基金会,并在当时提供了一套开发工具和服务。
>
> 可见微软的「魔爪」已经伸向 Java 系的领域。事实是 [Visual Studio](https://visualstudio.microsoft.com/) 在 「VS2015」版本时,在其安装选项中就有 JDK 选项,当时还是针对 [Android](https://developer.android.google.cn/)。但现在看来,微软的野心可不止这么窄。从 [dotnet core](https://dotnet.microsoft.com/) [](https://github.com/dotnet/core) 到收购 [Github](https://github.com),微软近年对于原来非微软传统领域,特别是开源领域的涉足越来越多。
官网:[https://www.microsoft.com/openjdk](https://www.microsoft.com/openjdk)
源码地址:[https://github.com/microsoft/openjdk](https://github.com/microsoft/openjdk)
---
### JDK8
新的版本 JDK8 的部分命令更改。
`java` 及 `javac` 查看版本信息的 ` --version` 选项已经没有了,只剩下 `-version` 方式可查看 jdk8 的版本信息。
所以在新版本 jdk8 中查看版本信息只能使用:`java -version` 和 `javac -version`。
但离奇的是,在 [JDK11](#JDK11) 及 [JDK17](#JDK17) 仍保持 `--version` 这种用法。猜测是想要把 java 8 跟后继的版本「区隔」开,而且给那些仍使用 java8 的「钉子户」程序员一个好像 java8 用不了的「错觉」。
> [!info] 关于 version 选项
>
> 通过 java 的帮助可以知道两种 `version` 是有一点区别的。
>
> `-version` 将产品版本输出到错误流并退出
>
> `--version` 将产品版本输出到输出流并退出
#### 新特性
##### 默认方法
「默认方法」:又称为「**扩展方法**」,使用 `default` 关键字进行修饰。
默认方法**必须**有方法的实现,即**必须有方法体**。
但访问时,不能通过接口直接访问默认方法,必须通过接口的实现类的实例进行访问:
```java
对象名.默认方法()
```
##### 静态方法
Java8 开始允许在接口中定义静态方法,此方法使用 `static` 关键字修饰。
接口中的静态方法,与 [默认方法](#默认方法) 一样,必须要有方法体。
静态方法既可以通过接口名进行访问,也可以通过接口实现类的实例进行访问:
```java
接口名.静态方示名()
```
##### 函数接口
「[函数接口](Java_Funcational_Note.md#Functional%20Interface) 」是 JDK8 最重要的特性。
[lambda](#lambda)、[方法引用](#方法引用)、[optional](#optional) 等特性都是围绕着函数接口而制定的新功能。
##### lambda
##### 方法引用
##### optional
##### Stream API
##### Base64
##### 并行数组
### JDK11
### JDK17
### JDK21
### JDK25
---
## JRE
Java Runtime Environment:Java 运行时环境。
JRE 是运行 Java 程序的必备环境,包含 JVM 和类库,确保 Java 程序在不同平台上顺利执行。
Java 的 JRE(Java Runtime Environment)用于运行 Java 应用程序。它包含以下主要组件:
1. Java 虚拟机([JVM](#JVM))
* 负责执行 Java 字节码,确保 Java 程序跨平台运行。
2. Java 类库(Java Class Library)
* 提供标准库,支持文件操作、网络通信、数据结构等功能。
3. 其他支持文件
* 包括配置文件、资源文件等,确保 Java 程序正常运行。
### 主要功能
* **运行 Java 程序**:JRE 提供执行 Java 应用程序所需的环境。
* **跨平台支持**:通过 [JVM](#JVM) 实现「一次编写,到处运行」。
### 与 JDK 的区别
* **JRE**:仅用于运行 Java 程序。
* **JDK**:包含 JRE 及开发工具(如编译器、调试器),用于开发和编译 Java 程序。
---
## JVM
JVM Java 虚拟机。
---
## Java 相关的配置
### Java11 生成 JRE
进入 jdk 安装目录后执行以下命令:
```shell
sudo ./bin/jlink --module-path jmods --add-modules java.desktop --output jre
```
>[!info]
>
> 把 jmodes 目录所有模块都生成 [JRE](#JRE):
>
> ```shell
> sudo ./bin/jlink --module-path jmods --add-modules ALL-MODULE-PATH --output jre
> ```
---
## IDE
### Eclipse
* [Eclipse 笔记](IDE/Java_IDE_Eclipse.md)
### IDEA
* [Idea 笔记](IDE/Java_IDE_Idea.md)
---
## SDKMan
[SDKMan](https://sdkman.io/) 是一个 Linux 系统中对 java 相关的软件管理器。它能够对软件安装、卸载、版本切换。
### SDKMan 安装
执行以下命令:
```shell
curl -s "https://get.sdkman.io" | bash
```
sdkman 安装目录是在 `~/.sdkman/` 下,装完云看到 `.sdkman` 下有没有 `bin` 目录,因为国外网站的关系,有可能在安装过程,因为网络环境而事实上没真正安装成功,如果是这样,在 `.sdkman` 目录上是缺少 bin 目录的。
### 配置环境变量
往 `.bashrc` 或 `.bash_profile` 或 `.profile` 文件,把 sdkman 的路径加进去:
```config
export SDKMAN_DIR="/home/silascript/.sdkman"
```
或者:
```shell
source "/Users/sky/.sdkman/bin/sdkman-init.sh"
```
这会自动将相关的配置加入到相应的配置文件,有可能是 `.bashrc`,也有可能是 `.zshrc`(如果用 zsh)。反正去看下吧,大概是以下这一段代码:
```config
export SDKMAN_DIR="$HOME/.sdkman"
[[ -s "$HOME/.sdkman/bin/sdkman-init.sh" ]] && source "$HOME/.sdkman/bin/sdkman-init.sh"
```
> [!tip] 配置文件经验
>
> 反正这段代码根据你自己习惯,可以移动到适合的 rc 或 profile 文件中。
>
> 我个人是放在 `.profle` 中,所有语言的环境变量配置我都放在 `.profile` 中,然后我又用 zsh,我就在 `.zshrc` 中 `source` 下 `.profile`,这样能保持 `.zhsrc` 文件不至于太多非 zsh 的配置信息,而且集中放在 `.profile` 中也能集中管理。
### SDKman 使用
使用 `sdk help` 能查看 SDKMan 帮助,这个帮助已经涵盖了 SDKMan 几乎所有常用操作。
SDKMane 语法 `sdk [candidate] [version]`。
* `command`:命令
* 最常用的命令:`list`、`install`、`uninstall`、`use`、`default`
* `candidate`:目标软件
* `version`:目标软件的版本号
#### list 命令
`list` 命令是用来浏览软件所有列表
`sdk list`:什么软件名都不带的,就是列出 SDKMan 可以装哪些软件,使用 `J`、`K` 上下滚动,`q` 离开列表浏览模式。
`sdk list 软件名`:列出此软件所有版本。
以 `sdk list java` 为例:

可以从截图看出列出了 SDKMan 包含的 JDK 版本信息。
`Status` 栏的信息一般是表明这个版本是已安装(「installed」),亦或是本地包(「local only」)。
`Use` 栏是表示此软件使用情况。`>` 表示当前正在使用,`*` 表示已经安装,`+` 表示本地安装包。
`Version` 栏是版本号。
`Dist` 栏是版本发行商。
`Identifier` 栏是版本标识符,用于安装时指定的版本。就是 `sdk [candidate] [version]` 命令语法中最后那个 `version` 的值。
#### install 命令
```shell
sdk inistall 软件名 版本标识符
```
> [!tip]
>
> 软件的版本标识符可以利用 [list 命令](#list%20命令) 来查询。
示例:
```shell
sdk install tomcat 11.0.18
```
---
## 异常
---
## IO 相关
[Java IO 笔记](Java_IO_Note.md)
---
## Lambda 相关
[Java 函数式编程](Java_Funcational_Note.md)
---
## 字节码
### 操作数栈
### 局部变量表
### int 类型入栈指令
#### 常量入栈
* 当 int 取值为 **-1~5** 采用 `iconst` 指令
* 当 int 取值为 **-128~127** 采用 `bipush` 指令
* 当 int 取值为 **-32768~32767** 采用 `sipush` 指令
* 当 int 取值为 **-2147473648~2147483647** 采用 `ldc` 指令
#### 局部变量表入栈
如果是从 [局部变量表](#局部变量表) 中入栈的,一般使用**load**指令。
* `iload_1`:将局部变量表中第一个 int 型变量「加载」至栈顶
* `fload_1`:将局部变量表中第一个 float 型变量「加载」至栈顶
* `dload_1`:将局部变量表中第一个 double 型变量「加载」至栈顶
* `aload_1`:将局部变量表中第一个引用类型的变量「加载」至栈顶
### 相关资料
* [两张图让你快速读懂JVM字节码指令 - 知乎](https://zhuanlan.zhihu.com/p/412472914)
---
## java 命令使用
### javac
命令一般格式:`javac xxx.java` ,即可编译 java 代码。
常用选项:
`javac -g xxx.java` 在编译 java 代码时加上 `-g` 选项,可以在使用 `javap` 命令时显示「局部变量表」的信息。
```shell
LocalVariableTable:
Start Length Slot Name Signature
0 7 0 args [Ljava/lang/String;
2 5 1 i I
4 3 2 j I
```
### javap
`javap` 是 jdk 自带的反编译工具。
一般常用的选项有三个:
* `-v` 不仅会输出行号、局部变量表信息、反编译汇编代码,还会输出当前类用到的常量池等信息
* `-l` 会输出行号和局部变量表信息
* `-c` 会对当前 class 字节码进行反编译生成汇编代码
示例:
源码:
```java
public class Test05{
public static void main(String[] args){
int i=2;
int j=0;
i=j;
}
}
```
使用的大致步骤:
4. 先使用 `javac -g Test05.java` 来编译,如上述所讲的,如果不加 `-g` 来编译,使用 `javap` 时,将不会显示「局部变量表」的信息。
5. 使用 `javap -v Test05` 后显示的内容:
```shell
javap -v Test05
Classfile /home/silascript/DevWorkSpace/JavaExercise/Test05.class
Last modified 2022年7月10日; size 411 bytes
MD5 checksum 26a137d802c1bb7d139bee1102f4eeed
Compiled from "Test05.java"
public class Test05
minor version: 0
major version: 55
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
this_class: #2 // Test05
super_class: #3 // java/lang/Object
interfaces: 0, fields: 0, methods: 2, attributes: 1
Constant pool:
#1 = Methodref #3.#20 // java/lang/Object."":()V
#2 = Class #21 // Test05
#3 = Class #22 // java/lang/Object
#4 = Utf8
#5 = Utf8 ()V
#6 = Utf8 Code
#7 = Utf8 LineNumberTable
#8 = Utf8 LocalVariableTable
#9 = Utf8 this
#10 = Utf8 LTest05;
#11 = Utf8 main
#12 = Utf8 ([Ljava/lang/String;)V
#13 = Utf8 args
#14 = Utf8 [Ljava/lang/String;
#15 = Utf8 i
#16 = Utf8 I
#17 = Utf8 j
#18 = Utf8 SourceFile
#19 = Utf8 Test05.java
#20 = NameAndType #4:#5 // "":()V
#21 = Utf8 Test05
#22 = Utf8 java/lang/Object
{
public Test05();
descriptor: ()V
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."":()V
4: return
LineNumberTable:
line 1: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this LTest05;
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=3, args_size=1
0: iconst_2
1: istore_1
2: iconst_0
3: istore_2
4: iload_2
5: istore_1
6: return
LineNumberTable:
line 5: 0
line 6: 2
line 8: 4
line 11: 6
LocalVariableTable:
Start Length Slot Name Signature
0 7 0 args [Ljava/lang/String;
2 5 1 i I
4 3 2 j I
}
SourceFile: "Test05.java"
```
---
## 基础深入
### 赋值
```java
public class Demo_1{
public static void main(String[] args){
int i =0;
i=15;
System.out.println(i);
}
}
```
能 [javac](#javac) 及 [javap](#javap) 命令查看部分字节码:
```
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=2, args_size=1
0: iconst_0地
1: istore_1
2: bipush 15
4: istore_1
5: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
8: iload_1
9: invokevirtual #13 // Method java/io/PrintStream.println:(I)V
12: return
LineNumberTable:
line 6: 0
line 8: 2
line 10: 5
line 15: 12
LocalVariableTable:
Start Length Slot Name Signature
0 13 0 args [Ljava/lang/String;
2 11 1 i I
}
```
`int=5;` 这个赋值语句对应的字节码是:
```
2: bipush 15
4: istore_1
```
> [!info] 关键字节码解析
>
> `bipush` 是入栈指令,int 的值范围不同,有不同的 [入栈指令](#int%20类型入栈指令)。
>
> 所谓「入栈」,即将值压入 [操作数栈](#操作数栈)。
>
> 最后 `istore` 指令,是将刚入栈的数值「出栈」保存进 [局部变量表](#局部变量表) 对应的位置。
>
> 经过上述两步,`i=5;` 这个赋值操作才算完成。
---
## 相关文档
* [Java17中文文档 - 全栈行动派](https://doc.qzxdp.cn/jdk/17/zh/api/index.html)
---
## 相关笔记
* [Java 视频清单](./Java_Videos.md)
* [Java 资料清单](Java_Material.md)
* [Kotlin 笔记](Kotlin/Kotlin_Note.md)
* [Java IO 笔记](Java_IO_Note.md)
* [Java 网络笔记](Java_Network.md)
* [Java Apache 笔记](Java_Apache_Note.md)
* [Java Web 笔记](Java_Servlet_Note.md)
* [Java 日志框架 笔记](Java_Log_Note.md)
* [Java 测试框架笔记](Test/Java_Test_Note.md)
* [Java WebService 笔记](WebService_RESTful/Java_WebService_Note.md)
* [Java RESTful 笔记](WebService_RESTful/Java_REST_Note.md)