Java類別問題
1.String與StringBuilder、StringBuffer的區別
如果要操作少量的數據用=String
單線程操作字符串緩沖區下操作大量數據=StringBuilder
多線程操作字符串緩沖區下操作大量數據=StringBuffer
2.Collection類,Collection包結構,與Collections的區別
Collection是集類,包含List有序列表,Set無序集合以及Map雙列集合
Collection是集合類的上級接口,子接口主要有Set和List、Map。
Collections是針對集合類的一個幫助類,提供了操作集合的工具方法:一系列靜態方法實現對各種集合的搜索、排序、線程安全化等操作。
3.java哪些集合類是線程安全的
vector:就比arraylist多了個同步化機制(線程安全),因為效率較低,現在已經不太建議使用。在web應用中,特別是前台頁面,往往效率(頁面響應速度)是優先考慮的。
statck:堆棧類,先進後出
enumeration:枚舉,相當於迭代器
hashtable:就比hashmap多了個線程安全
4.線程安全是什麼意思
就是線程同步的意思,就是當一個程序對一個線程安全的方法或者語句進行訪問的時候,其他的不能再對他進行操作了,必須等到這次訪問結束以後才能對這個線程安全的方法進行訪問
5.九種基本數據類型的大小,以及他們的封裝類。
java提供了一組基本數據類型,包括boolean,byte,char,short,int,long,float,double,void.同時,java也提供了這些類型的封裝類,分別為Boolean,Byte,Character,Short,Integer,Long,Float,Double,Void
既然提供了基本類型,為什麼還要使用封裝類呢
比如,如果想使用List來保存數值,由於List中只能添加對象,另外,有些情況下,我們也會編寫諸如func(Objecto)的這種方法
6.Switch能否用string做參數
在Java7之前,switch只能支持byte、short、char、int或者其對應的封裝類以及Enum類型。在Java7中,String支持被加上了。
7.equals與==的區別。
1.==是一個運算符。
2.Equals則是Object對象的方法,可以.(點)出來。
8.Java的四種引用,強弱軟虛,用到的場景
1.強引用,這是使用最普遍的引用。如果一個對象具有強引用,那就類似於必不可少的生活用品,垃圾回收器絕不會回收它。當內存空間不足,Java虛擬機寧願拋出OutOfMemoryError錯誤,使程序異常終止,也不會靠隨意回收具有強引用的對象來解決內存不足問題。
2.軟引用,如果一個對象只具有軟引用,那就類似於可有可物的生活用品。如果內存空間足夠,垃圾回收器就不會回收它,如果內存空間不足了,就會回收這些對象的內存。
3.弱引用,如果一個對象只具有弱引用,那就類似於可有可物的生活用品。弱引用與軟引用的區別在於:只具有弱引用的對象擁有更短暫的生命周期。在垃圾回收器線程掃描它所管轄的內存區域的過程中,一旦發現了只具有弱引用的對象,不管當前內存空間足夠與否,都會回收它的內存。
4.虛引用,"虛引用"顧名思義,就是形同虛設,與其他幾種引用都不同,虛引用並不會決定對象的生命周期。如果一個對象僅持有虛引用,那麼它就和沒有任何引用一樣,在任何時候都可能被垃圾回收。
9.Hashcode的作用
Hashcode這個方法是用來鑒定2個對象是否相等的,hashcode方法一般用戶不會去調用,比如在hashmap中,由於key是不可以重復的,他在判斷key是不是重復的時候就判斷了hashcode這個方法,而且也用到了equals方法。
10.ArrayList、LinkedList、Vector的區別
ArrayList,Vector底層是由數組實現,LinkedList底層是由雙線鏈表實現,從底層的實現可以得出它們的性能問題,ArrayList,Vector插入速度相對較慢,查詢速度相對較快,而LinkedList插入速度較快,而查詢速度較慢。再者由於Vevtor使用了線程安全鎖,所以ArrayList的運行效率高於Vector。
11.Map、Set、List、Queue、Stack的特點與用法
Set集合類似於一個罐子,"丟進"Set集合裡的多個對象之間沒有明顯的順序。
List集合代表元素有序、可重復的集合,集合中每個元素都有其對應的順序索引。
Stack是Vector提供的一個子類,用於模擬"棧"這種數據結構(LIFO後進先出)
Queue用於模擬"隊列"這種數據結構(先進先出FIFO)。
Map用於保存具有"映射關系"的數據,因此Map集合裡保存著兩組值
12.HashMap和HashTable的區別
Hashtable是基於陳舊的Dictionary類的,HashMap是Map接口的一個實現
Hashtable的方法是線程同步的,而HashMap的方法不是。
只有HashMap可以讓你將空值作為一個表的條目的key或value
13.TreeMap、HashMap、LindedHashMap的區別
Hashmap是一個最常用的Map,它根據鍵的HashCode值存儲數據,根據鍵可以直接獲取它的值,具有很快的訪問速度,遍歷時,取得數據的順序是完全隨機的。
LinkedHashMap保存了記錄的插入順序,在用Iterator遍歷LinkedHashMap時,先得到的記錄肯定是先插入的.也可以在構造時用帶參數,按照應用次數排序
TreeMap取出來的是排序後的鍵值對。但如果您要按自然順序或自定義順序遍歷鍵,那麼TreeMap會更好。
14.trycatchfinally,try裡有return,finally還執行麼
a.不管有木有出現異常,finally塊中代碼都會執行
b.當try和catch中有return時,finally仍然會執行
c.finally是在return後面的表達式運算後執行的(此時並沒有返回運算後的值,而是先把要返回的值保存起來,管finally中的代碼怎麼樣,返回的值都不會改變,任然是之前保存的值),所以函數返回值是在finally執行前確定的
d.finally中最好不要包含return,否則程序會提前退出,返回值不是try或catch中保存的返回值
15.OOM你遇到過哪些情況
java.lang.OutOfMemoryError:Javaheapspace------>java堆內存溢出,此種情況最常見,一般由於內存洩露或者堆的大小設置不當引起。
java.lang.OutOfMemoryError:PermGenspace------>java永久代溢出,即方法區溢出了,一般出現於大量Class或者jsp頁面,或者采用cglib等反射機制的情況,因為上述情況會產生大量的Class信息存儲於方法區。
java.lang.StackOverflowError------>不會拋OOMerror,但也是比較常見的Java內存溢出。JAVA虛擬機棧溢出,一般是由於程序中存在死循環或者深度遞歸調用造成的,棧大小設置太小也會出現此種溢出。可以通過虛擬機參數-Xss來設置棧的大小。
16.Java面向對象的三個特征與含義
封裝性:它是將類的一些敏感信息隱藏在類的類部,不讓外界直接訪問到
繼承性:子類通過一種方式來接受父類所有的公有的,受保護的成員變量和成員方法
多態性:程序在運行的過程中,同一種類型在不同的條件下表現不同的結果
17.Override和Overload的含義去區別
方法的重寫Overriding和重載Overloading是Java多態性的不同表現。重寫Overriding是父類與子類之間多態性的一種表現,重載Overloading是一個類中多態性的一種表現。如果在子類中定義某方法與其父類有相同的名稱和參數,我們說該方法被重寫(Overriding)。子類的對象使用這個方法時,將調用子類中的定義,對它而言,父類中的定義如同被“屏蔽”了。如果在一個類中定義了多個同名的方法,它們或有不同的參數個數或有不同的參數類型,則稱為方法的重載(Overloading)。Overloaded的方法是可以改變返回值的類型。
18.Interface與abstract類的區別
接口可以多重繼承,抽象類不可以
接口定義方法,不給實現;而抽象類可以實現部分方法
接口中基本數據類型的數據成員,都默認為static和final,抽象類則不是
19.Staticclass與nonstaticclass的區別
內部靜態類不需要有指向外部類的引用。但非靜態內部類需要持有對外部類的引用。
非靜態內部類能夠訪問外部類的靜態和非靜態成員。靜態類不能訪問外部類的非靜態成員。他只能訪問外部類的靜態成員。一個非靜態內部類不能脫離外部類實體被創建,一個非靜態內部類可以訪問外部類的數據和方法,因為他就在外部類裡面。
20.java多態的實現原理
ⅰ.設計時多態:方法【重載】實現的多態
ⅱ.運行時多態:方法【重寫】實現的多態
21.實現多線程的兩種方法:Thread與Runable
使用Runnable接口
實際工作中,幾乎所有的多線程應用都用實現Runnable這種方式。
Runnable適合多個相同程序代碼的線程去處理同一資源的情況。把虛擬CPU(線程)同程序的代碼、數據有效的分離,較好的體現了面向對象的設計思想。
避免由於Java的單繼承特性帶來的局限性。也就是如果新建的類要繼承其他類的話,因為JAVA中不支持多繼承,就只能實現java.lang.Runnable接口。
有利於程序的健壯性,代碼能夠被多個線程共享,代碼與數據是獨立的。
繼承Thread類
不能再繼承他類了。
編寫簡單,可以直接操縱線程,無需使用Thread.currentThread()。
22.線程同步的方法:sychronized、lock、reentrantLock等
sychronized是java中最基本同步互斥的手段,可以修飾代碼塊,方法,類,在修飾代碼塊的時候需要一個reference對象作為鎖的對象,在修飾方法的時候默認是當前對象作為鎖的對象,在修飾類時候默認是當前類的Class對象作為鎖的對象.
ReentrantLock除了synchronized的功能,多了三個高級功能.
等待可中斷,在持有鎖的線程長時間不釋放鎖的時候,等待的線程可以選擇放棄等待
公平鎖,按照申請鎖的順序來一次獲得鎖稱為公平鎖.synchronized的是非公平鎖,ReentrantLock可以通過構造函數實現公平鎖
綁定多個Condition.通過多次newCondition可以獲得多個Condition對象,可以簡單的實現比較復雜的線程同步的功能.通過await(),signal();
23.Java鎖的等級
方法鎖,synchronized標記的方法
對象鎖,在方法上加了synchronized的鎖,或者synchronized(this)的代碼段
類鎖,在代碼中的方法上加了static和synchronized的鎖,因為在靜態方法中加同步鎖會鎖住整個類
24.寫出生產者消費者模式
阻塞隊列實現生產者消費者模式超級簡單,它提供開箱即用支持阻塞的方法put()和take(),開發者不需要寫困惑的wait-nofity代碼去實現通信。BlockingQueue一個接口,Java5提供了不同的現實,如ArrayBlockingQueue和LinkedBlockingQueue,兩者都是先進先出(FIFO)順序。而ArrayLinkedQueue是自然有界的,LinkedBlockingQueue可選的邊界。
25.ThreadLocal的設計理念與作用
ThreadLocal並不是一個Thread,而是Thread的局部變量,也許把它命名為ThreadLocalVariable更容易讓人理解一些
當使用ThreadLocal維護變量時,ThreadLocal為每個使用該變量的線程提供獨立的變量副本,所以每一個線程都可以獨立地改變自己的副本,而不會影響其它線程所對應的副本。
26.ThreadPool用法與優勢
線程池是為突然大量爆發的線程設計的,通過有限的幾個固定線程為大量的操作服務,減少了創建和銷毀線程所需的時間,從而提高效率。
FixedThreadPool(intnThreads):創建一個可重用的固定線程數的線程池,如果池中所有的nThreads個線程都處於活動狀態時提交任務(任務通常是Runnable或Callable對象),任務將在隊列中等待,直到池中出現可用線程
CachedThreadPool():調用此方法創建的線程池可根據需要自動調整池中線程的數量,執行任務時將重用存在先前創建的線程(如果池中存在可用線程的話).如果池中沒有可用線程,將創建一個新的線程,並將其添加到池中.池中的線程超過60秒未被使用就會被銷毀,因此長時間保持空閒的
SingleThreadExecutor():創建一個單線程的Executor.這個Executor保證按照任務提交的順序依次執行任務.
ScheduledThreadPool(intcorePoolSize):創建一個可重用的固定線程數的線程池.ScheduledExecutorService是ExecutorService的子接口,調用ScheduledExecutorService的相關方法,可以延遲或定期執行任務.
以上靜態方法均使用默認的ThreadFactory(即Executors.defaultThreadFactory()方法的返回值)創建線程,如果想要指定ThreadFactory,可調用他們的重載方法.通過指定ThreadFactory,可以定制新建線程的名稱,線程組,優先級,守護線程狀態等.
如果Executors提供的創建線程池的方法無法滿足要求,可以使用ThreadPoolExecutor類創建線程池.
27.wait()和sleep()的區別
sleep指線程被調用時,占著CPU不工作,形象地說明為“占著CPU睡覺”,此時,系統的CPU部分資源被占用,其他線程無法進入,會增加時間限制。
wait指線程處於進入等待狀態,形象地說明為“等待使用CPU”,此時線程不占用任何資源,不增加時間限制
28.foreach與正常for循環效率對比
針對列表的foreach的效率是最低,耗時是普通for循環的2倍以上。個人理解它的實現應該和iterator相似
29.JavaIO與NIO
JavaNIO和IO之間第一個最大的區別是,IO是面向流的,NIO是面向緩沖區的。JavaIO面向流意味著每次從流中讀一個或多個字節,直至讀取所有字節,它們沒有被緩存在任何地方。此外,它不能前後移動流中的數據。如果需要前後移動從流中讀取的數據,需要先將它緩存到一個緩沖區。JavaNIO的緩沖導向方法略有不同。數據讀取到一個它稍後處理的緩沖區,需要時可在緩沖區中前後移動。這就增加了處理過程中的靈活性。但是,還需要檢查是否該緩沖區中包含所有您需要處理的數據。而且,需確保當更多的數據讀入緩沖區時,不要覆蓋緩沖區裡尚未處理的數據。
30.反射的作用於原理
JAVA反射(放射)機制:Reflection,Java程序可以加載一個運行時才得知名稱的class,獲悉其完整構造(但不包括methods定義),並生成其對象實體、或對其fields設值、或喚起其methods。
用途:Java反射機制主要提供了以下功能:在運行時判斷任意一個對象所屬的類;在運行時構造任意一個類的對象;在運行時判斷任意一個類所具有的成員變量和方法;在運行時調用任意一個對象的方法;生成動態代理。
31.泛型常用特點,List
泛型,即“參數化類型”。一提到參數,最熟悉的就是定義方法時有形參,然後調用此方法時傳遞實參。那麼參數化類型怎麼理解呢?顧名思義,就是將類型由原來的具體的類型參數化,類似於方法中的變量參數,此時類型也定義成參數形式(可以稱之為類型形參),然後在使用/調用時傳入具體的類型(類型實參)
在Java的泛型接口中把List
32.解析XML的幾種方式的原理與特點:DOM、SAX
Dom解析在內存中創建一個DOM樹,該結構通常需要加載整個文檔然後才能做工作。由於它是基於信息層次的,因而DOM被認為是基於樹或基於對象的,樹在內存中是持久的,因此可以修改它以便應用程序能對數據和結構作出更改能隨機訪問文件內容,也可以修改原文件內容
SAX解析SAX處理的優點非常類似於流媒體的優點。分析能夠立即開始,而不是等待所有的數據被處理。SAX解析器采用了基於事件的模型,它在解析XML文檔的時候可以觸發一系列的事件,當發現給定的tag的時候,它可以激活一個回調方法,告訴該方法制定的標簽已經找到。而且,由於應用程序只是在讀取數據時檢查數據,因此不需要將數據存儲在內存中。這對於大型文檔來說是個巨大的優點線性解析,不能隨機訪問,也無法修改原文件
33.設計模式:單例、工廠、適配器、責任鏈、觀察者等等
34.JNI的使用
JNI作為java和操作系統間的一個直接接口,可以通過JNI使得java直接調用操作系統的資源。目前JNI只能通過c/C++實現,因為jni只是對操作系統資源調用的一個橋接過程。所以理論上在windows下只要是dll文件均可以被調用。
jni一般有以下一些應用場景
1.高性能,在一些情況下因為處理運算量非常大,為了獲取高性能,直接使用java是不能勝任的,如:一些圖形的處理
2.調用一些硬件的驅動或者一些軟件的驅動,比如調用一些外部系統接口的驅動,如:讀卡器的驅動,OCI驅動
3.需要使用大內存,遠遠超過jvm所能分配的內存,如:進程內Cache
4.調用C或者操作系統提供的服務,如:java調用搜索服務,其中搜索是由C/C++實現的,不過這個一般可以設計成更加通用的方式,比如soa的方式
所有這些場景的前提是犧牲了java代碼的可移植性,不同的os,甚至版本都需要寫不同版本的native實現
35.mysql機制
InnoDB與Myisam
Innodb支持事務功能,Myisam不支持。
Myisam的執行速度更快,性能更好。
InnoDB為行級鎖,myisam為表級鎖
MyISAM:如果執行大量的SELECT,MyISAM是更好的選擇
InnoDB:如果你的數據執行大量的INSERT或UPDATE,出於性能方面的考慮,應該使用InnoDB表
MyISAM:selectcount(*)fromtable,MyISAM只要簡單的讀出保存好的行數,注意的是,當count(*)語句包含where條件時,兩種表的操作是一樣的
InnoDB:InnoDB中不保存表的具體行數,也就是說,執行selectcount(*)fromtable時,InnoDB要掃描一遍整個表來計算有多少行
36.Servlet的生命周期、Servlet是否線程安全的
a.在servlet容器啟動時初始化。在web.xml
b.servlet在第一次被訪問時初始化。即創建唯一的servlet實例。(單例多線程下面會說)
c.當有請求訪問該servlet是,servlet容器就會創建針對於這個請求的servletRequest於servletResponse,然後servlet的service方法被調用。當容器把servlet生成的響應結果發送給客戶,容器就會銷毀request和response對象
d.容器在銷毀該實例前調用servlet的destroy方法(釋放servlet所占用的資源,如關閉流和數據庫連接),此外還會銷毀與servlet對象關聯的ServletConfig對象。
e.servlet類只創建一個實例,對於可與客戶端的並發訪問,它是線程不安全的。
f.servlet的處理方式是,每次訪問時重新起一線程執行service方法。所以要想保證servlet的線程安全,不應該在servlet中定義實例變量。
g.當然完全可以通過加鎖保證線程安全,但對於成千上萬的並發訪問,性能下降。
JVM類別問題
1.內存模型以及分區,需要詳細到每個區放什麼。
程序計數器:當前線程執行的字節碼的行號指示器,線程私有
JAVA虛擬機棧:Java方法執行的內存模型,每個Java方法的執行對應著一個棧幀的進棧和出棧的操作。
本地方法棧:類似“JAVA虛擬機棧”,但是為native方法的運行提供內存環境。
JAVA堆:對象內存分配的地方,內存垃圾回收的主要區域,所有線程共享。可分為新生代,老生代。
方法區:用於存儲已經被JVM加載的類信息、常量、靜態變量、即時編譯器編譯後的代碼等數據。Hotspot中的“永久代”。
運行時常量池:方法區的一部分,存儲常量信息,如各種字面量、符號引用等。
直接內存:並不是JVM運行時數據區的一部分,可直接訪問的內存,比如NIO會用到這部分。
2.堆裡面的分區:Eden,survivalfromto,老年代,各自的特點。
3.對象創建方法,對象的內存分配,對象的訪問定位。
4.GC的兩種判定方法:引用計數與引用鏈。
引用計數方式最基本的形態就是讓每個被管理的對象與一個引用計數器關聯在一起,該計數器記錄著該對象當前被引用的次數,每當創建一個新的引用指向該對象時其計數器就加1,每當指向該對象的引用失效時計數器就減1。當該計數器的值降到0就認為對象死亡。
Java的內存回收機制可以形象地理解為在堆空間中引入了重力場,已經加載的類的靜態變量和處於活動線程的堆棧空間的變量是這個空間的牽引對象。這裡牽引對象是指按照Java語言規范,即便沒有其它對象保持對它的引用也不能夠被回收的對象,即Java內存空間中的本原對象。當然類可能被去加載,活動線程的堆棧也是不斷變化的,牽引對象的集合也是不斷變化的。對於堆空間中的任何一個對象,如果存在一條或者多條從某個或者某幾個牽引對象到該對象的引用鏈,則就是可達對象,可以形象地理解為從牽引對象伸出的引用鏈將其拉住,避免掉到回收池中
5.GC的三種收集方法:標記清除、標記整理、復制算法的原理與特點,分別用在什麼地方,如果讓你優化收集方法,有什麼思路?
標記清除算法是最基礎的收集算法,其他收集算法都是基於這種思想。標記清除算法分為“標記”和“清除”兩個階段:首先標記出需要回收的對象,標記完成之後統一清除對象。它的主要缺點:①.標記和清除過程效率不高。②.標記清除之後會產生大量不連續的內存碎片。
標記整理,標記操作和“標記-清除”算法一致,後續操作不只是直接清理對象,而是在清理無用對象完成後讓所有存活的對象都向一端移動,並更新引用其對象的指針。主要缺點:在標記-清除的基礎上還需進行對象的移動,成本相對較高,好處則是不會產生內存碎片。
復制算法,它將可用內存容量劃分為大小相等的兩塊,每次只使用其中的一塊。當這一塊用完之後,就將還存活的對象復制到另外一塊上面,然後在把已使用過的內存空間一次理掉。這樣使得每次都是對其中的一塊進行內存回收,不會產生碎片等情況,只要移動堆訂的指針,按順序分配內存即可,實現簡單,運行高效。主要缺點:內存縮小為原來的一半。
6.GC收集器有哪些?CMS收集器與G1收集器的特點。
單線程收集器,使用單線程去完成所有的gc工作,沒有線程間的通信,這種方式會相對高效
並行收集器,使用多線程的方式,利用多CUP來提高GC的效率,主要以到達一定的吞吐量為目標
並發收集器,使用多線程的方式,利用多CUP來提高GC的效率,並發完成大部分工作,使得gcpause短
G1具備如下特點:並行與並發、分代收集、空間整合、可預測的停頓
CMS具備了並發收集、低停頓的優點、CMS收集器對CPU資源非常敏感、CMS收集器無法處理浮動垃圾、收集結束時會產生大量空間碎片
7.MinorGC與FullGC分別在什麼時候發生?
MinorGC:通常是指對新生代的回收。指發生在新生代的垃圾收集動作,因為Java對象大多都具備朝生夕滅的特性,所以MinorGC非常頻繁,一般回收速度也比較快
MajorGC:通常是指對年老代的回收。
FullGC:MajorGC除並發gc外均需對整個堆進行掃描和回收。指發生在老年代的GC,出現了MajorGC,經常會伴隨至少一次的MinorGC(但非絕對的,在ParallelScavenge收集器的收集策略裡就有直接進行MajorGC的策略選擇過程)。MajorGC的速度一般會比MinorGC慢10倍以上。
8.幾種常用的內存調試工具:jmap、jstack、jconsole。
jmap(linux下特有,也是很常用的一個命令)觀察運行中的jvm物理內存的占用情況。
參數如下:
-heap:打印jvmheap的情況
-histo:打印jvmheap的直方圖。其輸出信息包括類名,對象數量,對象占用大小。
-histo:live:同上,但是只答應存活對象的情況
-permstat:打印permanentgenerationheap情況
jstack(linux下特有)可以觀察到jvm中當前所有線程的運行情況和線程當前狀態
jconsole一個圖形化界面,可以觀察到java進程的gc,class,內存等信息
jstat最後要重點介紹下這個命令。這是jdk命令中比較重要,也是相當實用的一個命令,可以觀察到classloader,compiler,gc相關信息
具體參數如下:
-class:統計classloader行為信息
-compile:統計編譯行為信息
-gc:統計jdkgc時heap信息
-gccapacity:統計不同的generations(不知道怎麼翻譯好,包括新生區,老年區,permanent區)相應的heap容量情況
-gccause:統計gc的情況,(同-gcutil)和引起gc的事件
-gcnew:統計gc時,新生代的情況
-gcnewcapacity:統計gc時,新生代heap容量
-gcold:統計gc時,老年區的情況
-gcoldcapacity:統計gc時,老年區heap容量
-gcpermcapacity:統計gc時,permanent區heap容量
-gcutil:統計gc時,heap情況
-printcompilation:不知道干什麼的,一直沒用過。
9.類加載的五個過程:加載、驗證、准備、解析、初始化。
“加載”(Loading)階段是“類加載”(ClassLoading)過程的第一個階段,在此階段,虛擬機需要完成以下三件事情:
1、通過一個類的全限定名來獲取定義此類的二進制字節流。
2、將這個字節流所代表的靜態存儲結構轉化為方法區的運行時數據結構。
3、在Java堆中生成一個代表這個類的java.lang.Class對象,作為方法區這些數據的訪問入口。
驗證是連接階段的第一步,這一階段的目的是為了確保Class文件的字節流中包含的信息符合當前虛擬機的要求,並且不會危害虛擬機自身的安全。
准備階段是為類的靜態變量分配內存並將其初始化為默認值,這些內存都將在方法區中進行分配。准備階段不分配類中的實例變量的內存,實例變量將會在對象實例化時隨著對象一起分配在Java堆中。
解析階段是虛擬機將常量池內的符號引用替換為直接引用的過程。
類初始化是類加載過程的最後一步,前面的類加載過程,除了在加載階段用戶應用程序可以通過自定義類加載器參與之外,其余動作完全由虛擬機主導和控制。到了初始化階段,才真正開始執行類中定義的Java程序代碼。
10.雙親委派模型:BootstrapClassLoader、ExtensionClassLoader、ApplicationClassLoader。
1、啟動類加載器,負責將存放在
2、擴展類加載器:負責加載
3、應用程序類加載器:負責加載用戶路徑上所指定的類庫,開發者可以直接使用這個類加載器,也是默認的類加載器。
三種加載器的關系:啟動類加載器->擴展類加載器->應用程序類加載器->自定義類加載器。
這種關系即為類加載器的雙親委派模型。其要求除啟動類加載器外,其余的類加載器都應當有自己的父類加載器。這裡類加載器之間的父子關系一般不以繼承關系實現,而是用組合的方式來復用父類的代碼。
雙親委派模型的工作過程:如果一個類加載器接收到了類加載的請求,它首先把這個請求委托給他的父類加載器去完成,每個層次的類加載器都是如此,因此所有的加載請求都應該傳送到頂層的啟動類加載器中,只有當父加載器反饋自己無法完成這個加載請求(它在搜索范圍中沒有找到所需的類)時,子加載器才會嘗試自己去加載。
好處:java類隨著它的類加載器一起具備了一種帶有優先級的層次關系。例如類java.lang.Object,它存放在rt.jar中,無論哪個類加載器要加載這個類,最終都會委派給啟動類加載器進行加載,因此Object類在程序的各種類加載器環境中都是同一個類。相反,如果用戶自己寫了一個名為java.lang.Object的類,並放在程序的Classpath中,那系統中將會出現多個不同的Object類,java類型體系中最基礎的行為也無法保證,應用程序也會變得一片混亂。
實現:在java.lang.ClassLoader的loadClass()方法中,先檢查是否已經被加載過,若沒有加載則調用父類加載器的loadClass()方法,若父加載器為空則默認使用啟動類加載器作為父加載器。如果父加載失敗,則拋出ClassNotFoundException異常後,再調用自己的findClass()方法進行加載。
11.分派:靜態分派與動態分派。
靜態分派與重載有關,虛擬機在重載時是通過參數的靜態類型,而不是運行時的實際類型作為判定依據的;靜態類型在編譯期是可知的;
動態分派與重寫(Override)相關,invokevirtual(調用實例方法)指令執行的第一步就是在運行期確定接收者的實際類型,根據實際類型進行方法調用;