乐途乐途
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
  • 学习路径
  • 第1章 Java概述与环境搭建

    • Java概述与环境搭建
    • Java语言概述
    • 解释型语言与编译型语言对比
    • JDK安装与配置
    • JDK、JRE、JVM 详解
    • HelloWorld程序详解
    • IDE 介绍
  • 第2章 标识符与基本数据类型

    • 章节导读
    • 变量概述
    • 常量概述
    • 基本类型与包装类
    • 字节型 byte
    • 短整型 short
    • 整型 int
    • 长整型 long
    • 单精度浮点型 float
    • 双精度浮点型 double
    • 字符型 char
    • 布尔型 boolean
    • 类型转换
  • 第3章 运算符与表达式

    • 章节导读
    • 算术运算符
    • 赋值运算符
    • 关系运算符
    • 逻辑运算符
    • 位运算符
    • 条件运算符
    • 运算符优先级
    • 表达式
  • 第4章 流程控制

    • 章节导读
    • 常见的程序运行流程
    • if-else 选择结构
    • switch 多分支选择
    • while 循环
    • do-while 循环
    • for 循环
    • break 与 continue
  • 第5章 数组

    • 章节导读
    • 一维数组
    • 多维数组
    • Arrays 工具类
  • 第6章 类与对象

    • 章节导读
    • 类与对象
    • 方法定义与调用
    • 构造方法
    • 封装
    • 访问修饰符
    • package 与 import
    • static 关键字
    • this 关键字
    • 参数传递 详解
    • 枚举
    • 成员内部类
    • 局部内部类
    • 静态内部类
    • 匿名内部类
  • 第7章 接口与继承

    • 章节导读
    • 继承
    • super 关键字
    • final 关键字
    • 多态
    • 向上转型与向下转型
    • 抽象类
    • 接口
    • 抽象类与接口对比
  • 第8章 注解

    • 章节导读
    • 注解基础
    • 元注解详解
    • 自定义注解
  • 第9章 常用类

    • 章节导读:Java 常用类
    • Object 类:万类之祖
    • 包装类:基本类型的对象化
    • String:不可变的字符串
    • StringBuffer:线程安全的可变字符串
    • StringBuilder:可变的字符串构建器
    • Math:数学运算工具类
    • Random:伪随机数生成器
    • 大数值运算 详解
    • 日期时间API 详解
  • 第10章 异常机制

    • 章节导读
    • 异常体系与分类
    • try-catch-finally
    • try-with-resources
    • throws 与 throw
    • 自定义异常
  • 第11章 泛型

    • 章节导读
    • 泛型基础
    • 通配符与PECS原则
    • 类型擦除
  • 第12章 集合框架

    • 章节导读
    • 集合框架概述
    • ArrayList
    • LinkedList
    • HashMap 详解
    • LinkedHashMap 详解
    • TreeMap 详解
    • HashSet
    • TreeSet 详解
    • TreeSet 与 Comparable
    • Collections 工具类详解
  • 第13章 IO流

    • 章节导读
    • IO流概述
    • 字节流
    • 字符流
    • 缓冲流
    • 转换流 详解
    • 序列化 详解
    • NIO与Files 详解
    • NIO与Files工具类
  • 第14章 多线程与并发

    • 第十六章 多线程与并发 —— 章节导读
    • 线程基础详解
    • synchronized 详解
    • Lock 与显式锁详解
    • volatile 详解
    • wait 与 notify 详解
    • ThreadLocal详解
    • 原子类详解
    • 并发工具类详解
    • 线程池详解
  • 第15章 反射

    • 章节导读
    • 反射概述与 Class 对象
    • Constructor 与对象创建
    • Field与Method详解
    • 反射应用详解
  • 第16章 JDK8新特性

    • 章节导读
    • Lambda 表达式
    • Stream API 基础
    • Stream API 高级详解
    • Optional 详解
    • 新日期时间API详解
  • 第17章 JDK9-11新特性

    • 章节导读
    • 模块化系统 — Project Jigsaw(JDK 9)
    • var 局部变量类型推断(JDK 10)
    • 集合工厂方法与增强(JDK 9 / 10 / 11)
    • 接口增强:private 方法(JDK 9)
    • Stream API 增强(JDK 9)
    • Optional 增强(JDK 9 / 10 / 11)
    • String 新增方法(JDK 11)
    • HTTP Client 与 Files 增强(JDK 11)
    • 直接运行 Java 源文件 — JEP 330(JDK 11)
  • 第18章 JDK12-17新特性

    • 章节导读
    • Switch 表达式(JDK 12 预览 / JDK 14 正式)
    • 文本块 Text Blocks(JDK 13 预览 / JDK 15 正式)
    • Records 记录类(JDK 14 预览 / JDK 16 正式)
    • 密封类 Sealed Classes(JDK 15 预览 / JDK 17 正式)
    • instanceof 模式匹配(JDK 14 预览 / JDK 16 正式)
    • Switch 模式匹配 — Pattern Matching for switch(JDK 17 预览 / JDK 21 正式)
    • Helpful NPE 与 String 增强(JDK 12 / JDK 14 / JDK 15)
    • Stream 增强(JDK 12 / JDK 16)
    • 日期时间增强 — Day Period 支持(JDK 16)
  • 第19章 JDK18-21新特性

    • 章节导读
    • 虚拟线程(JDK 19 预览 / JDK 20 第二预览 / JDK 21 正式)
    • 序列集合(JDK 21 正式)
    • Switch 模式匹配(JDK 17 预览 / JDK 18 第二预览 / JDK 20 第四预览 / JDK 21 正式)
    • Record 模式匹配(JDK 19 预览 / JDK 20 第二预览 / JDK 21 正式)
    • 未命名模式与变量(JDK 21 预览 / JDK 22 正式)
  • 第20章 JDK 22-25 新特性

    • 章节导读
    • 字符串模板(JDK 22 预览 / JDK 23 第二预览 / JDK 24 第三预览)
    • Stream Gatherers(JDK 22 预览 / JDK 24 第二预览)
    • 隐式声明类与实例方法(JDK 23 预览 / JDK 24 第二预览)
    • 原始类型模式匹配(JDK 24 预览)
  • 附录

    • Java 核心知识点
    • Java SE 专业术语
    • Java特性索引(JDK 8 → 25)

