classpath*: 和classpath:有什么区别_我们可以从Java“HelloWorld”中学到什么?
這是每個(gè)Java程序員都知道的程序。它很簡(jiǎn)單,但是簡(jiǎn)單的開(kāi)始可以導(dǎo)致對(duì)更復(fù)雜概念的深入理解。在這篇文章中,我將探討從這個(gè)簡(jiǎn)單的程序中學(xué)到什么。
公共 類(lèi) HelloWorld {
/ **
* @參數(shù)參數(shù)
* /
public static void main (String [ ] args ) {
// TODO自動(dòng)生成的方法存根
System。出來(lái)。println (“ Hello World” );
} }
1.為什么一切都從一堂課開(kāi)始?
Java程序是從類(lèi)構(gòu)建的,每個(gè)方法和字段都必須在一個(gè)類(lèi)中。這是由于它具有面向?qū)ο蟮墓δ?#xff1a;一切都是一個(gè)對(duì)象,它是一個(gè)類(lèi)的實(shí)例。相對(duì)于功能性編程語(yǔ)言,面向?qū)ο蟮木幊陶Z(yǔ)言具有很多優(yōu)勢(shì),例如更好的模塊化,可擴(kuò)展性等。
2.為什么總是有“主要”方法?
“ main”方法是程序入口,它是靜態(tài)的?!办o態(tài)”表示該方法是其類(lèi)的一部分,而不是對(duì)象的一部分。
這是為什么?我們?yōu)槭裁床粚⒎庆o態(tài)方法作為程序入口?
如果方法不是靜態(tài)的,則需要先創(chuàng)建一個(gè)對(duì)象才能使用該方法。因?yàn)楸仨氃趯?duì)象上調(diào)用該方法。為了進(jìn)入目的,這是不現(xiàn)實(shí)的。沒(méi)有雞肉,我們就無(wú)法獲得雞蛋。因此,程序進(jìn)入方法是靜態(tài)的。
參數(shù)“ String [] args”指示可以將字符串?dāng)?shù)組發(fā)送到程序以幫助程序初始化。
3. HelloWorld的字節(jié)碼
為了執(zhí)行該程序,首先將Java文件編譯為存儲(chǔ)在.class文件中的Java字節(jié)碼。字節(jié)碼是什么樣的?字節(jié)碼本身不可讀。如果我們使用十六進(jìn)制編輯器,則如下所示:
我們可以在上面的字節(jié)碼中看到很多操作碼(例如CA,4C等),每個(gè)操作碼都有一個(gè)對(duì)應(yīng)的助記碼(例如,在下面的示例中為aload_0)。操作碼不可讀,但是我們可以使用javap來(lái)查看.class文件的助記符形式。
“ javap -c”打印出該類(lèi)中每個(gè)方法的反匯編代碼。反匯編代碼表示組成Java字節(jié)碼的指令。
javap -classpath。-c HelloWorld
從“ HelloWorld.java”編譯而成的公共 類(lèi) HelloWorld 擴(kuò)展了 Java。郎。對(duì)象{ public HelloWorld ();
代碼:
0 : aload_0
1 : 調(diào)用特殊#1 ; //方法java / lang / Object?!?<init>” :()V
4 : 返回
公共 靜態(tài) 無(wú)效主( java中。郎。字符串[ ] );
代碼:
0 : 靜態(tài)#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 }
上面的代碼包含兩種方法:一種是默認(rèn)的構(gòu)造函數(shù),由編譯器推斷出來(lái);另一種是默認(rèn)的構(gòu)造函數(shù)。另一種是主要方法。
在每種方法之下,都有一系列指令,例如aload_0,invokespecial#1等??梢栽贘ava字節(jié)碼指令列表中查找每個(gè)指令的作用。例如,aload_0將局部變量0的引用加載到堆棧上,getstatic獲取類(lèi)的靜態(tài)字段值。請(qǐng)注意,在getstatic指令指向運(yùn)行時(shí)常量池之后,將顯示“#2”。常量池是JVM運(yùn)行時(shí)數(shù)據(jù)區(qū)域之一。這使我們看一下常量池,可以使用“ javap -verbose”命令來(lái)完成。
此外,每個(gè)指令都以數(shù)字開(kāi)頭,例如0、1、4等。在.class文件中,每個(gè)方法都有一個(gè)對(duì)應(yīng)的字節(jié)碼數(shù)組。這些數(shù)字對(duì)應(yīng)于存儲(chǔ)每個(gè)操作碼及其參數(shù)的數(shù)組的索引。每個(gè)操作碼的長(zhǎng)度為1個(gè)字節(jié),指令可以具有0個(gè)或多個(gè)參數(shù)。這就是為什么這些數(shù)字不連續(xù)的原因。
現(xiàn)在,我們可以使用“ javap -verbose”進(jìn)一步看一看該類(lèi)。
javap -classpath。詳細(xì)的HelloWorld
從“ HelloWorld.java”編譯而成的公共 類(lèi) HelloWorld 擴(kuò)展了 Java。郎。對(duì)象
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主函數(shù);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 = 類(lèi)別 #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
公共 靜態(tài) 無(wú)效主( 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規(guī)范開(kāi)始:運(yùn)行時(shí)常量池的功能類(lèi)似于常規(guī)編程語(yǔ)言的符號(hào)表,盡管它包含的數(shù)據(jù)范圍比典型的符號(hào)表還大。
“ invokespecial#1”指令中的“#1”指向常量池中的#1常量。該常量為“方法#6.#15;”。從數(shù)字中,我們可以遞歸獲得最終常數(shù)。
LineNumberTable向調(diào)試器提供信息,以指示Java源代碼的哪一行對(duì)應(yīng)于哪個(gè)字節(jié)代碼指令。例如,Java源代碼中的第9行對(duì)應(yīng)于main方法中的字節(jié)代碼0,而行10對(duì)應(yīng)于字節(jié)代碼8。
如果您想了解更多有關(guān)字節(jié)碼的信息,可以創(chuàng)建并編譯一個(gè)更復(fù)雜的類(lèi)以進(jìn)行查看。HelloWorld確實(shí)是這樣做的起點(diǎn)。
4.如何在JVM中執(zhí)行?
現(xiàn)在的問(wèn)題是,JVM如何加載類(lèi)并調(diào)用main方法?
在執(zhí)行main方法之前,JVM需要1)加載,2)鏈接和3)初始化類(lèi)。1)加載將類(lèi)/接口的二進(jìn)制形式帶入JVM。2)鏈接將二進(jìn)制類(lèi)型的數(shù)據(jù)合并到JVM的運(yùn)行時(shí)狀態(tài)中。鏈接包括3個(gè)步驟:驗(yàn)證,準(zhǔn)備和可選的解決方案。驗(yàn)證可確保類(lèi)/接口在結(jié)構(gòu)上正確;準(zhǔn)備工作涉及分配類(lèi)/接口所需的內(nèi)存;分辨率解析符號(hào)引用。最后3)初始化為類(lèi)變量分配了適當(dāng)?shù)某跏贾怠?/p>
此加載作業(yè)由Java類(lèi)加載器完成。啟動(dòng)JVM時(shí),將使用三個(gè)類(lèi)加載器:
1. Bootstrap類(lèi)加載器:加載位于以下位置的核心Java庫(kù): / jre / lib目錄。它是核心JVM的一部分,并用本機(jī)代碼編寫(xiě)。
2. 擴(kuò)展類(lèi)加載器:將代碼加載到擴(kuò)展目錄中(例如, / jar / lib / ext)。
3. 系統(tǒng)類(lèi)加載器:加載在CLASSPATH上找到的代碼。
因此,HelloWorld類(lèi)由系統(tǒng)類(lèi)加載器加載。當(dāng)main方法執(zhí)行時(shí),它將觸發(fā)其他依賴(lài)類(lèi)的加載,鏈接和初始化(如果存在)。
最后,將main()框架壓入JVM堆棧,并相應(yīng)地設(shè)置程序計(jì)數(shù)器(PC)。PC然后指示將println()幀推送到JVM堆棧。當(dāng)main()方法完成時(shí),它將從堆棧中彈出并執(zhí)行完畢。
最后,開(kāi)發(fā)這么多年我也總結(jié)了一套學(xué)習(xí)Java的資料與面試題,如果你在技術(shù)上面想提升自己的話(huà),可以關(guān)注我,私信發(fā)送領(lǐng)取資料或者在評(píng)論區(qū)留下自己的聯(lián)系方式,有時(shí)間記得幫我點(diǎn)下轉(zhuǎn)發(fā)讓跟多的人看到哦。
總結(jié)
以上是生活随笔為你收集整理的classpath*: 和classpath:有什么区别_我们可以从Java“HelloWorld”中学到什么?的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 现金价值以1000元为例怎么算,现金价值
- 下一篇: 市场监管总局:对锂离子电池等产品实施强制