Java基礎學習(一)---Java初識


一、Java介紹

關於Java的誕生和發展網上比較多,在此就不再贅述了,可以參考http://i.cnblogs.com/EditArticles.aspx?postid=4050233

1.1 Java的開發平台JDK

1.1.1 JDK 1.0----JRE+JDK

1995年,Sun雖然推出了Java,但這只是一種語言,如果想開發復雜的應用程序,必須要有一個強大的開發類庫。因此,Sun在1996年初發布了JDK 1.0。這是Sun公司發布的第一版JDK,這個版本包括兩部分:

  JRE 運行環境Java Runtime Environment):包括核心API、集成API,用戶界面API、發布技術、Java虛擬機(JVM)。
  JDK
開發環境Java Development Kit):開發環境包括編譯Java程序的編譯器(即javac命令)。

1.1.2 JDK 1.1----+JIT

接着,Sun在1997年2月18日發布了JDK 1.1。JDK 1.1增加了JIT即時編譯編譯器。JIT和傳統的編譯器不同,傳統的編譯器是編譯一條,運行完后將其扔掉。而JIT會將經常用到的指令保存在內存中,當下次調用時就不需要重新編譯了,通過這種方式讓JDK在效率上有了較大提升。

1.1.3 JDK 1.2----jsp/serverlet+EJB+Java版本

1998年12月,Sun發布了Java歷史上最重要的JDK版本:JDK l.2。伴隨JDK l.2一同發布的還有jsp/servlet3EJB4(Enterprise JavaBean)等規范,並將Java分成了J2EE、J2SEJ2ME三個版本。
  J2EE 企業版
Java 2 Platform,Enterprise Edition):Java技術中應用最廣泛的部分,J2EE提供了企業應用開發相關的完整解決方案。
  J2SE 標准版
Java 2 Platform, Simple Edition):整個Java技術的核心和基礎,它是J2ME和J2EE編程的基礎。
  J2ME 微縮版
Java Platform,Micro Edition): 主要用於控制移動設備信息家電等有限存儲的設備。
這標志着Java已經吹響了向企業、桌面移動3個領域進軍的號角,標志着Java已經進入Java 2時代,這個時期也是Java飛速發展的時期。在Java 2中,Java發生了很多革命性的變化,而這些革命性的變化一直沿用到現在,對Java的發展形成了深遠的影響。直到今天,我們還經常看到J2EE、J2ME等名稱。
不僅如此,JDK 1.2還把它的API分成了三大類:

核心API:由Sun公司制定的基本的API,所有的Java平台都應該提供。這就是我們平常所說的Java核心類庫。

可選API:這是Sun為JDK提供的擴充API,這些API因平台的不同而不同。

特殊API:用於滿足特殊要求的API。如用於JCA相JCE的第三方加密類庫。

1.1.4 JDK 1.4

2002年2月,Sun發布了JDK歷史上最為成熟的版本:JDK l.4.此時由於Compaq、Fujitsu、SAS、Symbian、IBM等公司的參與,使JDK 1.4成為發展最快的一個JDK版本。到JDK l.4為止,我們已經可以使用Java實現大多數的應用了。
在此期間.Java語言在企業應用領域大放異彩,涌現出大量基於Java語言的開源框架StrutsWebWorkHibemateSpring等;大量企業應用服務器也開始涌現:WebLogic、WebSphere、JBoss等,這些都標志着Java語言進入了飛速發展時期。

1.1.4 JDK 1.5

2004年10月,Sun發布了萬眾期待的JDK 1.5,同時,Sun將JDK 1.5改名為Java SE 5.0。J2EE、J2ME也相應地改名Java EE和Java ME。JDK1.5增加了諸如泛型增強的for語句可變數量的形參注釋(Annotations)自動拆箱裝箱等功能;同時,也發布了新的企業級平台規范如通過注釋等新特性來簡化EJB的復雜性,並推出了EJB3.0規范。還推出了自己的MVC框架規范:JSF,JSF規范類似於ASP.NET的服務器端控件,通過它可以快速地構建復雜的JSP界面。

1.1.4 JDK 1.6

2006年l2月.Sun公司發布手JDK l.6(也被稱為Java SE 6)。一直以來,Sun公司維持着大約2年發布一次JDK新版本盼習慣。但在2009年4月20日,Oracle宣布將以每股9.5美元韻價格收購Sun。該交易的總價值約為74億美元。而Orack通過收購Sun公司獲得了兩項軟件資產Java和Solaris。於是曾經代表一個時代的公面:Sun終於被“雨打風吹’’去,“江湖”上再也沒有了Sun的身影。
Sun倒下了,不過Java的大旗依然“獵獵"作響。2007年11月,Google宣布推出一款基於Linux平台的開源手機操作系統:Android。Android的出現順應了即將出現的移動互聯網潮流,而且Android系統的用戶體驗非常好,因此迅速成為手機操作系統的中堅力量。

Ancfioid平台使用了Dalvik虛擬機來運行.dex文件。

Dalvik虛擬機的作用類似於JVM虛擬機,只是它並未遵守JVM規范而已。

Android使用Java語言來開發應用程序,這也給了Java語言一個新的機會。在過去的歲月中Java語言作為服務器端編程語言,已經取得了極大盼成勱;而Android平台的流行,則讓Java謠衰獲得了在客戶端程序上大展拳腳的機會。

1.1.4 JDK 1.7

