[从C或Go或Python转Java]去除Java学习的拦路虎
[从C或Go或Python转Java]去除Java学习的拦路虎
0、[必杀技1:面向对象—和C、Go、Python极度不用的地方]Java文件命名规则详解
借助这个规则,你就能进一步强化:Java是面向对象
核心规则
- 一山不容二虎(public版)
- 一个
.java文件【必须包含且只能有一个】public修饰的类(class)或接口(interface),并且该public类的名字必须与文件名(不含.java扩展名)完全一致!
- 一个
- 可有家臣随从(非public版)
- 一个
.java文件中可以包含多个非public修饰的类(class)或接口(interface)
- 一个
- 文件名即入口点
- 如果找不到与文件名同名的
public类,直接编译失败。这是编译期就强制检查的。
- 如果找不到与文件名同名的
典型的good的
// ✅ 文件名必须为:Computer.java
// 这是唯一的public类,且名字必须叫Computer
public class Computer {
public void start() {
System.out.println("Computer starting...");
}
}
// ✅ 可以放一个非public的类
class Memory {
// 内存条类,不暴露给外部包
}
// ✅ 可以放一个非public的接口
interface InternalComponent {
// 内部组件接口
}
// ✅ 还可以再放一个非public的枚举
enum PowerState {
ON, OFF, SLEEP
}1、[必杀技2]Java中与这些语言最大的区别:没有类似C、Go、Python的一个全局的main函数!Java中只有class!
这是一个非常关键的认知转变!,一定要时刻记住
Java的“入口”哲学:Java没有全局函数,一切都是基于类的。他的所谓的对标你们C、Go的main方法只是一个特殊约定的静态方法。
那么问题来了
你可能就问第1个问题:这和我学的这些其他主流语言一点都不像啊!那Java的主程序咋进去啊?
我的答案是:在Java的某个全局class中,你猛地发现1个成员函数长这样
public class MyApp {
// 必须满足以下条件:
// 1. public - 可以被JVM调用
// 2. static - 不需要创建类的实例
// 3. void - 没有返回值
// 4. 方法名必须是main
// 5. 参数必须是String数组(或可变参数)
public static void main(String[] args) {
System.out.println("Hello Java!");
}
}也就是:public static void main
他就是整个Java代码的入库
上面代码的启动方式
# 编译
javac MyApp.java
# 运行 - 指定包含main方法的类
java MyApp然后你可能问第2个问题:我听说Java代码好多都是class组织的,那如果每个class中都有1个
public static void main那我岂不是摸不着头脑了,应该哪个开始是最开始的启动点啊?
答案:
1、首选,确实Java的每个class中确实都可以写个public static void main,就类似你写Python的时候,你写个那个if __name__ == "__main__":
- 典型的,你后边会发现SpringBoot框架人家的主入口的class里面其实也有
public static void main,但是你使用的时候其实不用调人家那个,你只会调他的成员函数!- 他的那个
public static void main其实是他自己测试自己或许运行自己使用的!
- 他的那个
2、你自己写的任何1个离线脚本或者大型的项目,你自己写多少个class确实也可以有多少个public static void main入口,【但是你自己要手动指定1个,如果不手动指定,那你好歹标记一下】,比如常见的的标记规则是这样的!
- 方法1:你直接idea点击启动某个
public static void main那你自己指定了,你肯定会!- 其实就等价于你命令行使用
java 某个ClassName那样,其实也就是从那个对应的public static void main进入
- 其实就等价于你命令行使用
- 方法2:实际项目通过构建工具或配置文件指定主类,典型的
- 子方式1:在Spring Boot项目中,主类通常通过注解标识而不是在pom.xml中直接配置
@SpringBootApplication // 这个注解标记了这是Spring Boot主类- 在Spring Boot项目中,通常不需要在pom.xml中显式指定主类,因为:
- 原因1:Spring Boot Maven Plugin的自动检测
- Spring Boot的Maven插件会自动:
- 查找带有
@SpringBootApplication注解的类 - 查找
public static void main方法 - 自动将其设置为主类
- 查找带有
- Spring Boot的Maven插件会自动:
- 子方式2:在pom.xml里面配置:
<mainClass>之类<mainClass>com.example.Application</mainClass>
- 子方式1:在Spring Boot项目中,主类通常通过注解标识而不是在pom.xml中直接配置
你可能问第3个问题:设计
public static void main的原理是什么?怎么进入程序?
答案:JVM会查找你指定的类中的public static void main方法作为入口点。
main 方法的这种特定签名并非偶然,而是由 Java语言规范(JLS) 和 Java虚拟机(JVM) 共同定义的,主要基于以下几个设计原理:
唯一且明确的入口点
一个程序需要有一个确定的开始位置。在C/C++中,这个入口是
main函数。Java延续了这个传统,便于理解和统一管理。JVM必须能够无歧义地找到从哪里开始执行。规定一个固定名称和签名的方法,就保证了这一点。
public(公开的)- 原因:
main方法必须能够被 JVM调用。JVM作为一个外部实体,需要访问这个方法。如果它不是public,JVM在类的外部就无法调用它,程序也就无法启动。
- 原因:
static(静态的)原因:在调用
main方法时,还不存在任何该类的实例对象。JVM需要不通过创建对象,而是直接通过类名来调用这个方法。静态方法属于类本身,而不是类的实例,因此可以在不创建对象的情况下直接调用。逻辑上也很合理:程序启动是“第一件事”,自然发生在任何对象被创建之前。
void(无返回值)- 原因:程序通常将退出状态(成功、错误代码)通过
System.exit(int code)或异常来传达,而不是通过方法返回值。void简化了定义,且与操作系统交互的方式保持一致(尽管JVM在进程结束时会有自己的退出状态,但这与main方法的返回值是两回事)。
- 原因:程序通常将退出状态(成功、错误代码)通过
String[] args(字符串数组参数)原因:这是程序与外界(通常是命令行)交互的主要方式。它允许用户在启动程序时传递配置参数、文件名或其他初始数据。
例如:
java MyApp -f input.txt -o output.txt,这里的-f、input.txt等参数会被JVM收集并转换成字符串数组,传递给args。
类比其他语言
| 语言 | 入口点 | Java对应 |
|---|---|---|
| C | int main(int argc, char *argv[]) | 某个类里面的:public static void main(String[] args) |
| Python | if __name__ == "__main__": | 某个类里面的:public static void main |
| Go | func main() | 某个类里面的:public static void main |
2、Java的导包使用import:你就模仿Go语言类似即可
感觉导包基本上和Go一样了,从Go转过来的基本上就很容易理解
可能学c语言的人稍微要适应从include导包到import导包!
3、Java的每个包最前面的package后边比Go语言复杂一点
我知道你写go可能是
package demo
// 可能是:项目根目录/lib/demo目录下,但是go的就只写最后1个
// 设计哲学:只需要包名,与目录结构解耦,文件可以放在项目的任何位置
import "fmt"
func Demo(){
fmt.Printf("你好\n")
}但是人家java就不一样了,他非常希望你写的很详细
package com.nageoffer.shortlink.admin;
/*
他的目录是:项目根目录/src/main/java/com/nageoffer/shortlink/admin
其实就是:2部分
// 包名 = 完全限定的路径(从src目录开始)
第1部分:项目根目录/src/main/java
第2部分:com/nageoffer/shortlink/admin其实就是把`/`号改为点就是com.nageoffer.shortlink.admin
这个设计其实和Go太类似了,
*/
// 省略导入的其他包哈
import org.mybatis.spring.annotation.MapperScan;
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients("com.nageoffer.shortlink.admin.remote")
@MapperScan("com.nageoffer.shortlink.admin.dao.mapper")
public class ShortLinkAdminApplication {
public static void main(String[] args) {
SpringApplication.run(ShortLinkAdminApplication.class, args);
}
}可能的引申问题:那我写go的package很爽,就1个单词,你这个java的这么长串,那我好难copy,并且我怕抄错了
很好,解决你这个问题,使用idea就行了
你自己新建1个class的时候,他很智能给你写package的全路径!

