这是每个Java程序员都知道的程序。它很简单,但是简单的开始可以导致对更复杂概念的深入理解。在这篇文章中,我将探讨从这个简单的程序中学到什么。

公共 HelloWorld {

/ **

* @参数参数

* /

public static void main (String [ ] args ) {

// TODO自动生成的方法存根

System。出来。println (“ Hello World” );

} }

1.为什么一切都从一堂课开始?

Java程序是从类构建的,每个方法和字段都必须在一个类中。这是由于它具有面向对象的功能:一切都是一个对象,它是一个类的实例。相对于功能性编程语言,面向对象的编程语言具有很多优势,例如更好的模块化,可扩展性等。

2.为什么总是有“主要”方法?

“ main”方法是程序入口,它是静态的。“静态”表示该方法是其类的一部分,而不是对象的一部分。

这是为什么?我们为什么不将非静态方法作为程序入口?

如果方法不是静态的,则需要先创建一个对象才能使用该方法。因为必须在对象上调用该方法。为了进入目的,这是不现实的。没有鸡肉,我们就无法获得鸡蛋。因此,程序进入方法是静态的。

参数“ String [] args”指示可以将字符串数组发送到程序以帮助程序初始化。

3. HelloWorld的字节码

为了执行该程序,首先将Java文件编译为存储在.class文件中的Java字节码。字节码是什么样的?字节码本身不可读。如果我们使用十六进制编辑器,则如下所示:

我们可以在上面的字节码中看到很多操作码(例如CA,4C等),每个操作码都有一个对应的助记码(例如,在下面的示例中为aload_0)。操作码不可读,但是我们可以使用javap来查看.class文件的助记符形式。

“ javap -c”打印出该类中每个方法的反汇编代码。反汇编代码表示组成Java字节码的指令。

javap -classpath。-c HelloWorld

从“ HelloWorld.java”编译而成的公共 HelloWorld 扩展了 Java。郎。对象{ public HelloWorld ();

代码:

0 : aload_0

1 : 调用特殊#1 ; //方法java / lang / Object。“ <init>” :()V

4 : 返回

公共 静态 无效主( java中。郎。字符串[ ] );

代码:

0 : 静态#2 ; //字段java / lang / System.out:Ljava / io / PrintStream;

3 : ldc#3 ; // String Hello World

5 : invokevirtual#4 ; //方法java / io / PrintStream.println:(Ljava / lang / String;)V

8 : return }

上面的代码包含两种方法:一种是默认的构造函数,由编译器推断出来;另一种是默认的构造函数。另一种是主要方法。

在每种方法之下,都有一系列指令,例如aload_0,invokespecial#1等。可以在Java字节码指令列表中查找每个指令的作用。例如,aload_0将局部变量0的引用加载到堆栈上,getstatic获取类的静态字段值。请注意,在getstatic指令指向运行时常量池之后,将显示“#2”。常量池是JVM运行时数据区域之一。这使我们看一下常量池,可以使用“ javap -verbose”命令来完成。

此外,每个指令都以数字开头,例如0、1、4等。在.class文件中,每个方法都有一个对应的字节码数组。这些数字对应于存储每个操作码及其参数的数组的索引。每个操作码的长度为1个字节,指令可以具有0个或多个参数。这就是为什么这些数字不连续的原因。

现在,我们可以使用“ javap -verbose”进一步看一看该类。

javap -classpath。详细的HelloWorld

从“ HelloWorld.java”编译而成的公共 HelloWorld 扩展了 Java。郎。对象

SourceFile : “ HelloWorld.java”

次要版本: 0

主要版本: 50

