手写的第一个 Java 应用程序,执行的时候发生了什么?

2024-08-29 11:32

本文主要是介绍手写的第一个 Java 应用程序,执行的时候发生了什么?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

这是蜗牛互联网的第 99 期原创。

作者 | 白色蜗牛

来源 | 蜗牛互联网(ID: woniu_internet)

转载请联系授权(微信ID: 919201148)

前言

在上一篇文章 超详细!JDK 8 下载、安装和环境配置(macOS 和 Windows 版本)的介绍下,我们已经搭好 Java 开发环境了,本文我们就实战一下,编一个 Java 应用程序,程序运行的时候能看到 Hello World 的输出。

我们同时分析下从编码到运行的整个过程,都发生了什么!

编码输出 Hello World

我们不借助任何的集成开发环境,就用最原始的手写的方式来编码!

计算机上手写的话,就是往记事本上敲代码。

Windows 用户可以直接打开记事本,macOS 用户可以在控制台键入以下命令来打开记事本:

open -a TextEdit

以下就是输出 Hello World 应用程序的极简代码。照敲就行,先不用在意每个码的含义,后边会讲到。

public class HelloWorld{public static void main(String[] args){System.out.println("Hello, World!!!");}
}

保存文件命名为 HelloWorld.java,代表这是 Java 源码文件。

编译源码文件

Java 文件只是源码文件,还不能执行,必须将它转换成字节码文件,也就是 .class 文件才能够执行。这个转换的过程就是编译。

编译指令是 javac,c 就是 compile(编译) 的首字母。

执行以下命令,HelloWorld.java 文件会被编译,然后同目录下就会生成 HelloWorld.class 文件。

javac HelloWorld.java

执行字节码文件

.class 文件生成,而且该文件内部有 main 函数,说明有程序执行的入口,那其实意味着 Hello World 程序已经写好并且达到可运行的状态了。

那怎么跑这个 Java 程序呢?

很简单,通过 java 命令即可,命令的参数就是 class 名,如下:

java HelloWorld

此时激动人心的时刻就到来了!我们看到控制台打印了 Hello, World!!! 然后程序退出。

这意味着我们成功写好了第一个 Java 应用程序,并顺利运行!

那么整个过程是怎么发生的呢,接下来我们分析一下。

源码分析

首先我们看源码,源码其实相当精简。

public class HelloWorld{public static void main(String[] args){System.out.println("Hello, World!!!");}
}

这里有三个 Java 的关键字,分别是 publicclassstatic

public 是 Java 语法中的访问权限修饰符,后边我们会细讲,这里简单提下。

public(公共的) 的兄弟还有 protected(受保护的)、default(默认的) 和 private(私有的),他们决定了 Java 世界中的 类、对象、方法和属性,能被多大的范围访问,是当前类,还是当前包,还是不受限的哪里都能访问。

简单讲,是一种权限控制,类似你发朋友圈,可以选择完全公开,可以选择部分人可见,也可以选择仅自己可见。

回到源码里,我们看到 public 修饰了 HelloWorld 这个类以及 main 这个方法。也正是 public,让我们执行程序时,没有遭到阻拦。

class(类)表明当前源码文件是个普通类,这个关键词是最常用的,它的兄弟还有interface(接口类)和 enum(枚举类)。

class 后边的 HelloWorld 就是编码时为当前这个类起的名字。按照命名规范,类名是字母和数字的组合,首个字符必须是大写字母。

类名后面的花括号即 {} 里边的内容就是类的定义。

static 是静态修饰符,表明被修饰的内容可以被当前的类直接引用,而不需要将类实例化。

此处修饰了 main 方法,表明 main 方法可以直接被 HelloWorld 引用。

void 是 main 方法的返回值,此处表示无返回值。

main 圆括号里的内容,就是 main 方法的入参,String[] 说明这是一个字符串数组,args 代表变量。

它的作用就是,启动 Java 应用的同时,能够传递一个 String 类型的数组来定制化应用的初始化属性。比如你在执行 java HelloWorld 这个指令时,可以传入你需要的参数。

方法申明后面的花括号即 {} 里边的内容就是方法的定义。

方法的代码每一行用;结束,这里只有一行代码,就是:

System.out.println("Hello, World!!!");

System.out 是 Java 提供的一个静态的打印流对象,通过他可以进行打印相关的操作,在它的基础上,调用 println 方法,就可以在控制台输出指定的信息。

接下来我们看下对源代码都做了哪些操作。

执行路径分析

一、用 JDK 中的 javac 命令将 Java 源代码进行编译,生成 Java 字节码,也就是 class 文件。

javac 命令可以在 JDK 家目录的 bin 目录下找到。

二、用 JRE 的 java 命令执行 class 文件时,Java 字节码会被传输到 JVM(Java 虚拟机),JVM 会合并字节码以及 JRE 中的库文件一起执行,输出特定硬件平台的机器码,或者说指令集。

三、机器码被底层物理硬件平台执行

通过这个过程,我们也会发现,要想做到 Write Once, Run Anywhere(一次编写,到处运行) 这样的跨平台特性,就必须保证 class 文件无论在哪个平台都能正常执行,但不同硬件平台接收的指令集有很大差异,那就需要有个东西基于不同的操作系统平台来做适配,担起这一重任的就是 JVM

因此,正是 JVM 的不跨平台特性,才实现了 Java 语言的跨平台特性。

像我们本文的 HelloWorld 的源码,经过编译生成了 HelloWorld.class,然后我在 macOs 上用 java HelloWorld 可以执行它。