2011年7月28,Oracle公司終於如約一發布了Java SE 7這次版本。升級經過了將近5年時間。Java SE 7也是Oracle發布的第一個Java版本。Javat.SE 7雖然並未完全滿足所存人的期望,不過它也加入了不少新特性。

1.2 Java的競爭對手及各自優勢

Java語言目前是最流行的面向對象編裎語言,與Java類似的程序設計語言還有C#、Ruby和Python等,它們在某些方面有自己的獨特優勢,因此都是Java語言有力的競爭者。

1.2.1 C#簡介和優勢

當年Microsoft也一度加入到Java語言陣營中,Microsoft曾經在Visual Studio中提供了Visual J++。正當Microsoft盡力在Visual J++基礎上拓展Java功能,並使之與Windows操作系統緊密結合在一起時.Sun公司對Nticrosoft提出法律訴訟,稱其違反了Java許可證協議中的條款,最終的結果是微軟公司不得不停止Visual J++-產品的開發。

1998年10月以來,Microsoft就不再發布新的Visual J++版本,而且導致Microsoft一直站在Java陣營的對立面,甚至在Windows XP系統中不再提供Java運行時環境的支持。接下來,Microson推出了.NET平台,並發布了C#語言,無論從哪個角度來看,C#程序設計語言都是Microsoft對Java語言的反擊。自C#誕生之日起,關於C#與Java之間的論戰便此起彼伏,至今不輟。

相同點:
(1) 從技術的角度來看
C#與Java是對傳統面向對象程序設計在組件化軟件時代的革新成果,可謂殊途同歸,兩種編程語言甚至有90%的重疊。Java和C撐都對傳統C++-艱深、晦澀的語法和語義進行了改進。
(2) 在語法方面
兩者都摒棄了C++中函數及其參數的const修飾宏代換全局變量全局函數等華而不實的地方;
(3) 在繼承方面
兩者都采用了更易於理解的單繼承多接口的實現方案;
(4) 在源代碼組織方面
都提出了聲明與實現於雖體的邏輯封裝

不同點:

C#也有其獨特的優勢:Microsoft提供的Visual Studio開發平台可以極好地提高C#程序的開發效率,而且Microsoft要比Java更善於利用Windows平台,當使用C#創建Windows服務記錄Windows事件日志訪問Windows注冊表時,.NET確實更方便。Microsof提供了Windows任務相關的大量基類,允許程序員通過向導、拖放等操作來快速開發應用因此比較容易使用。

Java的設計宗旨獨立於任何平台,自然不會提供太多的Windows特性。但這也正是Java語言的優勢:跨平台。對於一個企業應用而言,永遠無法確定這個應用需要在怎樣的平台上運行,如果你一旦選擇了c撐語言,那么你的應用就只能局限在Windows平台上。因此,對於一個開放式的企業應用而言,通常會選擇Java作為開發語言,而不是選擇C#。

1.2.2 Ruby簡介和優勢

Ruby語言由日本人松本行弘於1993年起開始着手研發,經歷2年時間,發布了Ruby語言的第一個版本:0.95版。據松本行弘的描述:他一直想發明一種語言,這種語言既能進行高效開發,又能讓開發人員享受編程的快樂。

事實上,Ruby確實是一種非常簡潔的解釋型語言1,一種純粹的面向對象編程語言。甚至比Java更純粹(在Java語言里,還有基本數據類型等不是對象的變量,但在Ruby語言里,一切都是對象)。除此之外,Ruby還提供了許多額外的便捷功能,比如閉包迭代集合等,這些都是為了達到Ruby語言刨始人的夢想:讓Ruby開發者能享受編程的快樂。

Ruby語言最大的特征就是簡潔

首先,它是一種弱類型的語言,變量無須聲明,變量沒有類型,因此Ruby的變量可以保存任何類型的數據:

其次,它還提供了強大的正則表達式支持,並支持運算符重載

除此,Ruby也提供了許多額外的便捷功能,比如閉包代碼塊迭代器集合等。

Ruby語言還有一個重要的優點:它也是完全跨平台的,可以在任何操作系統上解釋執行。

2004年,Ruby語言陣營里出現了一個優秀的MVC框架Ruby On Rails,這個開發框架被宣傳成現有企業框架的一個替代品。Ruby On Rails框架是一個真正意義上的敏捷開發框架,它提供了大量代碼生成器,通過使用這些代碼生成器可以極好地提高應用的開發效率。

相對於Java領域的眾多開發框架而言。Ruby on Rails提供了一個“一站式”的解決方案.Ruby On Rails框架提供了Web層的MVC框架、持久層的ORM等解決方案。借助於Ruby這種動態語言的優勢,整個應用的代碼相當簡潔,因而使得Ruby On Rails應用的開發非常快速。關於Rails框架和Java EE平台,算實是各有優勢的。

  • Rails平台的簡潔性、易用性會在中小型應用上發揮出更大的吸引力。
  • Java EE平台則提供了更多的選擇,適合對技術有精准把握的開發者,用於解決有復雜需求的大型企業級應用。

1.2.3 Python簡介和優勢

Python由Guido於1989年年底開發,Python語言是基於ABC教學語言2的。ABC這種語言非常優美和強大,是專門為非專業程序員設計的.但是.ABC語言並沒有獲得廣泛的應用,Guido認為是非開放造成的。

Guido決心在Python中避免這一錯誤,因此Guido加強了Python和其他語言如C、C#和Java的結合性。同時,他還實現了許多ABC中閃現過但未曾實現的東西。Python的第一個實現是基於Mac機的。Python由ABC語言發展而來,主要受到了Modula-3(另一種相當優美且強大的語言,為小型團體所設計)的影響,並且結合了UNIX shell和C的習慣。

