Java入門學(xué)習(xí)之環(huán)境變量與程序運(yùn)行原理詳解
前言
我在剛剛學(xué)習(xí)JAVA時只是抱著高中時期的:”跟著老師走,我就能理解一切“的心態(tài),按部就班按著老師所講的去學(xué)習(xí),并非沒用,但也不能算很有用,學(xué)校的老師講課會顧及難度,不會向我們?nèi)ソ虒?dǎo)一些更深層次的東西,當(dāng)我去問老師時,老師給的回答往往是讓我去網(wǎng)絡(luò)里尋求答案,對啊,現(xiàn)在是互聯(lián)網(wǎng)的時代,AI遍布我們的生活各處,技術(shù)文檔由眾多大佬分享,于是我對于一些當(dāng)時不是很理解的地方做了我自認(rèn)為的“淺層深挖”,目的是為了幫助我更加去理解原理,而不是只是迷迷糊糊的做一個打代碼工具。
一.為什么我們要去配置環(huán)境變量?
在我剛剛接觸JAVA的時候,老師課上交給我們的第一個任務(wù),便是"配置環(huán)境變量",這對于還是萌新的我而言十分的困難,反復(fù)的配置失敗以及一次次嘗試讓我不由得想:“為什么我們要配置JAVA的環(huán)境變量呢?”

如圖中,我在沒有配置環(huán)境變量之前嘗試在我的E:\train_code下去執(zhí)行命令:
javac HelloWord.java ,結(jié)果彈出提示:“javac不是內(nèi)部或外部命令,也不是可執(zhí)行程序”。
為什么呢?為什么會出現(xiàn)“javac不是內(nèi)部或外部命令”這個錯誤呢?我明明已經(jīng)安裝了JAVA!
原來在未配置環(huán)境變量時,系統(tǒng)無法在任意路徑下找到javac.exe,因?yàn)橄到y(tǒng)默認(rèn)只在當(dāng)前目錄和PATH環(huán)境變量指定的路徑中搜索可執(zhí)行文件。在環(huán)境變量沒被配置時,系統(tǒng)根本不知道javac.exe到底在哪里。
javac.exe通常藏在 C:\Program Files\Java\你的jdk版本名稱\bin 里面

而我如果需要運(yùn)行我的.java程序,我需要JDK(Java Development Kit - JAVA開發(fā)工具包)中bin目錄下的javac.exe來對.java程序進(jìn)行“編譯”,那么我想你應(yīng)該有一些理解了,之所以要配置環(huán)境變量,是為了使得我們的這個.java程序無論位于我們電腦的哪個盤符(C: / D: / E:........)下的哪個文件下,都可以通過javac.exe來進(jìn)行對.java程序的“編譯”。