刚刚演示的是在1个已知目录下加个class就已经这么智能了
那么接下来演示一下,新建1个新目录,新目录里面给你整个类,你看看!其实有2种方法
方法1:最好用的1个方法,在当前路径下写个你想要相对于本路径的路径最后.你要加的类的名字
比如demo.AAA,比如demo.yes.BBB

方法2:建议不要用,没必要的!那就是新建一个文件夹【在idea里面叫做:软件包】,然后再加个类
设计理念差异
Go的设计理念:
简洁性优先:包名不需要反映完整的目录结构
项目组织灵活:包可以放在任何位置,只要在 GOPATH/module 内
一个目录一个包:同一个目录下的所有 Go 文件必须属于同一个包
Java的设计理念:
明确唯一性:完全限定名确保全局唯一(反向域名习惯)
Maven/Gradle标准:与构建工具的目录约定紧密耦合
包=命名空间:不仅组织代码,还提供逻辑分层
当你确定要成为一名Spring工程师而不是1名纯Java工程师【请记住/src/main/java/这个路径!】
虽然听起来好笑,但是确实大家转Java都是要学这个的!
请记得Java所谓的根目录,Java(特别是 Maven/Gradle 项目)的一个关键约定:特特指:/src/main/java下面哈
这个设计的原因:
约定优于配置:所有 Java 项目都遵循相同结构
构建工具依赖:Maven/Gradle 默认从这里找代码
IDE 自动识别:IntelliJ IDEA/Eclipse 都支持这个结构
4、再来确定一遍:你成为一名Spring工程师
5、[Java特色]配置文件特别多
请多看几眼把,熟悉了就熟悉了
- .yaml
- .groovy
COLS.groovy可能是一个 Groovy 脚本文件
附录1、idea就没有类似go语言那样import某个github路径,然后就自动在pom.xml里面导包吗?
对,Java / Maven 的依赖机制和 Go 的模块机制是不同的,所以 IDEA 并没有完全像 Go 那样直接 import github.com/... 就自动下载依赖的功能。
Java / Maven 的机制(声明式)
- Java 是 声明依赖:
- 你必须在 pom.xml(Maven)或 build.gradle(Gradle)里写清楚 groupId / artifactId / version。
- IDEA 可以自动帮你:
当你写import com.alibaba.fastjson2.JSON;
IDEA 会提示: - Cannot resolve symbol ‘JSON’.Suggest to add Maven/Gradle dependency.
- 点击提示可以自动在 pom.xml 添加依赖,但前提是 该库已经发布到 Maven 仓库(比如 Maven Central 或阿里云镜像)。
- IDEA 可以帮你“半自动”添加依赖,但前提是库已经发布到 Maven 仓库
补救方法(Java 世界类似 Go 的体验)
- 使用 IDEA 的提示
- 写 import,按 Alt+Enter → Add Maven Dependency,自动在 pom.xml 添加。
- 直接用 Maven 坐标复制
- 去 Maven Central 找 artifact 坐标,复制到 pom.xml。