会议室里,小崔正盯着屏幕发呆。孔蓝凑过来:"崔哥,这十个词我抄了一年,Java 能不能像 Python 那样直接写 print?" 白歌笑着摇头:"以前确实不行——但 JDK 23 之后,还真可以。" 大翔推门进来:"正好,明天新人培训就用新语法,省得他们第一行代码就劝退。"

隐式声明类与实例方法(JDK 23 预览 / JDK 24 第二预览)


什么是隐式声明类

术语定义
隐式声明类 (Implicitly Declared Class)无需显式 class 声明,源文件自动成为顶层类,编译器为其隐式生成类名
实例 main 方法 (Instance Main Method)非 static 的 main 方法,运行于该类实例上,无需 public static void main(String[] args)
自动导入java.base 模块中导出的 50+ 包自动 import,无需手写 import 语句
源文件启动协议java --source N Hello.java 直接编译运行,无需 javac 先编译

样板代码退化史

从"仪式感"到"只写逻辑"的进化:


代码对比

传统写法(JDK 1.0 ~ JDK 22)

// === 场景说明:打印 "Hello World" 的传统写法 ===
public class Hello {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}

输出:

Hello, World!

对于新人,这一小段代码隐含五个概念:public、class、static、void、String[]——在写出第一行逻辑之前,已经背负了大量语法包袱。

JDK 23/24 简化写法

// === 场景说明:JDK 23/24 隐式声明类 + 实例 main ===
void main() {
    println("Hello, World!");
}

输出:

Hello, World!

无需类声明,无需 static,甚至无需 System.out.——因为 java.io.IO 的 println 是自动导入的静态方法之一。


运行方式

隐式声明类是预览特性,必须显式启用:

# JDK 23
java --enable-preview --source 23 Hello.java

# JDK 24
java --enable-preview --source 24 Hello.java

# JDK 25(如果落地)
java --source 25 Hello.java

--source 告诉编译器以指定版本规则处理源文件,同时自动调用 javac 编译后立即运行。


自动导入清单

编写隐式声明类时,以下包/类自动可用,无需显式 import:

// === 场景说明:无需 import,直接使用常用类型 ===
void main() {
    // java.lang 自动可用
    String name = "飞翔科技";
    var math = Math.sqrt(25);

    // java.util 核心接口
    List<String> members = List.of("大翔", "白歌", "小崔", "孔蓝");

    // java.io.IO 静态方法
    println("团队:" + members);

    // java.util.stream 处理数据
    members.stream()
           .filter(m -> m.contains("翔"))
           .forEach(System.out::println);
}

输出:

团队:[大翔, 白歌, 小崔, 孔蓝]
大翔

自动导入范围:

包路径自动可用内容
java.lang全部 public 类/接口
java.ioIO 类的静态方法(println、readln 等)
java.util集合接口 (List, Map, Set)、工具类 (Collections)
java.util.streamStream 接口及其演进
java.math大数运算相关

main 方法的多重形态

JDK 23/24 并非"废除"旧语法,而是新增了入口查找协议:

查找优先级: static main > 实例 main() > 实例 main(String[]),先匹配谁用谁。

// === 场景说明:三种合法 main 形态共存验证 ===

// 形态一:传统 static
static void main(String[] args) {
    println("传统 static 入口");
}

// 形态二:实例无参(优先级低于 static)
// void main() { println("实例入口"); }  // 与前一个不能同文件同时存在

// 形态三:实例带参
// void main(String[] args) { println("实例带参入口"); }

输出:

传统 static 入口

实战场景

场景一:新人第一行代码