此时,我把 HelloWorld.class 复制到 Linux 环境或者 Windows 环境中,同样用 java HelloWorld 来执行,是可以得到与 macOs 中相同的结果的。

事实上,如果我复制 HelloWorld.java 文件到 Linux 环境中,同样 javac,生成的 class 文件也是相同的。

再结合下面这个图,你也可以理解为什么我们下载 JDK 要区分操作系统版本了。

总结

本文通过实战 HelloWorld 的一个极简 Java 程序,学习了如何写 Java 代码以及如何运行 Java 程序,同时也分析了 Java 源码中涉及到的相关语法和规范,最后从这一切是怎么发生的角度上,分析了从源码到运行的整个执行路径,在分析的过程中,也帮助我们更深的理解了 Java 的跨平台特性。

有了对 Java 初步的认识和感知后,再学习 Java 的一些概念和语法就相对得心应手啦!


我是蜗牛,大厂程序员,专注技术原创和个人成长,正在互联网上摸爬滚打。欢迎关注我,和蜗牛一起成长,我们一起牛~下期见!


推荐阅读:

学习 Java,使用哪个版本最好

学习 Java 语言,你必须知道的 Java 简史

超详细!JDK 8 下载、安装和环境配置(macOS 和 Windows 版本)


由于微信公众号改版,文章推送会乱序。为了第一时间收到蜗牛的消息,请读者朋友动动小手,点击文章顶部的蓝字关注我后,在公号主页设置里加个星标

戳阅读原文,加入蜗牛的 交流群

这篇关于手写的第一个 Java 应用程序,执行的时候发生了什么?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1117738

相关文章

Java中流式并行操作parallelStream的原理和使用方法

《Java中流式并行操作parallelStream的原理和使用方法》本文详细介绍了Java中的并行流(parallelStream)的原理、正确使用方法以及在实际业务中的应用案例,并指出在使用并行流... 目录Java中流式并行操作parallelStream0. 问题的产生1. 什么是parallelS

Java中Redisson 的原理深度解析

《Java中Redisson的原理深度解析》Redisson是一个高性能的Redis客户端,它通过将Redis数据结构映射为Java对象和分布式对象,实现了在Java应用中方便地使用Redis,本文... 目录前言一、核心设计理念二、核心架构与通信层1. 基于 Netty 的异步非阻塞通信2. 编解码器三、

Linux kill正在执行的后台任务 kill进程组使用详解

《Linuxkill正在执行的后台任务kill进程组使用详解》文章介绍了两个脚本的功能和区别,以及执行这些脚本时遇到的进程管理问题,通过查看进程树、使用`kill`命令和`lsof`命令,分析了子... 目录零. 用到的命令一. 待执行的脚本二. 执行含子进程的脚本,并kill2.1 进程查看2.2 遇到的

SpringBoot基于注解实现数据库字段回填的完整方案

《SpringBoot基于注解实现数据库字段回填的完整方案》这篇文章主要为大家详细介绍了SpringBoot如何基于注解实现数据库字段回填的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以了解... 目录数据库表pom.XMLRelationFieldRelationFieldMapping基础的一些代

一篇文章彻底搞懂macOS如何决定java环境

《一篇文章彻底搞懂macOS如何决定java环境》MacOS作为一个功能强大的操作系统,为开发者提供了丰富的开发工具和框架,下面:本文主要介绍macOS如何决定java环境的相关资料,文中通过代码... 目录方法一:使用 which命令方法二:使用 Java_home工具(Apple 官方推荐)那问题来了,

Java HashMap的底层实现原理深度解析

《JavaHashMap的底层实现原理深度解析》HashMap基于数组+链表+红黑树结构,通过哈希算法和扩容机制优化性能,负载因子与树化阈值平衡效率,是Java开发必备的高效数据结构,本文给大家介绍... 目录一、概述:HashMap的宏观结构二、核心数据结构解析1. 数组(桶数组)2. 链表节点(Node

Java AOP面向切面编程的概念和实现方式

《JavaAOP面向切面编程的概念和实现方式》AOP是面向切面编程,通过动态代理将横切关注点(如日志、事务)与核心业务逻辑分离,提升代码复用性和可维护性,本文给大家介绍JavaAOP面向切面编程的概... 目录一、AOP 是什么?二、AOP 的核心概念与实现方式核心概念实现方式三、Spring AOP 的关

详解SpringBoot+Ehcache使用示例

《详解SpringBoot+Ehcache使用示例》本文介绍了SpringBoot中配置Ehcache、自定义get/set方式,并实际使用缓存的过程,文中通过示例代码介绍的非常详细,对大家的学习或者... 目录摘要概念内存与磁盘持久化存储:配置灵活性:编码示例引入依赖:配置ehcache.XML文件:配置

Java 虚拟线程的创建与使用深度解析

《Java虚拟线程的创建与使用深度解析》虚拟线程是Java19中以预览特性形式引入,Java21起正式发布的轻量级线程,本文给大家介绍Java虚拟线程的创建与使用,感兴趣的朋友一起看看吧... 目录一、虚拟线程简介1.1 什么是虚拟线程?1.2 为什么需要虚拟线程?二、虚拟线程与平台线程对比代码对比示例:三

Java中的.close()举例详解

《Java中的.close()举例详解》.close()方法只适用于通过window.open()打开的弹出窗口,对于浏览器的主窗口,如果没有得到用户允许是不能关闭的,:本文主要介绍Java中的.... 目录当你遇到以下三种情况时,一定要记得使用 .close():用法作用举例如何判断代码中的 input