JAVA基礎-02

來源:互聯網
上載者:User

標籤:

Java學習筆記

 

Java基礎 
基本類型不是new出來的則是放在棧裡面,對象的引用也是放在棧裡面的,只要是用new()來建立對象的,都會在堆中建立 

String類被設計成為不可改變(immutable)的類。如果你要改變其值,可以,但JVM在運行時根據新值悄悄建立了一個新對象,然後將這個對象的地址返回給原來類的引用。這個建立過程雖說是完全自動進行的,但它畢竟佔用了更多的時間。在對時間要求比較敏感的環境中,會帶有一定的不良影響。 

關於String str = "abc"的內部工作。Java內部將此語句轉化為以下幾個步驟: 
(1)先定義一個名為str的對String類的對象引用變數:String str; 
(2)在棧中尋找有沒有存放值為"abc"的地址,如果沒有,則開闢一個存放字面值為"abc"的地址,接著建立一個新的String類的對象o,並將o的字串值指向這個地址,而且在棧中這個地址旁邊記下這個引用的對象o。如果已經有了值為"abc"的地址,則尋找對象o,並返回o的地址。 
(3)將str指向對象o的地址。 
值得注意的是,一般String類中字串值都是直接存值的。但像String str = "abc";這種場合下,其字串值卻是儲存了一個指向存在棧中資料的引用! 

java記憶體泄露的兩個條件:無用,無法回收。 

BigInteger能表示任意精度的整數,BigDecimal能表示任意精度的浮點數, 但都是用精度換速度的做法



容器集合 
List的子類裡面LinkedList和ArrayList是非同步的,而Vector和Stack是同步的, LinkedList底層採用的是雙向鏈表(前指標+資料+後指標), 因此查詢效率低, 增刪效率高;ArrayList底層採用的是Array,因此查詢效率高, 增刪效率低; Vecotr是重量級的List,一般在並發保證安全執行緒時採用 

如果想跟蹤添加給HashSet的元素的順序,LinkedHashSet實現會有協助。LinkedHashSet的迭代器按照元素的插入順序來訪問各個元素。 

List中的元素有順序, 可重複, Set中的元素無序, 不可重複(SortedSet是有序的) 

Iterator的next方法將跳到下一個元素, 並返回剛剛跳過的元素, 因此使用remove方法的時候,必須先調用next方法 

在Map 中插入、刪除和定位元素,HashMap 是最好的選擇。但如果您要按自然順序或自訂順序遍曆鍵,那麼TreeMap會更好。 

LinkedHashMap擴充HashMap,以插入順序將關鍵字/值對添加進連結雜湊映像中。 

Hashtable 類似於 HashMap,但是不允許 null 鍵和 null 值。它也比 HashMap 慢,因為它是同步的。 



效率 
在方法內部頻繁存取變數的時候, 使用局部變數比使用執行個體變數和靜態變數要有更高的效率 

異常對效能不利。拋出異常首先要建立一個新的對象。Throwable介面的建構函式調用名為fillInStackTrace()的本地(Native)方法,fillInStackTrace()方法檢查堆棧,收集調用跟蹤資訊。只要有異常被拋出,VM就必須調整呼叫堆疊,因為在處理過程中建立了一個新的對象。 



I/O 
任何有能力產生資料流(源)的java io對象就可以看作是一個InputStream對象, 何有能力接收資料來源(流)的java io對象我們就可以看作是一個OutputStream對象 

io資料流有兩種類別,一種就是InputStream/OutputStream,一種是Reader/Writer, 分別用來處理位元組流和字元流, 字元也是一種位元組, 為什麼還要用Reader/Writer呢, 這是因為在處理字元的時候可能涉及到轉碼,轉碼主要是Reader與InputStream,以及Writer與OutputStream之間, 轉碼的過程都是通過InputStreamReader和OutputStreamWriter來做的, 有時候我們可能沒有顯式的調用這兩個類, 但是相關的類在內部是做了這種轉換的, 比如FileReader其實就是通過InputStreamReader將資料從FileInputStream取過來的, 比如將作業系統的文字編碼轉化為Unicode(因為在Java內部都是採用Unicode來儲存資料的),記住這裡有一個前提,那就是作業系統當前的編碼格式和文檔的編碼格式是一直的,如果不一致就必須指定當前的InputStream的編碼格式.如果不知道字元所採用何種編碼方式, 那麼就不要使用Reader和Writer而應該改用InputStream和OutStream 

對輸入/輸出流進行緩衝可以提高代碼執行效率, 也就是使用BufferedXxxx和BufferedXxxx對原有的流進行封裝, 緩衝是一個非常重要而基本的加速I/O訪問的技術 