Python是一種面向對象的解釋型編程語言,也是一種功能強大而完善的通用型語言,已經具有十多年的發展歷史,成熟且穩定。Python具有腳本語言中最豐富和強大的類庫,足以支持絕大多數日常應用。Python語言具有簡潔而清晰的語法特點,適合完成各種高層任務,幾乎可以在所有的主流操作系統上運行。

雖然Python也是一種解釋型的腳本語言,但一些大規模的軟件開發計划,比如Zope、Mnet、BitTorrent和Google都廣泛地使用了該語言,而Python的支持者喜歡稱它為高級動態編程語言,因此Python絕非JavaScript等只能處理簡單任務的腳本語言所能比擬的。

Python的兩大特色是可擴展性和清晰的語法。Python新的內置模塊(module)可以用C或C++寫成,也可為現成的模塊加上Python-的接口。Python的設計者在設計它的時候認為:對於一個特定的一問題,只要有一種最好的方法來解決就好了。因此.Python甚至不是一種格式自由的語言.例如.它要求if語句的下一行必須向右縮進,否則不能通過編譯。

Python在編程領域的占有率一直處於穩步上升之中根據最新的數據,Python排名第七。前六名分別是Java、C、VB、C++、PHP和Perl。最近,微軟也將Python入.NET平台,相信Python盼未來會更好。

1.3  Java程序運行機制

Java語言是一種特殊的高級語言,它既具有解釋型語言的特征,也具有編譯型語言的特征,因為Java程序要經過先編譯,后解釋兩個步驟。

1.3.1  高級語言的運行機制

計算機高級語言接程序的執行方式可以分為編譯型解釋型兩種。
(1) 編譯型語言

編譯型語言是指使用專門的編譯器,針對特定平台(操作系統)將某種高級語言源代碼一次性翻譯成可被該平台硬件執行的機器碼(包括機器指令和操作數),並包裝成該平台所能識別的可執行性程序的格式,這個轉換過程稱為編譯( Compile)。編譯生成的可執行性程序可以脫離開發環境,在特定的平台上獨立運行.

有些程序編譯結束后,還可能需要對其他編譯好的目標代碼進行鏈接,即組裝兩個以上的目標代碼模塊生成最終的可執行性程序,通過這種方式實現低層次的代碼復用。因為編譯型語言是—次性地編譯成機器碼,所以可以脫離開發環境獨立運行,而且通常運行效率較高。但因為編譯型語言的程序編譯成特定平台上的機器碼,因此編譯生成的可執行性程序通常無法移植到其他平台上運行;如果需要移植,則必須將源代碼復制到特定平台上,針對特定平台進行修改,至少也需要采用特定平台上的編譯器重新編譯。現有的CC++FORTRANPascal等高級語言都屬於編譯型語言。
(2) 解釋型語言

解釋型語言是指使用專門的解釋器對源程序逐行解釋成特定平台的機器碼立即執行的語言。解釋型語言通常不會進行整體性的編譯和鏈接處理,解釋型語言相當於把編譯型語言中的編譯和解釋過程混合到一起同時完成。可以認為:每次執行解釋型語言的程序都需要進行一次編譯,因此解釋型語言的程序運行效率通常較低,而且不能脫離解釋器獨立運行。但解釋型語言有一個優勢:跨平台比較容易,只需提供特定平合的解釋器即可,每個特定平台上的解釋器負責將源程序解釋成特定平台的機器指令即可。解釋型語言可以方便地實現源程序級的移植,但這是以犧牲程序執行效率為代價的。

現有的RubyPython等語言都屬於解釋型語言。

除此之外,還有一種偽編譯型語言,如Visual Basic,它屬於半編譯型語言,並不是真正的編譯型語言。它首先被編譯成P-代碼,並將解釋引擎封裝在可執行性程序內,當運行程序時P-代碼會被解析成真正的二進制代碼。表面上看起來,Visual Basic可以編譯生成可執行性的EXE文件,而且這個EXE文件也可以脫離開發環境,在特定平台上運行,非常像編譯型語言。實際上,在這個EXE文件中,既有程序的啟動代碼,也有鏈接解釋程序的代碼,而這部分代碼負責啟動Visual Basic解釋程序,再對Visual Basic代碼進行解釋並執行。

1.3.2 Java程序的運行機制和JVM

Java語言比較特殊,由Java語言編寫的程序需要經過編譯步驟,但這個編譯步驟並不會生成特定平台的機器碼,而是生成一種與平台無關字節碼(也就是.class文件)。當然,這種字節碼不是可執行性的,必須使用Java解釋器來解釋挾行。因此,我們可以認為:Java語言既是編譯型語言,也是解釋型語言。或者說,Java語言既不是純粹的編譯型語言,也不是純粹的解釋型語言Java程序的執行過程必須經過先編譯,后解釋兩個步驟,如圖所示。

Java語言里負責解釋執行字節碼文件的是Java虛擬機,即JVM(Java Virtual Machine)。JVM是可運行Java字節碼文件的虛擬計算機。所有平台上的JVM向編譯器提供相同的編程接口,而編譯器只需要面向虛擬機,生成虛擬機能理解的代碼,然后由虛擬機來解釋執行。在一些虛擬機的實現中,還會將虛擬機代碼轉換成特定系統的機器碼執行,從而提高執行效率。