環(huán)境變量PATH的配置,配置PATH后,無論當(dāng)前目錄在哪里,系統(tǒng)都會在C:\Program Files\Java\jdk-xx\bin中搜索javac.exe,可以理解為就是將我所配置的這個路徑當(dāng)作一個環(huán)境,我執(zhí)行哪個文件都相當(dāng)于是我在這個環(huán)境下去執(zhí)行的,當(dāng)然也就能使用這個環(huán)境內(nèi)的工具了,所以我們并不是不配置環(huán)境變量就無法運(yùn)行JAVA項(xiàng)目,配置環(huán)境變量后,我們就可以在任意目錄下編譯和運(yùn)行Java程序,無需每次切換到JDK的bin目錄。
二.“編譯”是什么過程?JAVA程序又是怎么樣去執(zhí)行的呢?
在“一”里面我們提到了一個詞,叫做“編譯”,這個詞本身我們是沒少聽的,我們常說編譯器,編譯器,難道編譯的作用就是把程序在我們的計算機(jī)運(yùn)行嗎?事實(shí)上,編譯只是我們程序運(yùn)行這個大過程中的一個小過程,舉個例子,比如運(yùn)行C語言程序,我們并不是只依靠編譯去運(yùn)行這個程序,而是先通過編譯將開發(fā)者寫出的這些由英文字母組成的代碼,轉(zhuǎn)換為機(jī)器所能看懂的二進(jìn)制的機(jī)器碼,然后再由機(jī)器去執(zhí)行這個二進(jìn)制的機(jī)器碼,但是JAVA呢?JAVA也是這樣嗎?
實(shí)則不然,JAVA程序的運(yùn)行過程要更多一點(diǎn),因?yàn)镴ava擁有一個優(yōu)勢:那就是JAVA可以實(shí)現(xiàn)跨平臺,通常稱之為“一次編寫,到處運(yùn)行”(Write Once, Run Anywhere, WORA)。
1.為什么JAVA可以實(shí)現(xiàn)跨平臺而C/C++不行呢?
C/C++都是直接由對應(yīng)操作系統(tǒng)的編譯器來編譯為.exe的可執(zhí)行文件,之后直接運(yùn)行的,他們所生成的這個.exe里面都是針對特定平臺的機(jī)器碼,所以C/C++并不能夠?qū)崿F(xiàn)跨平臺運(yùn)行,Windows的.exe就是Windows的,Linux的就是Linux的。
2.JAVA的運(yùn)行過程較為特殊,JAVA的運(yùn)行過程為:
首先,開發(fā)者寫出一份.JAVA程序,拿給環(huán)境變量里的JDK說:“我這里有個JAVA程序,請你幫我運(yùn)行他。”,然后JDK中的javac.exe就會把你給他的JAVA程序編譯為一份.CLASS的字節(jié)碼文件(.class文件就是JAVA實(shí)現(xiàn)跨平臺的關(guān)鍵),并且對你說:“這個你得等我會兒,我這里呢得先處理下你的程序,然后交給統(tǒng)一部門對你這個程序做更細(xì)化的處理。”
然后,這個.CLASS文件會被交給JVM,JVM類似每個手機(jī)廠商分布在各個城市的手機(jī)專賣店,雖然門店服務(wù)的地區(qū)不同,但是門店都是這個手機(jī)廠商旗下的,也就是說雖然不同操作系統(tǒng)下的JVM是不同的,但他們都有一個相同的“接口”來使得他們能以不同的JVM實(shí)現(xiàn)來達(dá)成同一個功能:那個功能就是他們都能夠?qū)⑦@個.CLASS文件進(jìn)行動態(tài)解釋或者編譯執(zhí)行
關(guān)于JAVA與C/C++的運(yùn)行過程(更清晰的展示):
C/C++:源碼 → 編譯為平臺特定的機(jī)器碼 → 直接運(yùn)行。
Java:源碼 → 編譯為平臺無關(guān)的字節(jié)碼 → JVM解釋/編譯執(zhí)行。
字節(jié)碼文件的核心作用:
跨平臺(平臺無關(guān)性):一次編譯,JVM運(yùn)行(Windows/Linux/Mac通用)。
安全可控:JVM檢查代碼,防止崩潰或病毒。
統(tǒng)一生態(tài):Java/Kotlin等語言最終都變成字節(jié)碼,互相兼容。
高效執(zhí)行:JIT編譯熱點(diǎn)代碼,速度接近C++。
一句話總結(jié):字節(jié)碼是Java跨平臺的“通用語言”,由JVM翻譯執(zhí)行,兼顧安全性和性能。
三.JAVA最基礎(chǔ)的程序代碼
public class Main {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}我所打的第一個JAVA程序,便是這個“Hellow,World!”,我一開始就對這個神奇的東西很不理解,這個String[] args是個什么玩意?main前面這一大串又是啥啊?
關(guān)于main
main方法是一個特殊的方法,它定義了JAVA程序的起始位置。如果沒有這個方法,JVM就無法啟動程序。如圖,可以看到,如果一個程序中沒有main方法,那么這個程序甚至無法運(yùn)行。
注意,這里說無法運(yùn)行并發(fā)完全無法運(yùn)行:
Java 9+支持模塊化啟動,可通過
jlink定制啟動類。但初學(xué)者場景下,main仍是標(biāo)準(zhǔn)入口。