final關鍵字修飾的變數,表明該變數是不變的, 但是這裡的不變只是所引用本身不變, 至於引用的對象是否改變則沒有約束, 比如final StringBuffer a=newStringBuffer("immutable");a.append(" broken!"); //編譯通過, 這裡我們可以看出, final只對引用的"值"(也就是它所指向的那個對象的記憶體位址)有效, 它迫使引用只能指向初始指向的那個對象, 改變它的指向會導致編譯器錯誤, 至於它所指向的對象的變化,final是不負責的. 

當你要clone的類裡面含有可修改的引用欄位的時候,那麼你一定要把整個類的藍圖進行複製,如果對你clone得到的對象進行修改的時候還會影響到原來的執行個體,那麼這是不可取的。所以應該這樣clone() 

 


JVM 
一般來說,我們使用虛擬機器的類裝載時需要繼承抽象類別java.lang.ClassLoader,其中必須實現的方法是loadClass(),對於這個方法需要實現如下操作:(1) 確認類的名稱;(2) 檢查請求要裝載的類是否已經被裝載;(3) 檢查請求載入的類是否是系統類別;(4) 嘗試從類裝載器的儲存區擷取所請求的類;(5) 在虛擬機器中定義所請求的類;(6) 解析所請求的類;(7) 返回所請求的類。 

Java中的類的裝載過程也就是代理裝載的過程。比如:Web瀏覽器中的JVM需要裝載一個小應用程式TestApplet。JVM調用小應用程式裝載器ACL(Applet ClassLoader)來完成裝載。ACL首先請求它的父裝載器, 即系統裝載器裝載TestApplet是否裝載了這個類, 由於TestApplet不在系統裝載器的裝載路徑中, 所以系統裝載器沒有找到這個類, 也就沒有裝載成功。接著ACL自己裝載TestApplet。ACL通過網路成功地找到了TestApplet.class 檔案並將它匯入到了JVM中。在裝載過程中, JVM發現TestAppet是從超類java.applet.Applet繼承的。所以JVM再次調用ACL來裝載java.applet.Applet類。ACL又再次按上面的順序裝載Applet類, 結果ACL發現他的父裝載器已經裝載了這個類, 所以ACL就直接將這個已經裝載的類返回給了JVM , 完成了Applet類的裝載。接下來,Applet類的超類也一樣處理。最後, TestApplet及所有有關的類都裝載到了JVM中。 

當 JVM 需要使用類時,它根據名稱向 ClassLoader 請求這個類,然後 ClassLoader 試圖返回一個表示這個類的 Class 對象。通過覆蓋對應於這個過程不同階段的方法,可以建立定製的 ClassLoader。其中有個loadClass(String name, boolean resolve)方法,該方法為ClassLoader的進入點,在jdk1.2以後,loadClass方法將預設調用findClass方法,詳細內容可以參考API文檔,我們編寫的ClassLoader主要就是為了覆蓋以上兩個方法。 

 


JavaEE 
Tomcat Server處理一個http請求的過程 
假設來自客戶的請求為: 
http://localhost:8080/wsota/wsota_index.jsp 
1) 請求被發送到本機連接埠8080,被在那裡偵聽的Coyote HTTP/1.1 Connector獲得 
2) Connector把該請求交給它所在的Service的Engine來處理,並等待來自Engine的回應 
3) Engine獲得請求localhost/wsota/wsota_index.jsp,匹配它所擁有的所有虛擬機器主機Host 
4) Engine匹配到名為localhost的Host(即使匹配不到也把請求交給該Host處理,因為該Host被定義為該Engine的預設主控件) 
5) localhost Host獲得請求/wsota/wsota_index.jsp,匹配它所擁有的所有Context 
6) Host匹配到路徑為/wsota的Context(如果匹配不到就把該請求交給路徑名為""的Context去處理) 
7) path="/wsota"的Context獲得請求/wsota_index.jsp,在它的mapping table中尋找對應的servlet 
8) Context匹配到URL PATTERN為*.jsp的servlet,對應於JspServlet類 
9) 構造HttpServletRequest對象和HttpServletResponse對象,作為參數調用JspServlet的doGet或doPost方法 
10)Context把執行完了之後的HttpServletResponse對象返回給Host 
11)Host把HttpServletResponse對象返回給Engine 
12)Engine把HttpServletResponse對象返回給Connector 
13)Connector把HttpServletResponse對象返回給客戶browser 