當使用Java編譯器編譯Java程序時,生成的是與平台無關的字節碼,這些字節碼不面向任何具體平台,只面向JVM。不同平台上的JVM都是不同的,但它們都提供了相同的接口。JVM是Java程序跨平台的關鍵部分,只要為不同平台實現了相應的虛擬機,編譯后的Java字節碼就可以在該平台上運行。顯然,相同的字節碼程序需要在不同的平台上運行,這幾乎是“不可能的”,只有通過中間的轉換器才可以實現,JVM就是這個轉換器。

JVM是一個抽象的計算機,和實際的計算機一樣,它具有指令集並使用不同的存儲區域。它負責執行指令,還要管理數據內存寄存器

注意:

  JVM的作用很容易理解,就像我們有兩支不同的筆,但需要把同一個筆帽套在兩支不同的筆上,這就需要為這兩支筆分別提供一個轉換器。這個轉換器:
    向上的接口相同,用於適應同一個筆帽;
    向下的接口不同,用於適應兩支不同的筆.
  在這個類比中,我們可以近似的理解兩支不同的筆就是不同的操作系統,而同一個筆帽就是Java字節碼程序,轉換器角色則對應JVM.類似地,我們也可以認為JVM分為向上和向下兩個部分,所有平台上的JVM
    向上提供給Java字節碼程序的接口完全相同
    向下適應不同平台的接口則互不相同。 

Sun公司制定的Java虛擬機規范,在技術上規定了JVM的統一標准,具體定義了JVM的如下細節:

  • 指今集
  • 寄存器
  • 類文件的格式
  • 存儲區

Sun公司制定這些規范的目的是為了提供統一的標准,最終實現Java程序的平台無關性。

二、 Java開發環境搭建和介紹

在開發Java程序之前,必須先完成一些准備工作,也就是在計算機上安裝並配置Java開發環境,開發Java程序必須配置安裝JDK。

JDK的全稱是Java SE Development Kit,即Java 標准版開發包,是Sun提供的一套用於開發Java應用程序的開發包。它提供了編譯、運行Java程序所需的各種工具和資源,包括Java編譯器Java行時環境以及常用的Java類庫等。
  JRE:Java運行時環境,它的全稱是Java Runtime Environment,因此也被稱為JRE它是運行Java程序的必需條件。

注意:

  簡單的說,JRE包含JVM。JVM是運行Java程序的核心虛擬機,而運行Java程序不僅需要核心虛擬機,還需要其他的類加載器字節碼校驗器以及大量的基礎類庫JRE除了包含JVM之外,還需要包含運行Java程序的其他環境的支持

  一般而言,如果只是運行Java程序,我們只安裝JRE,無需安裝JDk。如果要開發Java程序,則應選擇安裝JDK;當然,安裝了JDK之后,就包 含了JRE,也可以運行Java程序。但如果只是運行Java程序,則需要在計算機上安裝JRE。僅安裝JVM是不夠的。實際上,Sun網站上提供的就是 JRE的下載,並不提供單獨的JVM下載。

Sun把Java分為Java SE、Java EE和Java ME三個部分,而且為Java SE和Java EE分別提供了JDKJava EE SDKSoftware Development Kit)兩個開發包如果你只需要學習Java SE的編程知識,則可以下載標准的JDK;如果你還需要學習Java EE的相關內容也可以選擇下載Java EE SDK,有一個Java EE SDK版本里已經包含了最新版的JDK,安裝Java EE SDK就包含了JDK。

2.1 下載安裝JDK

下載和安裝步驟如下:
(1) 登陸 http://www.oracle.com/technetwork/java/javase/downloads/index.html頁面,下載Java SE Development Kit的最新版本

(2) 在該頁面中我們可以看到JDK不同的版本,目前我們可以看到,當前的最新版本是JDK 8,點擊如下圖2.1所示的頁面鏈接,進入JDK 8的下載界面,如圖2.2所示,在該頁面中我們可以看到兩種類型的JDK版本,一個是帶“java example”源碼,一個是不帶“java example”源碼的。並且每種類型,針對不同操作系統平台有對應不同的JDK版本:

  • 對於Windows平台,可以選擇Windows x86或Windows X64版本。
  • 對於Linux平台,可以選擇Linux平台的JDK。

圖 2.1

圖 2.2


(3) 下載完成后:

  • 對於Windows版本,會獲得一個EXE文件,可以通過雙擊來完成安裝。
  • 對於Linux平台,會獲得一個BIN文件,只需為該文件添加執行屬性,然后執行該安裝文件即可。

(4) Linux的安裝方式比較簡單,用tar命令將JDK包解壓,然后配置環境變量即可,不在贅述,可以參考http://www.cnblogs.com/sunddenly/p/3977809.html

Windows平台上安裝JDK的步驟:

1. 雙擊安裝包EXE文件,開始安裝后,第一個對話框提問是否同意Java的許可協議,單機“接受”按鈕,進入如圖2.3所示的組件界面。

圖 2.3

下面介紹一下JDK中的這些組件:
  公共JRE:是一個獨立的JRE系統,會單獨安裝在系統的其他路徑下。公用JRE會向Internet Explore瀏覽器和系統中注冊Java運行時環境。通過這種方式,系統中任何應用程序都可以使用公用JRE。但大部分時候,並不需要安裝所有組件,在圖2.3中我選擇安裝了兩個組件,沒有安裝公共JRE。由於現在在網頁上執行Applet的機會越來越少了,而且完全可以使用JDK目錄下的JRE來運行Java程序,因此,沒有太大必要安裝公用JRE
  Java開發工具:這是JDK的核心,包括編譯java程序的必需命令工具。實際上,這個選項里已經包含了運行Java程序的JRE了,這個JRE會安裝在JDK目錄的子目錄里這也是我不安裝公共jre的原因。
  源代碼:安裝這個選項將會安裝java所有核心類庫的源代碼