關(guān)于String[] args
main方法不只是一個簡單的入口,他里面?zhèn)魅氲膮?shù),也就是:String[] args參數(shù)(事實(shí)上,String[] args作為一個參數(shù),參數(shù)名并不強(qiáng)行要求為args,你甚至可以把它改成aaas),但要注意:
雖然args可以改名,但約定俗成用
args,提高代碼可讀性。其他常見命名如
argv(來自C傳統(tǒng))。
程序可以通過這個參數(shù)來處理用戶輸入的動態(tài)數(shù)據(jù),String[] args中存儲了當(dāng)該程序在終端或者命令提示符中運(yùn)行JAVA程序時,人為通過命令添加的額外參數(shù),比如我在終端中執(zhí)行:
java 類名 參數(shù)1 參數(shù)2 ...
那么這個時候,arg[0] = "參數(shù)一",而arg[1] = "參數(shù)二",讓我們來驗(yàn)證一下吧:
public class MyProgram {
public static void main(String[] args) {
// 獲取參數(shù)數(shù)組的長度
int numArgs = args.length;
System.out.println("命令行參數(shù)數(shù)量: " + numArgs);
// 遍歷并打印每個參數(shù)
for (int i = 0; i < numArgs; i++) {
System.out.println("args[" + i + "] = " + args[i]);
}
}
}我們在終端執(zhí)行 java MyProgram "hellow world" 123 ,我們運(yùn)行程序會輸出:
命令行參數(shù)數(shù)量: 2 args[0] = hello world args[1] = 123
關(guān)于System.out.println()
當(dāng)我寫出代碼時,我看著我打印出來的Hellow,World!陷入了一個思考,為什么這個名為System.out.println的東西能夠?qū)⑺竺胬ㄌ杻?nèi)的內(nèi)容打印出來呢?

這里面,System是JDK提供的工具類,out是其靜態(tài)字段(類型為PrintStream),println是PrintStream的方法。這些代碼是Java標(biāo)準(zhǔn)庫的一部分,初期只需知道它是輸出語句,后期可深入研究IO流和標(biāo)準(zhǔn)輸出的設(shè)計.
當(dāng)我們的鼠標(biāo)按住“Ctrl”鍵的同時將鼠標(biāo)指針移到這三個單詞的任意一個上面時,他會被高亮,這個時候我們點(diǎn)進(jìn)去,你就會發(fā)現(xiàn):

它跳轉(zhuǎn)到了一個我們不知道的地方,這里就是JDK的源代碼,我們的這個語句就是在這里被定義的,所以本質(zhì)上我們只是將大佬們定義好的方法拿過來去使用。
個人想說的話:
到此這篇關(guān)于Java入門學(xué)習(xí)之環(huán)境變量與程序運(yùn)行原理的文章就介紹到這了,更多相關(guān)Java環(huán)境變量與程序運(yùn)行原理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java arrayList遍歷的四種方法及Java中ArrayList類的用法
arraylist是動態(tài)數(shù)組,它具有三個好處分別是:動態(tài)的增加和減少元素 、實(shí)現(xiàn)了ICollection和IList接口、靈活的設(shè)置數(shù)組的大小,本文給大家介紹java arraylist遍歷及Java arraylist 用法,感興趣的朋友一起學(xué)習(xí)吧2015-11-11
spring?bean標(biāo)簽中的init-method和destroy-method詳解
這篇文章主要介紹了spring?bean標(biāo)簽中的init-method和destroy-method,在很多項(xiàng)目中,經(jīng)常在xml配置文件中看到init-method 或者 destroy-method ,因此整理收集下,方便以后參考和學(xué)習(xí),需要的朋友可以參考下2023-04-04
IDEA中Javaweb項(xiàng)目圖片加載不出來解決方案
在IDEA中能夠正常的預(yù)覽到圖片,但是在生成項(xiàng)目的war包時,項(xiàng)目的目錄結(jié)構(gòu)卻會發(fā)生變化,所以無法訪問圖片,本文主要介紹了IDEA中Javaweb項(xiàng)目圖片加載不出來解決方案,感興趣的可以了解一下2023-10-10
springmvc后臺基于@ModelAttribute獲取表單提交的數(shù)據(jù)
這篇文章主要介紹了springmvc后臺基于@ModelAttribute獲取表單提交的數(shù)據(jù),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-10-10
解決spring cloud zuul與nginx的域名轉(zhuǎn)發(fā)問題
這篇文章主要介紹了spring cloud zuul與nginx的域名轉(zhuǎn)發(fā)問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-07-07