JDK新特性 
注釋(Annotation),得先提一提什麼是中繼資料(metadata)。所謂中繼資料就是資料的資料。也就是說,中繼資料是描述資料的。就象資料表中的欄位一樣,每個欄位描述了這個欄位下的資料的含義。而J2SE5.0中提供的注釋就是java原始碼的中繼資料,也就是說注釋是描述java原始碼的。 


多線程線程 
實現線程,有兩種方法,一種是繼承Thread類,一種是實現Runnable介面。優先採用實現Runnable介面的方法。首先,把需要共用的資料放在一個實現Runnable介面的類裡面,然後,把這個類的執行個體傳給多個Thread的構造方法。這樣,新建立的多個Thread,都共同擁有一個Runnable執行個體,共用同一份資料。如果採用繼承Thread類的方法,就只好使用static靜態成員了。如果共用的資料比較多,就需要大量的static靜態成員,令程式資料結構混亂,難以擴充。這種情況應該盡量避免。使用Runnable還有一個好處就是多線程應用對象可以繼承別的對象而不是必須繼承Thread類, 從而提高多線程對象的靈活性. 

多線程的執行過程是當一個程式(一個線程)執行的過程中, 通過調用Thread.start(), 讓當前的程式(線程)繼續執行的同時, 那個start的Thread會同時執行位於run()方法中的代碼, 多段可執行代碼交替執行的過程. 

由於多個線程擁有度大力的執行對戰和程式執行內容, 因此定義線上程方法中的局部變數不會出現資源共用的問題, 資源共用同步主要發生在成員變數上. 
按照線程體在電腦系統記憶體中的狀態不同,可以將線程分為建立、就緒、運行、睡眠、掛起和死亡等類型。這些線程狀態類型下線程的特徵為: 
  建立狀態:當利用new關鍵字建立線程對象執行個體後,它僅僅作為一個對象執行個體存在,JVM沒有為其分配CPU時間片等線程運行資源; 
  就緒狀態:在處於建立狀態的線程中調用start方法將線程的狀態轉換為就緒狀態。這時,線程已經得到除CPU時間之外的其它系統資源,只等JVM的線程調度器按照線程的優先順序對該線程進行調度,從而使該線程擁有能夠獲得CPU時間片的機會。 
  睡眠狀態:線上程運行過程中可以調用sleep方法並在方法參數中指定線程的睡眠時間將線程狀態轉換為睡眠狀態。這時,該線程在不釋放佔用資源的情況下停止運行指定的睡眠時間。時間到達後,線程重新由JVM線程調度器進行調度和管理。 
  掛起狀態:可以通過調用suspend方法將線程的狀態轉換為掛起狀態。這時,線程將釋放佔用的所有資源,由JVM調度轉入臨時儲存空間,直至應用程式調用resume方法恢複線程運行。 
  死亡狀態:當線程體運行結束或者調用線程對象的stop方法後線程將終止運行,由JVM收回線程佔用的資源。 
在Java中比較特殊的線程是被稱為守護(Daemon)線程的低層級線程。這個線程具有最低的優先順序,用於為系統中的其它對象和線程提供服務。將一個使用者線程設定為守護線程的方式是線上程對象建立之前調用線程對象的setDaemon方法。典型的守護線程例子是JVM中的系統資源自動回收線程,它始終在低層級的狀態中運行,用於即時監控和管理系統中的可回收資源。 

jvm固定了線程和記憶體之間的關係,jvm的記憶體又分為主記憶體和工作記憶體, 線程要操作的資料放在工作記憶體中, 工作記憶體的變數是主記憶體的拷貝, 線程執行完後工作記憶體中的變數還需要更新主記憶體中對應的變數.對於使用了synchornized保護的代碼對主記憶體變數將被鎖定從而保證主記憶體和工作記憶體之間的變數報紙一致性.但是使用synchonrized的代碼在效能上會帶來不小的損失 

ThreadLocal並非是一個線程的本地實現版本,它並不是一個Thread,而是threadlocal variable(線程局部變數)。也許把它命名為ThreadLocalVar更加合適。線程局部變數(ThreadLocal)其實的功用非常簡單,就是為每一個使用該變數的線程都提供一個變數值的副本,是每一個線程都可以獨立地改變自己的副本,而不會和其它線程的副本衝突。它的內部其實可以理解為僅有一個Entry的Map, key是當前的thread,而value則是要儲存的變數.因此它只有兩個方法set()將變數跟thread關聯, get()方法從map中取出變數, 還有一個就是initValue方法, 是用來產生自己的ThreadLocal的時候用的, 用來給出預設值, 在get和set方法中調用

 

JAVA基礎-02

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.