(5) 選擇安裝路徑,安裝完成后可在JDK安裝路徑下看到如下文件路徑。

  • bin:該路徑下存放了JDK的各種工具命令,常用的javac和java等命令就存放在該路徑下。
  • db:該路徑是安裝javaDB的路徑。
  • demo:該路徑存放了一些java示例代碼供初學者參考。
  • jre:該路徑下安裝的就是運行java程序所必需的JRE環境。
  • lib:該路徑下存放的就是JDK工具命令的實際執行程序,如果使用WinRAR打開lib目錄下的tool.jar文件,將看到如圖2.4所示的目錄結構。
  • src.zip:該壓縮文件了存放的就是java所有核心類庫的源代碼。
  • README和LICENSE:是說明性文檔。
  • 在上面的路徑中,bin路徑是一個非常有用的路徑,這個路徑下包含了編譯和運行java程序的javac和java兩個命令。除此之外還包括了appletviewer.jar等大量工具。

圖 2.4

注意:
  用於編譯java程序所使用的javac.exe命令也是用java寫的,這個類就是lib目錄下tool.jar文件中sun\tools\javac路徑下的Main類JDK的bin目錄下的java.exe文件實際上僅僅是包裝了這個java類。不僅如此,bin目錄下的絕大部分命令都包裝了tool.jar文件里的工具類。

 三、環境變量

2.1 Path

2.1.1 變量的意義

path環境變量的值是一系列指令的路徑

在Windows操作系統中,當我們執行一條命令時,Windows會根據Path環境變量來查找這個命令。如果能找到這個命令,則該命令可執行。否則將出現“xxxx’不是內部或外部命令,也不是可運行的程序或批處理文件”的提示。

在Linux操作系統中,Linux也會根據PATH環境變量來查找命令。

因為Windows操作系統不區分大小寫 ,設置path和PATH並沒有區別;而Linux區分大小寫,設置path和PATH是有區別的,因此只需要設置PATH環境變量即可。

2.1.2 配置方式

Windows配置方式:

在windows中的配置方式如下圖所示:

(1) 打開計算機,點擊系統屬性。

(2) 點擊高級系統設置

(3) 點擊環境變量

(4) 環境變量有兩種類型,系統變量和用戶變量,我選擇系統變量,在系統變量里已經有一個Path變量,我們雙擊它。

 

(5) 在該窗口的,變量值選項的最后加入:;%JAVA_HOME%\bin;%JAVA_HOME%\jre\bin

注意:

  路徑中'%--%'表示引用操作,JAVA_HOME表示一個系統變量,'%JAVA_HOME%',表示對該變量的引用,但該變量未設置,下面我們將對其進行設置。

(6) 在系統變量欄,點擊新建,新建一個JAVA_HOME變量,變量的值為jdk的安裝路徑。

(7) 設置CLASSPATH,設置變量值為:.;%JAVA_HOME%\lib;%JAVA_HOME%\lib\tools.jar,下面會介紹。

注意:
  用戶變量和系統變量沒有太大的區別,只是用戶變量只對當前用戶有效,而系統變量對所有用戶有效。為了減少自己的操作對他人的影響。對於當 前用戶而言,設置用戶變量和系統變量效果大致相同,只是系統變量在用戶變量之前。可能出現這一種情況:如果Path系統變量的路徑里包含了java命令而 PATH用戶變量的路徑里也包含了java命令,則優先執行Path系統變量路徑里包含的java命令。

Linux配置方式:

在 linux 中環境變量的設置方法有以下三種(以PATH為例):

(1) 直接使用 export 命令
    [root@hadoop ~]# export PATH=$PATH:/usr/local/jdk/bin
在Linux中,變量之間的分隔符是“:”Windows中是";",查看是否已經設置好,可以使用命令 export 命令來查看,也可以直接$變量名來查看
    [root@hadoop ~]# $PATH
  -bash: .:/usr/local/hadoop/bin:/usr/local/zk/bin:/usr/local/zk/conf:/usr/local/jdk/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin:
    [root@hadoop ~]#

注意:

  直接使用 export 設置的變量,都是臨時變量,也就是說退出當前的 shell ,為該變量定義的值便不會生效了。如何能讓我們定義的變量永久生效呢,那就看我們的第二種定義的方式。

(2) 修改 /etc/profile
    [root@hadoop ~]# vi /etc/profile
    export PATH=$PATH:/usr/local/jdk/bin  # 在配置文件中加入此行配置

需要注意的是:修改完這個文件必須要使用 以下命令在不用重啟系統的情況下使修改的內容生效
    [root@hadoop ~]# source /etc/profile 或者是:[root@hadoop ~]# . /etc/profile

查看設置是否生效
    [root@hadoop ~]# echo $PATH
  .:/usr/local/hadoop/bin:/usr/local/zk/bin:/usr/local/zk/conf:/usr/local/jdk/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin
    [root@hadoop ~]#
 配置已經生效

(3) 修改 .bashrc 文件(在當前用戶 shell 下生效)
    # vi /root/.bashrc?在里面加入:
    export PATH=$PATH:/usr/local/jdk/bin

