Java虛擬機(JVM)是可運行Java代碼的假想計算機。
只要根據JVM規格描述將解釋器移植到特定的計算機上,就能保證經過編譯的任何Java代碼能夠在該系統上運行。
本文首先簡要介紹從Java文件的編譯到最終執行的過程,隨後對JVM規格描述作一說明。
一.Java源文件的編譯、下載、解釋和執行
Java應用程序的開發周期包括編譯、下載、解釋和執行幾個部分。
Java編譯程序將Java源程序翻譯為JVM可執行代碼?位元組碼。
這一編譯過程同C/C++的編譯有些不同。
當C編譯器編譯生成一個對象的代碼時,該代碼是為在某一特定硬體平台運行而產生的。
因此,在編譯過程中,編譯程序通過查表將所有對符號的引用轉換為特定的內存偏移量,以保證程序運行。
Java編譯器卻不將對變數和方法的引用編譯為數值引用,也不確定程序執行過程中的內存布局,而是將這些符號引用信息保留在位元組碼中,由解釋器在運行過程中創立內存布局,然後再通過查表來確定一個方法所在的地址。
這樣就有效的保證了Java的可移植性和安全性。
運行JVM位元組碼的工作是由解釋器來完成的。
解釋執行過程分三部進行:代碼的裝入、代碼的校驗和代碼的執行。
裝入代碼的工作由"類裝載器"(classloader)完成。
類裝載器負責裝入運行一個程序需要的所有代碼,這也包括程序代碼中的類所繼承的類和被其調用的類。
當類裝載器裝入一個類時,該類被放在自己的名字空間中。
除了通過符號引用自己名字空間以外的類,類之間沒有其他辦法可以影響其他類。
在本台計算機上的所有類都在同一地址空間內,而所有從外部引進的類,都有一個自己獨立的名字空間。
這使得本地類通過共享相同的名字空間獲得較高的運行效率,同時又保證它們與從外部引進的類不會相互影響。
當裝入了運行程序需要的所有類後,解釋器便可確定整個可執行程序的內存布局。
解釋器為符號引用同特定的地址空間建立對應關系及查詢表。
通過在這一階段確定代碼的內存布局,Java很好地解決了由超類改變而使子類崩潰的問題,同時也防止了代碼對地址的非法訪問。
隨後,被裝入的代碼由位元組碼校驗器進行檢查。
校驗器可發現操作數棧溢出,非法數據類型轉化等多種錯誤。
通過校驗後,代碼便開始執行了。
Java位元組碼的執行有兩種方式:
1.即時編譯方式:解釋器先將位元組碼編譯成機器碼,然後再執行該機器碼。
2.解釋執行方式:解釋器通過每次解釋並執行一小段代碼來完成Java位元組碼程序的所有操作。
通常採用的是第二種方法。
由於JVM規格描述具有足夠的靈活性,這使得將位元組碼翻譯為機器代碼的工作
具有較高的效率。
對於那些對運行速度要求較高的應用程序,解釋器可將Java位元組碼即時編譯為機器碼,從而很好地保證了Java代碼的可移植性和高性能。
二.JVM規格描述
JVM的設計目標是提供一個基於抽象規格描述的計算機模型,為解釋程序開發人員提很好的靈活性,同時也確保Java代碼可在符合該規范的任何系統上運行。
JVM對其實現的某些方面給出了具體的定義,特別是對Java可執行代碼,即位元組碼(Bytecode)的格式給出了明確的規格。
這一規格包括操作碼和操作數的語法和數值、標識符的數值表示方式、以及Java類文件中的Java對象、常量緩沖池在JVM的存儲映象。
這些定義為JVM解釋器開發人員提供了所需的信息和開發環境。
Java的設計者希望給開發人員以隨心所欲使用Java的自由。
JVM定義了控制Java代碼解釋執行和具體實現的五種規格,它們是:
JVM指令系統
JVM寄存器
JVM棧結構
JVM碎片回收堆
JVM存儲區
2.1JVM指令系統
JVM指令系統同其他計算機的指令系統極其相似。
Java指令也是由操作碼和操作數兩部分組成。
操作碼為8位二進制數,操作數進緊隨在操作碼的後面,其長度根據需要而不同。
操作碼用於指定一條指令操作的性質(在這里我們採用匯編符號的形式進行說明),如iload表示從存儲器中裝入一個整數,anewarray表示為一個新數組分配空間,iand表示兩個整數的"與",ret用於流程式控制制,表示從對某一方法的調用中返回。
當長度大於8位時,操作數被分為兩個以上位元組存放。
JVM採用了"bigendian"的編碼方式來處理這種情況,即高位bits存放在低位元組中。
這同Motorola及其他的RISCCPU採用的編碼方式是一致的,而與Intel採用的"littleendian"的編碼方式即低位bits存放在低位位元組的方法不同。
Java指令系統是以Java語言的實現為目的設計的,其中包含了用於調用方法和監視多先程系統的指令。
Java的8位操作碼的長度使得JVM最多有256種指令,目前已使用了160多種操作碼。
2.2JVM指令系統
所有的CPU均包含用於保存系統狀態和處理器所需信息的寄存器組。
如果虛擬機定義較多的寄存器,便可以從中得到更多的信息而不必對棧或內存進行訪問,這有利於提高運行速度。
然而,如果虛擬機中的寄存器比實際CPU的寄存器多,在實現虛擬機時就會佔用處理器大量的時間來用常規存儲器模擬寄存器,這反而會降低虛擬機的效率。
針對這種情況,JVM只設置了4個最為常用的寄存器。
它們是:
pc程序計數器
optop操作數棧頂指針
frame當前執行環境指針
vars指向當前執行環境中第一個局部變數的指針
所有寄存器均為32位。
pc用於記錄程序的執行。
optop,frame和vars用於記錄指向Java棧區的指針。
2.3JVM棧結構
作為基於棧結構的計算機,Java棧是JVM存儲信息的主要方法。
當JVM得到一個Java位元組碼應用程序後,便為該代碼中一個類的每一個方法創建一個棧框架,以保存該方法的狀態信息。
每個棧框架包括以下三類信息:
局部變數
執行環境
操作數棧
局部變數用於存儲一個類的方法中所用到的局部變數。
vars寄存器指向該變數表中的第一個局部變數。
執行環境用於保存解釋器對Java位元組碼進行解釋過程中所需的信息。
它們是:上次調用的方法、局部變數指針和操作數棧的棧頂和棧底指針。
執行環境是一個執行一個方法的控制中心。
例如:如果解釋器要執行iadd(整數加法),首先要從frame寄存器中找到當前執行環境,而後便從執行環境中找到操作數棧,從棧頂彈出兩個整數進行加法運算,最後將結果壓入棧頂。
操作數棧用於存儲運算所需操作數及運算的結果。
2.4JVM碎片回收堆
Java類的實例所需的存儲空間是在堆上分配的。
解釋器具體承擔為類實例分配空間的工作。
解釋器在為一個實例分配完存儲空間後,便開始記錄對該實例所佔用的內存區域的使用。
一旦對象使用完畢,便將其回收到堆中。
在Java語言中,除了new語句外沒有其他方法為一對象申請和釋放內存。
對內存進行釋放和回收的工作是由Java運行系統承擔的。
這允許Java運行系統的設計者自己決定碎片回收的方法。
在SUN公司開發的Java解釋器和HotJava環境中,碎片回收用後台線程的方式來執行。
這不但為運行系統提供了良好的性能,而且使程序設計人員擺脫了自己控制內存使用的風險。
2.5JVM存儲區
JVM有兩類存儲區:常量緩沖池和方法區。
常量緩沖池用於存儲類名稱、方法和欄位名稱以及串常量。
方法區則用於存儲Java方法的位元組碼。
對於這兩種存儲區域具體實現方式在JVM規格中沒有明確規定。
這使得Java應用程序的存儲布局必須在運行過程中確定,依賴於具體平台的實現方式。
JVM是為Java位元組碼定義的一種獨立於具體平台的規格描述,是Java平 *** 立性的基礎。
目前的JVM還存在一些限制和不足,有待於進一步的完善,但無論如何,JVM的思想是成功的。
對比分析:如果把Java原程序想像成我們的C++原程序,Java原程序編譯後生成的位元組碼就相當於C++原程序編譯後的80x86的機器碼(二進製程序文件),JVM虛擬機相當於80x86計算機系統,Java解釋器相當於80x86CPU。
在80x86CPU上運行的是機器碼,在Java解釋器上運行的是Java位元組碼。
Java解釋器相當於運行Java位元組碼的「CPU」,但該「CPU」不是通過硬體實現的,而是用軟體實現的。
Java解釋器實際上就是特定的平台下的一個應用程序。
只要實現了特定平台下的解釋器程序,Java位元組碼就能通過解釋器程序在該平台下運行,這是Java跨平台的根本。
當前,並不是在所有的平台下都有相應Java解釋器程序,這也是Java並不能在所有的平台下都能運行的原因,它只能在已實現了Java解釋器程序的平台下運行。
⑵ 如何在Windows上編譯java程序
1、執行cmd命令javac後,顯示如圖所示編譯成功,說明是java運行正常。
⑶ 如何用JDK編譯JAVA程序
JAVA版hello
world全攻略侯光敏
看到很多技術網站的BBS上面充斥著java初學者的關於運行第一個java程序的求助信息,我覺得作為過來人很有寫這篇文章的必要,因為他們遇到的都是些很低級的問題,但是讓這些問題占據bbs上那麼多寶貴的空間就太不應該了。
要搞清楚的基本概念
java是一種跨平台的網路語言,為了能夠在不同平台上運行,它使用了虛擬機這個概念。後綴名為java的文件是源代碼文件,它經過編譯後生成的是class文件。虛擬機執行的就是這些class文件,將它們轉化成為不同平台能夠運行的命令。這就是為什麼java的效率比較低的原因。也是因為這個原因,在java里沒有其它語言的使用者熟悉的exe文件的概念。
執行hello
world的方法
切記:在命令行中輸入
javac
源文件名.java
(編譯)
java
源文件名
(執行,沒有後綴)
這里說的是java
application,裡麵包括main函數。
如果hello
world是applet版的,在命令行中輸入appletviewer
源文件名
(已經編譯後的class文件)
如果class文件已經嵌入了html網頁中,直接用IE打開就行了。
application經常出現的錯誤
系統提示Exception
in
thread
"main
"
java.lang.NoClassDefFoundError。出現這個提示的原因可能有:
1
你把文件名拼錯了,java對大小寫是敏感的。打錯了當然找不到文件。
2
虛擬機沒有找到必須的類庫。你可能沒有在autoexec.bat文件中設置classpath。進入windows的運行,輸入sysedit,然後在autoexec.bat文件中加入這么一行:set
classpath=你的jdk的安裝目錄/lib;
例如set
classpath=c:/jdk1.3.0_02/lib;
保存退出後,你要在dos窗口的c根目錄下執行一遍autoexec.bat文件已保證被設置了,當然,如果你願意也可以重啟機器。
系統提示HelloWorld.java:1:
Public
class
helloworld
must
be
defined
in
a
file
called
"HelloWorld.java
".
public
class
helloworld{^
一個Java源程序中可以定義多個類,但是,具有public
屬性的類只能有一個,而且要與文件名相一致。還有,main方法一定要放在這個public
的類之中,這樣才能運行這個類。
系統提示Exception
in
thread
"main
"
java.lang.NoSuchMethodError:
main
出現這個異常是因為你在抄書上的代碼時抄錯了。主函數一定要這么寫:public
static
void
main(String
args[])
一個字都不能錯,切記!!!
applet常出現的錯誤
IE顯示applet已經啟動,但是還是只顯示灰色的一塊。這種問題在使用jBuilder等集成開發工具是最容易出現,用appletviewer就沒有問題。這是因為你在applet中使用了IE不支持的java版本。jBuilder在做applet是默認使用了swing組件,但是IE只支持jdk1.1,所以造成了這種情況。只要把導入swing的語句去掉就行了,然後按照提示修改一下代碼,不要用swing組件的方法。如果你覺得swing組件很漂亮,打死都要用,那麼就裝一個java的plug-in這個東西在你裝jdk的高版本時就自動裝上了。看看你的控制面版中有沒有那個紅鼻子的小東西。但是切記,如果你要用它,那麼你的html的文件的寫法就和從前不一樣了,不能簡單的用CODE來指明類了。至於怎麼寫,不在這篇文章的討論范圍內了(你寫一個hello
world還要用plug-in就搞大了)。網上有很多文章講怎麼寫。
用慣了點擊就執行的的exe文件自然就很不習慣打開dos窗口輸入命令行,你可以把它做成jar文件,但是對hello
world來說有點麻煩,有個簡單的傻辦法:自己做一個批處理文件。例如:用記事本寫一個run.txt文件,內容是:java
你的主文件名
,然後把後綴改成bat存到和主文件相同的目錄下。呵呵,雙擊就運行了,夠傻吧。
如果你非要用exe文件運行,jet等工具可以把class文件做成exe文件。但是這樣也失去了java的跨平台性。
以上就是hello
world的全攻略了,如果你還看不到hello
world,我倒!你還是別學java了。
⑷ 編譯java程序的命令是
javac是Java的編譯盯櫻命令,能將源代碼編譯成位元組碼,以。class擴展名存入Java工作目錄中。Java是Java解釋器,執行位元組碼程序,該程序是類名所指的類,必須是一個完整定義的名字。javadoc是Java文檔生成器,對Java源文件和包以XML格式生成API文檔。appletviewer是Java Applet瀏覽器。
Java是一種稿察編程語言,被特意設計用於互聯網的分布式環境。Java具有類似於C++語言的「形式和感覺」,但它要比C++語言更易於使用,而且在編程時徹底採用了凱敬叢一種「以對象為導向」的方式。
使用Java編寫的應用程序,既可以在一台單獨的電腦上運行,也可以被分布在一個網路的伺服器端和客戶端運行。另外,Java還可以被用來編寫容量很小的應用程序模塊或者applet,做為網頁的一部分使用。applet可使網頁使用者和網頁之間進行互動式操作。
⑸ 如何編譯java
用命令提示符編譯java程序的步驟:
1.先新建文本文檔,輸入自己的java程序。
這里我寫一個簡單的java程序,來做示範。
import java.util.*;
public class HelloDate{
public static void main(String[] args)
{
System.out.println("Hello,it's:");
System.out.println(new Date());
}
}
經驗總結:運行一個java程序的大概的流程是:
書寫源代碼------>編譯------->運行---->結束。
注意事項:
1.在輸入的時候一定要注意區分大小寫。
2.操作之前要保證自己的電腦配置了java的運行環境。
⑹ 如何編寫你的第一個Java程序 3種方法來編寫你的第一個Java程序
目錄方法1:編寫你的第一個Java程序1、要開始用Java編寫程序,先設置你的工作環境。2、任何一種類似記事本的程序都能夠用於Java編程。3、確保安裝了Java軟體開發工具包方法2:Hello World 程序1、我們將首先創建一個能列印"Hello World"的程序。2、聲明類和main方法。3、編寫將列印出"Hello World"的代碼行。4、把這些都放在一起。5、保存文件,並打開命令提示符或終端來編譯程序。6、運行程序。7、恭喜,你方法3:輸入和輸出1、我們現在將擴展我們的Hello World程序,以接受用戶的輸入。2、導入Scanner(掃描儀,由於編程時使用Scanner,故下文用Scanner)類。3、在main方法中,創建Scanner對象的一個新實例(instance)。4、提示用戶輸入。5、要求Scanner對象接受用戶鍵入的下一行,並將其存儲在變數中。6、向用戶顯示問候語。7、一起保存以上代碼。8、編譯並運行。Java是James Gosling於1995年創建的一種面向對象的編程語言,它用「欄位」(fields,描述對象的屬性),和「方法」(methods,對象可以執行的操作),將概念表示為「對象」(objects)。Java是一種「編寫一次,就可以在任何地方運行」的編程語言,可以在任何裝有Java虛擬機(JVM)的平台上運行。由於Java是一種用上大量英文單詞的編程語言,母語為英語的初學者很容易學習和理解,非英語母語者只要下一番苦功也能很快上手。本教程介紹如何用Java編寫程序。
方法1:編寫你的第一個Java程序
1、要開始用Java編寫程序,先設置你的工作環境。許多程序員使用集成開發環境(Integrated Development Environment,IDE)進行Java編程,比如Eclipse和NetBeans。但是不必使用臃腫的IDE,也可以編寫Java程序並編譯它。
2、任何一種類似記事本的程序都能夠用於Java編程。高級程序員有時更喜歡使用終端內的文本編輯器,如Vim和Emacs。我們推薦一個可以安裝在基於Windows和Linux系統(Mac、Ubuntu等)的文本編輯器:SublimeText。我們將在本教程中使用它。
3、確保安裝了Java軟體開發工具包。你要用它來編譯程序。在基於Windows的操作系統中,如果環境變數不正確,則可能在運行javac時出錯。有關JDK安裝的詳細信息,可以參閱如何安裝Java軟體開發工具包,以避免此錯誤。
方法2:Hello World 程序
1、我們將首先創建一個能列印"Hello World"的程序。在文本編輯器中,創建一個新文件,並將其另存為"HelloWorld.java"。HelloWorld是類名,你需要讓類名與文件同名。
2、聲明類和main方法。main方法 public static void main(String[] args)是程序運行時執行的方法。這個main方法在每個Java程序中都以相同方式調用。
public class HelloWorld { public static void main(String[] args) { }}
3、編寫將列印出"Hello World"的代碼行。
System.out.println("Hello World.");讓我們看看這一行的組成成分:System 告訴系統執行某些操作。
out 告訴系統我們要輸出一些內容。
println ?代表"列印行(print line)",我們用它告訴系統在輸出中列印一行文字。
("Hello World.") 周圍的圓括弧表示方法 System.out.println()接受一個參數。在本例中,該參數是字元串"Hello World."
注意,Java中有一些我們必須遵守的規則:必須始終在每行末尾添加分號。
Java區分大小寫,因此必須以正確的大小寫寫入方法名、變數名和類名,否則將出現錯誤。
某個方法或循環的特定代碼塊包含在花括弧中。
4、把這些都放在一起。最後Hello World程序應如下所示:
public class HelloWorld { public static void main(String[] args) {System.out.println("Hello World."); }}
5、保存文件,並打開命令提示符或終端來編譯程序。打開保存HelloWorld.java的文件夾,並鍵入javac HelloWorld.java。這告訴Java編譯器你想要編譯HelloWorld.java。如果有錯誤,編譯器會告訴你做錯了什麼。否則,你不應該看到來自編譯器的任何消息。如果現在查看helloworld.java所在的目錄,應該會看到helloworld.class。這是Java用來運行程序的文件。
6、運行程序。我們終於可以運行我們的程序了! 在命令提示符或終端中,鍵入java HelloWorld。這是在告訴Java你想運行HelloWorld類。你應該看到控制台出現 "Hello World"。
7、恭喜,你完成了第一個Java程序!
方法3:輸入和輸出
1、我們現在將擴展我們的Hello World程序,以接受用戶的輸入。在我們的Hello World程序中,我們列印出一個字元串供用戶查看,但是只有當程序能夠接收用戶輸入信息,才能稱之為程序的交互功能。我們現在將擴展程序,提示用戶輸入他或她的名字,然後用名字問候用戶。
2、導入Scanner(掃描儀,由於編程時使用Scanner,故下文用Scanner)類。在Java中,我們有一些可以訪問的內置庫,但是我們必須導入它們。其中一個庫是java.util,它包含我們獲取用戶輸入所需的Scanner對象。為了導入Scanner類,我們在代碼的開頭添加了以下行。
import java.util.Scanner;這告訴程序我們想使用java.util包中的Scanner對象。
如果希望訪問java.util包中的每個對象,只需在代碼的開頭編寫import java.util.*; 即可。
3、在main方法中,創建Scanner對象的一個新實例(instance)。Java是一種面向對象的編程語言,因此它使用對象來表示概念。Scanner對象是含有欄位和方法的對象。為了使用Scanner類,我們必須創建一個新的Scanner對象、它可以填充的欄位和使用的方法。示例如下:
Scanner userInputScanner = new Scanner(System.in);userInputScanner是剛剛創建的Scanner對象實例的名稱。注意名稱是用駱駝體(每個單詞首字母大寫)寫的,這是Java中變數命名的規定。
我們使用 new 運算符創建對象的新實例。因此在本例中,我們通過 new Scanner(System.in),創建了Scanner對象的新實例。
Scanner對象接受一個參數,該參數告訴對象要掃描什麼。在本例中,我們輸入System.in 作為參數。System.in告訴程序掃描來自系統的輸入,這是用戶將在程序中鍵入的輸入。
4、提示用戶輸入。我們必須提示用戶輸入,以便用戶知道何時在控制台中鍵入內容。這可以通過System.out.print或System.out.println實現。
System.out.print("What's your name? ");
5、要求Scanner對象接受用戶鍵入的下一行,並將其存儲在變數中。Scanner將始終接收用戶鍵入的數據。下面的行將要求Scanner接受用戶鍵入的姓名,並將其存儲在變數中:
String userInputName = userInputScanner.nextLine();在Java中,使用對象方法的規定是objectName.methodName(parameters)。在userInputScanner.nextLine()中,我們使用剛才給出的名稱調用Scanner對象,然後調用它的方法nextLine() ,該方法不接受任何參數。
注意,接下來程序將把下一行存儲在一個"字元串"對象中。我們已將字元串對象命名為userInputName
6、向用戶顯示問候語。現在我們已經存儲了用戶名,我們可以列印一個問候語給用戶。還記得我們在main類中編寫的 System.out.println("Hello World."); 嗎? 我們剛剛編寫的所有代碼都應該放在這一行上面。現在我們可以修改這一行,如:
System.out.println("Hello " + userInputName + "!");我們把"hello"、用戶名和"!" 通過編寫 "Hello " + userInputName + "!" 連起來的方式,稱為字元串串聯。
這里我們有三個字元串:"Hello "、userInputName和"!"。Java中的字元串是不可更改的。因此,當我們連接這三個字元串時,我們實際上創建了一個包含問候語的新字元串。
然後將這個新字元串作為參數輸入System.out.println。
7、一起保存以上代碼。我們的代碼現在應該如下所示:
import java.util.Scanner;public class HelloWorld { public static void main(String[] args) {Scanner userInputScanner = new Scanner(System.in);System.out.print("What's your name? ");String userInputName = userInputScanner.nextLine();System.out.println("Hello " + userInputName + "!"); }}
8、編譯並運行。進入命令提示符或終端,並運行與我們在第一次迭代HelloWorld.java時運行的命令。我們必須首先編譯程序:javac helloworld.java。然後我們可以運行它:java HelloWorld。
小提示Java是一種面向對象的編程語言,建議你閱讀更多關於面向對象編程語言的基礎知識,非常有用。
面向對象編程有許多特徵。其中三個主要特徵是:封裝:限制訪問對象某些組件的能力。Java為欄位和方法提供私有(private)、受保護(protected)和公共(public)三種修飾符。
多態:對象可以轉換標識。在Java中,可以將一個對象轉換為另一個對象,以使用另一個對象的方法。
繼承:使用與當前對象位於同一層次結構中的另一個類的欄位和方法的能力。
⑺ 編譯Java程序的命令是:
javac {Java的類名}
如果Java類不在當前目錄下的話,類名前面還需要有類所在的路徑。
⑻ 如何編譯java程序
三種方法:
1.在IDE中,如eclipse中寫的Java程序,在點擊保存後eclipse就會調用javac編譯程序編譯,編譯文件在當前項目的bin目錄下。
2.作為一個獨立的文件且沒有定義Java環境變數,需要在cmd窗口中切換到java bin目錄下執行Javac程序,執行格式為javac 空格 Java源文件;如 javac C://hello.java;
3.作為一個獨立的文件且定義了Java環境變數,打開cmd窗口,可以在任意目錄輸入javac java源文件,如javac D://hi.java。
Java也是一種高級語言,要讓計算機執行你撰寫的Java程序,也得通過編譯程序的編譯。但是Java編譯程序並不直接將Java源代碼編譯為相依於計算機平台的0、1序列,而是將其編譯為位元組碼。
Java源代碼的擴展名為.java,經過編譯程序編譯之後生成擴展名為.class的位元組碼。