// === 场景说明:孔蓝的入职培训 —— 零语法负担上手 ===
void main() {
    var welcome = "欢迎加入飞翔科技!";
    println(welcome);
    println("Java 版本:" + Runtime.version());
}

输出:

欢迎加入飞翔科技!
Java 版本:23.0.1+11-39

场景二:数据批处理脚本

// === 场景说明:小崔的月报 —— 快速处理 CSV 数据 ===
void main() {
    var data = """
        大翔,CTO,5
        白歌,架构师,4
        小崔,后端,3
        孔蓝,后端,0.5
        """;

    data.lines()
        .filter(line -> !line.isBlank())
        .map(line -> line.split(","))
        .sorted((a, b) -> Double.compare(
            Double.parseDouble(b[2]), Double.parseDouble(a[2])))
        .forEach(arr -> printf("%-6s | %-6s | %s年%n", arr[0], arr[1], arr[2]));
}

输出:

大翔     | CTO    | 5年
白歌     | 架构师  | 4年
小崔     | 后端   | 3年
孔蓝     | 后端   | 0.5年

场景三:算法刷题

// === 场景说明:白歌指导孔蓝刷 LeetCode —— 不用 class 包裹 ===
void main() {
    println(twoSum(new int[]{2, 7, 11, 15}, 9));
}

int[] twoSum(int[] nums, int target) {
    var map = new java.util.HashMap<Integer, Integer>();
    for (int i = 0; i < nums.length; i++) {
        int complement = target - nums[i];
        if (map.containsKey(complement)) {
            return new int[]{map.get(complement), i};
        }
        map.put(nums[i], i);
    }
    return new int[]{-1, -1};
}

输出:

[0, 1]

与 Python / Go / JavaScript 入口对比

语言入口类型系统包管理
Java 23void main()静态强类型自动导入 java.base
Python顶层语句动态类型built-in 自动可用
Gofunc main()静态强类型显式 import
JS顶层语句动态弱类型无

Java 23 的目标不是变成脚本语言,而是让单文件程序的启动成本趋近于脚本语言,同时保留完整的类型安全和 JVM 生态。


易错场景

// ❌ 错误 1:忘记 --enable-preview
// 直接 javac Hello.java 或 java Hello
// 报错:error: implicitly declared classes are a preview feature

// ❌ 错误 2:在普通类中混用隐式语法
public class App {
    public static void main(String[] args) {
        // 可以正常运行,但类声明已经显式存在
        // 隐式声明类的便利(自动导入、实例 main)不适用
    }
}

// ❌ 错误 3:隐式类中使用 package 声明
package com.example;  // 编译错误!
void main() { }

// ❌ 错误 4:多个 main 候选导致歧义
static void main(String[] args) { }
void main() { }  // 歧义!只能有一个入口
// ✅ 正确 1:跳过编译步骤,直接 --source 运行
// java --enable-preview --source 23 Hello.java

// ✅ 正确 2:使用自动导入的 IO.println
void main() {
    println("无需 System.out. 前缀");
}

// ✅ 正确 3:实例 main 配合实例方法
void main() {
    greet("孔蓝");
}
void greet(String name) {
    println("你好, " + name);
}

面试考点

Q1:JDK 23 隐式声明类的入口查找协议是怎样的?

JVM 启动隐式声明类时按优先级查找入口:第一优先 static void main(String[] args)(兼容传统),第二优先实例方法 void main(),第三优先实例方法 void main(String[] args)。找到第一个匹配即停止,若三者都不存在则编译报错。这保证了新语法的同时,旧代码完全不受影响。

Q2:java --source 25 Hello.java 与 javac Hello.java && java Hello 有何区别?

java --source N 是"源文件启动协议",它跳过显式编译步骤,由 java 命令内部调用编译器(类似 shebang 风格)。关键区别:1) 隐式类只能通过 --source 运行,不能用 javac 单独编译再 java 运行(因为编译器会拒绝预览特性);2) --source 模式下 javac 在内存中生成字节码,不产生 .class 文件;3) 隐式声明类的自动导入和 main 查找协议只在此模式下生效。

Q3:为什么 Java 要引入隐式声明类和实例 main,而不是继续坚持 public static void main?

三个核心驱动力:1) 降低入门门槛——新人第一行代码不需要理解 public、static、String[]、class 等六个关键字,直接写逻辑;2) 提升脚本化能力——Java 单文件程序可用于数据处理、系统管理、CI/CD 脚本,不需项目脚手架;3) 对齐现代语言体验——Python/Go/JS 等的简洁入口倒逼 Java 演进,同时保留强类型和 JVM 性能优势。本质是"仪式感削减"而非"语言降级"。


孔蓝合上笔记本:"第一行 Java,原来也可以这么简单。" 白歌补了一句:"简单和强大不矛盾——该用 Spring Boot 时用 Spring,该写脚本时用隐式类,工具适配场景,而不是反过来。"

上一页
Stream Gatherers(JDK 22 预览 / JDK 24 第二预览)
下一页
原始类型模式匹配(JDK 24 预览)