修改這個文件之后同樣也需要使用 source 或者是 . 使配置文件生效。再來使用 echo $PATH看下變量是否生效  
  [root@hadoop ~]# echo $PATH
  .:/usr/local/hadoop/bin:/usr/local/zk/bin:/usr/local/zk/conf:/usr/local/jdk/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin
    [root@hadoop ~]#

export命令參數
     
    功能:設置或顯示環境變量,export的效力僅及於該此登陸操作。
    語法export [-fnp][變量名稱]=[變量設置值]
    參數
           -f  代表[變量名稱]中為函數名稱。
           -n  刪除指定的變量。變量實際上並未刪除,只是不會輸出到后續指令的執行環境中。
           -p  列出所有的shell賦予程序的環境變量。
    補充:在shell中執行程序時,shell會提供一組環境變量。 export可新增,修改或刪除環境變量,供后續執行的程序使用。
    一個變量創建時,它不會自動地為在它之后創建的shell進程所知。而命令export可以向后面的shell傳遞變量的值。當一個shell腳本調用並執行時,它不會自動得到原為腳本(調用者)里定義的變量的訪問權,除非這些變量已經被顯式地設置為可用。export命令可以用於傳遞一個或多個變量的值到任何后繼腳本

2.1.3 運行java程序

我們知道,編譯和運行java程序必須經過兩個步驟。

(1) 將源文件編譯成字節碼。

(2) 解釋執行平台無關字節碼。

上面的兩個步驟分別需要使用java和javac兩個命令。當我們在操作系統的命令窗口,輸入java和 javac命令,將看到如下提示:

java’不是內部或外部命令,也不是可運行的程序或批處理文件

javac’不是內部或外部命令,也不是可運行的程序或批處理文件

則說明我們JDK的Path環境變量沒有配置,需要按照上面的步驟進行配置。

設置完Path環境變量,我們就可以使用這兩個命令來編譯和執行我們的java程序了。下面在Linux上,以運行一個小程序來分析javac和java的作用

步驟下所示:
  [root@hadoop code]# pwd
  /usr/code
  [root@hadoop code]# vi HelloWorld.java  
  public class HelloWorld{
          public static void main(String args[]){
                  System.out.println("HelloWorld");
          }
  }
  [root@hadoop code]# javac HelloWorld.java
  [root@hadoop code]# ls
  HelloWorld.class  HelloWorld.java
  [root@hadoop code]# java HelloWorld
  HelloWorld

由上面的操作可知,我們的當前路徑是/usr/code,在該路徑下新建一個".java"源文件,編輯文件內容輸入程序代碼。然后經過javac編譯生成".class"平台無關字節碼,默認名稱為其中類名,最后由“java 類名”命令來執行該字節碼,輸出最終結果“HelloWorld”。下面我們輸入javac命令,看一下它的參數:

注意

代碼中含有包名的時候,編譯之后,再次是“java 類名”,就會出現錯誤,我新建了一個帶有包名的源文件如下:
  [root@hadoop code]# vi PackageTest.java
  package build.classes;
  public class HelloWorld{
      public static void main(String args[]){
    System.out.println("HelloWorld");
      }
  }
  [root@hadoop code]# ls
  HelloWorld.class  HelloWorld.java  PackageTest.java
  [root@hadoop code]# javac PackageTest.java

  [root@hadoop code]# java PackageTest.java
  Exception in thread "main" java.lang.NoClassDefFoundError: PackageTest/java
  Caused by: java.lang.ClassNotFoundException: PackageTest.java
  ………………
  Could not find the main class: PackageTest.java.  Program will exit.
從上面的錯誤提示信息,我們可以知道錯誤原因是找不到PackageTest,其實者這不難理解,既然在代碼中加入了“package build.classes;”這行代碼,就表示了PackageTest這個源文件,是在build/classes路徑下,可是並沒有該路徑,所以會找不到,而且此時執行的時候不能用“java 類名”而應該是“java 包名.類名”

所以一種解決方案如下:

  [root@hadoop code]# javac -d ./ PackageTest.java
  [root@hadoop code]# ls
  build  HelloWorld.class  HelloWorld.java  jar.jar  PackageTest.class  PackageTest.java
  [root@hadoop code]# java build.classes.PackageTest
  HelloWorld

我們可以發現,在執行 javac -d ./ PackageTest.java時會在指定目錄生成相應包名。

另一種解決方案:感覺最簡單,直接把包名刪除,在當前路徑執行javac、java。

關於java和javac的詳細介紹,可參考:

  http://www.cnblogs.com/pengxl/archive/2010/12/10/1902082.html

  http://www.cnblogs.com/JeffChen/archive/2008/01/16/1041783.html

總結:
   使用如下命令對此類進行編譯,編譯的前提是安裝過JDK ,並且配置了環境變量。
   javac: 對類文件進行編譯 javac 類.java
   java: 對類文件進行解析 java  類
   如果有包就需要javac -d . 類.java(為了反映包的目錄結構)

2.2  CLASSPATH

2.2.1 變量意義(一)---定位字節碼

由下圖javac的命令參數可知,classpath選項,主要用來指定用戶類文件。那么由此可知,環境變量“CLASSPATH”也是用來定位類的,當我們執行“java 類名時”JRE默認從當前位置搜索“.class”文件,當我們在系統中設置了CLSSPATH時,就會從CLASSPATH路徑查找“.class”字節碼文件。