常量池:const#1 = Method #6。#15 ; // java / lang / Object。“ <init>” :()V const#2 = 字段 #16。#17 ; // java / lang / System.out:Ljava / io / PrintStream;const#3 = 字符串 #18 ; // Hello World const#4 = Method #19。#20 ; // java / io / PrintStream.println:(Ljava / lang / String;)V const#5 = class #21 ; // HelloWorld const#6 = class #22 ; // java / lang / Object const#7 = Asciz < init >; const#8 = Asciz () V ; const#9 = ASCII码; const#10 = Asciz LineNumberTable ; const#11 = Asciz主函数const#12 = Asciz ([ Ljava / lang / String ; ) V ; const#13 = Asciz SourceFile ; const#14 = Asciz HelloWorld。java ; const#15 = NameAndType#7 :#8 ; //“ <init>” :()V const#16 = class #23 ; // java / lang / System const#17 = NameAndType#24 :#25 ; // out:Ljava / io / PrintStream; const#18 = Asciz你好世界; const#19 = 类别 #26 ; // java / io / PrintStreamconst#20 = NameAndType#27 :#28 ; // println:(Ljava / lang / String;)V const#21 = Asciz HelloWorld ; const#22 = Asciz java / lang / Object ; const#23 = Asciz java / lang / System ; const#24 = ASCII输出; const#25 = Asciz Ljava / io/ PrintStream ;; const#26 = Asciz java / io / PrintStream ; const#27 = Asciz println ; const#28 = Asciz ( Ljava / lang / String ; ) V ;

{ 公共 HelloWorld ();

代码:

堆栈= 1,Locals = 1,Args_size = 1

0 : aload_0

1 : invokespecial#1 ; //方法java / lang / Object。“ <init>” :()V

4 : 返回

LineNumberTable :

第2行: 0

公共 静态 无效主( java中。郎。字符串[ ] );

代码:

堆栈= 2,Locals = 1,Args_size = 1

0 : getstatic#2 ; //字段java / lang / System.out:Ljava / io / PrintStream;

3 : ldc#3 ; // String Hello World

5 : invokevirtual#4 ; //方法java / io / PrintStream.println:(Ljava / lang / String;)V

8 : 返回

LineNumberTable :

行9 : 0

行10 : 8 }

从JVM规范开始:运行时常量池的功能类似于常规编程语言的符号表,尽管它包含的数据范围比典型的符号表还大。

“ invokespecial#1”指令中的“#1”指向常量池中的#1常量。该常量为“方法#6.#15;”。从数字中,我们可以递归获得最终常数。

LineNumberTable向调试器提供信息,以指示Java源代码的哪一行对应于哪个字节代码指令。例如,Java源代码中的第9行对应于main方法中的字节代码0,而行10对应于字节代码8。

如果您想了解更多有关字节码的信息,可以创建并编译一个更复杂的类以进行查看。HelloWorld确实是这样做的起点。

4.如何在JVM中执行?

现在的问题是,JVM如何加载类并调用main方法?

在执行main方法之前,JVM需要1)加载,2)链接和3)初始化类。1)加载将类/接口的二进制形式带入JVM。2)链接将二进制类型的数据合并到JVM的运行时状态中。链接包括3个步骤:验证,准备和可选的解决方案。验证可确保类/接口在结构上正确;准备工作涉及分配类/接口所需的内存;分辨率解析符号引用。最后3)初始化为类变量分配了适当的初始值。

此加载作业由Java类加载器完成。启动JVM时,将使用三个类加载器:

1. Bootstrap类加载器:加载位于以下位置的核心Java库: / jre / lib目录。它是核心JVM的一部分,并用本机代码编写。

2. 扩展类加载器:将代码加载到扩展目录中(例如, / jar / lib / ext)。

3. 系统类加载器:加载在CLASSPATH上找到的代码。

因此,HelloWorld类由系统类加载器加载。当main方法执行时,它将触发其他依赖类的加载,链接和初始化(如果存在)。

最后,将main()框架压入JVM堆栈,并相应地设置程序计数器(PC)。PC然后指示将println()帧推送到JVM堆栈。当main()方法完成时,它将从堆栈中弹出并执行完毕。

最后,开发这么多年我也总结了一套学习Java的资料与面试题,如果你在技术上面想提升自己的话,可以关注我,私信发送领取资料或者在评论区留下自己的联系方式,有时间记得帮我点下转发让跟多的人看到哦。

