Java常问面试题
知識(shí)點(diǎn)1:
&運(yùn)算符:兩個(gè)數(shù)都轉(zhuǎn)為二進(jìn)制,然后從兩個(gè)數(shù)的最高位進(jìn)行與運(yùn)算,兩個(gè)都為真(1),結(jié)果才為真(1),否則為假(0)13:01101 17:10001結(jié)果:00001,既為1。
補(bǔ)充:
與運(yùn)算 (“ & ”)
參與運(yùn)算的兩個(gè)數(shù)據(jù),按照二進(jìn)制位進(jìn)行“與運(yùn)算”。
運(yùn)算規(guī)則:0&0=0; 0&1=0; 1&0=0; 1&1=1;
即:兩位同時(shí)為1,則值為1。否則為0
例如:6 & 7 = 110 & 111 = 110 = 6
8 & 3 = 1000 & 11 = 0 = 0
或運(yùn)算 (“ | ”)
參與運(yùn)算的兩個(gè)數(shù)據(jù),按照二進(jìn)制位進(jìn)行“或運(yùn)算”。
運(yùn)算規(guī)則:0&0=0; 0&1=1; 1&0=1; 1&1=1;
即:參與運(yùn)算的兩個(gè)數(shù)據(jù)只要有一個(gè)值為1 那么值為1
例如:12 | 5 = 1100 | 101 = 1101 = 13
4 | 5 = 100 | 101 = 101 = 5
異或運(yùn)算 (“ ^ ”)
參與 運(yùn)算的兩個(gè)數(shù)據(jù),按照二進(jìn)制位進(jìn)行“異或運(yùn)算”。
運(yùn)算規(guī)則: 0&0=0; 0&1=1; 1&0=1; 1&1=0;
即:參加運(yùn)算的兩個(gè)對(duì)象,如果兩個(gè)相應(yīng)位為“異”(值不同),則該位結(jié)果為1,否則為0。
例如:9^5可寫成算式如下: 00001001^00000101=00001100 (十進(jìn)制為12)可見9^5=12
知識(shí)點(diǎn)2:
包的作用
1、把功能相似或相關(guān)的類或接口組織在同一個(gè)包中,方便類的查找和使用。
2、如同文件夾一樣,包也采用了樹形目錄的存儲(chǔ)方式。同一個(gè)包中的類名字是不同的,不同的包中的類的名字是可以相同的,當(dāng)同時(shí)調(diào)用兩個(gè)不同包中相同類名的類時(shí),應(yīng)該加上包名加以區(qū)別。因此,包可以避免名字沖突。
3、包也限定了訪問(wèn)權(quán)限,擁有包訪問(wèn)權(quán)限的類才能訪問(wèn)某個(gè)包中的類。
Java 使用包(package)這種機(jī)制是為了防止命名沖突,訪問(wèn)控制,提供搜索和定位類(class)、接口、枚舉(enumerations)和注釋(annotation)等。
知識(shí)點(diǎn)3:
把常用的tar解壓命令總結(jié)下,當(dāng)作備忘:
tar
-c: 建立壓縮檔案
-x:解壓
-t:查看內(nèi)容
-r:向壓縮歸檔文件末尾追加文件
-u:更新原壓縮包中的文件
知識(shí)點(diǎn)4:
i++和++i命令的區(qū)別有:
1、賦值順序不同
++ i 是先加后賦值;i ++ 是先賦值后加;++i和i++都是分兩步完成的。
因?yàn)?#43;+i 是后面一步才賦值的,所以它能夠當(dāng)作一個(gè)變量進(jìn)行級(jí)聯(lián)賦值,++i = a =b,即 ++i 是一個(gè)左值;i++ 的后面一步是自增,不是左值。
形象的理解可以是i++先做別的事,再自己加1,++i先自己加1,再做別的事情。
2、效率不同
比如i=3,b=i++就是說(shuō)b=3,完成之后讓i變成4,b=++i就是先讓i++變成4,然后b=4,其中++i比i++效率要高些。一般來(lái)說(shuō)在循環(huán)域里面,這兩者并沒(méi)有什么很大的區(qū)別,但是要注意其生存周期,以及i值在程序流中的變化。
3、 i++ 不能作為左值,而++i 可以。
知識(shí)點(diǎn)5:
shell中的特殊變量: 變量名 含義 $0 shell或shell腳本的名字 $* 以一對(duì)雙引號(hào)給出參數(shù)列表 $@ 將各個(gè)參數(shù)分別加雙引號(hào)返回 $# 參數(shù)的個(gè)數(shù) $_ 代表上一個(gè)命令的最后一個(gè)參數(shù) $$ 代表所在命令的PID $! 代表最后執(zhí)行的后臺(tái)命令的PID $? 代表上一個(gè)命令執(zhí)行后的退出狀態(tài) echo $? 如果返回值是0,就是執(zhí)行成功;如果是返回值是0以外的值,就是失敗。知識(shí)點(diǎn)6:
Stack 棧 先進(jìn)后出
Queue 隊(duì)列 先進(jìn)先出
List 集合 有下標(biāo) 存的順序與取得的順序一致
LinedList 類 是Queue的子類 存的順序與取得的順序一致
知識(shí)點(diǎn)7:
Java只支持單繼承,實(shí)現(xiàn)多重繼承三種方式:
(1)直接實(shí)現(xiàn)多個(gè)接口
(2)擴(kuò)展(extends)一個(gè)類然后實(shí)現(xiàn)一個(gè)或多個(gè)接口
(3)通過(guò)內(nèi)部類去繼承其他類
知識(shí)點(diǎn)8:
flush()函數(shù)強(qiáng)制將緩沖區(qū)中的字符流、字節(jié)流等輸出,目的是如果輸出流輸出到緩沖區(qū)完成后,緩沖區(qū)并沒(méi)有填滿,那么緩沖區(qū)將會(huì)一直等待被填滿。所以在關(guān)閉輸出流之前要調(diào)用flush()。
線程圖
知識(shí)點(diǎn)9:
數(shù)據(jù)段 :數(shù)據(jù)段(data segment)通常是指用來(lái)存放程序中 已初始化 的 全局變量 的一塊內(nèi)存區(qū)域。數(shù)據(jù)段屬于靜態(tài)內(nèi)存分配。
代碼段: 代碼段(code segment/text segment)通常是指用來(lái)存放 程序執(zhí)行代碼 的一塊內(nèi)存區(qū)域。這部分區(qū)域的大小在程序運(yùn)行前就已經(jīng)確定,并且內(nèi)存區(qū)域通常屬于 只讀 , 某些架構(gòu)也允許代碼段為可寫,即允許修改程序。在代碼段中,也有可能包含一些 只讀的常數(shù)變量 ,例如字符串常量等。程序段為程序代碼在內(nèi)存中的映射.一個(gè)程序可以在內(nèi)存中多有個(gè)副本.
堆(heap) :堆是用于存放進(jìn)程運(yùn)行中被動(dòng)態(tài)分配的內(nèi)存段,它的大小并不固定,可動(dòng)態(tài)擴(kuò)張或縮減。當(dāng)進(jìn)程調(diào)用malloc/free等函數(shù)分配內(nèi)存時(shí),新分配的內(nèi)存就被動(dòng)態(tài)添加到堆上(堆被擴(kuò)張)/釋放的內(nèi)存從堆中被剔除(堆被縮減)
棧(stack) :棧又稱堆棧, 存放程序的 局部變量 (但不包括static聲明的變量, static 意味著 在數(shù)據(jù)段中 存放變量)。除此以外,在函數(shù)被調(diào)用時(shí),棧用來(lái)傳遞參數(shù)和返回值。由于棧的先進(jìn)先出特點(diǎn),所以棧特別方便用來(lái)保存/恢復(fù)調(diào)用現(xiàn)場(chǎng)。儲(chǔ)動(dòng)態(tài)內(nèi)存分配,需要程序員手工分配,手工釋放
知識(shí)點(diǎn)10:
大多數(shù) JVM 將內(nèi)存區(qū)域劃分為 Method Area(Non-Heap)(方法區(qū)) ,Heap(堆) , Program Counter Register(程序計(jì)數(shù)器) , VM Stack(虛擬機(jī)棧,也有翻譯成JAVA 方法棧的),Native Method Stack ( 本地方法棧 ),其中Method Area 和 Heap 是線程共享的 ,VM Stack,Native Method Stack 和Program Counter Register 是非線程共享的。為什么分為 線程共享和非線程共享的呢?請(qǐng)繼續(xù)往下看。
首先我們熟悉一下一個(gè)一般性的 Java 程序的工作過(guò)程。一個(gè) Java 源程序文件,會(huì)被編譯為字節(jié)碼文件(以 class 為擴(kuò)展名),每個(gè)java程序都需要運(yùn)行在自己的JVM上,然后告知 JVM 程序的運(yùn)行入口,再被 JVM 通過(guò)字節(jié)碼解釋器加載運(yùn)行。那么程序開始運(yùn)行后,都是如何涉及到各內(nèi)存區(qū)域的呢?
概括地說(shuō)來(lái),JVM初始運(yùn)行的時(shí)候都會(huì)分配好 Method Area(方法區(qū)) 和Heap(堆) ,而JVM 每遇到一個(gè)線程,就為其分配一個(gè) Program Counter Register(程序計(jì)數(shù)器) , VM Stack(虛擬機(jī)棧)和Native Method Stack (本地方法棧), 當(dāng)線程終止時(shí),三者(虛擬機(jī)棧,本地方法棧和程序計(jì)數(shù)器)所占用的內(nèi)存空間也會(huì)被釋放掉。這也是為什么我把內(nèi)存區(qū)域分為線程共享和非線程共享的原因,非線程共享的那三個(gè)區(qū)域的生命周期與所屬線程相同,而線程共享的區(qū)域與JAVA程序運(yùn)行的生命周期相同,所以這也是系統(tǒng)垃圾回收的場(chǎng)所只發(fā)生在線程共享的區(qū)域(實(shí)際上對(duì)大部分虛擬機(jī)來(lái)說(shuō)知發(fā)生在Heap上)的原因。
知識(shí)點(diǎn)11:
PROPAGATION_SUPPORTS 從翻譯上看--僅僅支持事務(wù),沒(méi)有就沒(méi)有唄 PROPAGATION_REQUIRED 支持事務(wù),如果有,就用著,沒(méi)有的話就自己弄一個(gè) PROPAGATION_REQUIRES_NEW 比較有個(gè)性,不管有沒(méi)有,都自己弄一個(gè)(把原來(lái)的放在一邊) PROPAGATION_MANDATORY 強(qiáng)制必須要有事務(wù),要是沒(méi)有,就不開心了(拋出異常) PROPAGATION_NOT_SUPPORTED 不支持事務(wù),有就掛起來(lái) PROPAGATION_NEVER 此處事務(wù)與狗不得入內(nèi),如果有,就趕出去(拋出異常)知識(shí)點(diǎn)12:
Servlet的生命周期分為5個(gè)階段:加載、創(chuàng)建、初始化、處理客戶請(qǐng)求、卸載。
(1)加載:容器通過(guò)類加載器使用servlet類對(duì)應(yīng)的文件加載servlet
(2)創(chuàng)建:通過(guò)調(diào)用servlet構(gòu)造函數(shù)創(chuàng)建一個(gè)servlet對(duì)象
(3)初始化:調(diào)用init方法初始化
(4)處理客戶請(qǐng)求:每當(dāng)有一個(gè)客戶請(qǐng)求,容器會(huì)創(chuàng)建一個(gè)線程來(lái)處理客戶請(qǐng)求
(5)卸載:調(diào)用destroy方法讓servlet自己釋放其占用的資源
servlet在多線程下其本身并不是線程安全的。
如果在類中定義成員變量,而在service中根據(jù)不同的線程對(duì)該成員變量進(jìn)行更改,那么在并發(fā)的時(shí)候就會(huì)引起錯(cuò)誤。最好是在方法中,定義局部變量,而不是類變量或者對(duì)象的成員變量。由于方法中的局部變量是在棧中,彼此各自都擁有獨(dú)立的運(yùn)行空間而不會(huì)互相干擾,因此才做到線程安全。
知識(shí)點(diǎn)13:
redirect:請(qǐng)求重定向:客戶端行為,本質(zhì)上為2次請(qǐng)求,地址欄改變,前一次請(qǐng)求對(duì)象消失。舉例:你去銀行辦事(forward.jsp),結(jié)果告訴你少帶了東西,你得先去局辦(index.html)臨時(shí)身份證,這時(shí)你就會(huì)走出銀行,自己前往***局,地址欄變?yōu)閕ndex.html.
forward:請(qǐng)求轉(zhuǎn)發(fā):服務(wù)器行為,地址欄不變。舉例:你把錢包落在出租車上,你去警察局(forward.jsp)報(bào)案,警察局說(shuō)錢包落在某某公司的出租車上(index.html),這時(shí)你不用親自去找某某公司的出租車,警察局讓出租車自己給你送來(lái),你只要在警察局等就行。所以地址欄不變,依然為forward.jsp
知識(shí)點(diǎn)14:
-Xmx10240m:代表最大堆
-Xms10240m:代表最小堆
-Xmn5120m:代表新生代
-XXSurvivorRatio=3:代表Eden:Survivor = 3 根據(jù)Generation-Collection算法(目前大部分JVM采用的算法),一般根據(jù)對(duì)象的生存周期將堆內(nèi)存分為若干不同的區(qū)域,一般情況將新生代分為Eden ,兩塊Survivor; 計(jì)算Survivor大小, Eden:Survivor = 3,總大小為5120,3x+x+x=5120 x=1024
新生代大部分要回收,采用Copying算法,快!
老年代 大部分不需要回收,采用Mark-Compact算法
知識(shí)點(diǎn)15:
**選擇排序:**每次從數(shù)組中選出一個(gè)最小數(shù)(最大數(shù))放到數(shù)組最前面,存放在序列的起始位置,直到全部待排序的數(shù)據(jù)元素排完。
**希爾排序:**設(shè)置增量分割數(shù)組,逐步進(jìn)行直接插入排序,增量逐趟減少,并最后使得整個(gè)數(shù)組基本有序,再對(duì)整體進(jìn)行直接插入排序。
**插入排序:**構(gòu)建有序序列,未排序數(shù)據(jù)依次從已排序數(shù)據(jù)按從后往前比較,插入到合適的位置。
**歸并排序:**把序列分成兩個(gè)長(zhǎng)度為n/2的子序列,對(duì)這兩個(gè)子序列分別歸并排序(循環(huán)將兩個(gè)數(shù)組的第一個(gè)值比較,并彈出第一個(gè)值, 直到數(shù)組長(zhǎng)度都不存在),將兩個(gè)排序好的子序列合并成一個(gè)最終的排序序列
知識(shí)點(diǎn)16:
信號(hào)量的P、V操作,P表示申請(qǐng)一個(gè)資源,每次P操作使信號(hào)量減1,V是釋放一個(gè)資源,每次V操作使信號(hào)量加1.信號(hào)量表示的是當(dāng)前可用的資源個(gè)數(shù),當(dāng)信號(hào)量為負(fù)時(shí),申請(qǐng)資源的進(jìn)程就只能等待了.所以,信號(hào)量是負(fù)的多少,就表明有多少個(gè)進(jìn)程申請(qǐng)了資源但無(wú)資源可用只能處于等待狀態(tài).
NIO是同步非阻塞,通過(guò)選擇器Selector監(jiān)聽多個(gè)通道(Channel),響應(yīng)其感興趣的事件(每個(gè)通道在選擇器上注冊(cè)的事件).(Reactor模式)
知識(shí)點(diǎn)17:
1.數(shù)據(jù)庫(kù)的事務(wù)交給JDBC的Connection去處理.
? connection.autoCommit(false); //相當(dāng)于在數(shù)據(jù)庫(kù)端開啟事務(wù) start transaction;
? connection.setTransactioIsolation(isolation); //設(shè)置隔離級(jí)別;
? connection.commit(); //提交事務(wù)
? connection.rollback(savePoint);//回滾
2.JTA是指Java Transaction API,JTA允許應(yīng)用程序執(zhí)行分布式事務(wù)處理.
? 分布式事務(wù)(distributed transaction)包括一個(gè)事務(wù)管理器(transaction manager)和一個(gè)或多個(gè)資源管理器(resource manager).
知識(shí)點(diǎn)18:
1.抽象方法只能定義在抽象類中,抽象方法和抽象類必須由abstract修飾,abstract關(guān)鍵字只能描述類和方法,不能描述變量。抽象方法只定義方法聲明,不定義方法實(shí)現(xiàn)。抽象類不可以被實(shí)例化(創(chuàng)建對(duì)象),只有通過(guò)子類繼承抽象類并覆蓋抽象類中的所有抽象方法后,該子類才可以被實(shí)例化,否則該子類還是一個(gè)抽象類。抽象類中有構(gòu)造函數(shù)用于給子類對(duì)象進(jìn)行初始化,同時(shí)抽象類中可以含有非抽象方法。abstract關(guān)鍵字不可以與final,private,static關(guān)鍵字共存,因?yàn)楸籪inal修飾的方法不可以被重寫,意味著子類不可以重寫該方法,如果abstract和final共同修飾父類中的方法,子類要實(shí)現(xiàn)抽象方法(abstract的作用),而final又不讓該方法重寫,這相互矛盾。如果private和abstract共同修飾父類中的方法,private修飾則該方法不可以被子類訪問(wèn),但是abstract修飾需要子類去實(shí)現(xiàn),兩者產(chǎn)生矛盾。如果static和abstract共同修飾父類中的方法,static表示是靜態(tài)的方法,隨著類的加載而加載,則該方法不需要在子類中去實(shí)現(xiàn),這與abstract關(guān)鍵字矛盾。 2.static用于修飾成員變量和成員函數(shù),想要實(shí)現(xiàn)對(duì)象中的共性數(shù)據(jù)的對(duì)象共享,可以將這個(gè)數(shù)據(jù)進(jìn)行靜態(tài)修飾,被靜態(tài)修飾的成員可以直接被類名調(diào)用,靜態(tài)隨著類的加載而加載,而且優(yōu)先于對(duì)象存在。靜態(tài)方法只能訪問(wèn)靜態(tài)成員(靜態(tài)方法和靜態(tài)變量),不可以訪問(wèn)非靜態(tài)成員,這是因?yàn)殪o態(tài)方法加載時(shí),優(yōu)先于對(duì)象存在,所以沒(méi)有辦法訪問(wèn)對(duì)象中的成員。靜態(tài)方法中不能使用this和super關(guān)鍵字,因?yàn)閠his代表本類對(duì)象,super代表父類對(duì)象,而靜態(tài)時(shí),有可能沒(méi)有對(duì)象存在,所以this和super無(wú)法使用。 3.final關(guān)鍵字可以修飾類,方法,變量(成員變量?jī)?nèi),局部變量,靜態(tài)變量),被final修飾的類是一個(gè)最終類,不可以被繼承,被final修飾的方法是一個(gè)最終方法,不可以被覆蓋,但是可以被繼承。被final修飾的變量只能是一個(gè)常量,只能賦值一次。內(nèi)部類被定義在類中的局部位置上時(shí),只能訪問(wèn)局部被final修飾的局部變量。
知識(shí)點(diǎn)19:
JDK中提供了三個(gè)ClassLoader,根據(jù)層級(jí)從高到低為:
JVM加載類的實(shí)現(xiàn)方式,我們稱為 雙親委托模型:
如果一個(gè)類加載器收到了類加載的請(qǐng)求,他首先不會(huì)自己去嘗試加載這個(gè)類,而是把這個(gè)請(qǐng)求委托給自己的父加載器,每一層的類加載器都是如此,因此所有的類加載請(qǐng)求最終都應(yīng)該傳送到頂層的Bootstrap ClassLoader中,只有當(dāng)父加載器反饋?zhàn)约簾o(wú)法完成加載請(qǐng)求時(shí),子加載器才會(huì)嘗試自己加載。
雙親委托模型的重要用途是為了解決類載入過(guò)程中的安全性問(wèn)題。
假設(shè)有一個(gè)開發(fā)者自己編寫了一個(gè)名為Java.lang.Object的類,想借此欺騙JVM。現(xiàn)在他要使用自定義ClassLoader來(lái)加載自己編寫的java.lang.Object類。然而幸運(yùn)的是,雙親委托模型不會(huì)讓他成功。因?yàn)镴VM會(huì)優(yōu)先在Bootstrap ClassLoader的路徑下找到java.lang.Object類,并載入它
知識(shí)點(diǎn)20:
final
如果一個(gè)類被聲明為final,意味著它不能再派生出新的子類,不能作為父類被繼承。因此一個(gè)類不能既被聲明為 abstract的,又被聲明為final的。將變量或方法聲明為final,可以保證它們?cè)谑褂弥胁槐桓淖?。被聲明為final的變量必須在new一個(gè)對(duì)象時(shí)初始化(即只能在聲明變量或構(gòu)造器或代碼塊內(nèi)初始化),而在以后的引用中只能讀取,不可修改。被聲明為final的方法也同樣只能使用,不能覆蓋(重寫)。
finally
在異常處理時(shí)提供 finally 塊來(lái)執(zhí)行任何清除操作。如果拋出一個(gè)異常,那么相匹配的 catch 子句就會(huì)執(zhí)行,然后控制就會(huì)進(jìn)入 finally 塊(如果有的話)。
finalize
方法名。Java 技術(shù)允許使用 finalize() 方法在垃圾收集器將對(duì)象從內(nèi)存中清除出去之前做必要的清理工作。這個(gè)方法是由垃圾收集器在確定這個(gè)對(duì)象沒(méi)有被引用時(shí)對(duì)這個(gè)對(duì)象調(diào)用的。它是在 Object 類中定義的,因此所有的類都繼承了它。子類覆蓋 finalize() 方法以整理系統(tǒng)資源或者執(zhí)行其他清理工作。finalize() 方法是在垃圾收集器刪除對(duì)象之前對(duì)這個(gè)對(duì)象調(diào)用的。注意:finalize不一定被jvm調(diào)用,只有當(dāng)垃圾回收器要清除垃圾時(shí)才被調(diào)用。
知識(shí)點(diǎn)21:
/*** Definition of TreeNode:* public class TreeNode {* public int val;* public TreeNode left, right;* public TreeNode(int val) {* this.val = val;* this.left = this.right = null;* }* }*/public class Solution {/*** @param root: A Tree* @return: Preorder in ArrayList which contains node values.*//*** 先序遍歷二叉樹*/public List<Integer> preorderTraversal(TreeNode root) {// write your code hereArrayList<Integer> list = new ArrayList<Integer>();if(root == null){return list;}else{list.add(root.val);}if(root.left != null){list.addAll(preorderTraversal(root.left));}if(root.right != null){list.addAll(preorderTraversal(root.right));}return list;} }知識(shí)點(diǎn)22:
初始化過(guò)程:
1. 初始化父類中的靜態(tài)成員變量和靜態(tài)代碼塊 ;
2. 初始化子類中的靜態(tài)成員變量和靜態(tài)代碼塊 ;
3.初始化父類的普通成員變量和代碼塊,再執(zhí)行父類的構(gòu)造方法;
4.初始化子類的普通成員變量和代碼塊,再執(zhí)行子類的構(gòu)造方法;
(1)初始化父類的普通成員變量和代碼塊,執(zhí)行 Y y=new Y(); 輸出Y
(2)再執(zhí)行父類的構(gòu)造方法;輸出X
(3) 初始化子類的普通成員變量和代碼塊,執(zhí)行 Y y=new Y(); 輸出Y
(4)再執(zhí)行子類的構(gòu)造方法;輸出Z
所以輸出YXYZ
知識(shí)點(diǎn)23:
按照流是否直接與特定的地方(如磁盤、內(nèi)存、設(shè)備等)相連,分為節(jié)點(diǎn)流和處理流兩類。
- 節(jié)點(diǎn)流:可以從或向一個(gè)特定的地方(節(jié)點(diǎn))讀寫數(shù)據(jù)。如FileReader.
- 處理流:是對(duì)一個(gè)已存在的流的連接和封裝,通過(guò)所封裝的流的功能調(diào)用實(shí)現(xiàn)數(shù)據(jù)讀寫。如BufferedReader.處理流的構(gòu)造方法總是要帶一個(gè)其他的流對(duì)象做參數(shù)。一個(gè)流對(duì)象經(jīng)過(guò)其他流的多次包裝,稱為流的鏈接。
JAVA常用的節(jié)點(diǎn)流:
- 文 件 FileInputStream FileOutputStrean FileReader FileWriter 文件進(jìn)行處理的節(jié)點(diǎn)流。
- 字符串 StringReader StringWriter 對(duì)字符串進(jìn)行處理的節(jié)點(diǎn)流。
- 數(shù) 組 ByteArrayInputStream ByteArrayOutputStreamCharArrayReader CharArrayWriter 對(duì)數(shù)組進(jìn)行處理的節(jié)點(diǎn)流(對(duì)應(yīng)的不再是文件,而是內(nèi)存中的一個(gè)數(shù)組)。
- 管 道 PipedInputStream PipedOutputStream PipedReaderPipedWriter對(duì)管道進(jìn)行處理的節(jié)點(diǎn)流。
常用處理流(關(guān)閉處理流使用關(guān)閉里面的節(jié)點(diǎn)流)
-
緩沖流:BufferedInputStrean BufferedOutputStream BufferedReader BufferedWriter 增加緩沖功能,避免頻繁讀寫硬盤。
-
轉(zhuǎn)換流:InputStreamReader OutputStreamReader 實(shí)現(xiàn)字節(jié)流和字符流之間的轉(zhuǎn)換。
-
數(shù)據(jù)流 DataInputStream DataOutputStream 等-提供將基礎(chǔ)數(shù)據(jù)類型寫入到文件中,或者讀取出來(lái).
流的關(guān)閉順序
知識(shí)點(diǎn)24:
1、LinkedBlockingQueue:基于鏈接節(jié)點(diǎn)的可選限定的blocking queue 。 這個(gè)隊(duì)列排列元素FIFO(先進(jìn)先出)。 隊(duì)列的頭部是隊(duì)列中最長(zhǎng)的元素。 隊(duì)列的尾部是隊(duì)列中最短時(shí)間的元素。 新元素插入隊(duì)列的尾部,隊(duì)列檢索操作獲取隊(duì)列頭部的元素。 鏈接隊(duì)列通常具有比基于陣列的隊(duì)列更高的吞吐量,但在大多數(shù)并發(fā)應(yīng)用程序中的可預(yù)測(cè)性能較低。
blocking queue說(shuō)明:不接受null元素;可能是容量有限的;實(shí)現(xiàn)被設(shè)計(jì)為主要用于生產(chǎn)者 - 消費(fèi)者隊(duì)列;不支持任何類型的“關(guān)閉”或“關(guān)閉”操作,表示不再添加項(xiàng)目實(shí)現(xiàn)是線程安全的;
2、PriorityQueue:
2.1、基于優(yōu)先級(jí)堆的無(wú)限優(yōu)先級(jí)queue 。 優(yōu)先級(jí)隊(duì)列的元素根據(jù)它們的有序natural ordering ,或由一個(gè)Comparator在隊(duì)列構(gòu)造的時(shí)候提供,這取決于所使用的構(gòu)造方法。 優(yōu)先隊(duì)列不允許null元素。 依靠自然排序的優(yōu)先級(jí)隊(duì)列也不允許插入不可比較的對(duì)象(這樣做可能導(dǎo)致ClassCastException )。
2.2、該隊(duì)列的頭部是相對(duì)于指定順序的最小元素。 如果多個(gè)元素被綁定到最小值,那么頭就是這些元素之一 - 關(guān)系被任意破壞。 隊(duì)列檢索操作poll , remove , peek和element訪問(wèn)在隊(duì)列的頭部的元件。
2.3、優(yōu)先級(jí)隊(duì)列是無(wú)限制的,但是具有管理用于在隊(duì)列上存儲(chǔ)元素的數(shù)組的大小的內(nèi)部容量 。 它始終至少與隊(duì)列大小一樣大。 當(dāng)元素被添加到優(yōu)先級(jí)隊(duì)列中時(shí),其容量會(huì)自動(dòng)增長(zhǎng)。 沒(méi)有規(guī)定增長(zhǎng)政策的細(xì)節(jié)。
2.4、該類及其迭代器實(shí)現(xiàn)Collection和Iterator接口的所有可選方法。 方法iterator()中提供的迭代器不能保證以任何特定順序遍歷優(yōu)先級(jí)隊(duì)列的元素。 如果需要有序遍歷,請(qǐng)考慮使用Arrays.sort(pq.toArray()) 。
2.5、請(qǐng)注意,此實(shí)現(xiàn)不同步。 如果任何線程修改隊(duì)列,多線程不應(yīng)同時(shí)訪問(wèn)PriorityQueue實(shí)例。 而是使用線程安全的PriorityBlockingQueue類。
實(shí)現(xiàn)注意事項(xiàng):此實(shí)現(xiàn)提供了O(log(n))的時(shí)間入隊(duì)和出隊(duì)方法( offer , poll , remove()和add ); remove(Object)和contains(Object)方法的線性時(shí)間; 和恒定時(shí)間檢索方法( peek , element和size )。
3、ConcurrentLinkedQueue:基于鏈接節(jié)點(diǎn)的***并發(fā)deque(deque是雙端隊(duì)列) 。 并發(fā)插入,刪除和訪問(wèn)操作可以跨多個(gè)線程安全執(zhí)行。 A ConcurrentLinkedDeque是許多線程將共享對(duì)公共集合的訪問(wèn)的適當(dāng)選擇。像大多數(shù)其他并發(fā)集合實(shí)現(xiàn)一樣,此類不允許使用null元素。
知識(shí)點(diǎn)25:
ThreadLocal類用來(lái)提供線程內(nèi)部的局部變量。這種變量在多線程環(huán)境下訪問(wèn)(通過(guò)get或set方法訪問(wèn))時(shí)能保證各個(gè)線程里的變量相對(duì)獨(dú)立于其他線程內(nèi)的變量。ThreadLocal實(shí)例通常來(lái)說(shuō)都是private static類型的,用于關(guān)聯(lián)線程和線程的上下文。 可以總結(jié)為一句話:ThreadLocal的作用是提供線程內(nèi)的局部變量,這種變量在線程的生命周期內(nèi)起作用,減少同一個(gè)線程內(nèi)多個(gè)函數(shù)或者組件之間一些公共變量的傳遞的復(fù)雜度。 舉個(gè)例子,我出門需要先坐公交再做地鐵,這里的坐公交和坐地鐵就好比是同一個(gè)線程內(nèi)的兩個(gè)函數(shù),我就是一個(gè)線程,我要完成這兩個(gè)函數(shù)都需要同一個(gè)東西:公交卡(北京公交和地鐵都使用公交卡),那么我為了不向這兩個(gè)函數(shù)都傳遞公交卡這個(gè)變量(相當(dāng)于不是一直帶著公交卡上路),我可以這么做:將公交卡事先交給一個(gè)機(jī)構(gòu),當(dāng)我需要刷卡的時(shí)候再向這個(gè)機(jī)構(gòu)要公交卡(當(dāng)然每次拿的都是同一張公交卡)。這樣就能達(dá)到只要是我(同一個(gè)線程)需要公交卡,何時(shí)何地都能向這個(gè)機(jī)構(gòu)要的目的。 有人要說(shuō)了:你可以將公交卡設(shè)置為全局變量啊,這樣不是也能何時(shí)何地都能取公交卡嗎?但是如果有很多個(gè)人(很多個(gè)線程)呢?大家可不能都使用同一張公交卡吧(我們假設(shè)公交卡是實(shí)名認(rèn)證的),這樣不就亂套了嘛?,F(xiàn)在明白了吧?這就是ThreadLocal設(shè)計(jì)的初衷:提供線程內(nèi)部的局部變量,在本線程內(nèi)隨時(shí)隨地可取,隔離其他線程。
知識(shí)點(diǎn)26:
final可以修飾類、方法、成員變量
當(dāng)final修飾類的時(shí)候,說(shuō)明該類不能被繼承
當(dāng)final修飾方法的時(shí)候,說(shuō)明該方法不能被重寫
在早期,可能使用final修飾的方法,編譯器針對(duì)這些方法的所有調(diào)用都轉(zhuǎn)成內(nèi)嵌調(diào)用,這樣提高效率(但到現(xiàn)在一般我們不會(huì)去管這事了,編譯器和JVM都越來(lái)越聰明了)
當(dāng)final修飾成員變量時(shí),有兩種情況:
如果修飾的是基本類型,說(shuō)明這個(gè)變量的所代表數(shù)值永不能變(不能重新賦值)!
如果修飾的是引用類型,該變量所的引用不能變,但引用所代表的對(duì)象內(nèi)容是可變的!
知識(shí)點(diǎn)27:
依賴注入和控制反轉(zhuǎn)是同一概念:
依賴注入和控制反轉(zhuǎn)是對(duì)同一件事情的不同描述,從某個(gè)方面講,就是它們描述的角度不同。依賴注入是從應(yīng)用程序的角度在描述,可以把依賴注入描述完整點(diǎn):應(yīng)用程序依賴容器創(chuàng)建并注入它所需要的外部資源;而控制反轉(zhuǎn)是從容器的角度在描述,描述完整點(diǎn):容器控制應(yīng)用程序,由容器反向的向應(yīng)用程序注入應(yīng)用程序所需要的外部資源。
知識(shí)點(diǎn)28:
1、**抽象類中的抽象方法(其前有abstract修飾)不能用private、static、synchronized、native訪問(wèn)修飾符修飾。**原因如下:抽象方法沒(méi)有方法體,是用來(lái)被繼承的,所以不能用private修飾;static修飾的方法可以通過(guò)類名來(lái)訪問(wèn)該方法(即該方法的方法體),抽象方法用static修飾沒(méi)有意義;使用synchronized關(guān)鍵字是為該方法加一個(gè)鎖。。而如果該關(guān)鍵字修飾的方法是static方法。則使用的鎖就是class變量的鎖。如果是修飾 類方法。則用this變量鎖。但是抽象類不能實(shí)例化對(duì)象,因?yàn)樵摲椒ú皇窃谠摮橄箢愔袑?shí)現(xiàn)的。是在其子類實(shí)現(xiàn)的。所以。鎖應(yīng)該歸其子類所有。所以。抽象方 法也就不能用synchronized關(guān)鍵字修飾了;native,這個(gè)東西本身就和abstract沖突,他們都是方法的聲明,只是一個(gè)吧方法實(shí)現(xiàn)移交給子類,另一個(gè)是移交給本地操作系統(tǒng)。如果同時(shí)出現(xiàn),就相當(dāng)于即把實(shí)現(xiàn)移交給子類,又把實(shí)現(xiàn)移交給本地操作系統(tǒng),那到底誰(shuí)來(lái)實(shí)現(xiàn)具體方法呢?
2、**接口是一種特殊的抽象類,接口中的方法全部是抽象方法(但其前的abstract可以省略),所以抽象類中的抽象方法不能用的訪問(wèn)修飾符這里也不能用。**而且protected訪問(wèn)修飾符也不能使用,因?yàn)榻涌诳梢宰屗械念惾?實(shí)現(xiàn)(非繼承) ,不只是其子類,但是要用public去修飾。接口可以去繼承一個(gè)已有的接口。
抽象類
特點(diǎn):
1.抽象類中可以構(gòu)造方法
2.抽象類中可以存在普通屬性,方法,靜態(tài)屬性和方法。
3.抽象類中可以存在抽象方法。
4.如果一個(gè)類中有一個(gè)抽象方法,那么當(dāng)前類一定是抽象類;抽象類中不一定有抽象方法。
5.抽象類中的抽象方法,需要有子類實(shí)現(xiàn),如果子類不實(shí)現(xiàn),則子類也需要定義為抽象的。
6,抽象類不能被實(shí)例化,抽象類和抽象方法必須被abstract修飾
關(guān)鍵字使用注意:
抽象類中的抽象方法(其前有abstract修飾)不能用private、static、synchronized、native訪問(wèn)修飾符修飾。
接口
1.在接口中只有方法的聲明,沒(méi)有方法體。
2.在接口中只有常量,因?yàn)槎x的變量,在編譯的時(shí)候都會(huì)默認(rèn)加上public static final
3.在接口中的方法,永遠(yuǎn)都被public來(lái)修飾。
4.接口中沒(méi)有構(gòu)造方法,也不能實(shí)例化接口的對(duì)象。(所以接口不能繼承類)
5.接口可以實(shí)現(xiàn)多繼承
6.接口中定義的方法都需要有實(shí)現(xiàn)類來(lái)實(shí)現(xiàn),如果實(shí)現(xiàn)類不能實(shí)現(xiàn)接口中的所有方法則實(shí)現(xiàn)類定義為抽象類。
7,接口可以繼承接口,用extends
知識(shí)點(diǎn)29:
JSP內(nèi)置對(duì)象有:
1.request對(duì)象
客戶端的請(qǐng)求信息被封裝在request對(duì)象中,通過(guò)它才能了解到客戶的需求,然后做出響應(yīng)。它是HttpServletRequest類的實(shí)例。
2.response對(duì)象
response對(duì)象包含了響應(yīng)客戶請(qǐng)求的有關(guān)信息,但在JSP中很少直接用到它。它是HttpServletResponse類的實(shí)例。
3.session對(duì)象
session對(duì)象指的是客戶端與服務(wù)器的一次會(huì)話,從客戶連到服務(wù)器的一個(gè)WebApplication開始,直到客戶端與服務(wù)器斷開連接為止。它是HttpSession類的實(shí)例.
4.out對(duì)象
out對(duì)象是JspWriter類的實(shí)例,是向客戶端輸出內(nèi)容常用的對(duì)象
5.page對(duì)象
page對(duì)象就是指向當(dāng)前JSP頁(yè)面本身,有點(diǎn)象類中的this指針,它是java.lang.Object類的實(shí)例
6.application對(duì)象
application對(duì)象實(shí)現(xiàn)了用戶間數(shù)據(jù)的共享,可存放全局變量。它開始于服務(wù)器的啟動(dòng),直到服務(wù)器的關(guān)閉,在此期間,此對(duì)象將一直存在;這樣在用戶的前后連接或不同用戶之間的連接中,可以對(duì)此對(duì)象的同一屬性進(jìn)行操作;在任何地方對(duì)此對(duì)象屬性的操作,都將影響到其他用戶對(duì)此的訪問(wèn)。服務(wù)器的啟動(dòng)和關(guān)閉決定了application對(duì)象的生命。它是ServletContext類的實(shí)例。
7.exception對(duì)象
exception對(duì)象是一個(gè)例外對(duì)象,當(dāng)一個(gè)頁(yè)面在運(yùn)行過(guò)程中發(fā)生了例外,就產(chǎn)生這個(gè)對(duì)象。如果一個(gè)JSP頁(yè)面要應(yīng)用此對(duì)象,就必須把isErrorPage設(shè)為true,否則無(wú)法編譯。他實(shí)際上是java.lang.Throwable的對(duì)象
8.pageContext對(duì)象
pageContext對(duì)象提供了對(duì)JSP頁(yè)面內(nèi)所有的對(duì)象及名字空間的訪問(wèn),也就是說(shuō)他可以訪問(wèn)到本頁(yè)所在的SESSION,也可以取本頁(yè)面所在的application的某一屬性值,他相當(dāng)于頁(yè)面中所有功能的集大成者,它的本 類名也叫pageContext。
9.config對(duì)象
config對(duì)象是在一個(gè)Servlet初始化時(shí),JSP引擎向它傳遞信息用的,此信息包括Servlet初始化時(shí)所要用到的參數(shù)(通過(guò)屬性名和屬性值構(gòu)成)以及服務(wù)器的有關(guān)信息(通過(guò)傳遞一個(gè)ServletContext對(duì)象)
知識(shí)點(diǎn)30:
Object 類中方法及說(shuō)明如下:
registerNatives() //私有方法
getClass() //返回此 Object 的運(yùn)行類。
hashCode() //用于獲取對(duì)象的哈希值。
equals(Object obj) //用于確認(rèn)兩個(gè)對(duì)象是否“相同”。
clone() //創(chuàng)建并返回此對(duì)象的一個(gè)副本。
toString() //返回該對(duì)象的字符串表示。
notify() //喚醒在此對(duì)象監(jiān)視器上等待的單個(gè)線程。
notifyAll() //喚醒在此對(duì)象監(jiān)視器上等待的所有線程。
wait(long timeout) //在其他線程調(diào)用此對(duì)象的 notify() 方法或 notifyAll() 方法,或 者超過(guò)指定的時(shí)間量前,導(dǎo)致當(dāng)前線程等待。
wait(long timeout, int nanos) //在其他線程調(diào)用此對(duì)象的 notify() 方法或 notifyAll() 方法,或者其他某個(gè)線程中斷當(dāng)前線程,或者已超過(guò)某個(gè)實(shí)際時(shí)間量前,導(dǎo)致當(dāng)前線程等待。
wait() //用于讓當(dāng)前線程失去操作權(quán)限,當(dāng)前線程進(jìn)入等待序列
finalize() //當(dāng)垃圾回收器確定不存在對(duì)該對(duì)象的更多引用時(shí),由對(duì)象的垃圾回收器調(diào)用此方法。
知識(shí)點(diǎn)31:
- 這道題目想考察的知識(shí)點(diǎn)是MySQL組合索引(復(fù)合索引)的最左優(yōu)先原則。最左優(yōu)先就是說(shuō)組合索引的第一個(gè)字段必須出現(xiàn)在查詢組句中,這個(gè)索引才會(huì)被用到。只要組合索引最左邊第一個(gè)字段出現(xiàn)在Where中,那么不管后面的字段出現(xiàn)與否或者出現(xiàn)順序如何,MySQL引擎都會(huì)自動(dòng)調(diào)用索引來(lái)優(yōu)化查詢效率。
- 根據(jù)最左匹配原則可以知道B-Tree建立索引的過(guò)程,比如假設(shè)有一個(gè)3列索引(col1,col2,col3),那么MySQL只會(huì)會(huì)建立三個(gè)索引(col1),(col1,col2),(col1,col2,col3)。
- 所以題目會(huì)創(chuàng)建三個(gè)索引(plat_order_id)、(plat_order_id與plat_game_id的組合索引)、(plat_order_id、plat_game_id與plat_id的組合索引)。根據(jù)最左匹配原則,where語(yǔ)句必須要有plat_order_id才能調(diào)用索引(如果沒(méi)有plat_order_id字段那么一個(gè)索引也調(diào)用不到),如果同時(shí)出現(xiàn)plat_order_id與plat_game_id則會(huì)調(diào)用兩者的組合索引,如果同時(shí)出現(xiàn)三者則調(diào)用三者的組合索引。
- 題目問(wèn)有哪些sql能使用到索引,個(gè)人認(rèn)為只要Where后出現(xiàn)了plat_order_id字段的SQL語(yǔ)句都會(huì)調(diào)用到索引,只不過(guò)是所調(diào)用的索引不同而已,所以選BCDE。如果題目說(shuō)清楚是調(diào)用到三個(gè)字段的復(fù)合索引,那答案才是BD。
知識(shí)點(diǎn)32:
補(bǔ)充Java內(nèi)存管理知識(shí):
1. 內(nèi)存分配策略
按照編譯原理的觀點(diǎn),程序運(yùn)行時(shí)的內(nèi)存分配有三種策略,分別是靜態(tài)的,棧式的,和堆式的。
靜態(tài)存儲(chǔ)分配是指在編譯時(shí)就能確定每個(gè)數(shù)據(jù)目標(biāo)在運(yùn)行時(shí)刻的存儲(chǔ)空間需求,因而在編譯時(shí)就可以給他們分配固定的內(nèi)存空間。這種分配策略要求程序代碼中不允許有可變數(shù)據(jù)結(jié)構(gòu)(比如可變數(shù)組)的存在,也不允許有嵌套或者遞歸的結(jié)構(gòu)出現(xiàn),因?yàn)樗鼈兌紩?huì)導(dǎo)致編譯程序無(wú)法計(jì)算準(zhǔn)確的存儲(chǔ)空間需求。
棧式存儲(chǔ)分配也可稱為動(dòng)態(tài)存儲(chǔ)分配,是由一個(gè)類似于堆棧的運(yùn)行棧來(lái)實(shí)現(xiàn)的。和靜態(tài)存儲(chǔ)分配相反,在棧式存儲(chǔ)方案中,程序?qū)?shù)據(jù)區(qū)的需求在編譯時(shí)是完全未知的,只有到運(yùn)行的時(shí)候才能夠知道,但是規(guī)定在運(yùn)行中進(jìn)入一個(gè)程序模塊時(shí),必須知道該程序模塊所需的數(shù)據(jù)區(qū)大小才能夠?yàn)槠浞峙鋬?nèi)存。和我們?cè)跀?shù)據(jù)結(jié)構(gòu)所熟知的棧一樣,棧式存儲(chǔ)分配按照先進(jìn)后出的原則進(jìn)行分配。
靜態(tài)存儲(chǔ)分配要求在編譯時(shí)能知道所有變量的存儲(chǔ)要求,棧式存儲(chǔ)分配要求在過(guò)程的入口處必須知道所有的存儲(chǔ)要求,而堆式存儲(chǔ)分配則專門負(fù)責(zé)在編譯時(shí)或運(yùn)行時(shí)模塊入口處都無(wú)法確定存儲(chǔ)要求的數(shù)據(jù)結(jié)構(gòu)的內(nèi)存分配,比如可變長(zhǎng)度串和對(duì)象實(shí)例。堆由大片的可利用塊或空閑塊組成,堆中的內(nèi)存可以按照任意順序分配和釋放。
2. JVM中的堆和棧
JVM是基于堆棧的虛擬機(jī)。JVM為每個(gè)新創(chuàng)建的線程都分配一個(gè)堆棧,也就是說(shuō),對(duì)于一個(gè)Java程序來(lái)說(shuō),它的運(yùn)行就是通過(guò)對(duì)堆棧的操作來(lái)完成的。堆棧以幀為單位保存線程的狀態(tài)。JVM對(duì)堆棧只進(jìn)行兩種操作:以幀為單位的壓棧和出棧操作。
java把內(nèi)存分兩種:一種是棧內(nèi)存,另一種是堆內(nèi)存
棧(stack)與堆(heap)都是Java用來(lái)在Ram中存放數(shù)據(jù)的地方。與C++不同,Java自動(dòng)管理?xiàng):投?#xff0c;程序員不能直接地設(shè)置棧或堆。
棧(stack):是一個(gè)先進(jìn)后出的數(shù)據(jù)結(jié)構(gòu),通常用于保存方法(函數(shù))中的參數(shù),局部變量。
堆(heap):是一個(gè)可動(dòng)態(tài)申請(qǐng)的內(nèi)存空間(其記錄空閑內(nèi)存空間的鏈表由操作系統(tǒng)維護(hù)),是一個(gè)運(yùn)行時(shí)數(shù)據(jù)區(qū),C中的malloc語(yǔ)句所產(chǎn)生的內(nèi)存空間就在堆中。
3. 堆和棧優(yōu)缺點(diǎn)比較
棧的優(yōu)勢(shì)是,存取速度比堆要快,僅次于直接位于CPU中的寄存器。但缺點(diǎn)是,存在棧中的數(shù)據(jù)大小與生存期必須是確定的,缺乏靈活性。另外,棧數(shù)據(jù)可以共享,詳見第3點(diǎn)。
堆的優(yōu)勢(shì)是可以動(dòng)態(tài)地分配內(nèi)存大小,生存期也不必事先告訴編譯器,Java的垃圾收集器會(huì)自動(dòng)收走這些不再使用的數(shù)據(jù)。但缺點(diǎn)是,由于要在運(yùn)行時(shí)動(dòng)態(tài)分配內(nèi)存,存取速度較慢。
4. Java中的數(shù)據(jù)類型有兩種
一種是基本類型
共有8種,即int, short, long, byte, float, double, boolean, char(注意,并沒(méi)有string的基本類型)。
這種類型的定義是通過(guò)諸如int a = 3; long b = 255L;的形式來(lái)定義的,稱為自動(dòng)變量。值得注意的是,自動(dòng)變量存的是字面值,不是類的實(shí)例,即不是類的引用,這里并沒(méi)有類的存在。如int a = 3; 這里的a是一個(gè)指向int類型的引用,指向3這個(gè)字面值。這些字面值的數(shù)據(jù),由于大小可知,生存期可知(這些字面值固定定義在某個(gè)程序塊里面,程序塊退出后,字段值就消失了),出于追求速度的原因,就存在于棧中。
另外,**棧有一個(gè)很重要的特殊性,就是存在棧中的數(shù)據(jù)可以共享。**假設(shè)我們同時(shí)定義:
int a = 3;
int b = 3;
編譯器先處理int a = 3;首先它會(huì)在棧中創(chuàng)建一個(gè)變量為a的引用,然后查找有沒(méi)有字面值為3的地址,沒(méi)找到,就開辟一個(gè)存放3這個(gè)字面值的地址,然后將a指向3的地址。接著處理int b = 3;在創(chuàng)建完b的引用變量后,由于在棧中已經(jīng)有3這個(gè)字面值,便將b直接指向3的地址。這樣,就出現(xiàn)了a與b同時(shí)均指向3的情況。
特別注意的是,這種字面值的引用與類對(duì)象的引用不同。假定兩個(gè)類對(duì)象的引用同時(shí)指向一個(gè)對(duì)象,如果一個(gè)對(duì)象引用變量修改了這個(gè)對(duì)象的內(nèi)部狀態(tài),那么另一個(gè)對(duì)象引用變量也即刻反映出這個(gè)變化。相反,通過(guò)字面值的引用來(lái)修改其值,不會(huì)導(dǎo)致另一個(gè)指向此字面值的引用的值也跟著改變的情況。如上例,我們定義完a與b的值后,再令a=4;那么,b不會(huì)等于4,還是等于3。在編譯器內(nèi)部,遇到a=4;時(shí),它就會(huì)重新搜索棧中是否有4的字面值,如果沒(méi)有,重新開辟地址存放4的值;如果已經(jīng)有了,則直接將a指向這個(gè)地址。因此a值的改變不會(huì)影響到b的值。
另一種是包裝類數(shù)據(jù)
如Integer, String, Double等將相應(yīng)的基本數(shù)據(jù)類型包裝起來(lái)的類。這些類數(shù)據(jù)全部存在于堆中,Java用new()語(yǔ)句來(lái)顯示地告訴編譯器,在運(yùn)行時(shí)才根據(jù)需要?jiǎng)討B(tài)創(chuàng)建,因此比較靈活,但缺點(diǎn)是要占用更多的時(shí)間。
String是一個(gè)特殊的包裝類數(shù)據(jù)。即可以用String str = new String(“abc”);的形式來(lái)創(chuàng)建,也可以用String str = “abc”;的形式來(lái)創(chuàng)建(作為對(duì)比,在JDK 5.0之前,你從未見過(guò)Integer i = 3;的表達(dá)式,因?yàn)轭惻c字面值是不能通用的,除了String。而在JDK 5.0中,這種表達(dá)式是可以的!因?yàn)榫幾g器在后臺(tái)進(jìn)行Integer i = new Integer(3)的轉(zhuǎn)換)。前者是規(guī)范的類的創(chuàng)建過(guò)程,即在Java中,一切都是對(duì)象,而對(duì)象是類的實(shí)例,全部通過(guò)new()的形式來(lái)創(chuàng)建。Java中的有些類,如DateFormat類,可以通過(guò)該類的getInstance()方法來(lái)返回一個(gè)新創(chuàng)建的類,似乎違反了此原則。其實(shí)不然。該類運(yùn)用了單例模式來(lái)返回類的實(shí)例,只不過(guò)這個(gè)實(shí)例是在該類內(nèi)部通過(guò)new()來(lái)創(chuàng)建的,而getInstance()向外部隱藏了此細(xì)節(jié)。那為什么在String str = “abc”;中,并沒(méi)有通過(guò)new()來(lái)創(chuàng)建實(shí)例,是不是違反了上述原則?其實(shí)沒(méi)有。
5.String在內(nèi)存中的存放
String是一個(gè)特殊的包裝類數(shù)據(jù),可以用用以下兩種方式創(chuàng)建:
String str = new String(“abc”);第一種創(chuàng)建方式是用new()來(lái)新建對(duì)象的,它會(huì)存放于堆中。每調(diào)用一次就會(huì)創(chuàng)建一個(gè)新的對(duì)象。
String str = “abc”; 第二種創(chuàng)建方式先在棧中創(chuàng)建一個(gè)對(duì)String類的對(duì)象引用變量str,然后在棧中查找有沒(méi)有存放值為”abc”的地址,如果沒(méi)有,則開辟一個(gè)存放字面值為”abc”的地址,接著創(chuàng)建一個(gè)新的String類的對(duì)象o,并將o的字符串值指向這個(gè)地址,而且在棧中這個(gè)地址旁邊記下這個(gè)引用的對(duì)象o。如果已經(jīng)有了值為”abc”的地址,則查找對(duì)象o,并返回o的地址,最后將str指向?qū)ο髈的地址。
值得注意的是,一般String類中字符串值都是直接存值的。但像String str = “abc”;這種場(chǎng)合下,其字符串值卻是保存了一個(gè)指向存在棧中數(shù)據(jù)的引用!
6.數(shù)組在內(nèi)存中的存放
int x[] 或者int []x 時(shí),在內(nèi)存??臻g中創(chuàng)建一個(gè)數(shù)組引用,通過(guò)該數(shù)組名來(lái)引用數(shù)組。
x = new int[5] 將在堆內(nèi)存中分配5個(gè)保存int型數(shù)據(jù)的空間,堆內(nèi)存的首地址放到棧內(nèi)存中,每個(gè)數(shù)組元素被初始化為0。
7.static變量在內(nèi)存中的存放
用 static的修飾的變量和方法,實(shí)際上是指定了這些變量和方法在內(nèi)存中的“固定位置”-static storage。既然要有“固定位置”那么他們的 “大小”似乎就是固定的了,有了固定位置和固定大小的特征了,在棧中或堆中開辟空間那就是非常的方便了。如果靜態(tài)的變量或方法在不出其作用域的情況下,其引用句柄是不會(huì)發(fā)生改變的。
8. java中變量在內(nèi)存中的分配
1、類變量(static修飾的變量)
在程序加載時(shí)系統(tǒng)就為它在堆中開辟了內(nèi)存,堆中的內(nèi)存地址存放于棧以便于高速訪問(wèn)。靜態(tài)變量的生命周期一直持續(xù)到整個(gè)”系統(tǒng)”關(guān)閉
2、實(shí)例變量
當(dāng)你使用java關(guān)鍵字new的時(shí)候,系統(tǒng)在堆中開辟并不一定是連續(xù)的空間分配給變量(比如說(shuō)類實(shí)例),然后根據(jù)零散的堆內(nèi)存地址,通過(guò)哈希算法換算為一長(zhǎng)串?dāng)?shù)字以表征這個(gè)變量在堆中的”物理位置”。 實(shí)例變量的生命周期–當(dāng)實(shí)例變量的引用丟失后,將被GC(垃圾回收器)列入可回收“名單”中,但并不是馬上就釋放堆中內(nèi)存
3、局部變量
局部變量,由聲明在某方法,或某代碼段里(比如for循環(huán)),執(zhí)行到它的時(shí)候在棧中開辟內(nèi)存,當(dāng)局部變量一但脫離作用域,內(nèi)存立即釋放
知識(shí)點(diǎn)33:
兩個(gè)最基本的java回收算法:復(fù)制算法和標(biāo)記清理算法
復(fù)制算法:兩個(gè)區(qū)域A和B,初始對(duì)象在A,繼續(xù)存活的對(duì)象被轉(zhuǎn)移到B。此為新生代最常用的算法
標(biāo)記清理:一塊區(qū)域,標(biāo)記可達(dá)對(duì)象(可達(dá)性分析),然后回收不可達(dá)對(duì)象,會(huì)出現(xiàn)碎片,那么引出
標(biāo)記-整理算法:多了碎片整理,整理出更大的內(nèi)存放更大的對(duì)象
兩個(gè)概念:新生代和年老代
新生代:初始對(duì)象,生命周期短的
永久代:長(zhǎng)時(shí)間存在的對(duì)象
整個(gè)java的垃圾回收是新生代和年老代的協(xié)作,這種叫做分代回收。
P.S:Serial New收集器是針對(duì)新生代的收集器,采用的是復(fù)制算法
Parallel New(并行)收集器,新生代采用復(fù)制算法,老年代采用標(biāo)記整理
Parallel Scavenge(并行)收集器,針對(duì)新生代,采用復(fù)制收集算法
Serial Old(串行)收集器,新生代采用復(fù)制,老年代采用標(biāo)記整理
Parallel Old(并行)收集器,針對(duì)老年代,標(biāo)記整理
CMS收集器,基于標(biāo)記清理
G1收集器:整體上是基于標(biāo)記 整理 ,局部采用復(fù)制
綜上:新生代基本采用復(fù)制算法,老年代采用標(biāo)記整理算法。cms采用標(biāo)記清理。
知識(shí)點(diǎn)34:
Servlet的生命周期
init():僅執(zhí)行一次,負(fù)責(zé)在裝載Servlet時(shí)初始化Servlet對(duì)象
service() :核心方法,一般HttpServlet中會(huì)有g(shù)et,post兩種處理方式。在調(diào)用doGet和doPost方法時(shí)會(huì)構(gòu)造servletRequest和servletResponse請(qǐng)求和響應(yīng)對(duì)象作為參數(shù)。
destory():在停止并且卸載Servlet時(shí)執(zhí)行,負(fù)責(zé)釋放資源
初始化階段:Servlet啟動(dòng),會(huì)讀取配置文件中的信息,構(gòu)造指定的Servlet對(duì)象,創(chuàng)建ServletConfig對(duì)象,將ServletConfig作為參數(shù)來(lái)調(diào)用init()方法。所以選ACD。B是在調(diào)用service方法時(shí)才構(gòu)造的
知識(shí)點(diǎn)35:
結(jié)構(gòu)型模式是描述如何將類對(duì)象結(jié)合在一起,形成一個(gè)更大的結(jié)構(gòu),結(jié)構(gòu)模式描述兩種不同的東西:類與類的實(shí)例。故可以分為類結(jié)構(gòu)模式和對(duì)象結(jié)構(gòu)模式。
在GoF設(shè)計(jì)模式中,結(jié)構(gòu)型模式有:
1.適配器模式 Adapter
適配器模式是將一個(gè)類的接口轉(zhuǎn)換成客戶希望的另外一個(gè)接口。適配器模式使得原本由于接口不兼容 而不能一起工作的那些類可以一起工作。
兩個(gè)成熟的類需要通信,但是接口不同,由于開閉原則,我們不能去修改這兩個(gè)類的接口,所以就需要一個(gè)適配器來(lái)完成銜接過(guò)程。
2.橋接模式 Bridge
橋接模式將抽象部分與它的實(shí)現(xiàn)部分分離,是它們都可以獨(dú)立地變化。它很好的支持了開閉原則和組合鋸和復(fù)用原則。實(shí)現(xiàn)系統(tǒng)可能有多角度分類,每一種分類都有可能變化,那么就把這些多角度分離出來(lái)讓他們獨(dú)立變化,減少他們之間的耦合。
3.組合模式 Composite
組合模式將對(duì)象組合成樹形結(jié)構(gòu)以表示部分-整體的層次結(jié)構(gòu),組合模式使得用戶對(duì)單個(gè)對(duì)象和組合對(duì)象的使用具有一致性。
4.裝飾模式 Decorator
裝飾模式動(dòng)態(tài)地給一個(gè)對(duì)象添加一些額外的職責(zé),就增加功能來(lái)說(shuō),它比生成子類更靈活。也可以這樣說(shuō),裝飾模式把復(fù)雜類中的核心職責(zé)和裝飾功能區(qū)分開了,這樣既簡(jiǎn)化了復(fù)雜類,有去除了相關(guān)類中重復(fù)的裝飾邏輯。 裝飾模式?jīng)]有通過(guò)繼承原有類來(lái)擴(kuò)展功能,但卻達(dá)到了一樣的目的,而且比繼承更加靈活,所以可以說(shuō)裝飾模式是繼承關(guān)系的一種替代方案。
5.外觀模式 Facade
外觀模式為子系統(tǒng)中的一組接口提供了同意的界面,外觀模式定義了一個(gè)高層接口,這個(gè)接口使得這一子系統(tǒng)更加容易使用。
外觀模式中,客戶對(duì)各個(gè)具體的子系統(tǒng)是不了解的,所以對(duì)這些子系統(tǒng)進(jìn)行了封裝,對(duì)外只提供了用戶所明白的單一而簡(jiǎn)單的接口,用戶直接使用這個(gè)接口就可以完成操作,而不用去理睬具體的過(guò)程,而且子系統(tǒng)的變化不會(huì)影響到用戶,這樣就做到了信息隱蔽。
6.享元模式 Flyweight
享元模式為運(yùn)用共享技術(shù)有效的支持大量細(xì)粒度的對(duì)象。因?yàn)樗梢酝ㄟ^(guò)共享大幅度地減少單個(gè)實(shí)例的數(shù)目,避免了大量非常相似類的開銷。.
? 享元模式是一個(gè)類別的多個(gè)對(duì)象共享這個(gè)類別的一個(gè)對(duì)象,而不是各自再實(shí)例化各自的對(duì)象。這樣就達(dá)到了節(jié)省內(nèi)存的目的。
總結(jié)
- 上一篇: 基于神经网络的PID控制,pid神经网络
- 下一篇: Android DCIM相册保存