因此,只要在我們的CLASSPATH對應的路徑中有我們的字節碼文件時,那么就可以在任何路徑下通過java命令來執行我們的“.class”字節碼文件。如下圖所示,在/usr目錄下有一個子目錄,code中有一個子目錄classes,code中存放的是".java"源碼,classes中存放的是“.class”字節碼,這樣我們就可以將字節碼目錄的路徑設置為CLASSPATH,當我們在任意路徑上,通過“java 類名”來運行java程序。目錄結構如下圖所示,我的CLASSPATH設置的路徑為:“/usr/code/classess”

    |---usr
       |---code
         |---".java"
         |---classes
            |---".class"

我以,含有包名“build.classes”的PackageTest.java源碼為例,對上述進行測試,步驟如下:

   [root@hadoop code]#vi PackageTest.java
   package build.classes;
   public class PackageTest{
          public static void main(String args[]){
        System.out.println("HelloWorld");
          }
  }
  [root@hadoop code]# ls
  PackageTest.java
  [root@hadoop code]# javac -d ./classes PackageTest.java
  [root@hadoop code]# java build.classes.PackageTest
  HelloWorld

2.2 變量意義(二)---定位“jar”包

我在學習ZooKeeper編程時,打算在Linux系統中,通過javac和java命令來執行一段程序,代碼如下:

package org.zk;

import java.io.IOException;
import java.util.concurrent.CountDownLatch;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;

public class CreateGroup implements Watcher{
    private static final int SESSION_TIMEOUT=5000;
    
    private ZooKeeper zk;
    private CountDownLatch connectedSignal=new CountDownLatch(1);
    @Override
    public void process(WatchedEvent event) {
        if(event.getState()==KeeperState.SyncConnected){
            connectedSignal.countDown();
        }
    }
    
    public static void main(String[] args) throws IOException, InterruptedException, KeeperException {
        CreateGroup createGroup = new CreateGroup();
        createGroup.connect("10.1.14.24:2181");
        createGroup.create("zoo");
        createGroup.close();
    }

    private void close() throws InterruptedException {
        zk.close();
    }

    private void create(String groupName) throws KeeperException, InterruptedException {
        String path="/"+groupName;
        if(zk.exists(path, false)== null){
            zk.create(path, null/*data*/, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        }
        System.out.println("Created:"+path);
    } 

    private void connect(String hosts) throws IOException, InterruptedException {
        zk = new ZooKeeper(hosts, SESSION_TIMEOUT, this);
        connectedSignal.await();
    }
}
View Code

需要注意的有兩處:
(1) 程序中需要導入“.jar"包,如下圖所示。

(2) 使用main函數的args參數,如下圖所示。

對應的處理有兩處:
(1) 將ZooKeeper的所有jar包,加入到CLASSPATH,如下圖所示。


(2) 執行“java 類名”時,后面加入對應的參數,即主機號和節點名稱,如下所示。

  java org.zk.CreateGroup localhost:2181 zoo1

運行結果:

  [root@hadoop code]# ls
  build  classes  CreateGroup.java  HelloWorld.java  jar.jar  PackageTest.java  zookeeper.out
  [root@hadoop code]# javac -d ./classes CreateGroup.java
  [root@hadoop code]# java org.zk.CreateGroup localhost:2181 zoo1
  2014-10-28 18:00:26,154 [myid:] - INFO  [main:Environment@100] - Client environment:zookeeper.version=3.4.5-1392090, built on 09/30/2012
  2014-10-28 18:00:26,157 [myid:] - INFO  [main:Environment@100] - Client environment:host.name=hadoop
  2014-10-28 18:00:26,157 [myid:] - INFO  [main:Environment@100] - Client environment:java.version=1.6.0_24
  2014-10-28 18:00:26,157 [myid:] - INFO  [main:Environment@100] - Client environment:java.vendor=Sun Microsystems Inc.
  2014-10-28 18:00:26,158 [myid:] - INFO  [main:Environment@100] - Client environment:java.home=/usr/local/jdk/jre
  2014-10-28 18:00:26,158 [myid:] - INFO  [main:Environment@100] - Client environment:java.class.path=.:/usr/local/jdk/lib:……
  ……
  Created:/zoo1
  2014-10-28 18:00:26,236 [myid:] - INFO  [main:ZooKeeper@684] - Session: 0x4956f7f1d70005 closed
  2014-10-28 18:00:26,237 [myid:] - INFO  [main-EventThread:ClientCnxn$EventThread@509] - EventThread shut down
  [root@hadoop code]#