classpath*: 和classpath:有什么区别_我们可以从Java“HelloWorld”中学到什么?相关推荐

  1. java跟c 的区别_【c++跟java的区别】java跟c语言的区别

    Java与C/C++作为编程语言的两大巨头,他们有什么区别呢?下面是小编为大家准备的c++跟java的区别,希望大家喜欢! c++的定义 C++是一种面向对象的计算机程序设计语言.C++这个词在中国大 ...

  2. java主线程和子线程区别_主线程异常– Java

    java主线程和子线程区别 Being a Java Programmer, you must have seen exception in thread main sometimes while r ...

  3. java comp env 区别_加和不加java:comp/env/前缀有什么区别?

    java:comp/env是标准的J2EE环境查找规则 使用这种方式必须做一次环境名到JNDI名的映射 这种隔离使得在写程序时不必关注真正的JNDI名字 其实说白了跟把JNDI名放到配置文件里是一样的 ...

  4. java和脚本语言 区别_脚本语言和java语言有什么不同

    分析原因:快捷方式的打开方式被病毒等修改了! 将下面的代码保存为 .reg 然后双击运行,选择导入即可! Windows Registry Editor Version 5.00 [HKEY_CLAS ...

  5. web.xml 配置中classpath: 与classpath*:的区别

    首先 classpath是指 WEB-INF文件夹下的classes目录 (1)什么事classes目录?classes就是:  1.存放各种资源配置文件 eg.init.properties log ...

  6. Java和pathion_Spring配置中的classpath:与classpath*:的区别

    概念解释及使用场景: classpath是指WEB-INF文件夹下的classes目录. 通常我们一般使用这种写法实在web.xml中,比如spring加载bean的上下文时,如下: contextC ...

  7. Spring配置中的classpath:与classpath*:的区别研究

    文章目录 概念解释及使用场景 classpath:和classpath*:区别 概念解释及使用场景 classpath是指WEB-INF文件夹下的classes目录. 通常我们一般使用这种写法实在we ...

  8. web.xml配置中classpath:与classpath*:的区别

    classpath是指 WEB-INF文件夹下的classes目录 解释classes含义: 1.存放各种资源配置文件 eg.init.properties log4j.properties stru ...

  9. 4、Spring配置中的classpath:与classpath*:的区别

    2019独角兽企业重金招聘Python工程师标准>>> 一.概念解释及使用场景: classpath是指WEB-INF文件夹下的classes目录. 通常我们一般使用这种写法实在we ...

最新文章

  1. cocoa 坑爹的委托
  2. 搭建prometheus+grafana监控系统
  3. 【译】 Web Components 的高级工具
  4. mysql查询锁表语句和kill对应的线程
  5. 2.2.5 操作系统之调度算法(时间片轮转调度算法、优先级调度算法、多级反馈队列调度算法)
  6. Java技术分享:Lambda表达式之接口实例化
  7. MySQL双主(主主)架构方案
  8. OpenJudge:熄灯问题
  9. 关于JSP与Int不得不说的故事
  10. cad文件管理服务器,CAD文件管理(ZT)
  11. 初识STM32F103
  12. RC串联延时电路电容充电时间计算
  13. python输入年份判断生肖_python年份判断生肖
  14. POJ 3422 Kaka's Matrix Travels(拆点+最大费用流)题解
  15. 我的世界服务器怎么做无限的弓,我的世界怎么用命令方块做无限弓?
  16. 2022年第十七届研电赛报名|安谋科技(Arm China)命题:基于特定开发平台的理性智能体设计
  17. z-index的使用小结
  18. 程序员怎么接单赚外快,去这6个平台就可以了!
  19. 【JUC高并发编程】—— 初见JUC
  20. 【OSPF的特殊区域和特性】ospf的lsdb优化、特殊区域、路由汇总、静默接口、ospf报文认证、LSA路由汇总、高级特性(PRC、智能计时器、FRR、ospf database overflow)

热门文章

  1. 在SAP分析云里利用词云技术显示大段文本里的关键词
  2. 小技巧,找出所有check table设置为某个数据库表的数据库表
  3. HubSpot company数据在UI上的展示和通过API方式进行获取
  4. SAP Fiori 修改catalog group名称的技术实现
  5. automatic asynchronous creation if no note exists
  6. Appointment get entity debug
  7. why we need a undefined parameter in function signature
  8. How is navigation target url request handled by backend
  9. 打印某个user在指定时间段内做过的personalization detail
  10. Cloud for Customer里的Shell menu manager