 2.3 環境變量CLASSPATH和classpath選項

CLASSPATH環境變量常常設置為:.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar, 我們知道CLASSPATH作用是,在通過“java 類名”解釋執行java程序時,JRE會去搜索類文件,而CLASSPATH就為JRE提供了搜索路徑。下面,我對上面的CLASSPATH環境變量做一下解釋:

(1) 引用符和分隔符

在Windows上,分隔符:“;”
                     引用符:“%……%”

在Linux上,     分隔符:“:”
                     引用符:“$”
(2) 變量的意義
上面有三個路徑,用兩個分號隔開,它們的意義如下:

1.“.”:

‘點’也表示路徑,他表示的是當前路徑。因為在默認情況下,我們會在當前路徑下生成類文件,所以需要把該路徑添加到CLASSPATH環境變量里

2.“%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar”:

編譯和運行Java程序還需要JDK的lib路徑下的dt.jar和tool.jar文件中的Java類,所以還需要把這兩個文件添加到CLASSPATH環境變量里。

實際上,如果使用1.5以上版本的JDK,JRE會自動搜索當前路徑下的類文件,而且使用Java編譯和運行工具時系統可以自動加載dt.jar和tools.jar文件中的Java類,因此即使不設置CLASSPATH環境變量,也能運行java程序。但1.4以前版本的JDK都沒這個功能,這意味着即使當前路徑已經包含了HeIloWorld.class並在當前路徑下執行“java HeIIoWorld",系統將一樣提示找不到HeIIoWorld類。

如果使用更早版本的JDK,通常需要設置CLASSPATH環境變量。如果想在運行Java程序時臨時指定JRE搜索Javtr類的路徑,則可以使用-classpath選項,即按如下格式來運行java命令:

java -classpath dirl;dir2,dir3……;dirN Java類

classpath選項的值可以是一系列的路徑,多個路徑之間在Windows平台上以分號";"隔開,在LinUX平台上財以冒號":"隔開。

如果在運行Java程序時指定了-classpath選項的值,JRE將嚴格按-classpath選項所指定的路徑來搜索Java類,即不會在當前路徑下搜索Java類,CLASSPATH環境變量所指定的搜索路徑也不再有效。

如果想使CLASSPATH環境變量指定的搜索路徑有效,而且還會在當前路徑下搜索Java類,則可以按如下格式來運行Java程序:

java -classpath %CLASSPATH%;.;dir1;dir2;dir3……;dirN java類

上面命令通過%CLASSPATH%來引用CLASSPATH環境變量的值,並在classpath選項的值里添加了一點,強制JRE在當前路徑下搜索Java類。

三、垃圾回收機制

3.1 不同內存分配的方式的比較

傳統的C/C++等編程語言,需要程序員負責回收已經分配的內存。顯式進行垃圾回收是一件比較困難的事情,因為程序員並不總是知道內存應該何時被釋放。如果一些分配出去的內存得不到及時回收,就會引起系統運行速度下降,甚至導致程序癱瘓,這種現象被稱為內存泄漏。總體而言,顯式進行垃圾回收主要有如下兩個缺點

(1) 程序忘記及時回收無用內存,從而導致內存泄漏,降低系統性能。
(2) 程序錯誤地回收程序核心類庫的內存,從而導致系統崩潰

與C/C++程序不同,Java語言不需要程序員直接控制內存回收,Java程序的內存分配和回收都是由JRE在后台自動進行的。JRE會負責回收那些不再使用的內存,這種機制被稱為垃圾回收GarbageCollection,也被稱為GC。通常JRE會提供一個后台線程來進行檢測和控制,一般都是在CPU空閑或內存不足時自動進行垃圾回收,而程序員無法精確控制垃圾回收的時間相順序等。

Java的堆內存是一個運行時數據區,用以保存類的實例(對象),Java虛擬機的堆內存中存儲着正在運行的應用程序所建立的所有對象,這些對象不需要程序通過代碼來顯式地釋放。一般來說,堆內存的回收由垃圾回收來負責,所有的JVM實現都有一個由垃圾回收器管理的堆內存。垃圾回收是一種動態存儲管理技術,它自動地釋放不再被程序引用的對象,按照特定的垃圾回收算法來實現內存資源的自動回收功能。

在C/C++中,對象所占的內存在程序結束運行之前一直被占用,被明確釋放之前不能分配給其他對象;在Java中,當沒有對象引用指向原先分配給某個對象的內存時,該內存便成為垃圾。JVM的一個超級線程會自動釋放該內存區。垃圾回收意味着程序不再需要的對象是“垃圾信息”,這些信息將被丟棄。

當一個對象不再被引用時,內存回收它占領的空間,以便空間被后來的新對象使用。事實上,除了釋放沒用的對象外,垃圾回收也可以清除內存記錄碎片。由於創建對象垃圾回收器釋放丟棄對象所占的內存空間內存會出現碎片碎片是分配給對象的內存塊之間的空閑內存區,碎片整理將所占用的堆內存移到堆的一端,JVM將整理出的內存分配給新的對象。

3.2 java垃圾回收機制的優缺點

優點:

垃圾回收能自動稃放內存空間,減輕編程的負擔。這使Java虛擬機具有兩個顯著的優點
(1) 垃圾回收機制可以很好地提高編程效率

在沒有垃圾回收機制時,可能要花許多時間來解決一個難懂的存儲器問題。在用Java語言編程時,依靠垃圾回收機制可大大縮短時間。

(2) 垃圾回收機制保護程序的完整性,垃圾回收是Java語言安全性策略的一個重要部分。

缺點:

垃圾回收的一個潛在缺點是它的開銷影響程序性能

(1) Java虛擬機必須跟蹤程序中有用的對象,才可以確定哪些對象是無用的對象,並最終釋放這些無用的對象。這個過程需要花費處理器的時間。

(2) 垃圾回收算法的不完備性,早先采用的某些垃圾回收算法就不能保證100%收集到所有的廢棄內存。

當然,隨着垃圾回收算法的不斷改進,以及軟硬件運行效率的不斷提升,這些問題都可以迎刃而解。

如果,您認為閱讀這篇博客讓您有些收獲,不妨點擊一下右下角的【推薦】。
如果,您希望更容易地發現我的新博客,不妨點擊一下左下角的【關注我】。
如果,您對我的博客所講述的內容有興趣,請繼續關注我的后續博客,我是【Sunddenly】。

本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM