第一篇:面試題匯總
本題集由尚學(xué)堂學(xué)員整理,列舉了眾多IT公司面試真題,對(duì)應(yīng)聘Java程序員職位的常見考點(diǎn)和知識(shí)體系都進(jìn)行的分類和歸納整理。
本題集適合應(yīng)聘Java和JavaEE職位的程序員作為面試復(fù)習(xí)、學(xué)習(xí)和強(qiáng)化的資料,也適合其他程序員作為拓展讀物進(jìn)行閱讀。
本題集包含了常見的算法、面試題,也包含了新的高級(jí)技術(shù),比如:微服務(wù)架構(gòu)等技術(shù)的面試題目。本題集非常全面,對(duì)于工作1-5年左右的java程序員面試有非常好的指導(dǎo)作用。
大家也可以訪問(直接在線觀看最新版的面試題):bj0393.com.cn/javamianshiti.html
1.JAVA專業(yè),1000課 | 3.大數(shù)據(jù)專業(yè),500課 |
2.Python專業(yè),500課 | 4.人工智能專業(yè),500課 |
四個(gè)專業(yè)都要學(xué),從零開始2000小時(shí),成為高端人才,打下一生技術(shù)基礎(chǔ),不再是低端碼農(nóng)。
2.掃一掃,咨詢?cè)斍椋?/p>
訪問官網(wǎng) www.itbaizhan.cn
Java基礎(chǔ)、語法:
C/C++語言都直接編譯成針對(duì)特定平臺(tái)機(jī)器碼。如果要跨平臺(tái),需要使用相應(yīng)的編譯器重新編譯。
Java源程序(.java)要先編譯成與平臺(tái)無關(guān)的字節(jié)碼文件(.class),然后字節(jié)碼文件再解釋成機(jī)器碼運(yùn)行。解釋是通過Java虛擬機(jī)來執(zhí)行的。
字節(jié)碼文件不面向任何具體平臺(tái),只面向虛擬機(jī)。
Java虛擬機(jī)是可運(yùn)行Java字節(jié)碼文件的虛擬計(jì)算機(jī)。不同平臺(tái)的虛擬機(jī)是不同的,但它們都提供了相同的接口。
Java語言具有一次編譯,到處運(yùn)行的特點(diǎn)。就是說編譯后的.class可以跨平臺(tái)運(yùn)行,前提是該平臺(tái)具有相應(yīng)的Java虛擬機(jī)。但是性能比C/C++要低。
Java的跨平臺(tái)原理決定了其性能沒有C/C++高
語言層次的安全性主要體現(xiàn)在:
Java取消了強(qiáng)大但又危險(xiǎn)的指針,而代之以引用。由于指針可進(jìn)行移動(dòng)運(yùn)算,指針可隨便指向一個(gè)內(nèi)存區(qū)域,而不管這個(gè)區(qū)域是否可用,這樣做是危險(xiǎn)的,因?yàn)樵瓉磉@個(gè)內(nèi)存地址可能存儲(chǔ)著重要數(shù)據(jù)或者是其他程序運(yùn)行所占用的,并且使用指針也容易數(shù)組越界。
垃圾回收機(jī)制:不需要程序員直接控制內(nèi)存回收,由垃圾回收器在后臺(tái)自動(dòng)回收不再使用的內(nèi)存。避免程序忘記及時(shí)回收,導(dǎo)致內(nèi)存泄露。避免程序錯(cuò)誤回收程序核心類庫(kù)的內(nèi)存,導(dǎo)致系統(tǒng)崩潰。
異常處理機(jī)制:Java異常機(jī)制主要依賴于try、catch、finally、throw、throws五個(gè)關(guān)鍵字。
強(qiáng)制類型轉(zhuǎn)換:只有在滿足強(qiáng)制轉(zhuǎn)換規(guī)則的情況下才能強(qiáng)轉(zhuǎn)成功。
底層的安全性可以從以下方面來說明
Java在字節(jié)碼的傳輸過程中使用了公開密鑰加密機(jī)制(PKC)。
在運(yùn)行環(huán)境提供了四級(jí)安全性保障機(jī)制:
字節(jié)碼校驗(yàn)器 -類裝載器 -運(yùn)行時(shí)內(nèi)存布局 -文件訪問限制
Java2平臺(tái)包括標(biāo)準(zhǔn)版(J2SE)、企業(yè)版(J2EE)和微縮版(J2ME)三個(gè)版本:
Standard Edition(標(biāo)準(zhǔn)版) J2SE 包含那些構(gòu)成Java語言核心的類。
比如:數(shù)據(jù)庫(kù)連接、接口定義、輸入/輸出、網(wǎng)絡(luò)編程
Enterprise Edition(企業(yè)版) J2EE 包含J2SE 中的類,并且還包含用于開發(fā)企業(yè)級(jí)應(yīng)用的類。
比如servlet、JSP、XML、事務(wù)控制
Micro Edition(微縮版) J2ME 包含J2SE中一部分類,用于消費(fèi)類電子產(chǎn)品的軟件開發(fā)。
比如:呼機(jī)、智能卡、手機(jī)、PDA、機(jī)頂盒
他們的范圍是:J2SE包含于J2EE中,J2ME包含了J2SE的核心類,但新添加了一些專有類
應(yīng)用場(chǎng)合,API的覆蓋范圍各不相同。
JVM :JVM是Java Virtual Machine(Java虛擬機(jī))的縮寫,它是整個(gè)java實(shí)現(xiàn)跨平臺(tái)的最核心的部分,所有的java程序會(huì)首先被編譯為.class的類文件,這種類文件可以在虛擬機(jī)上執(zhí)行,也就是說class并不直接與機(jī)器的操作系統(tǒng)相對(duì)應(yīng),而是經(jīng)過虛擬機(jī)間接與操作系統(tǒng)交互,由虛擬機(jī)將程序解釋給本地系統(tǒng)執(zhí)行。JVM是Java平臺(tái)的基礎(chǔ),和實(shí)際的機(jī)器一樣,它也有自己的指令集,并且在運(yùn)行時(shí)操作不同的內(nèi)存區(qū)域。?JVM通過抽象操作系統(tǒng)和CPU結(jié)構(gòu),提供了一種與平臺(tái)無關(guān)的代碼執(zhí)行方法,即與特殊的實(shí)現(xiàn)方法、主機(jī)硬件、主機(jī)操作系統(tǒng)無關(guān)。JVM的主要工作是解釋自己的指令集(即字節(jié)碼)到CPU的指令集或?qū)?yīng)的系統(tǒng)調(diào)用,保護(hù)用戶免被惡意程序騷擾。?JVM對(duì)上層的Java源文件是不關(guān)心的,它關(guān)注的只是由源文件生成的類文件(.class文件)。
JRE:JRE是java runtime environment(java運(yùn)行環(huán)境)的縮寫。光有JVM還不能讓class文件執(zhí)行,因?yàn)樵诮忉宑lass的時(shí)候JVM需要調(diào)用解釋所需要的類庫(kù)lib。在JDK的安裝目錄里你可以找到j(luò)re目錄,里面有兩個(gè)文件夾bin和lib,在這里可以認(rèn)為bin里的就是jvm,lib中則是jvm工作所需要的類庫(kù),而jvm和lib和起來就稱為jre。所以,在你寫完java程序編譯成.class之后,你可以把這個(gè).class文件和jre一起打包發(fā)給朋友,這樣你的朋友就可以運(yùn)行你寫程序了(jre里有運(yùn)行.class的java.exe)。JRE是Sun公司發(fā)布的一個(gè)更大的系統(tǒng),它里面就有一個(gè)JVM。JRE就與具體的CPU結(jié)構(gòu)和操作系統(tǒng)有關(guān),是運(yùn)行Java程序必不可少的(除非用其他一些編譯環(huán)境編譯成.exe可執(zhí)行文件……),JRE的地位就象一臺(tái)PC機(jī)一樣,我們寫好的Win32應(yīng)用程序需要操作系統(tǒng)幫我們運(yùn)行,同樣的,我們編寫的Java程序也必須要JRE才能運(yùn)行。?
JDK:JDK是java development kit(java開發(fā)工具包)的縮寫。每個(gè)學(xué)java的人都會(huì)先在機(jī)器上裝一個(gè)JDK,那 讓我們看一下JDK的安裝目錄。在目錄下面有六個(gè)文件夾、一個(gè)src類庫(kù)源碼壓縮包、和其他幾個(gè)聲明文件。其中,真正在運(yùn)行java時(shí)起作用的是以下四個(gè)文件夾:bin、include、lib、jre?,F(xiàn)在我們可以看出這樣一個(gè)關(guān)系,JDK包含JRE,而JRE包含JVM。
bin:最主要的是編譯器(javac.exe)
include:java和JVM交互用的頭文件
lib:類庫(kù)??????
jre:java運(yùn)行環(huán)境?
(注意:這里的bin、lib文件夾和jre里的bin、lib是不同的)總的來說JDK是用于java程序的開發(fā),而jre則是只能運(yùn)行class而沒有編譯的功能。eclipse、idea等其他IDE有自己的編譯器而不是用JDK?bin目錄中自帶的,所以在安裝時(shí)你會(huì)發(fā)現(xiàn)他們只要求你選jre路徑就ok了。
JDK,JRE,JVM三者關(guān)系概括如下:
jdk是JAVA程序開發(fā)時(shí)用的開發(fā)工具包,其內(nèi)部也有JRE運(yùn)行環(huán)境JRE。JRE是JAVA程序運(yùn)行時(shí)需要的運(yùn)行環(huán)境,就是說如果你光是運(yùn)行JAVA程序而不是去搞開發(fā)的話,只安裝JRE就能運(yùn)行已經(jīng)存在的JAVA程序了。JDk、JRE內(nèi)部都包含JAVA虛擬機(jī)JVM,JAVA虛擬機(jī)內(nèi)部包含許多應(yīng)用程序的類的解釋器和類加載器等等。
共有單行注釋、多行注釋、文檔注釋3種注釋類型。使用如下:
單行注釋,采用“//”方式.只能注釋一行代碼。如://類成員變量
多行注釋,采用“/*...*/”方式,可注釋多行代碼,其中不允許出現(xiàn)嵌套。如:
/*System.out.println("a");
System.out.println("b");
System.out.println("c");*/
文檔注釋,采用“/**...*/”方式。如:
/**
* 子類 Dog
* @author Administrator
**/
public class Dog extends Animal{}
數(shù)據(jù)類型 | 關(guān)鍵字 | 字節(jié)數(shù) | |
數(shù)值型 | 整數(shù)型 | byte | 1 |
short | 2 | ||
int | 4 | ||
long | 8 | ||
浮點(diǎn)型 | float | 4 | |
double | 8 | ||
布爾型 | boolean | 1(位) | |
字符型 | char | 2 |
共同點(diǎn):
1、i++和++i都是變量自增1,都等價(jià)于i=i+1
2、如果i++,++i是一條單獨(dú)的語句,兩者沒有任何區(qū)別
3、i++和++i的使用僅僅針對(duì)變量。 5++和++5會(huì)報(bào)錯(cuò),因?yàn)?不是變量。
不同點(diǎn):
如果i++,++i不是一條單獨(dú)的語句,他們就有區(qū)別i++ :先運(yùn)算后增1。如:
int x=5; int y=x++; System.out.println("x="+x+", y="+y); //以上代碼運(yùn)行后輸出結(jié)果為:x=6, y=5
++i : 先增1后運(yùn)算。如:
int x=5; int y=++x; System.out.println("x="+x+", y="+y); //以上代碼運(yùn)行后輸出結(jié)果為:x=6, y=6
&和&&的聯(lián)系(共同點(diǎn)):
&和&&都可以用作邏輯與運(yùn)算符,但是要看使用時(shí)的具體條件來決定。
操作數(shù)1&操作數(shù)2,操作數(shù)1&&操作數(shù)2,
表達(dá)式1&表達(dá)式2,表達(dá)式1&&表達(dá)式2,
情況1:當(dāng)上述的操作數(shù)是boolean類型變量時(shí),&和&&都可以用作邏輯與運(yùn)算符。
情況2:當(dāng)上述的表達(dá)式結(jié)果是boolean類型變量時(shí),&和&&都可以用作邏輯與運(yùn)算符。
表示邏輯與(and),當(dāng)運(yùn)算符兩邊的表達(dá)式的結(jié)果或操作數(shù)都為true時(shí),整個(gè)運(yùn)算結(jié)果才為true,否則,只要有一方為false,結(jié)果都為false。
&和&&的區(qū)別(不同點(diǎn)):
(1)、&邏輯運(yùn)算符稱為邏輯與運(yùn)算符,&&邏輯運(yùn)算符稱為短路與運(yùn)算符,也可叫邏輯與運(yùn)算符。
對(duì)于&:無論任何情況,&兩邊的操作數(shù)或表達(dá)式都會(huì)參與計(jì)算。
對(duì)于&&:當(dāng)&&左邊的操作數(shù)為false或左邊表達(dá)式結(jié)果為false時(shí),&&右邊的操作數(shù)或表達(dá)式將不參與計(jì)算,此時(shí)最終結(jié)果都為false。
綜上所述,如果邏輯與運(yùn)算的第一個(gè)操作數(shù)是false或第一個(gè)表達(dá)式的結(jié)果為false時(shí),對(duì)于第二個(gè)操作數(shù)或表達(dá)式是否進(jìn)行運(yùn)算,對(duì)最終的結(jié)果沒有影響,結(jié)果肯定是false。推介平時(shí)多使用&&,因?yàn)樗矢咝?/p>
、&還可以用作位運(yùn)算符。當(dāng)&兩邊操作數(shù)或兩邊表達(dá)式的結(jié)果不是boolean類型時(shí),&用于按位與運(yùn)算符的操作。
|和||的區(qū)別和聯(lián)系與&和&&的區(qū)別和聯(lián)系類似
使用位運(yùn)算來實(shí)現(xiàn)效率最高。位運(yùn)算符是對(duì)操作數(shù)以二進(jìn)制比特位為單位進(jìn)行操作和運(yùn)算,操作數(shù)和結(jié)果都是整型數(shù)。對(duì)于位運(yùn)算符“<<”, 是將一個(gè)數(shù)左移n位,就相當(dāng)于乘以了2的n次方,那么,一個(gè)數(shù)乘以8只要將其左移3位即可,位運(yùn)算cpu直接支持的,效率最高。所以,2乘以8等于幾的最效率的方法是2 << 3
基本類型轉(zhuǎn)換分為自動(dòng)轉(zhuǎn)換和強(qiáng)制轉(zhuǎn)換。
自動(dòng)轉(zhuǎn)換規(guī)則:容量小的數(shù)據(jù)類型可以自動(dòng)轉(zhuǎn)換成容量大的數(shù)據(jù)類型,也可
以說低級(jí)自動(dòng)向高級(jí)轉(zhuǎn)換。這兒的容量指的不是字節(jié)數(shù),而是指類型表述的范圍。
強(qiáng)制轉(zhuǎn)換規(guī)則:高級(jí)變?yōu)榈图?jí)需要強(qiáng)制轉(zhuǎn)換。
如何轉(zhuǎn)換:
(1)賦值運(yùn)算符“=”右邊的轉(zhuǎn)換,先自動(dòng)轉(zhuǎn)換成表達(dá)式中級(jí)別最高的數(shù)據(jù)類型,再進(jìn)行運(yùn)算。
(2)賦值運(yùn)算符“=”兩側(cè)的轉(zhuǎn)換,若左邊級(jí)別>右邊級(jí)別,會(huì)自動(dòng)轉(zhuǎn)換;若左邊級(jí)別 == 右邊級(jí)別,不用轉(zhuǎn)換;若左邊級(jí)別 < 右邊級(jí)別,需強(qiáng)制轉(zhuǎn)換。
(3)可以將整型常量直接賦值給byte, short, char等類型變量,而不需要進(jìn)行強(qiáng)制類型轉(zhuǎn)換,前提是不超出其表述范圍,否則必須進(jìn)行強(qiáng)制轉(zhuǎn)換。
相同之處:都是分支語句,多超過一種的情況進(jìn)行判斷處理。
不同之處:
switch更適合用于多分支情況,就是有很多種情況需要判斷處理,判斷條件類型單一,只有一個(gè)入口,在分支執(zhí)行完后(如果沒有break跳出),不加判斷地執(zhí)行下去;而if—elseif---else多分枝主要適用于分支較少的分支結(jié)構(gòu),判斷類型不是單一,只要一個(gè)分支被執(zhí)行后,后邊的分支不再執(zhí)行。switch為等值判斷(不允許比如>= <=),而if為等值和區(qū)間都可以,if的使用范圍大。
while先判斷后執(zhí)行,第一次判斷為false,循環(huán)體一次都不執(zhí)行
do while先執(zhí)行 后判斷,最少執(zhí)行1次。
如果while循環(huán)第一次判斷為true, 則兩種循環(huán)沒有區(qū)別。
break: 結(jié)束當(dāng)前循環(huán)并退出當(dāng)前循環(huán)體。
break還可以退出switch語句
continue: 循環(huán)體中后續(xù)的語句不執(zhí)行,但是循環(huán)沒有結(jié)束,繼續(xù)進(jìn)行循環(huán)條件的判斷(for循環(huán)還會(huì)i++)。continue只是結(jié)束本次循環(huán)。
package com.bjsxt; import java.io.File; public class $ { public static void main(String[] args) { String path = "D:/301SXT"; test(path); } private static void test(String path) { File f = new File(path); File[] fs = f.listFiles(); if (fs == null) { return; } for (File file : fs) { if (file.isFile()) { System.out.println(file.getPath()); } else { test(file.getPath()); } } }
遞歸算法是一種直接或者間接地調(diào)用自身算法的過程。在計(jì)算機(jī)編寫程序中,遞歸算法對(duì)解決一大類問題是十分有效的,它往往使算法的描述簡(jiǎn)潔而且易于理解。
遞歸算法解決問題的特點(diǎn):
(1) 遞歸就是在過程或函數(shù)里調(diào)用自身。
(2) 在使用遞歸策略時(shí),必須有一個(gè)明確的遞歸結(jié)束條件,稱為遞歸出口。
(3) 遞歸算法解題通常顯得很簡(jiǎn)潔,但運(yùn)行效率較低。所以一般不提倡用遞歸算法設(shè)計(jì)程序。
(4) 在遞歸調(diào)用的過程當(dāng)中系統(tǒng)為每一層的返回點(diǎn)、局部量等開辟了棧來存儲(chǔ)。遞歸次數(shù)過多容易造成棧溢出等。所以一般不提倡用遞歸算法設(shè)計(jì)程序。
數(shù)組是(相同類型數(shù)據(jù))的(有序)(集合)
數(shù)組會(huì)在內(nèi)存中開辟一塊連續(xù)的空間,每個(gè)空間相當(dāng)于之前的一個(gè)變量,稱為數(shù)組的元素element
元素的表示 數(shù)組名[下標(biāo)或者索引] scores[7] scores[0] scores[9]
索引從0開始
每個(gè)數(shù)組元素有默認(rèn)值 double 0.0 boolean false int 0
數(shù)組元素有序的,不是大小順序,是索引 的順序
數(shù)組中可以存儲(chǔ)基本數(shù)據(jù)類型,可以存儲(chǔ)引用數(shù)據(jù)類型;但是對(duì)于一個(gè)數(shù)組而言,數(shù)組的類型是固定的,只能是一個(gè)
length:數(shù)組的長(zhǎng)度
數(shù)組的長(zhǎng)度是固定的,一經(jīng)定義,不能再發(fā)生變化(數(shù)組的擴(kuò)容)
package com.bjsxt; public class TestBubbleSort { public static void sort(int[] a) { int temp = 0; // 外層循環(huán),它決定一共走幾趟 for (int i = 0; i <a.length-1; ++i) { //內(nèi)層循環(huán),它決定每趟走一次 for (int j = 0; j <a.length-i-1 ; ++j) { //如果后一個(gè)大于前一個(gè) if (a[j + 1] < a[j]) { //換位 temp = a[j];a[j] = a[j + 1];a[j + 1] = temp; } } } public static void sort2(int[] a) { int temp = 0; for (int i = 0; i <a.length-1; ++i) { //通過符號(hào)位可以減少無謂的比較,如果已經(jīng)有序了,就退出循環(huán) int flag = 0; for (int j = 0; j <a.length-1-i ; ++j) { if (a[j + 1] < a[j]) { temp = a[j]; a[j] = a[j + 1]; a[j + 1] = temp; flag = 1; } } if(flag == 0){ break; } } } }
package com.bjsxt; public class TestSelectSort { public static void sort(int arr[]) { int temp = 0; for (int i = 0; i < arr.length - 1; i++) { // 認(rèn)為目前的數(shù)就是最小的, 記錄最小數(shù)的下標(biāo) int minIndex = i; for (int j = i + 1; j < arr.length; j++) { if (arr[minIndex] > arr[j]) { // 修改最小值的下標(biāo) minIndex = j; } } // 當(dāng)退出for就找到這次的最小值 if (i != minIndex) { temp = arr[i]; arr[i] = arr[minIndex]; arr[minIndex] = temp; } } } }
package com.bjsxt; public class TestInsertSort { public static void sort(int arr[]) { int i, j; for (i = 1; i < arr.length; i++) { int temp = arr[i]; for (j = i; j > 0 && temp < arr[j - 1]; j--) { arr[j] = arr[j - 1]; } arr[j] = temp; } } }
總結(jié)1:可變參數(shù)
1.可變參數(shù)的形式 ...
2.可變參數(shù)只能是方法的形參
3.可變參數(shù)對(duì)應(yīng)的實(shí)參可以0,1,2.....個(gè),也可以是一個(gè)數(shù)組
4.在可變參數(shù)的方法中,將可變參數(shù)當(dāng)做數(shù)組來處理
5.可變參數(shù)最多有一個(gè),只能是最后一個(gè)
6.可變參數(shù)好處:方便 簡(jiǎn)單 減少重載方法的數(shù)量
7.如果定義了可變參數(shù)的方法,不允許同時(shí)定義相同類型數(shù)組參數(shù)的方法
總結(jié)2:數(shù)組做形參和可變參數(shù)做形參聯(lián)系和區(qū)別
聯(lián)系:
1.實(shí)參都可以是數(shù)組;2.方法體中,可變參數(shù)當(dāng)做數(shù)組來處理
區(qū)別:
1.個(gè)數(shù)不同 可變參數(shù)只能有一個(gè)數(shù)組參數(shù)可以多個(gè)
2.位置不同 可變參數(shù)只能是最后一個(gè) 數(shù)組參數(shù)位置任意
3.實(shí)參不同 可變參數(shù)實(shí)參可以0,1,2.....個(gè),也可以是一個(gè)數(shù)組,數(shù)組的實(shí)參只能是數(shù)組
類是對(duì)象的抽象,而對(duì)象是類的具體實(shí)例。類是抽象的,不占用內(nèi)存,而對(duì)象是具體的,占用存儲(chǔ)空間。類是用于創(chuàng)建對(duì)象的藍(lán)圖,它是一個(gè)定義包括在特定類型的對(duì)象中的方法和變量的軟件模板。
類和對(duì)象好比圖紙和實(shí)物的關(guān)系,模具和鑄件的關(guān)系。
比如人類就是一個(gè)概念,人類具有身高,體重等屬性。人類可以做吃飯、說話等方法。
小明就是一個(gè)具體的人,也就是實(shí)例,他的屬性是具體的身高200cm,體重180kg,他做的方法是具體的吃了一碗白米飯,說了“12345”這樣一句話。
兩者都是軟件開發(fā)思想,先有面向過程,后有面向?qū)ο?。在大型?xiàng)目中,針對(duì)面向過程的不足推出了面向?qū)ο箝_發(fā)思想。
比喻
蔣介石和毛澤東分別是面向過程和面向?qū)ο蟮慕艹龃恚@樣充分說明,在解決復(fù)制問題時(shí),面向?qū)ο笥懈蟮膬?yōu)越性。
面向過程是蛋炒飯,面向?qū)ο笫巧w澆飯。蓋澆飯的好處就是“菜”“飯”分離,從而提高了制作蓋澆飯的靈活性。飯不滿意就換飯,菜不滿意換菜。用軟件工程的專業(yè)術(shù)語就是“可維護(hù)性”比較好,“飯” 和“菜”的耦合度比較低。
區(qū)別
編程思路不同: 面向過程以實(shí)現(xiàn)功能的函數(shù)開發(fā)為主,而面向?qū)ο笠紫瘸橄蟪鲱?、屬性及其方法,然后通過實(shí)例化類、執(zhí)行方法來完成功能。
封裝性:都具有封裝性,但是面向過程是封裝的是功能,而面向?qū)ο蠓庋b的是數(shù)據(jù)和功能。
面向?qū)ο缶哂欣^承性和多態(tài)性,而面向過程沒有繼承性和多態(tài)性,所以面向?qū)ο髢?yōu)勢(shì)是明顯。
方法重載和方法重寫(覆蓋)的區(qū)別
英文 | 位置不同 | 作用不同 | |
重載 | overload | 同一個(gè)類中 | 在一個(gè)類里面為一種行為提供多種實(shí)現(xiàn)方式并提高可讀性 |
重寫 | override | 子類和父類間 | 父類方法無法滿足子類的要求,子類通過方法重寫滿足要求 |
修飾符 | 返回值 | 方法名 | 參數(shù) | 拋出異常 | |
重載 | 無關(guān) | 無關(guān) | 相同 | 不同 | 無關(guān) |
重寫 | 大于等于 | 小于等于 | 相同 | 相同 | 小于等于 |
this是對(duì)象內(nèi)部指代自身的引用,同時(shí)也是解決成員變量和局部變量同名問題;this可以調(diào)用成員變量,不能調(diào)用局部變量;this也可以調(diào)用成員方法,但是在普通方法中可以省略this,在構(gòu)造方法中不允許省略,必須是構(gòu)造方法的第一條語句。,而且在靜態(tài)方法當(dāng)中不允許出現(xiàn)this關(guān)鍵字。
super代表對(duì)當(dāng)前對(duì)象的直接父類對(duì)象的引用,super可以調(diào)用直接父類的成員變量(注意權(quán)限修飾符的影響,比如不能訪問private成員)
super可以調(diào)用直接父類的成員方法(注意權(quán)限修飾符的影響,比如不能訪問private成員);super可以調(diào)用直接父類的構(gòu)造方法,只限構(gòu)造方法中使用,且必須是第一條語句。
static可以修飾變量、方法、代碼塊和內(nèi)部類
static屬性屬于這個(gè)類所有,即由該類創(chuàng)建的所有對(duì)象共享同一個(gè)static屬性??梢詫?duì)象創(chuàng)建后通過對(duì)象名.屬性名和類名.屬性名兩種方式來訪問。也可以在沒有創(chuàng)建任何對(duì)象之前通過類名.屬性名的方式來訪問。
static變量和非static變量的區(qū)別(都是成員變量,不是局部變量)
1.在內(nèi)存中份數(shù)不同
不管有多少個(gè)對(duì)象,static變量只有1份。對(duì)于每個(gè)對(duì)象,實(shí)例變量都會(huì)有單獨(dú)的一份
static變量是屬于整個(gè)類的,也稱為類變量。而非靜態(tài)變量是屬于對(duì)象的,也稱為實(shí)例變量
2.在內(nèi)存中存放的位置不同
2.在內(nèi)存中存放的位置不同
3.訪問的方式不同
實(shí)例變量: 對(duì)象名.變量名 stu1.name="小明明";
靜態(tài)變量:對(duì)象名.變量名 stu1.schoolName="西二旗小學(xué)"; 不推薦如此使用
類名.變量名 Student.schoolName="東三旗小學(xué)"; 推薦使用
4.在內(nèi)存中分配空間的時(shí)間不同
Student.schoolName="東三旗小學(xué)";或者Student stu1 = new Student("小明","男",20,98);
static方法也可以通過對(duì)象名.方法名和類名.方法名兩種方式來訪問
static代碼塊。當(dāng)類被第一次使用時(shí)(可能是調(diào)用static屬性和方法,或者創(chuàng)建其對(duì)象)執(zhí)行靜態(tài)代碼塊,且只被執(zhí)行一次,主要作用是實(shí)現(xiàn)static屬性的初始化。
static內(nèi)部類:屬于整個(gè)外部類,而不是屬于外部類的每個(gè)對(duì)象。不能訪問外部類的非靜態(tài)成員(變量或者方法),.可以訪問外部類的靜態(tài)成員
final和abstract是功能相反的兩個(gè)關(guān)鍵字,可以對(duì)比記憶
abstract可以用來修飾類和方法,不能用來修飾屬性和構(gòu)造方法;使用abstract修飾的類是抽象類,需要被繼承,使用abstract修飾的方法是抽象方法,需要子類被重寫。
final可以用來修飾類、方法和屬性,不能修飾構(gòu)造方法。使用final修飾的類不能被繼承,使用final修飾的方法不能被重寫,使用final修飾的變量的值不能被修改,所以就成了常量。
特別注意:final修飾基本類型變量,其值不能改變,由原來的變量變?yōu)槌A浚坏莊inal修飾引用類型變量,棧內(nèi)存中的引用不能改變,但是所指向的堆內(nèi)存中的對(duì)象的屬性值仍舊可以改變。例如
package com.bjsxt; class Test { public static void main(String[] args) { final Dog dog = new Dog("歐歐"); dog.name = "美美";//正確 dog = new Dog("亞亞");//錯(cuò)誤 } }
final修飾符(關(guān)鍵字)如果一個(gè)類被聲明為final,意味著它不能再派生出新的子類,不能作為父類被繼承例如:String類、Math類等。將變量或方法聲明為final,可以保證它們?cè)谑褂弥胁槐桓淖儭1宦暶鳛閒inal的變量必須在聲明時(shí)給定初值,而在以后的引用中只能讀取,不可修改。被聲明為final的方法也同樣只能使用,不能重寫,但是能夠重載。 使用final修飾的對(duì)象,對(duì)象的引用地址不能變,但是對(duì)象的值可以變!
finally在異常處理時(shí)提供 finally 塊來執(zhí)行任何清除操作。如果有finally的話,則不管是否發(fā)生異常,finally語句都會(huì)被執(zhí)行。一般情況下,都把關(guān)閉物理連接(IO流、數(shù)據(jù)庫(kù)連接、Socket連接)等相關(guān)操作,放入到此代碼塊中。
finalize方法名。Java 技術(shù)允許使用 finalize() 方法在垃圾收集器將對(duì)象從內(nèi)存中清除出去之前做必要清理工作。finalize() 方法是在垃圾收集器刪除對(duì)象之前被調(diào)用的。它是在 Object 類中定義的,因此所有的類都繼承了它。子類覆蓋 finalize() 方法以整理系統(tǒng)資源或者執(zhí)行其他清理工作。 一般情況下,此方法由JVM調(diào)用,程序員不要去調(diào)用!
(1)public boolean equals(java.lang.Object)
比較對(duì)象的地址值是否相等,如果子類重寫,則比較對(duì)象的內(nèi)容是否相等;
(2)public native int hashCode() 獲取哈希碼
(3)public java.lang.String toString() 把數(shù)據(jù)轉(zhuǎn)變成字符串
(4)public final native java.lang.Class getClass() 獲取類結(jié)構(gòu)信息
(5)protected void finalize() throws java.lang.Throwable
垃圾回收前執(zhí)行的方法
(6)protected native Object clone() throws
java.lang.CloneNotSupportedException 克隆
(7)public final void wait() throws java.lang.InterruptedException
多線程中等待功能
(8)public final native void notify() 多線程中喚醒功能
(9)public final native void notifyAll() 多線程中喚醒所有等待線程的功能
同一個(gè)類 | 同一個(gè)包 | 子類 | 所有類 | |
private | * | |||
defailt | * | * | ||
protected | * | * | * | |
public | * | * | * | * |
類的訪問權(quán)限只有兩種
public公共的 可被同一項(xiàng)目中所有的類訪問。 (必須與文件名同名)
default默認(rèn)的 可被同一個(gè)包中的類訪問。
成員(成員變量或成員方法)訪問權(quán)限共有四種:
public 公共的 可以被項(xiàng)目中所有的類訪問。(項(xiàng)目可見性)
protected 受保護(hù)的 可以被這個(gè)類本身訪問;同一個(gè)包中的所有其他的類訪問;被它的子類(同一個(gè)包以及不同包中的子類)訪問。(子類可見性)
default 默認(rèn)的被這個(gè)類本身訪問;被同一個(gè)包中的類訪問。(包可見性)
private 私有的 只能被這個(gè)類本身訪問。(類可見性)
繼承條件下構(gòu)造方法的調(diào)用規(guī)則如下:
情況1:如果子類的構(gòu)造方法中沒有通過super顯式調(diào)用父類的有參構(gòu)造方法,也沒有通過this顯式調(diào)用自身的其他構(gòu)造方法,則系統(tǒng)會(huì)默認(rèn)先調(diào)用父類的無參構(gòu)造方法。在這種情況下,寫不寫“super();”語句,效果是一樣的。
情況2:如果子類的構(gòu)造方法中通過super顯式調(diào)用父類的有參構(gòu)造方法,那將執(zhí)行父類相應(yīng)構(gòu)造方法,而不執(zhí)行父類無參構(gòu)造方法。
情況3:如果子類的構(gòu)造方法中通過this顯式調(diào)用自身的其他構(gòu)造方法,在相應(yīng)構(gòu)造方法中應(yīng)用以上兩條規(guī)則。
特別注意的是,如果存在多級(jí)繼承關(guān)系,在創(chuàng)建一個(gè)子類對(duì)象時(shí),以上規(guī)則會(huì)多次向更高一級(jí)父類應(yīng)用,一直到執(zhí)行頂級(jí)父類Object類的無參構(gòu)造方法為止。
“==”是關(guān)系運(yùn)算符,equals()是方法,同時(shí)他們的結(jié)果都返回布爾值;
“==”使用情況如下:
a) 基本類型,比較的是值
b) 引用類型,比較的是地址
c) 不能比較沒有父子關(guān)系的兩個(gè)對(duì)象
equals()方法使用如下:
a) 系統(tǒng)類一般已經(jīng)覆蓋了equals(),比較的是內(nèi)容。
b) 用戶自定義類如果沒有覆蓋equals(),將調(diào)用父類的equals (比如是Object),而Object的equals的比較是地址(return (this == obj);)
c) 用戶自定義類需要覆蓋父類的equals()
注意:Object的==和equals比較的都是地址,作用相同
實(shí)現(xiàn)多態(tài)的三個(gè)條件(前提條件,向上轉(zhuǎn)型、向下轉(zhuǎn)型)
1、繼承的存在;(繼承是多態(tài)的基礎(chǔ),沒有繼承就沒有多態(tài))
2、子類重寫父類的方法。(多態(tài)下會(huì)調(diào)用子類重寫后的方法)
3、父類引用變量指向子類對(duì)象。(涉及子類到父類的類型轉(zhuǎn)換)
向上轉(zhuǎn)型 Student person = new Student()
將一個(gè)父類的引用指向一個(gè)子類對(duì)象,成為向上轉(zhuǎn)型,自動(dòng)進(jìn)行類型轉(zhuǎn)換。此時(shí)通過父類引用變量調(diào)用的方法是子類覆蓋或繼承父類的方法,而不是父類的方法此時(shí)通過父類引用變量無法調(diào)用子類特有的方法。
向下轉(zhuǎn)型 Student stu = (Student)person;
將一個(gè)指向子類對(duì)象的引用賦給一個(gè)子類的引用,成為向下轉(zhuǎn)型,此時(shí)必須進(jìn)行強(qiáng)制類型轉(zhuǎn)換。向下轉(zhuǎn)型必須轉(zhuǎn)換為父類引用指向的真實(shí)子類類型,,否則將出現(xiàn)ClassCastException,不是任意的強(qiáng)制轉(zhuǎn)換
向下轉(zhuǎn)型時(shí)可以結(jié)合使用instanceof運(yùn)算符進(jìn)行強(qiáng)制類型轉(zhuǎn)換,比如出現(xiàn)轉(zhuǎn)換異常---ClassCastException
傳統(tǒng)的C/C++語言,需要程序員負(fù)責(zé)回收已經(jīng)分配內(nèi)存。
顯式回收垃圾回收的缺點(diǎn):
1)程序忘記及時(shí)回收,從而導(dǎo)致內(nèi)存泄露,降低系統(tǒng)性能。
2)程序錯(cuò)誤回收程序核心類庫(kù)的內(nèi)存,導(dǎo)致系統(tǒng)崩潰。
Java語言不需要程序員直接控制內(nèi)存回收,是由JRE在后臺(tái)自動(dòng)回收不再使用的內(nèi)存,稱為垃圾回收機(jī)制,簡(jiǎn)稱GC;
1)可以提高編程效率。
2)保護(hù)程序的完整性。
3)其開銷影響性能。Java虛擬機(jī)必須跟蹤程序中有用的對(duì)象,確定哪些是無用的。
垃圾回收機(jī)制的 特點(diǎn)
1)垃圾回收機(jī)制回收J(rèn)VM堆內(nèi)存里的對(duì)象空間,不負(fù)責(zé)回收棧內(nèi)存數(shù)據(jù)。
2)對(duì)其他物理連接,比如數(shù)據(jù)庫(kù)連接、輸入流輸出流、Socket連接無能為力。
3)垃圾回收發(fā)生具有不可預(yù)知性,程序無法精確控制垃圾回收機(jī)制執(zhí)行。
4)可以將對(duì)象的引用變量設(shè)置為null,暗示垃圾回收機(jī)制可以回收該對(duì)象。
現(xiàn)在的JVM有多種垃圾回收 實(shí)現(xiàn)算法,表現(xiàn)各異。
垃圾回收機(jī)制回收任何對(duì)象之前,總會(huì)先調(diào)用它的finalize方法(如果覆蓋該方法,讓一個(gè)新的引用變量重新引用該對(duì)象,則會(huì)重新激活對(duì)象)。
程序員可以通過System.gc()或者Runtime.getRuntime().gc()來通知系統(tǒng)進(jìn)行垃圾回收,會(huì)有一些效果,但是系統(tǒng)是否進(jìn)行垃圾回收依然不確定。
永遠(yuǎn)不要主動(dòng)調(diào)用某個(gè)對(duì)象的finalize方法,應(yīng)該交給垃圾回收機(jī)制調(diào)用。
1) 八個(gè)基本數(shù)據(jù)類型的包裝類
基本數(shù)據(jù)類型 | 包裝類 |
byte | Byte |
boolean | Boolean |
short | Short |
char | Character |
int | Integer |
long | Long |
float | Float |
double | Double |
2)為什么為基本類型引入包裝類
2.1基本數(shù)據(jù)類型有方便之處,簡(jiǎn)單、高效。
2.2但是Java中的基本數(shù)據(jù)類型卻是不面向?qū)ο蟮模]有屬性、方法),這在實(shí)際使用時(shí)存在很多的不便(比如集合的元素只能是Object)。
為了解決這個(gè)不足,在設(shè)計(jì)類時(shí)為每個(gè)基本數(shù)據(jù)類型設(shè)計(jì)了一個(gè)對(duì)應(yīng)的類進(jìn)行包裝,這樣八個(gè)和基本數(shù)據(jù)類型對(duì)應(yīng)的類統(tǒng)稱為包裝類(Wrapper Class)。
3) 包裝類和基本數(shù)據(jù)類型之間的轉(zhuǎn)換
3.1包裝類------ wrapperInstance.xxxValue() ------>基本數(shù)據(jù)類型
3.2包裝類-------new WrapperClass(primitive)
3.2包裝類-------new WrapperClass(primitive)
4) 自動(dòng)裝箱和自動(dòng)拆箱
JDK1.5提供了自動(dòng)裝箱(autoboxing)和自動(dòng)拆箱(autounboxing)功能, 從而實(shí)現(xiàn)了包裝類和基本數(shù)據(jù)類型之間的自動(dòng)轉(zhuǎn)換
5) 包裝類還可以實(shí)現(xiàn)基本類型變量和字符串之間的轉(zhuǎn)換
基本類型變量--->String.valueof()--->字符串 基本類型變量<---WrapperClass.parseXxx(string)---字符串
int是java提供的8種原始數(shù)據(jù)類型之一,Java為每個(gè)原始類型提供了封裝類,Integer是java為int提供的封裝類。
int是java提供的8種原始數(shù)據(jù)類型之一,Java為每個(gè)原始類型提供了封裝類,Integer是java為int提供的封裝類。
在Hibernate中,如果將OID定義為Integer類型,那么Hibernate就可以根據(jù)其值是否為null而判斷一個(gè)對(duì)象是否是臨時(shí)的,如果將OID定義為了int類型,還需要在hbm映射文件中設(shè)置其unsaved-value屬性為0。
另外,Integer提供了多個(gè)與整數(shù)相關(guān)的操作方法,例如,將一個(gè)字符串轉(zhuǎn)換成整數(shù),Integer中還定義了表示整數(shù)的最大值和最小值的常量。
1) java.sql.Date是java.util.Date的子類,是一個(gè)包裝了毫秒值的瘦包裝器,允許 JDBC 將毫秒值標(biāo)識(shí)為 SQL DATE 值。毫秒值表示自 1970 年 1 月 1 日 00:00:00 GMT 以來經(jīng)過的毫秒數(shù)。 為了與 SQL DATE 的定義一致,由 java.sql.Date 實(shí)例包裝的毫秒值必須通過將時(shí)間、分鐘、秒和毫秒設(shè)置為與該實(shí)例相關(guān)的特定時(shí)區(qū)中的零來“規(guī)范化”。 說白了,java.sql.Date就是與數(shù)據(jù)庫(kù)Date相對(duì)應(yīng)的一個(gè)類型,而java.util.Date是純java的Date。
2)JAVA里提供的日期和時(shí)間類,java.sql.Date和java.sql.Time,只會(huì)從數(shù)據(jù)庫(kù)里讀取某部分值,這有時(shí)會(huì)導(dǎo)致丟失數(shù)據(jù)。例如一個(gè)包含2002/05/22 5:00:57 PM的字段,讀取日期時(shí)得到的是2002/05/22,而讀取時(shí)間時(shí)得到的是5:00:57 PM. 你需要了解數(shù)據(jù)庫(kù)里存儲(chǔ)時(shí)間的精度。有些數(shù)據(jù)庫(kù),比如MySQL,精度為毫秒,然而另一些數(shù)據(jù)庫(kù),包括Oracle,存儲(chǔ)SQL DATE類型數(shù)據(jù)時(shí),毫秒部分的數(shù)據(jù)是不保存的。以下操作中容易出現(xiàn)不易被發(fā)現(xiàn)的BUG:獲得一個(gè)JAVA里的日期對(duì)象。 從數(shù)據(jù)庫(kù)里讀取日期 試圖比較兩個(gè)日期對(duì)象是否相等。如果毫秒部分丟失,本來認(rèn)為相等的兩個(gè)日期對(duì)象用Equals方法可能返回false。.sql.Timestamp類比java.util.Date類精確度要高。這個(gè)類包了一個(gè)getTime()方法,但是它不會(huì)返回額外精度部分的數(shù)據(jù),因此必須使用...
總之,java.util.Date 就是Java的日期對(duì)象,而java.sql.Date 是針對(duì)SQL語句使用的,只包含日期而沒有時(shí)間部分。
package com.bjsxt; import java.io.File; public class $ { public static void main(String[] args) { String path = "D:/301SXT"; test(path); } private static void test(String path) { File f = new File(path); File[] fs = f.listFiles(); if (fs == null) { return; } for (File file : fs) { if (file.isFile()) { System.out.println(file.getPath()); } else { test(file.getPath()); } } }
A | Java程序經(jīng)編譯后產(chǎn)生machine code |
B. | Java程序經(jīng)編譯后會(huì)生產(chǎn)byte code |
C. | Java程序經(jīng)編譯后會(huì)產(chǎn)生DLL |
D. | 以上都不正確 |
答案:B
分析: Java是解釋型語言,編譯出來的是字節(jié)碼; 因此A不正確,C是C/C++語言編譯動(dòng)態(tài)鏈接庫(kù)的文件為.DLL; 正確答案為B
|
A | class中的construtor不可省略 |
B. | construtor與class同名,但方法不能與class同名 |
C. | construtor在一個(gè)對(duì)象被new時(shí)執(zhí)行 |
D. | 一個(gè)class只能定義一個(gè)construtor |
答案:C
分析:A:如果class中的construtor省略不寫,系統(tǒng)會(huì)默認(rèn)提供一個(gè)無參構(gòu)造
B:方法名可以與類名同名,只是不符合命名規(guī)范
D:一個(gè)class中可以定義N多個(gè)construtor,這些construtor構(gòu)成構(gòu)造方法的重載
|
A | private |
B. | protected |
C. | final |
D. | abstract |
答案:D
分析:接口中的訪問權(quán)限修飾符只可以是public或default
接口中的所有的方法必須要實(shí)現(xiàn)類實(shí)現(xiàn),所以不能使用final
接口中所有的方法默認(rèn)都是abstract的,所以接口可以使用abstract修飾,但通常abstract可以省略不寫
|
class A { public A(){ System.out.println("A"); } } class B extends A{ public B(){ System.out.println("B"); } public static void main(String[] args) { B b=new B(); } }
A | 不能通過編譯 |
B. | 通過編譯,輸出AB |
C. | 通過編譯,輸出B |
D. | 通過編譯,輸出A |
答案:B
分析:在繼承關(guān)系下,創(chuàng)建子類對(duì)象,先執(zhí)行父類的構(gòu)造方法,再執(zhí)行子類的構(gòu)造方法。
|
A | abstract不能與final并列修飾同一個(gè)類 |
B. | abstract類中可以有private的成員 |
C. | abstract方法必須在abstract類中 |
D. | static方法能處理非static的屬性 |
答案:D
分析:因?yàn)閟tatic得方法在裝載class得時(shí)候首先完成,比 構(gòu)造方法早,此時(shí)非static得屬性和方法還沒有完成初始化所以不能調(diào)用。
|
A | 程序員必須創(chuàng)建一個(gè)線程來釋放內(nèi)存 |
B. | 內(nèi)存回收程序負(fù)責(zé)釋放無用內(nèi)存 |
C. | 內(nèi)存回收程序允許程序員直接釋放內(nèi)存 |
D. | 內(nèi)存回收程序可以在指定的時(shí)間釋放內(nèi)存對(duì)象 |
答案:B
分析: A. 程序員不需要?jiǎng)?chuàng)建線程來釋放內(nèi)存.
C. 也不允許程序員直接釋放內(nèi)存.
D. 不一定在什么時(shí)刻執(zhí)行垃圾回收.
|
A | _sysl_111 |
B. | 2 mail |
C. | $change |
D. | class |
答案:AC
分析: 標(biāo)識(shí)符的命令規(guī)范,可以包含字母、數(shù)字、下劃線、$,不能以數(shù)字開頭,不能是Java關(guān)鍵字
|
A | java.lang.Cloneable是類 |
B. | java.langRunnable是接口 |
C. | Double對(duì)象在java.lang包中 |
D. | Double a=1.0是正確的java語句 |
Double a=1.0是正確的java語句
分析:java.lang.Cloneable是接口
|
A | 45.定義一個(gè)類名為”MyClass.java”的類,并且該類可被一個(gè)工程中的所有類訪問,那么該類的正確聲明為()(選擇兩項(xiàng)) |
B. | class MyClass extends Object |
C. | public class MyClass |
D. | public class MyClass extends Object |
答案:CD
分析: A 類的訪問權(quán)限只能是public或default
B使用默認(rèn)訪問權(quán)限的類,只能在本包中訪問
|
答: 面向?qū)ο蟮娜筇卣鳎悍庋b、繼承、多態(tài)。
舉例:(比如設(shè)計(jì)一個(gè)游戲)我現(xiàn)在創(chuàng)建了一個(gè)對(duì)象,名叫戰(zhàn)士。
戰(zhàn)士的屬性是—性別,年齡,職業(yè),等級(jí),戰(zhàn)斗力,血量。
它的方法—戰(zhàn)斗,逃跑,吃飯,睡覺,死。
后來,我又建了一個(gè)對(duì)象,叫人。
屬性:性別,年齡,職業(yè),等級(jí),血量
方法:逃跑,吃飯,睡覺,死。
我讓人,成為戰(zhàn)士的父類,戰(zhàn)士可以直接繼承人的屬性和方法。
戰(zhàn)士修改成—
屬性:戰(zhàn)斗力。
方法:戰(zhàn)斗。
看上去戰(zhàn)士的資料變少了,實(shí)際上沒有,我們?nèi)匀豢梢哉{(diào)用方法—戰(zhàn)士.死。
而且我們還可以重載戰(zhàn)士.死的方法,簡(jiǎn)稱重載死法。
我還建了一個(gè)對(duì)象—法師,父類也是人。
屬性:法力值
方法:施法,泡妞。
你看,用了繼承,創(chuàng)建對(duì)象變得更方便了。
再后來,我又建立了一個(gè)對(duì)象,叫怪物。
屬性:等級(jí),戰(zhàn)力,血量。
方法:戰(zhàn)斗,死。
建了個(gè)對(duì)象,叫白兔怪,父類怪物,可繼承怪物所有的屬性和方法。
屬性:毛色。
方法:賣萌,吃胡蘿卜。
答:
內(nèi)存溢出 out of memory,是指程序在申請(qǐng)內(nèi)存時(shí),沒有足夠的內(nèi)存空間供其使用,出現(xiàn)out of memory;比如申請(qǐng)了一個(gè)integer,但給它存了long才能存下的數(shù),那就是內(nèi)存溢出。
內(nèi)存泄露 memory leak,是指程序在申請(qǐng)內(nèi)存后,無法釋放已申請(qǐng)的內(nèi)存空間,一次內(nèi)存泄露危害可以忽略,但內(nèi)存泄露堆積后果很嚴(yán)重,無論多少內(nèi)存,遲早會(huì)被占光。
memory leak會(huì)最終會(huì)導(dǎo)致out of memory!
答:Java中的序列化機(jī)制能夠?qū)⒁粋€(gè)實(shí)例對(duì)象(只序列化對(duì)象的屬性值,而不會(huì)去序列化什么所謂的方法。)的狀態(tài)信息寫入到一個(gè)字節(jié)流中使其可以通過socket進(jìn)行傳輸、或者持久化到存儲(chǔ)數(shù)據(jù)庫(kù)或文件系統(tǒng)中;然后在需要的時(shí)候通過字節(jié)流中的信息來重構(gòu)一個(gè)相同的對(duì)象。一般而言,要使得一個(gè)類可以序列化,只需簡(jiǎn)單實(shí)現(xiàn)java.io.Serializable接口即可。
對(duì)象的序列化主要有兩種用途:
1) 把對(duì)象的字節(jié)序列永久地保存到硬盤上,通常存放在一個(gè)文件中;
2) 在網(wǎng)絡(luò)上傳送對(duì)象的字節(jié)序列。
在很多應(yīng)用中,需要對(duì)某些對(duì)象進(jìn)行序列化,讓它們離開內(nèi)存空間,入住物理硬盤,以便長(zhǎng)期保存。比如最常見的是Web服務(wù)器中的Session對(duì)象,當(dāng)有 10萬用戶并發(fā)訪問,就有可能出現(xiàn)10萬個(gè)Session對(duì)象,內(nèi)存可能吃不消,于是Web容器就會(huì)把一些seesion先序列化到硬盤中,等要用了,再把保存在硬盤中的對(duì)象還原到內(nèi)存中。
當(dāng)兩個(gè)進(jìn)程在進(jìn)行遠(yuǎn)程通信時(shí),彼此可以發(fā)送各種類型的數(shù)據(jù)。無論是何種類型的數(shù)據(jù),都會(huì)以二進(jìn)制序列的形式在網(wǎng)絡(luò)上傳送。發(fā)送方需要把這個(gè)Java對(duì)象轉(zhuǎn)換為字節(jié)序列,才能在網(wǎng)絡(luò)上傳送;接收方則需要把字節(jié)序列再恢復(fù)為Java對(duì)象。
答:Java創(chuàng)建對(duì)象的幾種方式(重要):
1、 用new語句創(chuàng)建對(duì)象,這是最常見的創(chuàng)建對(duì)象的方法。
2、 運(yùn)用反射手段,調(diào)用java.lang.Class或者java.lang.reflect.Constructor類的newInstance()實(shí)例方法。
3、 調(diào)用對(duì)象的clone()方法。
4、運(yùn)用反序列化手段,調(diào)用java.io.ObjectInputStream對(duì)象的 readObject()方法。
(1)和(2)都會(huì)明確的顯式的調(diào)用構(gòu)造函數(shù) ;(3)是在內(nèi)存上對(duì)已有對(duì)象的影印,所以不會(huì)調(diào)用構(gòu)造函數(shù) ;(4)是從文件中還原類的對(duì)象,也不會(huì)調(diào)用構(gòu)造函數(shù)。
答:匿名內(nèi)部類是沒有名字的內(nèi)部類,不能繼承其它類,但一個(gè)內(nèi)部類可以作為一個(gè)接口,由另一個(gè)內(nèi)部類實(shí)現(xiàn).
1、由于匿名內(nèi)部類沒有名字,所以它沒有構(gòu)造函數(shù)。因?yàn)闆]有構(gòu)造函數(shù),所以它必須完全借用父類的構(gòu)造函數(shù)來實(shí)例化,換言之:匿名內(nèi)部類完全把創(chuàng)建對(duì)象的任務(wù)交給了父類去完成。
2、在匿名內(nèi)部類里創(chuàng)建新的方法沒有太大意義,但它可以通過覆蓋父類的方法達(dá)到神奇效果,如上例所示。這是多態(tài)性的體現(xiàn)。
3、因?yàn)槟涿麅?nèi)部類沒有名字,所以無法進(jìn)行向下的強(qiáng)制類型轉(zhuǎn)換,持有對(duì)一個(gè)匿名內(nèi)部類對(duì)象引用的變量類型一定是它的直接或間接父類類型。
(1) 在Java中是使用泛型來約束HashMap中的key和value的類型的,即HashMap< K, V>;而泛型在Java的規(guī)定中必須是對(duì)象Object類型的,也就是說HashMap< K, V>可以理解為HashMap< Object, Object>,很顯然基本數(shù)據(jù)類型不是Object類型的,因此不能作為鍵值,只能是引用類型。雖然我們?cè)贖ashMap中可以這樣添加數(shù)據(jù):“map.put(1, “Java”);”,但實(shí)際上是將其中的key值1進(jìn)行了自動(dòng)裝箱操作,變?yōu)榱薎nteger類型。
(1) 在Java中是使用泛型來約束HashMap中的key和value的類型的,即HashMap< K, V>;而泛型在Java的規(guī)定中必須是對(duì)象Object類型的,也就是說HashMap< K, V>可以理解為HashMap< Object, Object>,很顯然基本數(shù)據(jù)類型不是Object類型的,因此不能作為鍵值,只能是引用類型。雖然我們?cè)贖ashMap中可以這樣添加數(shù)據(jù):“map.put(1, “Java”);”,但實(shí)際上是將其中的key值1進(jìn)行了自動(dòng)裝箱操作,變?yōu)榱薎nteger類型。
實(shí)現(xiàn)多態(tài)有三個(gè)前提條件:
1、 繼承的存在;(繼承是多態(tài)的基礎(chǔ),沒有繼承就沒有多態(tài))。
2、子類重寫父類的方法。(多態(tài)下會(huì)調(diào)用子類重寫后的方法)。
3、父類引用變量指向子類對(duì)象。(涉及子類到父類的類型轉(zhuǎn)換)。
最后使用父類的引用變量調(diào)用子類重寫的方法即可實(shí)現(xiàn)多態(tài)。
A | Java中的繼承允許一個(gè)子類繼承多個(gè)父類 |
B. | 父類更具有通用性,子類更具體 |
C. | Java中的繼承存在著傳遞性 |
D. | 當(dāng)實(shí)例化子類時(shí)會(huì)遞歸調(diào)用父類中的構(gòu)造方法 |
答案:A
分析:Java是單繼承的,一個(gè)類只能繼承一個(gè)父類。
|
54.Java 中 Math.random()/Math.random()值為?
如果除數(shù)與被除數(shù)均為0.0的話,則運(yùn)行結(jié)果為NaN(Not a Number的簡(jiǎn)寫),計(jì)算錯(cuò)誤。
不是,兩者沒有任何關(guān)聯(lián);
Pair是單獨(dú)的類,只不過用不同類型的參數(shù)(泛型)進(jìn)行了相應(yīng)的實(shí)例化而已;所以,Pair< Manager>和Pair< Employee>不是子類的關(guān)系。
56.接口和抽象類的區(qū)別
抽象類和接口均包含抽象方法,類必須實(shí)現(xiàn)所有的抽象方法,否則是抽象類
抽象類和接口都不能實(shí)例化,他們位于繼承樹的頂端,用來被其他類繼承和實(shí)現(xiàn)
兩者的區(qū)別主要體現(xiàn)在兩方面:語法方面和設(shè)計(jì)理念方面
語法方面的區(qū)別是比較低層次的,非本質(zhì)的,主要表現(xiàn)在:
接口中只能定義全局靜態(tài)常量,不能定義變量。抽象類中可以定義常量和變量。
接口中所有的方法都是全局抽象方法。抽象類中可以有0個(gè)、1個(gè)或多個(gè),甚至全部都是抽象方法。
抽象類中可以有構(gòu)造方法,但不能用來實(shí)例化,而在子類實(shí)例化是執(zhí)行,完成屬于抽象類的初始化操作。接口中不能定義構(gòu)造方法。
一個(gè)類只能有一個(gè)直接父類(可以是抽象類),但可以充實(shí)實(shí)現(xiàn)多個(gè)接口。一個(gè)類使用extends來繼承抽象類,使用implements來實(shí)現(xiàn)接口。
一個(gè)類只能有一個(gè)直接父類(可以是抽象類),但可以充實(shí)實(shí)現(xiàn)多個(gè)接口。一個(gè)類使用extends來繼承抽象類,使用implements來實(shí)現(xiàn)接口。
抽象類體現(xiàn)了一種繼承關(guān)系,目的是復(fù)用代碼,抽象類中定義了各個(gè)子類的相同代碼,可以認(rèn)為父類是一個(gè)實(shí)現(xiàn)了部分功能的“中間產(chǎn)品”,而子類是“最終產(chǎn)品”。父類和子類之間必須存在“is-a”的關(guān)系,即父類和子類在概念本質(zhì)上應(yīng)該是相同的。
接口并不要求實(shí)現(xiàn)類和接口在概念本質(zhì)上一致的,僅僅是實(shí)現(xiàn)了接口定義的約定或者能力而已。接口定義了“做什么”,而實(shí)現(xiàn)類負(fù)責(zé)完成“怎么做”,體現(xiàn)了功能(規(guī)范)和實(shí)現(xiàn)分離的原則。接口和實(shí)現(xiàn)之間可以認(rèn)為是一種“has-a的關(guān)系”
相同點(diǎn):
同步方法就是在方法前加關(guān)鍵字synchronized,然后被同步的方法一次只能有一個(gè)線程進(jìn)入,其他線程等待。而同步代碼塊則是在方法內(nèi)部使用大括號(hào)使得一個(gè)代碼塊得到同步。同步代碼塊會(huì)有一個(gè)同步的“目標(biāo)”,使得同步塊更加靈活一些(同步代碼塊可以通過“目標(biāo)”決定需要鎖定的對(duì)象)。
一般情況下,如果此“目標(biāo)”為this,同步方法和代碼塊沒有太大的區(qū)別。
區(qū)別:
同步方法直接在方法上加synchronized實(shí)現(xiàn)加鎖,同步代碼塊則在方法內(nèi)部加鎖。很明顯,同步方法鎖的范圍比較大,而同步代碼塊范圍要小點(diǎn)。一般同步的范圍越大,性能就越差。所以一般需要加鎖進(jìn)行同步的時(shí)候,范圍越小越好,這樣性能更好。
靜態(tài)內(nèi)部類不需要有指向外部類的引用。但非靜態(tài)內(nèi)部類需要持有對(duì)外部類的引用。
靜態(tài)內(nèi)部類可以有靜態(tài)成員(方法,屬性),而非靜態(tài)內(nèi)部類則不能有靜態(tài)成員(方法,屬性)。
非靜態(tài)內(nèi)部類能夠訪問外部類的靜態(tài)和非靜態(tài)成員。靜態(tài)內(nèi)部類不能訪問外部類的非靜態(tài)成員,只能訪問外部類的靜態(tài)成員。
實(shí)例化方式不同:
1) 靜態(tài)內(nèi)部類:不依賴于外部類的實(shí)例,直接實(shí)例化內(nèi)部類對(duì)象
2) 非靜態(tài)內(nèi)部類:通過外部類的對(duì)象實(shí)例生成內(nèi)部類對(duì)象
反射的概念:
反射,一種計(jì)算機(jī)處理方式。是程序可以訪問、檢測(cè)和修改它本身狀態(tài)或行為的一種能力。
Java反射可以于運(yùn)行時(shí)加載,探知和使用編譯期間完全未知的類.
程序在運(yùn)行狀態(tài)中, 可以動(dòng)態(tài)加載一個(gè)只有名稱的類, 對(duì)于任意一個(gè)已經(jīng)加載的類,都能夠知道這個(gè)類的所有屬性和方法; 對(duì)于任意一個(gè)對(duì)象,都能調(diào)用他的任意一個(gè)方法和屬性;
加載完類之后, 在堆內(nèi)存中會(huì)產(chǎn)生一個(gè)Class類型的對(duì)象(一個(gè)類只有一個(gè)Class對(duì)象), 這個(gè)對(duì)象包含了完整的類的結(jié)構(gòu)信息,而且這個(gè)Class對(duì)象就像一面鏡子,透過這個(gè)鏡子看到類的結(jié)構(gòu),所以被稱之為:反射.
java反射使得我們可以在程序運(yùn)行時(shí)動(dòng)態(tài)加載一個(gè)類,動(dòng)態(tài)獲取類的基本信息和定義的方法,構(gòu)造函數(shù),域等。
除了檢閱類信息外,還可以動(dòng)態(tài)創(chuàng)建類的實(shí)例,執(zhí)行類實(shí)例的方法,獲取類實(shí)例的域值。反射使java這種靜態(tài)語言有了動(dòng)態(tài)的特性。
反射的作用:
通過反射可以使程序代碼訪問裝載到JVM 中的類的內(nèi)部信息
1) 獲取已裝載類的屬性信息
2) 獲取已裝載類的方法
3) 獲取已裝載類的構(gòu)造方法信息
反射的優(yōu)點(diǎn):
增加程序的靈活性。
如struts中。請(qǐng)求的派發(fā)控制。
當(dāng)請(qǐng)求來到時(shí)。struts通過查詢配置文件。找到該請(qǐng)求對(duì)應(yīng)的action。已經(jīng)方法。
然后通過反射實(shí)例化action。并調(diào)用響應(yīng)method。
如果不適用反射,那么你就只能寫死到代碼里了。
所以說,一個(gè)靈活,一個(gè)不靈活。
很少情況下是非用反射不可的。大多數(shù)情況下反射是為了提高程序的靈活性。因此一般框架中使用較多。因?yàn)榭蚣芤m用更多的情況。對(duì)靈活性要求較高。
A | java.sql |
B. | java.awt |
C. | java.lang |
D. | java.swing |
答案:A
分析:
java.awt和javax.swing兩個(gè)包是圖形用戶界面編程所需要的包;
java.lang包則提供了Java編程中用到的基礎(chǔ)類。
|
A | && |
B. | <> |
C. | if |
D. | = |
答案:AD
分析:
&&是邏輯運(yùn)算符中的短路與;
<>表示不等于,但是Java中不能這么使用,應(yīng)該是!=;
if不是運(yùn)算符;
=是賦值運(yùn)算符。
|
public class Test1 { public static void main(String[] args) { int a = 0; int c = 0; do{ --c; a = a - 1; } while (a > 0); System.out.println(c); } }
A | 0 |
B. | 1 |
C. | -1 |
D. | 死循環(huán) |
答案:C
分析:
do-while循環(huán)的特點(diǎn)是先執(zhí)行后判斷,所以代碼先執(zhí)行--c操作,得到c為-1,之后執(zhí)行a=a-1的操作,得到a為-1,然后判斷a是否大于0,判斷條件不成立,退出循環(huán),輸出c為-1。
|
A | abstract修飾符可修飾字段,方法和類 |
B. | 抽象方法的body部分必須用一對(duì)大括號(hào){}包住 |
C. | 聲明抽象方法,大括號(hào)可有可無 |
D. | 聲明抽象方法不可寫出大括號(hào) |
答案:D
分析:
abstract只能修飾方法和類,不能修飾字段;
抽象方法不能有方法體,即沒有{};
同B。
|
A | 形式參數(shù)可被視為local Variable |
B. | 形式參數(shù)可被視為local Variable |
C. | 形式參數(shù)可被所有的字段修飾符修飾 |
D. | 形式參數(shù)為方法被調(diào)用時(shí),真正被傳遞的參數(shù) |
答案:A
分析:
local Variable為局部變量,形參和局部變量一樣都只有在方法內(nèi)才會(huì)發(fā)生作用,也只能在方法中使用,不會(huì)在方法外可見;
對(duì)于形式參數(shù)只能用final修飾符,其它任何修飾符都會(huì)引起編譯器錯(cuò)誤;
真正被傳遞的參數(shù)是實(shí)參;
形式參數(shù)可是基本數(shù)據(jù)類型也可以是引用類型(對(duì)象)。
|
A | 實(shí)例方法可直接調(diào)用超類的實(shí)例方法 |
B. | 實(shí)例方法可直接調(diào)用超類的類方法 |
C. | 實(shí)例方法可直接調(diào)用其他類的實(shí)例方法 |
D. | 實(shí)例方法可直接調(diào)用本類的類方法 |
答案:D
分析:
實(shí)例方法不可直接調(diào)用超類的私有實(shí)例方法;
實(shí)例方法不可直接調(diào)用超類的私有的類方法;
要看訪問權(quán)限。
|
A | 類 (Class) |
B. | Applet |
C. | Application |
D. | Servlet |
答案:BCD
分析:
是Java中的類,不是程序;
內(nèi)嵌于Web文件中,由瀏覽器來觀看的Applet;
可獨(dú)立運(yùn)行的 Application;
服務(wù)器端的 Servlet。
|
A | 環(huán)境變量可在編譯source code時(shí)指定 |
B. | 在編譯程序時(shí),所指定的環(huán)境變置不包括class path |
C. | javac —次可同時(shí)編譯數(shù)個(gè)Java 源文件 |
D. | javac.exe能指定編譯結(jié)果要置于哪個(gè)目錄(directory) |
答案:BCD
分析:
環(huán)境變量一般都是先配置好再編譯源文件。
|
A | new |
B. | $Usdollars |
C. | 1234 |
D. | car.taxi |
答案:ACD
分析:
new是Java的關(guān)鍵字;
C. 數(shù)字不能開頭;
D. 不能有“.”。
|
A | 數(shù)組是—種對(duì)象 |
B. | 數(shù)組屬于一種原生類 |
C. | int number[]=(31,23,33,43,35,63) |
D. | 數(shù)組的大小可以任意改變 |
答案:BCD
分析:
B. Java中的原生類(即基本數(shù)據(jù)類型)有8種,但不包括數(shù)組;
C. 語法錯(cuò)誤,應(yīng)該“{···}”,而不是“(···)”;
D. 數(shù)組的長(zhǎng)度一旦確定就不能修改。
|
A | private |
B. | public |
C. | protected |
D. | static |
答案:ACD
分析:
能夠修飾interface的只有public、abstract以及默認(rèn)的三種修飾符。
|
A | call by value不會(huì)改變實(shí)際參數(shù)的數(shù)值 |
B. | call by reference能改變實(shí)際參數(shù)的參考地址 |
C. | call by reference 不能改變實(shí)際參數(shù)的參考地址 |
D. | call by reference 能改變實(shí)際參數(shù)的內(nèi)容 |
答案:ACD
分析:
Java中參數(shù)的傳遞有兩種,一種是按值傳遞(call by value:傳遞的是具體的值,如基礎(chǔ)數(shù)據(jù)類型),另一種是按引用傳遞(call by reference:傳遞的是對(duì)象的引用,即對(duì)象的存儲(chǔ)地址)。前者不能改變實(shí)參的數(shù)值,后者雖然不能改變實(shí)參的參考地址,但可以通過該地址訪問地址中的內(nèi)容從而實(shí)現(xiàn)內(nèi)容的改變。
|
A | 在類方法中可用this來調(diào)用本類的類辦法 |
B. | 在類方法中調(diào)用本類的類方法時(shí)可以直接調(diào)用 |
C. | 在類方法中只能調(diào)用本類中的類方法 |
D. | 在類方法中絕對(duì)不能調(diào)用實(shí)例方法 |
答案:ACD
分析:
類方法是在類加載時(shí)被加載到方法區(qū)存儲(chǔ)的,此時(shí)還沒有創(chuàng)建對(duì)象,所以不能使用this或者super關(guān)鍵字;
C. 在類方法中還可以調(diào)用其他類的類方法;
D. 在類方法可以通過創(chuàng)建對(duì)象來調(diào)用實(shí)例方法。
|
A | Java面向?qū)ο笳Z言容許單獨(dú)的過棧與函數(shù)存在 |
B. | Java面向?qū)ο笳Z言容許單獨(dú)的方法存在 |
C. | Java語言中的方法屬于類中的成員(member) |
D. | Java語言中的方法必定隸屬于某一類(對(duì)象),調(diào)用方法與過程或函數(shù)相同 |
答案:ABC
分析:
B. Java不允許單獨(dú)的方法,過程或函數(shù)存在,需要隸屬于某一類中;
C. 靜態(tài)方法屬于類的成員,非靜態(tài)方法屬于對(duì)象的成員。
|
A | 能被java.exe成功運(yùn)行的java class文件必須有main()方法 |
B. | J2SDK就是Java API |
C. | Appletviewer.exe可利用jar選項(xiàng)運(yùn)行.jar文件 |
D. | 能被Appletviewer成功運(yùn)行的java class文件必須有main()方法 |
答案:BCD
分析:
B. J2SDK是sun公司編程工具,API是指的應(yīng)用程序編程接口;
C. Appletviewer.exe就是用來解釋執(zhí)行java applet應(yīng)用程序的,一種執(zhí)行HTML文件上的Java小程序類的Java瀏覽器;
D. 能被Appletviewer成功運(yùn)行的java class文件可以沒有main()方法。
|
A | float |
B. | double |
C. | Float |
D. | Double |
答案:B
分析:
小數(shù)默認(rèn)是雙精度浮點(diǎn)型即double類型的。
|
A | private |
B. | protected |
C. | final |
D. | abstract |
答案:D
分析:
能夠修飾interface的只有public、abstract以及默認(rèn)的三種修飾符。
|
A | 是 |
B. | 否 |
答案:A
分析:
Java創(chuàng)建對(duì)象的幾種方式:
(1) 用new語句創(chuàng)建對(duì)象,這是最常見的創(chuàng)建對(duì)象的方法。
(2) 運(yùn)用反射手段,調(diào)用java.lang.Class或者
java.lang.reflect.Constructor類的newInstance()實(shí)例方法。
(3) 調(diào)用對(duì)象的clone()方法。
(4) 運(yùn)用反序列化手段,調(diào)用java.io.ObjectInputStream對(duì)象的readObject()方法。
(1)和(2)都會(huì)明確的顯式的調(diào)用構(gòu)造函數(shù);(3)是在內(nèi)存上對(duì)已有對(duì)象的影印,所以不會(huì)調(diào)用構(gòu)造函數(shù);(4)是從文件中還原類的對(duì)象,也不會(huì)調(diào)用構(gòu)造函數(shù)。
|
78.存在使i+1< i的數(shù)么?
接口可以繼承接口,抽象類可以實(shí)現(xiàn)接口,抽象類可以繼承實(shí)體類。
int是java提供的8種原始數(shù)據(jù)類型之一。Java為每個(gè)原始類型提供了封裝類,Integer是java為int提供的封裝類。int的默認(rèn)值為0,而Integer的默認(rèn)值為null,即Integer可以區(qū)分出未賦值和值為0的區(qū)別,int則無法表達(dá)出未賦值的情況,例如,要想表達(dá)出沒有參加考試和考試成績(jī)?yōu)?的區(qū)別,則只能使用Integer。在JSP開發(fā)中,Integer的默認(rèn)為null,所以用el表達(dá)式在文本框中顯示時(shí),值為空白字符串,而int默認(rèn)的默認(rèn)值為0,所以用el表達(dá)式在文本框中顯示時(shí),結(jié)果為0,所以,int不適合作為web層的表單數(shù)據(jù)的類型。
在Hibernate中,如果將OID定義為Integer類型,那么Hibernate就可以根據(jù)其值是否為null而判斷一個(gè)對(duì)象是否是臨時(shí)的,如果將OID定義為了int類型,還需要在hbm映射文件中設(shè)置其unsaved-value屬性為0。另外,Integer提供了多個(gè)與整數(shù)相關(guān)的操作方法,例如,將一個(gè)字符串轉(zhuǎn)換成整數(shù),Integer中還定義了表示整數(shù)的最大值和最小值的常量。
SerialVersionUid,簡(jiǎn)言之,其目的是序列化對(duì)象版本控制,有關(guān)各版本反序列化時(shí)是否兼容。如果在新版本中這個(gè)值修改了,新版本就不兼容舊版本,反序列化時(shí)會(huì)拋出InvalidClassException異常。如果修改較小,比如僅僅是增加了一個(gè)屬性,我們希望向下兼容,老版本的數(shù)據(jù)都能保留,那就不用修改;如果我們刪除了一個(gè)屬性,或者更改了類的繼承關(guān)系,必然不兼容舊數(shù)據(jù),這時(shí)就應(yīng)該手動(dòng)更新版本號(hào),即SerialVersionUid。
< a\b[^>]+\bhref="([^"]*)"[^>]*>([\s\S]*?)< /a>
< a\b[^>]+\bhref="([^"]*)"[^>]*>([\s\S]*?)< /a>
答: 110
答:Java程序中創(chuàng)建新的類對(duì)象,使用關(guān)鍵字new是正確的; 回收無用的類對(duì)象使用關(guān)鍵字free是錯(cuò)誤的.
答:getDeclaredFields(): 可以獲取所有本類自己聲明的方法, 不能獲取繼承的方法
getFields(): 只能獲取所有public聲明的方法, 包括繼承的方法
答:不正確。
通常情況下,進(jìn)行比較判斷的處理,switch 和if-else可以互相轉(zhuǎn)換來寫;if-else作用的范圍比switch-case作用范圍要大,但是當(dāng)switch-case和if-else都可以用的情況下,通常推薦使用switch-case。
比如:
switch (ch) { case 'a': System.out.println("A"); break; case 'b': System.out.println("B"); break; case 'c': System.out.println("C"); break; case 'd': System.out.println("D"); break; case 'e': System.out.println("E"); break; default: System.out.println("other"); break; }
換為if-else
if (ch == 'a') { System.out.println("A"); } else if (ch == 'b') { System.out.println('B'); } else if (ch == 'c') { System.out.println("C"); } else if (ch == 'd') { System.out.println("D"); } else if (ch == 'e') { System.out.println("E"); } else { System.out.println("Other"); }
&和&&的聯(lián)系(共同點(diǎn)):
&和&&都可以用作邏輯與運(yùn)算符,但是要看使用時(shí)的具體條件來決定。
操作數(shù)1&操作數(shù)2,操作數(shù)1&&操作數(shù)2,
操作數(shù)1&操作數(shù)2,操作數(shù)1&&操作數(shù)2,
情況1:當(dāng)上述的操作數(shù)是boolean類型變量時(shí),&和&&都可以用作邏輯與運(yùn)算符。
情況2:當(dāng)上述的表達(dá)式結(jié)果是boolean類型變量時(shí),&和&&都可以用作邏輯與運(yùn)算符。
表示邏輯與(and),當(dāng)運(yùn)算符兩邊的表達(dá)式的結(jié)果或操作數(shù)都為true時(shí),整個(gè)運(yùn)算結(jié)果才為true,否則,只要有一方為false,結(jié)果都為false。
表示邏輯與(and),當(dāng)運(yùn)算符兩邊的表達(dá)式的結(jié)果或操作數(shù)都為true時(shí),整個(gè)運(yùn)算結(jié)果才為true,否則,只要有一方為false,結(jié)果都為false。
(1)、&邏輯運(yùn)算符稱為邏輯與運(yùn)算符,&&邏輯運(yùn)算符稱為短路與運(yùn)算符,也可叫邏輯與運(yùn)算符。
對(duì)于&:無論任何情況,&兩邊的操作數(shù)或表達(dá)式都會(huì)參與計(jì)算。
對(duì)于&&:當(dāng)&&左邊的操作數(shù)為false或左邊表達(dá)式結(jié)果為false時(shí),&&右邊的操作數(shù)或表達(dá)式將不參與計(jì)算,此時(shí)最終結(jié)果都為false。
綜上所述,如果邏輯與運(yùn)算的第一個(gè)操作數(shù)是false或第一個(gè)表達(dá)式的結(jié)果為false時(shí),對(duì)于第二個(gè)操作數(shù)或表達(dá)式是否進(jìn)行運(yùn)算,對(duì)最終的結(jié)果沒有影響,結(jié)果肯定是false。推介平時(shí)多使用&&,因?yàn)樗矢咝?/p>
(2)、&還可以用作位運(yùn)算符。當(dāng)&兩邊操作數(shù)或兩邊表達(dá)式的結(jié)果不是boolean類型時(shí),&用于按位與運(yùn)算符的操作。
final修飾基本類型變量,其值不能改變。
但是final修飾引用類型變量,棧內(nèi)存中的引用不能改變,但是所指向的堆內(nèi)存中的對(duì)象的屬性值仍舊可以改變。
例如:
class Test { public static void main(String[] args) { final Dog dog = new Dog("歐歐"); dog.name = "美美";//正確 dog = new Dog("亞亞");//錯(cuò)誤 } }
\d: 匹配一個(gè)數(shù)字字符。等價(jià)于[0-9]
\D: 匹配一個(gè)非數(shù)字字符。等價(jià)于[^0-9]
\s: 匹配任何空白字符,包括空格、制表符、換頁符等等。等價(jià)于 [ \f\n\r\t\v]
. :匹配除換行符 \n 之外的任何單字符。要匹配 . ,請(qǐng)使用 \. 。
*:匹配前面的子表達(dá)式零次或多次。要匹配 * 字符,請(qǐng)使用 \*。
+:匹配前面的子表達(dá)式一次或多次。要匹配 + 字符,請(qǐng)使用 \+。
|:將兩個(gè)匹配條件進(jìn)行邏輯“或”(Or)運(yùn)算
[0-9]{6}:匹配連續(xù)6個(gè)0-9之間的數(shù)字
\d+:匹配至少一個(gè)0-9之間的數(shù)字
A | m.length() |
B. | m.length |
C. | m.length()+1 |
D. | m.length+1 |
答案:B
分析:數(shù)組的長(zhǎng)度是.length
|
A | long l = 4990 |
B. | int i = 4L |
C. | float f = 1.1 |
D. | double d = 34.4 |
答案:AD
分析:B int屬于整數(shù)型應(yīng)該是int=4 C應(yīng)該是float f=1.1f
|
A | int k=new String(“aa”) |
B. | String str = String(“bb”) |
C. | char c=74; |
D. | long j=8888; |
答案:CD
分析:A需要強(qiáng)制類型轉(zhuǎn)換 B String str =new String(“bb”)
|
System.out.println(""+("12"=="12"&&"12".equals("12"))); (“12”==”12”&&”12”.equals(“12”)) “12”==”12”&&”12”.equals(“12”)
true
false
A | & |
B. | && |
C. | | |
D. | || |
答案:BD
分析:A C是邏輯與計(jì)算
|
A | private void example(int m){...} |
B. | public int example(){...} |
C. | public void example2(){...} |
D. | public int example(int m.float f){...} |
答案:AD
分析:BC定義的是新函數(shù)
|
int i=1; Int j=i++; If((j>++j)&&(i++==j)){j+=i:} System.out.println(j);
A | 1 |
B. | 2 |
C. | 3 |
D. | 4 |
答案:B
分析: i++先引用后。++i 先增加后引用
|
A | for |
B. | do...while |
C. | while |
D. | while...do |
答案:B
分析: ACD都不一定進(jìn)行循環(huán)
|
package com.bjsxt; public class smaillT{ public static void main(String args[]){ smaillT t=new smaillT(); int b = t.get(); System.out.println(b); } public int get() { try { return 1; }finally{ return 2; } } }
輸出結(jié)果:2
int i=9; switch (i) { default: System.out.println("default"); case 0: System.out.println("zero"); break; case 1: System.out.println("one"); break; case 2: System.out.println("two"); break; }
打印結(jié)果:
打印結(jié)果:
zero
繼承(英語:inheritance)是面向?qū)ο筌浖夹g(shù)當(dāng)中的一個(gè)概念。如果一個(gè)類別A“繼承自”另一個(gè)類別B,就把這個(gè)A稱為“B的子類別”,而把B稱為“A的父類別”也可以稱“B是A的超類”。繼承可以使得子類別具有父類別的各種屬性和方法,而不需要再次編寫相同的代碼。在令子類別繼承父類別的同時(shí),可以重新定義某些屬性,并重寫某些方法,即覆蓋父類別的原有屬性和方法,使其獲得與父類別不同的功能。另外,為子類別追加新的屬性和方法也是常見的做法。 一般靜態(tài)的面向?qū)ο缶幊陶Z言,繼承屬于靜態(tài)的,意即在子類別的行為在編譯期就已經(jīng)決定,無法在執(zhí)行期擴(kuò)充。
那么如何使用繼承呢?用extends關(guān)鍵字來繼承父類。
如上面A類與B類,當(dāng)寫繼承語句時(shí), class A類 extends B類{ } 其中A類是子類,B類是父類。
英文 | 位置不同 | 作用不同 | |
重載 | overload | 同一個(gè)類中 |
在一個(gè)類里面為一種行為提供多種實(shí)現(xiàn)方式并提高可讀性
現(xiàn)方式并提高可讀性
|
重寫 | override | 子類和父類間 |
父類方法無法滿足子類的要求,子類通
過方法重寫滿足要求
|
計(jì)算機(jī)不能直接理解高級(jí)語言,只能理解和運(yùn)行機(jī)器語言,所以必須要把高級(jí)語言翻譯成機(jī)器語言,計(jì)算機(jī)才能運(yùn)行高級(jí)語言所編寫的程序。翻譯的方式有兩種,一個(gè)是編譯,一個(gè)是解釋。
用編譯型語言寫的程序執(zhí)行之前,需要一個(gè)專門的編譯過程,通過編譯系統(tǒng)把高級(jí)語言翻譯成機(jī)器語言,把源高級(jí)程序編譯成為機(jī)器語言文件,比如windows下的exe文件。以后就可以直接運(yùn)行而不需要編譯了,因?yàn)榉g只做了一次,運(yùn)行時(shí)不需要翻譯,所以一般而言,編譯型語言的程序執(zhí)行效率高。
解釋型語言在運(yùn)行的時(shí)候才翻譯,比如VB語言,在執(zhí)行的時(shí)候,專門有一個(gè)解釋器能夠?qū)B語言翻譯成機(jī)器語言,每個(gè)語句都是執(zhí)行時(shí)才翻譯。這樣解釋型語言每執(zhí)行一次就要翻譯一次,效率比較低。
編譯型與解釋型,兩者各有利弊。前者由于程序執(zhí)行速度快,同等條件下對(duì)系統(tǒng)要求較低,因此像開發(fā)操作系統(tǒng)、大型應(yīng)用程序、數(shù)據(jù)庫(kù)系統(tǒng)等時(shí)都采用它,像C/C++、Pascal/Object Pascal(Delphi)等都是編譯語言,而一些網(wǎng)頁腳本、服務(wù)器腳本及輔助開發(fā)接口這樣的對(duì)速度要求不高、對(duì)不同系統(tǒng)平臺(tái)間的兼容性有一定要求的程序則通常使用解釋性語言,如JavaScript、VBScript、Perl、Python、Ruby、MATLAB 等等。
JAVA語言是一種編譯型-解釋型語言,同時(shí)具備編譯特性和解釋特性(其實(shí),確切的說java就是解釋型語言,其所謂的編譯過程只是將.java文件編程成平臺(tái)無關(guān)的字節(jié)碼.class文件,并不是向C一樣編譯成可執(zhí)行的機(jī)器語言,在此請(qǐng)讀者注意Java中所謂的“編譯”和傳統(tǒng)的“編譯”的區(qū)別)。作為編譯型語言,JAVA程序要被統(tǒng)一編譯成字節(jié)碼文件——文件后綴是class。此種文件在java中又稱為類文件。java類文件不能再計(jì)算機(jī)上直接執(zhí)行,它需要被java虛擬機(jī)翻譯成本地的機(jī)器碼后才能執(zhí)行,而java虛擬機(jī)的翻譯過程則是解釋性的。java字節(jié)碼文件首先被加載到計(jì)算機(jī)內(nèi)存中,然后讀出一條指令,翻譯一條指令,執(zhí)行一條指令,該過程被稱為java語言的解釋執(zhí)行,是由java虛擬機(jī)完成的。
&和&&都可以用作邏輯與運(yùn)算符,但是要看使用時(shí)的具體條件來決定。
操作數(shù)1&操作數(shù)2 | 操作數(shù)1&&操作數(shù)2 |
表達(dá)式1&表達(dá)式2 | 表達(dá)式1&&表達(dá)式2 |
情況1:當(dāng)上述的操作數(shù)是boolean類型變量時(shí),&和&&都可以用作邏輯與運(yùn)算符。
情況2:當(dāng)上述的表達(dá)式結(jié)果是boolean類型變量時(shí),&和&&都可以用作邏輯與運(yùn)算符。
表示邏輯與(and),當(dāng)運(yùn)算符兩邊的表達(dá)式的結(jié)果或操作數(shù)都為true時(shí),整個(gè)運(yùn)算結(jié)果才為true,否則,只要有一方為false,結(jié)果都為false。
&和&&的區(qū)別(不同點(diǎn)):
(1)、&邏輯運(yùn)算符稱為邏輯與運(yùn)算符,&&邏輯運(yùn)算符稱為短路與運(yùn)算符,也可叫邏輯與運(yùn)算符。
對(duì)于&:無論任何情況,&兩邊的操作數(shù)或表達(dá)式都會(huì)參與計(jì)算。
對(duì)于&&:當(dāng)&&左邊的操作數(shù)為false或左邊表達(dá)式結(jié)果為false時(shí),&&右邊的操作數(shù)或表達(dá)式將不參與計(jì)算,此時(shí)最終結(jié)果都為false。
綜上所述,如果邏輯與運(yùn)算的第一個(gè)操作數(shù)是false或第一個(gè)表達(dá)式的結(jié)果為false時(shí),對(duì)于第二個(gè)操作數(shù)或表達(dá)式是否進(jìn)行運(yùn)算,對(duì)最終的結(jié)果沒有影響,結(jié)果肯定是false。推介平時(shí)多使用&&,因?yàn)樗矢咝?/p>
(2)、&還可以用作位運(yùn)算符。當(dāng)&兩邊操作數(shù)或兩邊表達(dá)式的結(jié)果不是boolean類型時(shí),&用于按位與運(yùn)算符的操作。
|和||的區(qū)別和聯(lián)系與&和&&的區(qū)別和聯(lián)系類似
在異常處理時(shí)提供 finally 塊來執(zhí)行任何清除操作。
如果有finally的話,則不管是否發(fā)生異常,finally語句都會(huì)被執(zhí)行,包括遇到return語句。
finally中語句不執(zhí)行的唯一情況中執(zhí)行了System.exit(0)語句。
A | al.java |
B. | al.class |
C. | al |
D. | 都對(duì) |
答案:A
分析:.class是java的解析文件
|
A | 類型定義機(jī)制 |
B. | 數(shù)據(jù)封裝機(jī)制 |
C. | 類型定義機(jī)制和數(shù)據(jù)封裝機(jī)制 |
D. | 上述都不對(duì) |
答案:C
|
A | 用基本數(shù)據(jù)類型作為參數(shù) |
B. | 用對(duì)象作為參數(shù) |
C. | A和B都對(duì) |
D. | A和B都不對(duì) |
答案:B
分析:基本數(shù)據(jù)類型不能改變實(shí)參的值
|
A | 安全性 |
B. | 多線性 |
C. | 跨平臺(tái) |
D. | 可移植 |
可移植
|
A | 構(gòu)造函數(shù)的返回類型只能是void型 |
B. | 構(gòu)造函數(shù)是類的一種特殊函數(shù),它的方法名必須與類名相同 |
C. | 構(gòu)造函數(shù)的主要作用是完成對(duì)類的對(duì)象的初始化工作 |
D. | 一般在創(chuàng)建新對(duì)象時(shí),系統(tǒng)會(huì)自動(dòng)調(diào)用構(gòu)造函數(shù) |
答案:A
分析:構(gòu)造函數(shù)的名字與類的名字相同,并且不能指定返回類型。
|
A | static |
B. | package |
C. | private |
D. | public |
答案:A
|
package com.bjsxt; public class Test { public static void main(String[] args) { outer: for (int i = 0; i < 3; i++) inner: for (int j = 0; j < 2; j++) { if (j == 1) continue outer; System.out.println(j + " and " + i); } } }
A |
0 and 0
0 and 1
0 and 2
|
B. |
1 and 0
1 and 1
1 and 2
|
C. |
2 and 0
2 and 1
2 and 2
|
答案:A
|
package com.bjsxt; public class Test { private int m; public static void fun() { // some code… } }
A | 將private int m 改為 protected int m |
B. | 將private int m 改為 public int m |
C. | 將private int m 改為 static int m |
D. | 將private int m 改為int m |
答案:C
|
A | public void example(int m){…} |
B. | public int example(int m){…} |
C. | public void example2(){…} |
D. | public int example(int m,float f){…} |
答案:ABD
|
父類:
package com.bjsxt; public class FatherClass { public FatherClass() { System.out.println("FatherClassCreate"); } }
子類:
package com.bjsxt; import com.bjsxt.FatherClass; public class ChildClass extends FatherClass { public ChildClass() { System.out.println("ChildClass Create"); } public static void main(String[] args) { FatherClass fc = new FatherClass(); ChildClass cc = new ChildClass(); } }
執(zhí)行:C:\>java com.bjsxt.ChildClass
輸出結(jié)果:?
答:
FatherClassCreate
FatherClassCreate
ChildClass Create
答:因?yàn)轭怉、B不是接口,所以是不可以直接實(shí)現(xiàn)的,但可以將A、B類定義成父子類,那么C類就能實(shí)現(xiàn)A、B類的功能了。假如A為B的父類,B為C的父類,此時(shí)C就能使用A、B的功能。
答:構(gòu)造方法可以被重載,但是構(gòu)造方法不能被重寫,子類也不能繼承到父類的構(gòu)造方法
答:范圍是-128至127
public class TestDateFormat2 { public static void main(String[] args) throws Exception { //第一步:將字符串(2013-02-18 10:53:10)轉(zhuǎn)換成日期Date DateFormat sdf=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); String sdate="2013-02-18 10:53:10"; Date date=sdf.parse(sdate); System.out.println(date); //第二步:將日期Date轉(zhuǎn)換成字符串String DateFormat sdf2=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); String sdate2=sdf2.format(date); System.out.println(sdate2); } }
A. | 是 |
B. | 否 |
分析:答案:A
Java創(chuàng)建對(duì)象的幾種方式(重要):
(1) 用new語句創(chuàng)建對(duì)象,這是最常見的創(chuàng)建對(duì)象的方法。
(2) 運(yùn)用反射手段,調(diào)用java.lang.Class或者
java.lang.reflect.Constructor類的newInstance()實(shí)例方法。
(3) 調(diào)用對(duì)象的clone()方法
(4) 運(yùn)用反序列化手段,調(diào)用java.io.ObjectInputStream對(duì)象的 readObject()方法。
(1)和(2)都會(huì)明確的顯式的調(diào)用構(gòu)造函數(shù) ;(3)是在內(nèi)存上對(duì)已有對(duì)象的影印,所以不會(huì)調(diào)用構(gòu)造函數(shù) ;(4)是從文件中還原類的對(duì)象,也不會(huì)調(diào)用構(gòu)造函數(shù)。
(1)和(2)都會(huì)明確的顯式的調(diào)用構(gòu)造函數(shù) ;(3)是在內(nèi)存上對(duì)已有對(duì)象的影印,所以不會(huì)調(diào)用構(gòu)造函數(shù) ;(4)是從文件中還原類的對(duì)象,也不會(huì)調(diào)用構(gòu)造函數(shù)。
|
A. | DES |
B. | MD5 |
C. | DSA |
D. | RSA |
分析:答案:A
分析:常用的對(duì)稱加密算法有:DES、3DES、RC2、RC4、AES
常用的非對(duì)稱加密算法有:RSA、DSA、ECC
使用單向散列函數(shù)的加密算法:MD5、SHA
|
publicstaticint get Value(int i){ int result=0; switch(i){ case 1: result=result +i case 2: result=result+i*2 case 3: result=result+i*3 } return result; }
A. | 0 |
B. | 2 |
C. | 4 |
D. | 10 |
答案:C
分析:result = 0 + 2 * 2;
|
publicvoid test(){ String a="a"; String b="b"; String c="c"; c=a+""+b+""+c; System.out.print(c); }
分析:答案: 一個(gè)對(duì)象,因?yàn)榫幾g期進(jìn)行了優(yōu)化,3個(gè)字符串常量直接折疊為一個(gè)
答案: -11
分析:小數(shù)點(diǎn)后第一位=5
正數(shù):Math.round(11.5)=12
負(fù)數(shù):Math.round(-11.5)=-11
小數(shù)點(diǎn)后第一位<5
正數(shù):Math.round(11.46)=11
負(fù)數(shù):Math.round(-11.46)=-11
小數(shù)點(diǎn)后第一位>5
正數(shù):Math.round(11.68)=12
負(fù)數(shù):Math.round(-11.68)=-12
根據(jù)上面例子的運(yùn)行結(jié)果,我們還可以按照如下方式總結(jié),或許更加容易記憶:
參數(shù)的小數(shù)點(diǎn)后第一位<5,運(yùn)算結(jié)果為參數(shù)整數(shù)部分。
參數(shù)的小數(shù)點(diǎn)后第一位>5,運(yùn)算結(jié)果為參數(shù)整數(shù)部分絕對(duì)值+1,符號(hào)(即正負(fù))不變。
參數(shù)的小數(shù)點(diǎn)后第一位=5,正數(shù)運(yùn)算結(jié)果為整數(shù)部分+1,負(fù)數(shù)運(yùn)算結(jié)果為整數(shù)部分。
終結(jié):大于五全部加,等于五正數(shù)加,小于五全不加。
分析:十進(jìn)制數(shù)278的對(duì)應(yīng)十六進(jìn)制數(shù)是116
分析:
1:“字節(jié)”是byte,“位”是bit ;
2: 1 byte = 8 bit ;
char 在Java中是2個(gè)字節(jié)。java采用unicode,2個(gè)字節(jié)(16位)來表示一個(gè)字符。
short 2個(gè)字節(jié)
int 4個(gè)字節(jié)
long 8個(gè)字節(jié)
分析:'a'是char型,1 是int行,int與char相加,char會(huì)被強(qiáng)轉(zhuǎn)為int行,char的ASCII碼對(duì)應(yīng)的值是97,所以加一起打印98
A. | java程序經(jīng)編譯后會(huì)產(chǎn)生machine code |
B. | java程序經(jīng)編譯后會(huì)產(chǎn)生 byte code |
C. | java程序經(jīng)編譯后會(huì)產(chǎn)生DLL |
D. | 以上都不正確 |
答案:B
分析:java程序編譯后會(huì)生成字節(jié)碼文件,就是.class文件
|
A. | class中的constructor不可省略 |
B. | constructor必須與class同名,但方法不能與class同名 |
C. | constructor在一個(gè)對(duì)象被new時(shí)執(zhí)行 |
D. | 一個(gè)class只能定義一個(gè)constructor |
答案:C
|
a=0;c=0; do{ ——c; a=a-1; }while(a>0); 后,c的值是()
A. | 0 |
B. | 1 |
C. | -1 |
D. | 死循環(huán) |
答案:C
do{...}while(...);語句至少執(zhí)行一次
|
A. | abstract修飾符可修飾字段、方法和類 |
B. | 抽象方法的body部分必須用一對(duì)大括號(hào){}包住 |
C. | 聲明抽象方法,大括號(hào)可有可無 |
D. | 聲明抽象方法不可寫出大括號(hào) |
答案:D
分析: abstract不能修飾字段。既然是抽象方法,當(dāng)然是沒有實(shí)現(xiàn)的方法,根本就沒有body部分。
|
A. | 形式參數(shù)可被視為local variable |
B. | 形式參數(shù)可被字段修飾符修飾 |
C. | 形式參數(shù)為方法被調(diào)用時(shí),真正被傳遞的參數(shù) |
D. | 形式參數(shù)不可以是對(duì)象 |
答案A:
分析:
A:形式參數(shù)可被視為local variable。形參和局部變量一樣都不能離開方法。都只有在方法內(nèi)才會(huì)發(fā)生作用,也只有在方法中使用,不會(huì)在方法外可見。
B:對(duì)于形式參數(shù)只能用final修飾符,其它任何修飾符都會(huì)引起編譯器錯(cuò)誤。但是用這個(gè)修飾符也有一定的限制,就是在方法中不能對(duì)參數(shù)做任何修改。 不過一般情況下,一個(gè)方法的形參不用final修飾。只有在特殊情況下,那就是:方法內(nèi)部類。? 一個(gè)方法內(nèi)的內(nèi)部類如果使用了這個(gè)方法的參數(shù)或者局部變量的話,這個(gè)參數(shù)或局部變量應(yīng)該是final。?
C:形參的值在調(diào)用時(shí)根據(jù)調(diào)用者更改,實(shí)參則用自身的值更改形參的值(指針、引用皆在此列),也就是說真正被傳遞的是實(shí)參。
D:方法的參數(shù)列表指定要傳遞給方法什么樣的信息,采用的都是對(duì)象的形式。因此,在參數(shù)列表中必須指定每個(gè)所傳遞對(duì)象的類型及名字。想JAVA中任何傳遞對(duì)象的場(chǎng)合一樣,這里傳遞的實(shí)際上也是引用,并且引用的類型必須正確。--《Thinking in JAVA》
|
1、兩個(gè)變量的生命周期不同。
成員變量隨著對(duì)象的創(chuàng)建而存在,隨著對(duì)象的被回收而釋放。
靜態(tài)變量隨著類的加載而存在,隨著類的消失而消失。
2、調(diào)用方式不同。
成員變量只能被對(duì)象調(diào)用。
成員變量只能被對(duì)象調(diào)用。
成員變量只能被對(duì)象調(diào)用。
類名調(diào)用 :Person.country
3、別名不同。
成員變量也稱為實(shí)例變量。
靜態(tài)變量稱為類變量。?
4、數(shù)據(jù)存儲(chǔ)位置不同。
成員變量數(shù)據(jù)存儲(chǔ)在堆內(nèi)存的對(duì)象中,所以也叫對(duì)象的特有數(shù)據(jù).
靜態(tài)變量數(shù)據(jù)存儲(chǔ)在方法區(qū)(共享數(shù)據(jù)區(qū))的靜態(tài)區(qū),所以也叫對(duì)象的共享數(shù)據(jù).
1、用final修飾的類不能被擴(kuò)展,也就是說不可能有子類;
2、用final修飾的方法不能被替換或隱藏:
① 使用final修飾的實(shí)例方法在其所屬類的子類中不能被替換(overridden);
② 使用final修飾的靜態(tài)方法在其所屬類的子類中不能被重定義(redefined)而隱藏(hidden);
3、用final修飾的變量最多只能賦值一次,在賦值方式上不同類型的變量或稍有不同:
① 靜態(tài)變量必須明確賦值一次(不能只使用類型缺省值);作為類成員的靜態(tài)變量,賦值可以在其聲明中通過初始化表達(dá)式完成,也可以在靜態(tài)初始化塊中進(jìn)行;作為接口成員的靜態(tài)變量,賦值只能在其聲明中通過初始化表達(dá)式完成;
② 實(shí)例變量同樣必須明確賦值一次(不能只使用類型缺省值);賦值可以在其聲明中通過初始化表達(dá)式完成,也可以在實(shí)例初始化塊或構(gòu)造器中進(jìn)行;
③ 方法參數(shù)變量在方法被調(diào)用時(shí)創(chuàng)建,同時(shí)被初始化為對(duì)應(yīng)實(shí)參值,終止于方法體 (body)結(jié)束,在此期間其值不能改變;
④ 構(gòu)造器參數(shù)變量在構(gòu)造器被調(diào)用(通過實(shí)例創(chuàng)建表達(dá)式或顯示的構(gòu)造器調(diào)用)時(shí)創(chuàng)建,同時(shí)被初始化,為對(duì)應(yīng)實(shí)參值,終止于構(gòu)造器體結(jié)束,在此期間其值不能改變;
⑤ 異常處理器參數(shù)變量在有異常被try語句的catch子句捕捉到時(shí)創(chuàng)建,同時(shí)被初始化為實(shí)際的異常對(duì)象,終止于catch語句塊結(jié)束,在此期間其值不能改變;
⑥ 局部變量在其值被訪問之前必須被明確賦值;
A. | 除以10 |
B. | 除以2 |
C. | 乘以2 |
D. | 乘以10 |
乘以10
分析:可以看個(gè)例子
101.1 對(duì)應(yīng)的十進(jìn)制為 2^2*1 + 2^1*0 + 2^0*1 + 2^-1*1 = 5.5小數(shù)點(diǎn)右移一位
1011 對(duì)應(yīng)的十進(jìn)制為 2^3*1 + 2^2*0 + 2^1*1 + 2^0*1 = 11所以是擴(kuò)大到原來的2倍
|
答:面向?qū)ο蟮奶卣髦饕幸韵聨讉€(gè)方面:
1、抽象:抽象是將一類對(duì)象的共同特征總結(jié)出來構(gòu)造類的過程,包括數(shù)據(jù)抽象和行為抽象兩方面。抽象只關(guān)注對(duì)象有哪些屬性和行為,并不關(guān)注這些行為的細(xì)節(jié)是什么。
2、繼承:繼承是從已有類得到繼承信息創(chuàng)建新類的過程。提供繼承信息的類被稱為父類(超類、基類);得到繼承信息的類被稱為子類(派生類)。繼承讓變化中的軟件系統(tǒng)有了一定的延續(xù)性,同時(shí)繼承也是封裝程序中可變因素的重要手段(如果不能理解請(qǐng)閱讀閻宏博士的《Java與模式》或《設(shè)計(jì)模式精解》中關(guān)于橋梁模式的部分)。
3、封裝:通常認(rèn)為封裝是把數(shù)據(jù)和操作數(shù)據(jù)的方法綁定起來,對(duì)數(shù)據(jù)的訪問只能通過已定義的接口。面向?qū)ο蟮谋举|(zhì)就是將現(xiàn)實(shí)世界描繪成一系列完全自治、封閉的對(duì)象。我們?cè)陬愔芯帉懙姆椒ň褪菍?duì)實(shí)現(xiàn)細(xì)節(jié)的一種封裝;我們編寫一個(gè)類就是對(duì)數(shù)據(jù)和數(shù)據(jù)操作的封裝??梢哉f,封裝就是隱藏一切可隱藏的東西,只向外界提供最簡(jiǎn)單的編程接口(可以想想普通洗衣機(jī)和全自動(dòng)洗衣機(jī)的差別,明顯全自動(dòng)洗衣機(jī)封裝更好因此操作起來更簡(jiǎn)單;我們現(xiàn)在使用的智能手機(jī)也是封裝得足夠好的,因?yàn)閹讉€(gè)按鍵就搞定了所有的事情)。
4、多態(tài)性:多態(tài)性是指允許不同子類型的對(duì)象對(duì)同一消息作出不同的響應(yīng)。簡(jiǎn)單的說就是用同樣的對(duì)象引用調(diào)用同樣的方法但是做了不同的事情。多態(tài)性分為編譯時(shí)的多態(tài)性和運(yùn)行時(shí)的多態(tài)性。如果將對(duì)象的方法視為對(duì)象向外界提供的服務(wù),那么運(yùn)行時(shí)的多態(tài)性可以解釋為:當(dāng)A系統(tǒng)訪問B系統(tǒng)提供的服務(wù)時(shí),B系統(tǒng)有多種提供服務(wù)的方式,但一切對(duì)A系統(tǒng)來說都是透明的(就像電動(dòng)剃須刀是A系統(tǒng),它的供電系統(tǒng)是B系統(tǒng),B系統(tǒng)可以使用電池供電或者用交流電,甚至還有可能是太陽能,A系統(tǒng)只會(huì)通過B類對(duì)象調(diào)用供電的方法,但并不知道供電系統(tǒng)的底層實(shí)現(xiàn)是什么,究竟通過何種方式獲得了動(dòng)力)。方法重載(overload)實(shí)現(xiàn)的是編譯時(shí)的多態(tài)性(也稱為前綁定),而方法重寫(override)實(shí)現(xiàn)的是運(yùn)行時(shí)的多態(tài)性(也稱為后綁定)。運(yùn)行時(shí)的多態(tài)是面向?qū)ο笞罹璧臇|西,要實(shí)現(xiàn)多態(tài)需要做兩件事:1. 方法重寫(子類繼承父類并重寫父類中已有的或抽象的方法);2. 對(duì)象造型(用父類型引用引用子類型對(duì)象,這樣同樣的引用調(diào)用同樣的方法就會(huì)根據(jù)子類對(duì)象的不同而表現(xiàn)出不同的行為)。
答:不正確。3.4是雙精度數(shù),將雙精度型(double)賦值給浮點(diǎn)型(float)屬于下轉(zhuǎn)型(down-casting,也稱為窄化)會(huì)造成精度損失,因此需要強(qiáng)制類型轉(zhuǎn)換float f =(float)3.4; 或者寫成float f =3.4F;。
答:對(duì)于short s1 = 1; s1 = s1 + 1;由于1是int類型,因此s1+1運(yùn)算結(jié)果也是int 型,需要強(qiáng)制轉(zhuǎn)換類型才能賦值給short型。而short s1 = 1; s1 += 1;可以正確編譯,因?yàn)閟1+= 1;相當(dāng)于s1 = (short)(s1 + 1);其中有隱含的強(qiáng)制類型轉(zhuǎn)換。
答: goto 是Java中的保留字,在目前版本的Java中沒有使用。(根據(jù)James Gosling(Java之父)編寫的《The Java Programming Language》一書的附錄中給出了一個(gè)Java關(guān)鍵字列表,其中有g(shù)oto和const,但是這兩個(gè)是目前無法使用的關(guān)鍵字,因此有些地方將其稱之為保留字,其實(shí)保留字這個(gè)詞應(yīng)該有更廣泛的意義,因?yàn)槭煜語言的程序員都知道,在系統(tǒng)類庫(kù)中使用過的有特殊意義的單詞或單詞的組合都被視為保留字)
答:Java是一個(gè)近乎純潔的面向?qū)ο缶幊陶Z言,但是為了編程的方便還是引入不是對(duì)象的基本數(shù)據(jù)類型,但是為了能夠?qū)⑦@些基本數(shù)據(jù)類型當(dāng)成對(duì)象操作,Java為每一個(gè)基本數(shù)據(jù)類型都引入了對(duì)應(yīng)的包裝類型(wrapper class),int的包裝類就是Integer,從JDK 1.5開始引入了自動(dòng)裝箱/拆箱機(jī)制,使得二者可以相互轉(zhuǎn)換。
Java 為每個(gè)原始類型提供了包裝類型:
原始類型: boolean,char,byte,short,int,long,float,double
包裝類型:Boolean,Character,Byte,Short,Integer,Long,F(xiàn)loat,Double
package com.bjsxt; public class AutoUnboxingTest { public static void main(String[] args) { Integer a = new Integer(3); Integer b = 3; // 將3自動(dòng)裝箱成Integer類型 int c = 3; System.out.println(a == b); // false 兩個(gè)引用沒有引用同一對(duì)象 System.out.println(a == c); // true a自動(dòng)拆箱成int類型再和c比較 } }
補(bǔ)充:最近還遇到一個(gè)面試題,也是和自動(dòng)裝箱和拆箱相關(guān)的,代碼如下所示:
public class Test03 { public static void main(String[] args) { Integer f1 = 100, f2 = 100, f3 = 150, f4 = 150; System.out.println(f1 == f2); System.out.println(f3 == f4); } }
如果不明就里很容易認(rèn)為兩個(gè)輸出要么都是true要么都是false。首先需要注意的是f1、f2、f3、f4四個(gè)變量都是Integer對(duì)象,所以下面的==運(yùn)算比較的不是值而是引用。裝箱的本質(zhì)是什么呢?當(dāng)我們給一個(gè)Integer對(duì)象賦一個(gè)int值的時(shí)候,會(huì)調(diào)用Integer類的靜態(tài)方法valueOf,如果看看valueOf的源代碼就知道發(fā)生了什么。
public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }
IntegerCache是Integer的內(nèi)部類,其代碼如下所示:
/* Cache to support the object identity semantics of autoboxing for values between * -128 and 127 (inclusive) as required by JLS. * * The cache is initialized on first usage. The size of the cache * may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option. * During VM initialization, java.lang.Integer.IntegerCache.high property * may be set and saved in the private system properties in the * sun.misc.VM class. */ private static class IntegerCache { static final int low = -128; static final int high; static final Integer cache[]; static { // high value may be configured by property int h = 127; String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); if (integerCacheHighPropValue != null) { try { int i = parseInt(integerCacheHighPropValue); i = Math.max(i, 127); // Maximum array size is Integer.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE - (-low) -1); } catch( NumberFormatException nfe) { // If the property cannot be parsed into an int, ignore it. } } high = h; cache = new Integer[(high - low) + 1]; int j = low; for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); // range [-128, 127] must be interned (JLS7 5.1.7) assert IntegerCache.high >= 127; } private IntegerCache() {} }
簡(jiǎn)單的說,如果字面量的值在-128到127之間,那么不會(huì)new新的Integer對(duì)象,而是直接引用常量池中的Integer對(duì)象,所以上面的面試題中f1==f2的結(jié)果是true,而f3==f4的結(jié)果是false。越是貌似簡(jiǎn)單的面試題其中的玄機(jī)就越多,需要面試者有相當(dāng)深厚的功力。
答:&運(yùn)算符有兩種用法:(1)按位與;(2)邏輯與。&&運(yùn)算符是短路與運(yùn)算。邏輯與跟短路與的差別是非常巨大的,雖然二者都要求運(yùn)算符左右兩端的布爾值都是true整個(gè)表達(dá)式的值才是true。&&之所以稱為短路運(yùn)算是因?yàn)?,如?&左邊的表達(dá)式的值是false,右邊的表達(dá)式會(huì)被直接短路掉,不會(huì)進(jìn)行運(yùn)算。很多時(shí)候我們可能都需要用&&而不是&,例如在驗(yàn)證用戶登錄時(shí)判定用戶名不是null而且不是空字符串,應(yīng)當(dāng)寫為:username != null &&!username.equals(“”),二者的順序不能交換,更不能用&運(yùn)算符,因?yàn)榈谝粋€(gè)條件如果不成立,根本不能進(jìn)行字符串的equals比較,否則會(huì)產(chǎn)生NullPointerException異常。注意:邏輯或運(yùn)算符(|)和短路或運(yùn)算符(||)的差別也是如此。
補(bǔ)充:如果你熟悉JavaScript,那你可能更能感受到短路運(yùn)算的強(qiáng)大,想成為 JavaScript的高手就先從玩轉(zhuǎn)短路運(yùn)算開始吧。
答:Math.round(11.5)的返回值是12,Math.round(-11.5)的返回值是-11。四舍五入的原理是在參數(shù)上加0.5然后進(jìn)行下取整。
答:早期的JDK中,switch(expr)中,expr可以是byte、short、char、int。從1.5版開始,Java中引入了枚舉類型(enum),expr也可以是枚舉,從JDK 1.7版開始,還可以是字符串(String)。長(zhǎng)整型(long)是不可以的。
答: 2 << 3(左移3位相當(dāng)于乘以2的3次方,右移3位相當(dāng)于除以2的3次方)。
補(bǔ)充: 我們?yōu)榫帉懙念愔貙慼ashCode方法時(shí),可能會(huì)看到如下所示的代碼,其實(shí)我們不太理解為什么要使用這樣的乘法運(yùn)算來產(chǎn)生哈希碼(散列碼),而且為什么這個(gè)數(shù)是個(gè)素?cái)?shù),為什么通常選擇31這個(gè)數(shù)?前兩個(gè)問題的答案你可以自己百度一下,選擇31是因?yàn)榭梢杂靡莆缓蜏p法運(yùn)算來代替乘法,從而得到更好的性能。說到這里你可能已經(jīng)想到了:31 * num <==> (num << 5) - num,左移5位相當(dāng)于乘以2的5次方(32)再減去自身就相當(dāng)于乘以31?,F(xiàn)在的VM都能自動(dòng)完成這個(gè)優(yōu)化。
package com.bjsxt; public class PhoneNumber { private int areaCode; private String prefix; private String lineNumber; @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + areaCode; result = prime * result + ((lineNumber == null) ? 0 : lineNumber.hashCode()); result = prime * result + ((prefix == null) ? 0 : prefix.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; PhoneNumber other = (PhoneNumber) obj; if (areaCode != other.areaCode) return false; if (lineNumber == null) { if (other.lineNumber != null) return false; } else if (!lineNumber.equals(other.lineNumber)) return false; if (prefix == null) { if (other.prefix != null) return false; } else if (!prefix.equals(other.prefix)) return false; return true; } }
答:在最外層循環(huán)前加一個(gè)標(biāo)記如A,然后用break A;可以跳出多重循環(huán)。(Java中支持帶標(biāo)簽的break和continue語句,作用有點(diǎn)類似于C和C++中的goto語句,但是就像要避免使用goto一樣,應(yīng)該避免使用帶標(biāo)簽的break和continue,因?yàn)樗粫?huì)讓你的程序變得更優(yōu)雅,很多時(shí)候甚至有相反的作用,所以這種語法其實(shí)不知道更好)
答:構(gòu)造器不能被繼承,因此不能被重寫,但可以被重載。
答:不對(duì),如果兩個(gè)對(duì)象x和y滿足x.equals(y) == true,它們的哈希碼(hash code)應(yīng)當(dāng)相同。Java對(duì)于eqauls方法和hashCode方法是這樣規(guī)定的:(1)如果兩個(gè)對(duì)象相同(equals方法返回true),那么它們的hashCode值一定要相同;(2)如果兩個(gè)對(duì)象的hashCode相同,它們并不一定相同。當(dāng)然,你未必要按照要求去做,但是如果你違背了上述原則就會(huì)發(fā)現(xiàn)在使用容器時(shí),相同的對(duì)象可以出現(xiàn)在Set集合中,同時(shí)增加新元素的效率會(huì)大大下降(對(duì)于使用哈希存儲(chǔ)的系統(tǒng),如果哈希碼頻繁的沖突將會(huì)造成存取性能急劇下降)。
補(bǔ)充:關(guān)于equals和hashCode方法,很多Java程序都知道,但很多人也就是僅僅知道而已,在Joshua Bloch的大作《Effective Java》(很多軟件公司,《Effective Java》、《Java編程思想》以及《重構(gòu):改善既有代碼質(zhì)量》是Java程序員必看書籍,如果你還沒看過,那就趕緊去亞馬遜買一本吧)中是這樣介紹equals方法的:首先equals方法必須滿足自反性(x.equals(x)必須返回true)、對(duì)稱性(x.equals(y)返回true時(shí),y.equals(x)也必須返回true)、傳遞性(x.equals(y)和y.equals(z)都返回true時(shí),x.equals(z)也必須返回true)和一致性(當(dāng)x和y引用的對(duì)象信息沒有被修改時(shí),多次調(diào)用x.equals(y)應(yīng)該得到同樣的返回值),而且對(duì)于任何非null值的引用x,x.equals(null)必須返回false。實(shí)現(xiàn)高質(zhì)量的equals方法的訣竅包括:1. 使用==操作符檢查“參數(shù)是否為這個(gè)對(duì)象的引用”;2. 使用instanceof操作符檢查“參數(shù)是否為正確的類型”;3. 對(duì)于類中的關(guān)鍵屬性,檢查參數(shù)傳入對(duì)象的屬性是否與之相匹配;4. 編寫完equals方法后,問自己它是否滿足對(duì)稱性、傳遞性、一致性;5. 重寫equals時(shí)總是要重寫hashCode;6. 不要將equals方法參數(shù)中的Object對(duì)象替換為其他的類型,在重寫時(shí)不要忘掉@Override注解。
答:是值傳遞。Java 編程語言只有值傳遞參數(shù)。當(dāng)一個(gè)對(duì)象實(shí)例作為一個(gè)參數(shù)被傳遞到方法中時(shí),參數(shù)的值就是對(duì)該對(duì)象的引用。對(duì)象的屬性可以在被調(diào)用過程中被改變,但對(duì)象的引用是永遠(yuǎn)不會(huì)改變的。C++和C#中可以通過傳引用或傳輸出參數(shù)來改變傳入的參數(shù)的值。
補(bǔ)充:Java中沒有傳引用實(shí)在是非常的不方便,這一點(diǎn)在Java 8中仍然沒有得到改進(jìn),正是如此在Java編寫的代碼中才會(huì)出現(xiàn)大量的Wrapper類(將需要通過方法調(diào)用修改的引用置于一個(gè)Wrapper類中,再將Wrapper對(duì)象傳入方法),這樣的做法只會(huì)讓代碼變得臃腫,尤其是讓從C和C++轉(zhuǎn)型為Java程序員的開發(fā)者無法容忍。
答:Java的三大特征之一,多態(tài)機(jī)制,包括方法的多態(tài)和對(duì)象的多態(tài);方法的重載和重寫都是實(shí)現(xiàn)多態(tài)的方式,區(qū)別在于前者實(shí)現(xiàn)的是編譯時(shí)的多態(tài)性,而后者實(shí)現(xiàn)的是運(yùn)行時(shí)的多態(tài)性。重載(overload)發(fā)生在同一個(gè)類中,相同的方法,如果有不同的參數(shù)列表(參數(shù)類型不同、參數(shù)個(gè)數(shù)不同或者二者都不同)則視為重載;重寫(override)發(fā)生在子類與父類之間也就是繼承機(jī)制當(dāng)中,當(dāng)父類的方法不能滿足子類的要求,此時(shí)子類重寫父類的方法;要求:方法名、形參列表相同;返回值類型和異常類型,子類小于等于父類;訪問權(quán)限,子類大于等于父類,切記父類的私有方法以及被final修飾的方法不能被子類重寫;重載對(duì)返回類型沒有特殊的要求。
答:方法的重載,即使返回值類型不同,也不能改變實(shí)現(xiàn)功能相同或類似這一既定事實(shí);同時(shí)方法的重載只是要求兩同三不同,即在同一個(gè)類中,相同的方法名稱,參數(shù)列表當(dāng)中的參數(shù)類型、個(gè)數(shù)、順序不同;跟權(quán)限修飾符和返回值類無關(guān)
答:內(nèi)部類就是在一個(gè)類的內(nèi)部定義的類,內(nèi)部類中不能定義靜態(tài)成員(靜態(tài)成員不是對(duì)象的特性,只是為了找一個(gè)容身之處,所以需要放到一個(gè)類中而已,這么一點(diǎn)小事,你還要把它放到類內(nèi)部的一個(gè)類中,過分了啊!提供內(nèi)部類,不是為讓你干這種事情,無聊,不讓你干。我想可能是既然靜態(tài)成員類似c語言的全局變量,而內(nèi)部類通常是用于創(chuàng)建內(nèi)部對(duì)象用的,所以,把“全局變量”放在內(nèi)部類中就是毫無意義的事情,既然是毫無意義的事情,就應(yīng)該被禁止),內(nèi)部類可以直接訪問外部類中的成員變量,內(nèi)部類可以定義在外部類的方法外面,也可以定義在外部類的方法體中,如下所示:
public class Outer { int out_x = 0; public void method() { Inner1 inner1 = new Inner1(); public class Inner2 //在方法體內(nèi)部定義的內(nèi)部類 { public method() { out_x = 3; } } Inner2 inner2 = new Inner2(); } public class Inner1 //在方法體外面定義的內(nèi)部類 { } }
在方法體外面定義的內(nèi)部類的訪問類型可以是public,protecte,默認(rèn)的,private等4種類型,這就好像類中定義的成員變量有4種訪問類型一樣,它們決定這個(gè)內(nèi)部類的定義對(duì)其他類是否可見;對(duì)于這種情況,我們也可以在外面創(chuàng)建內(nèi)部類的實(shí)例對(duì)象,創(chuàng)建內(nèi)部類的實(shí)例對(duì)象時(shí),一定要先創(chuàng)建外部類的實(shí)例對(duì)象,然后用這個(gè)外部類的實(shí)例對(duì)象去創(chuàng)建內(nèi)部類的實(shí)例對(duì)象,代碼如下:
Outer outer = new Outer();
Outer.Inner1 inner1 = outer.new Innner1();
在方法內(nèi)部定義的內(nèi)部類前面不能有訪問類型修飾符,就好像方法中定義的局部變量一樣,但這種內(nèi)部類的前面可以使用final或abstract修飾符。這種內(nèi)部類對(duì)其他類是不可見的其他類無法引用這種內(nèi)部類,但是這種內(nèi)部類創(chuàng)建的實(shí)例對(duì)象可以傳遞給其他類訪問。這種內(nèi)部類必須是先定義,后使用,即內(nèi)部類的定義代碼必須出現(xiàn)在使用該類之前,這與方法中的局部變量必須先定義后使用的道理也是一樣的。這種內(nèi)部類可以訪問方法體中的局部變量,但是,該局部變量前必須加final修飾符。
對(duì)于這些細(xì)節(jié),只要在eclipse寫代碼試試,根據(jù)開發(fā)工具提示的各類錯(cuò)誤信息就可以馬上了解到。
在方法體內(nèi)部還可以采用如下語法來創(chuàng)建一種匿名內(nèi)部類,即定義某一接口或類的子類的同時(shí),還創(chuàng)建了該子類的實(shí)例對(duì)象,無需為該子類定義名稱:
public class Outer { public void start() { new Thread( new Runable(){ public void run(){}; } ).start(); } }
最后,在方法外部定義的內(nèi)部類前面可以加上static關(guān)鍵字,從而成為Static Nested Class,它不再具有內(nèi)部類的特性,所有,從狹義上講,它不是內(nèi)部類。Static Nested Class與普通類在運(yùn)行時(shí)的行為和功能上沒有什么區(qū)別,只是在編程引用時(shí)的語法上有一些差別,它可以定義成public、protected、默認(rèn)的、private等多種類型,而普通類只能定義成public和默認(rèn)的這兩種類型。在外面引用Static Nested Class類的名稱為“外部類名.內(nèi)部類名”。在外面不需要?jiǎng)?chuàng)建外部類的實(shí)例對(duì)象,就可以直接創(chuàng)建Static Nested Class,例如,假設(shè)Inner是定義在Outer類中的Static Nested Class,那么可以使用如下語句創(chuàng)建Inner類:
Outer.Inner inner = newOuter.Inner();
由于static Nested Class不依賴于外部類的實(shí)例對(duì)象,所以,static Nested Class能訪問外部類的非static成員變量(不能直接訪問,需要?jiǎng)?chuàng)建外部類實(shí)例才能訪問非靜態(tài)變量)。當(dāng)在外部類中訪問Static Nested Class時(shí),可以直接使用Static Nested Class的名字,而不需要加上外部類的名字了,在Static Nested Class中也可以直接引用外部類的static的成員變量,不需要加上外部類的名字。
在靜態(tài)方法中定義的內(nèi)部類也是Static Nested Class,這時(shí)候不能在類前面加static關(guān)鍵字,靜態(tài)方法中的Static Nested Class與普通方法中的內(nèi)部類的應(yīng)用方式很相似,它除了可以直接訪問外部類中的static的成員變量,還可以訪問靜態(tài)方法中的局部變量,但是,該局部變量前必須加final修飾符。
備注:首先根據(jù)你的印象說出你對(duì)內(nèi)部類的總體方面的特點(diǎn):例如,在兩個(gè)地方可以定義,可以訪問外部類的成員變量,不能定義靜態(tài)成員,這是大的特點(diǎn)。然后再說一些細(xì)節(jié)方面的知識(shí),例如,幾種定義方式的語法區(qū)別,靜態(tài)內(nèi)部類,以及匿名內(nèi)部類。
Static Nested Class是被聲明為靜態(tài)(static)的內(nèi)部類,它可以不依賴于外部類實(shí)例被實(shí)例化。而通常的內(nèi)部類需要在外部類實(shí)例化后才能實(shí)例化,其語法看起來挺詭異的,如下所示。
package com.bjsxt; /** * 撲克類(一副撲克) * @author sxt * */ public class Poker { private static String[] suites = {"黑桃", "紅桃", "草花", "方塊"}; private static int[] faces = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}; private Card[] cards; /** * 構(gòu)造器 */ public Poker() { cards = new Card[52]; for(int i = 0; i < suites.length; i++) { for(int j = 0; j < faces.length; j++) { cards[i * 13 + j] = new Card(suites[i], faces[j]); } } } /** * 洗牌 (隨機(jī)亂序) */ public void shuffle() { for(int i = 0, len = cards.length; i < len; i++) { int index = (int) (Math.random() * len); Card temp = cards[index]; cards[index] = cards[i]; cards[i] = temp; } } /** * 發(fā)牌 * @param index 發(fā)牌的位置 */ public Card deal(int index) { return cards[index]; } /** * 卡片類(一張撲克) * [內(nèi)部類] * @author sxt */ public class Card { private String suite; // 花色 private int face; // 點(diǎn)數(shù) public Card(String suite, int face) { this.suite = suite; this.face = face; } @Override public String toString() { String faceStr = ""; switch(face) { case 1: faceStr = "A"; break; case 11: faceStr = "J"; break; case 12: faceStr = "Q"; break; case 13: faceStr = "K"; break; default: faceStr = String.valueOf(face); } return suite + faceStr; } } }
測(cè)試類:
package com.bjsxt; class PokerTest { public static void main(String[] args) { Poker poker = new Poker(); poker.shuffle(); // 洗牌 Poker.Card c1 = poker.deal(0); // 發(fā)第一張牌 // 對(duì)于非靜態(tài)內(nèi)部類Card // 只有通過其外部類Poker對(duì)象才能創(chuàng)建Card對(duì)象 Poker.Card c2 = poker.new Card("紅心", 1); // 自己創(chuàng)建一張牌 System.out.println(c1); // 洗牌后的第一張 System.out.println(c2); // 打印: 紅心A } }
答:都不能。抽象方法需要子類重寫,而靜態(tài)的方法是無法被重寫的,因此二者是矛盾的。本地方法是由本地代碼(如C代碼)實(shí)現(xiàn)的方法,而抽象方法是沒有實(shí)現(xiàn)的,也是矛盾的。synchronized和方法的實(shí)現(xiàn)細(xì)節(jié)有關(guān),抽象方法不涉及實(shí)現(xiàn)細(xì)節(jié),因此也是相互矛盾的。
答:靜態(tài)變量是被static修飾符修飾的變量,也稱為類變量,它屬于類,不屬于類的任何一個(gè)對(duì)象,一個(gè)類不管創(chuàng)建多少個(gè)對(duì)象,靜態(tài)變量在內(nèi)存中有且僅有一個(gè)拷貝;實(shí)例變量必須依存于某一實(shí)例,需要先創(chuàng)建對(duì)象然后通過對(duì)象才能訪問到它,靜態(tài)變量可以實(shí)現(xiàn)讓多個(gè)對(duì)象共享內(nèi)存。兩者的相同點(diǎn):都有默認(rèn)值而且在類的任何地方都可以調(diào)用。在Java開發(fā)中,上下文類和工具類中通常會(huì)有大量的靜態(tài)成員。?
答:不可以,靜態(tài)方法只能訪問靜態(tài)成員,因?yàn)榉庆o態(tài)方法的調(diào)用要先創(chuàng)建對(duì)象,因此在調(diào)用靜態(tài)方法時(shí)可能對(duì)象并沒有被初始化。?
package com.bjsxt; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; public class MyUtil { private MyUtil() { throw new AssertionError(); } public static <T> T clone(T obj) throws Exception { ByteArrayOutputStream bout = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bout); oos.writeObject(obj); ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bin); return (T) ois.readObject(); // 說明:調(diào)用ByteArrayInputStream或ByteArrayOutputStream對(duì)象的close方法沒有任何意義 // 這兩個(gè)基于內(nèi)存的流只要垃圾回收器清理對(duì)象就能夠釋放資源 } }
答:有兩種方式:
1.實(shí)現(xiàn)Cloneable接口并重寫Object類中的clone()方法;
2.實(shí)現(xiàn)Serializable接口,通過對(duì)象的序列化和反序列化實(shí)現(xiàn)克隆,可以實(shí)現(xiàn)真正的深度克隆,代碼如下。
下面是測(cè)試代碼:
package com.bjsxt; import java.io.Serializable; /** * 人類 * @author sxt */ class Person implements Serializable { private static final long serialVersionUID = -9102017020286042305L; private String name; // 姓名 private int age; // 年齡 private Car car; // 座駕 public Person(String name, int age, Car car) { this.name = name; this.age = age; this.car = car; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Car getCar() { return car; } public void setCar(Car car) { this.car = car; } @Override public String toString() { return "Person [name=" + name + ", age=" + age + ", car=" + car + "]"; } } /** * 小汽車類 * @author sxt */ class Car implements Serializable { private static final long serialVersionUID = -5713945027627603702L; private String brand; // 品牌 private int maxSpeed; // 最高時(shí)速 public Car(String brand, int maxSpeed) { this.brand = brand; this.maxSpeed = maxSpeed; } public String getBrand() { return brand; } public void setBrand(String brand) { this.brand = brand; } public int getMaxSpeed() { return maxSpeed; } public void setMaxSpeed(int maxSpeed) { this.maxSpeed = maxSpeed; } @Override public String toString() { return "Car [brand=" + brand + ", maxSpeed=" + maxSpeed + "]"; } } class CloneTest { public static void main(String[] args) { try { Person p1 = new Person("Hao LUO", 33, new Car("Benz", 300)); Person p2 = MyUtil.clone(p1); // 深度克隆 p2.getCar().setBrand("BYD"); // 修改克隆的Person對(duì)象p2關(guān)聯(lián)的汽車對(duì)象的品牌屬性 // 原來的Person對(duì)象p1關(guān)聯(lián)的汽車不會(huì)受到任何影響 // 因?yàn)樵诳寺erson對(duì)象時(shí)其關(guān)聯(lián)的汽車對(duì)象也被克隆了 System.out.println(p1); } catch (Exception e) { e.printStackTrace(); } } }
注意:基于序列化和反序列化實(shí)現(xiàn)的克隆不僅僅是深度克隆,更重要的是通過泛型限定,可以檢查出要克隆的對(duì)象是否支持序列化,這項(xiàng)檢查是編譯器完成的,不是在運(yùn)行時(shí)拋出異常,這種是方案明顯優(yōu)于使用Object類的clone方法克隆對(duì)象。
答:接口可以繼承接口。抽象類可以實(shí)現(xiàn)(implements)接口,抽象類可以繼承具體類。抽象類中可以有靜態(tài)的main方法。
備注:只要明白了接口和抽象類的本質(zhì)和作用,這些問題都很好回答,你想想,如果你是java語言的設(shè)計(jì)者,你是否會(huì)提供這樣的支持,如果不提供的話,有什么理由嗎?如果你沒有道理不提供,那答案就是肯定的了。
只有記住抽象類與普通類的唯一區(qū)別就是不能創(chuàng)建實(shí)例對(duì)象和允許有abstract方法。?
答:可以,但一個(gè)源文件中最多只能有一個(gè)公開類(public class)而且文件名必須和公開類的類名完全保持一致。?
答:可以繼承其他類或?qū)崿F(xiàn)其他接口,在Swing編程中常用此方式來實(shí)現(xiàn)事件監(jiān)聽和回調(diào)。?但是有一點(diǎn)需要注意,它只能繼承一個(gè)類或一個(gè)接口。
答:一個(gè)內(nèi)部類對(duì)象可以訪問創(chuàng)建它的外部類對(duì)象的成員,包括私有成員。如果要訪問外部類的局部變量,此時(shí)局部變量必須使用final修飾,否則無法訪問。
(1) 修飾類:表示該類不能被繼承;
(2) 修飾方法:表示方法不能被重寫但是允許重載;
(3) 修飾變量:表示變量只能一次賦值以后值不能被修改(常量);
(4) 修飾對(duì)象:對(duì)象的引用地址不能變,但是對(duì)象的初始化值可以變。
package com.bjsxt; class A{ static{ System.out.print("1"); } public A(){ System.out.print("2"); } } class B extends A{ static{ System.out.print("a"); } public B(){ System.out.print("b"); } } public class Hello{ public static void main(String[] args){ A ab = new B(); ab = new B(); } }
答:執(zhí)行結(jié)果:1a2b2b。創(chuàng)建對(duì)象時(shí)構(gòu)造器的調(diào)用順序是:先初始化靜態(tài)成員,然后調(diào)用父類構(gòu)造器,再初始化非靜態(tài)成員,最后調(diào)用自身構(gòu)造器。?
考點(diǎn):靜態(tài)代碼塊優(yōu)先級(jí) > 構(gòu)造方法的優(yōu)先級(jí)如果再加一個(gè)普通代碼塊,優(yōu)先順序如下:靜態(tài)代碼塊>普通代碼塊>構(gòu)造方法
1 ) 如何將字符串轉(zhuǎn)換為基本數(shù)據(jù)類型?
2 ) 如何將基本數(shù)據(jù)類型轉(zhuǎn)換為字符串?
答:
1 ) 調(diào)用基本數(shù)據(jù)類型對(duì)應(yīng)的包裝類中的方法parseXXX(String)或valueOf(String)即可返回相應(yīng)基本類型;
2 ) 一種方法是將基本數(shù)據(jù)類型與空字符串(””)連接(+)即可獲得其所對(duì)應(yīng)的字符串;另一種方法是調(diào)用String 類中的valueOf(…)方法返回相應(yīng)字符串?
答:方法很多,可以自己寫實(shí)現(xiàn)也可以使用String或StringBuffer / StringBuilder中的方法。有一道很常見的面試題是用遞歸實(shí)現(xiàn)字符串反轉(zhuǎn),代碼如下所示:
package com.bjsxt; public class A{ public static String reverse(String originStr) { if(originStr == null || originStr.length() <= 1) return originStr; return reverse(originStr.substring(1)) + originStr.charAt(0); } }
答:代碼如下所示:
String s1 = "你好";
String s2 = newString(s1.getBytes("GB2312"), "ISO-8859-1");?
在String類的構(gòu)造方法當(dāng)中,存在一個(gè)字符集設(shè)置的方法,具體如下:
1 ) 如何取得年月日、小時(shí)分鐘秒?
2 ) 如何取得從1970年1月1日0時(shí)0分0秒到現(xiàn)在的毫秒數(shù)?
3 ) 如何取得某月的最后一天?
4 ) 如何格式化日期?
答:操作方法如下所示:
1 ) 創(chuàng)建java.util.Calendar 實(shí)例,調(diào)用其get()方法傳入不同的參數(shù)即可獲得參數(shù)所對(duì)應(yīng)的值
2 ) 以下方法均可獲得該毫秒數(shù):
Calendar.getInstance().getTimeInMillis();
time.getActualMaximum(Calendar.DAY_OF_MONTH);
4 ) 利用java.text.DataFormat 的子類(如SimpleDateFormat類)中的format(Date)方法可將日期格式化。
package com.bjsxt; import java.util.Calendar; public class YesterdayCurrent { public static void main(String[] args){ Calendar cal = Calendar.getInstance(); cal.add(Calendar.DATE, -1); System.out.println(cal.getTime()); } }
在JDK中,主要由以下類來實(shí)現(xiàn)Java反射機(jī)制,這些類都位于java.lang.reflect包中
1)Class類:代表一個(gè)類
2)Field 類:代表類的成員變量(屬性)
3)Method類:代表類的成員方法
4)Constructor 類:代表類的構(gòu)造方法
5)Array類:提供了動(dòng)態(tài)創(chuàng)建數(shù)組,以及訪問數(shù)組的元素的靜態(tài)方法
Class類是Java 反射機(jī)制的起源和入口,用于獲取與類相關(guān)的各種信息,提供了獲取類信息的相關(guān)方法。Class類繼承自O(shè)bject類
Class類是所有類的共同的圖紙。每個(gè)類有自己的對(duì)象,好比圖紙和實(shí)物的關(guān)系;每個(gè)類也可看做是一個(gè)對(duì)象,有共同的圖紙Class,存放類的 結(jié)構(gòu)信息,能夠通過相應(yīng)方法取出相應(yīng)信息:類的名字、屬性、方法、構(gòu)造方法、父類和接口
方 法 | 示 例 |
對(duì)象名 .getClass() |
String str="bdqn";
Class clazz = str.getClass();
|
對(duì)象名 .getSuperClass() |
Student stu = new Student();
Class c1 = stu.getClass();
Class c2 = stu.getSuperClass();
|
Class.forName() |
Class clazz = Class.forName("java.lang.Object");
Class.forName("oracle.jdbc.driver.OracleDriver");
|
類名.class |
類名.class
Class c2 = Student.class;
Class c2 = int.class
|
包裝類.TYPE |
包裝類.TYPE
Class c2 = Boolean.TYPE;
|
1)使用場(chǎng)合
在編譯時(shí)根本無法知道該對(duì)象或類可能屬于哪些類,程序只依靠運(yùn)行時(shí)信息來發(fā)現(xiàn)該對(duì)象和類的真實(shí)信息。
2)主要作用
通過反射可以使程序代碼訪問裝載到JVM 中的類的內(nèi)部信息,獲取已裝載類的屬性信息,獲取已裝載類的方法,獲取已裝載類的構(gòu)造方法信息
3)反射的優(yōu)點(diǎn)
反射提高了Java程序的靈活性和擴(kuò)展性,降低耦合性,提高自適應(yīng)能力。它允許程序創(chuàng)建和控制任何類的對(duì)象,無需提前硬編碼目標(biāo)類;反射是其它一些常用語言,如C、C++、Fortran 或者Pascal等都不具備的
4) Java反射技術(shù)應(yīng)用領(lǐng)域很廣,如軟件測(cè)試等;許多流行的開源框架例如Struts、Hibernate、Spring在實(shí)現(xiàn)過程中都采用了該技術(shù)
5)反射的缺點(diǎn)
性能問題:使用反射基本上是一種解釋操作,用于字段和方法接入時(shí)要遠(yuǎn)慢于直接代碼。因此Java反射機(jī)制主要應(yīng)用在對(duì)靈活性和擴(kuò)展性要求很高的系統(tǒng)框架上,普通程序不建議使用。
使用反射會(huì)模糊程序內(nèi)部邏輯:程序人員希望在源代碼中看到程序的邏輯,反射等繞過了源代碼的技術(shù),因而會(huì)帶來維護(hù)問題。反射代碼比相應(yīng)的直接代碼更復(fù)雜。
面向?qū)ο笤O(shè)計(jì)原則是面向?qū)ο笤O(shè)計(jì)的基石,面向?qū)ο笤O(shè)計(jì)質(zhì)量的依據(jù)和保障,設(shè)計(jì)模式是面向?qū)ο笤O(shè)計(jì)原則的經(jīng)典應(yīng)用
1)單一職責(zé)原則SRP
2)開閉原則OCP
3)里氏替代原則LSP
4)依賴注入原則DIP
5)接口分離原則ISP
6)迪米特原則LOD
7)組合/聚合復(fù)用原則CARP
8)開閉原則具有理想主義的色彩,它是面向?qū)ο笤O(shè)計(jì)的終極目標(biāo)。其他設(shè)計(jì)原則都可以看作是開閉原則的實(shí)現(xiàn)手段或方法
String相關(guān):
String str1="hello"; String str2=new String("hello"); System.out.println(str1==str2);
A. | true |
B. | false |
C. | hello |
D. | he |
答案:B
分析:str1沒有使用new關(guān)鍵字,在堆中沒有開辟空間,其值”hello”在常量池中,str2使用new關(guān)鍵字創(chuàng)建了一個(gè)對(duì)象,在堆中開辟了空間,”==”比較的是對(duì)象的引用,即內(nèi)存地址,所以str1與str2兩個(gè)對(duì)象的內(nèi)存地址是不相同的
|
A. | int16 |
B. | int32 |
C. | int |
D. | long |
答案:C
|
public class Example { String str=new String("good"); char [] ch={'a','b','c'}; public static void main(String[] args) { Example ex=new Example(); ex.change(ex.str, ex.ch); System.out.print(ex.str+"and"); System.out.print(ex.ch); } public void change(String str,char ch[]){ str="test ok"; ch[0]='g'; } }
A. | goodandabc |
B. | goodandgbc |
C. | test okandabc |
D. | test okandgbc |
答案:B
分析:在方法調(diào)用時(shí),在change方法中對(duì)str的值進(jìn)行修改,是將str指向了常量江池中的”test ok”,而主方法中的ex.str仍然指向的是常量池中的”good”。字符型數(shù)組在方法調(diào)用時(shí),將主方法中ex.ch的引用傳遞給change方法中的ch,指向是堆中的同一堆空間,所以修改ch[0]的時(shí)候,ex.ch可以看到相同的修改后的結(jié)果。
|
String[] s=new String[10];
A. | s[10]為”” |
B. | s[9]為null |
C. | s[0]為未定義 |
D. | s.length為10 |
答案:BD
分析: 引用數(shù)據(jù)類型的默認(rèn)值均為null
s.length數(shù)組的長(zhǎng)度 |
思路說明:replaceAll方法的本質(zhì)是使用正則表達(dá)式進(jìn)行匹配,最終調(diào)用的其實(shí)是Matcher對(duì)象的replaceAll方法。
import java.util.regex.Matcher; import java.util.regex.Pattern; public class TestStringReplaceAll { public static void main(String[] args) { String str = "a1s2d3f4h5j6k7"; // 將字符串中的數(shù)字全部替換為0 System.out.println(replaceAll(str, "\\d", "0")); } /** * @param str:源字符串 * @param regex:正則表達(dá)式 * @param newStr:替換后的子字符串 * @return 返回替換成功后的字符串 */ public static String replaceAll(String str, String regex, String newStr) { Pattern pattern = Pattern.compile(regex); Matcher mathcer = pattern.matcher(str); String reslut = mathcer.replaceAll(newStr); return reslut; } }
String []a=new String[10];
則:a[0]~a[9]=null;
a.length=10;
如果是int[]a=new int[10];
則:a[0]~a[9]= (0)
a.length= (10)
答:不可以,因?yàn)镾tring類有final修飾符,而final修飾的類是不能被繼承的,實(shí)現(xiàn)細(xì)節(jié)不允許改變。
public final class String implements java.io.Serializable,
Comparable< String>, CharSequence
public class Solution { public boolean isAnagram(String s, String t) { if(s.length()!=t.length()) return false; int bit[] = new int[26]; for(int i=0;i<s.length();i++){ bit[s.charAt(i)-'a']++; } for(int i=0;i<s.length();i++){ if(--bit[t.charAt(i)-'a']<0) return false; } return true; } }
兩個(gè)或一個(gè),”abc”對(duì)應(yīng)一個(gè)對(duì)象,這個(gè)對(duì)象放在字符串常量緩沖區(qū),常量”abc”不管出現(xiàn)多少遍,都是緩沖區(qū)中的那一個(gè)。New String每寫一遍,就創(chuàng)建一個(gè)新的對(duì)象,它一句那個(gè)常量”abc”對(duì)象的內(nèi)容來創(chuàng)建出一個(gè)新String對(duì)象。如果以前就用過’abc’,這句代表就不會(huì)創(chuàng)建”abc”自己了,直接從緩沖區(qū)拿。
String str1=“hello”; Sring str2=“he”+new String(“l(fā)lo”); Sysem.out.println(str1==str2)); Sysem.out.println(str.equal(str2));
false
true
import java.util.*; public class Test 6{ public static void main(String[] args) { for (int i = 0; i < 10; i++) { Integer k=new Integer(i); System.out.println(k+" Hello world"); } } }
0 Hello world
1 Hello world
2 Hello world
3 Hello world
4 Hello world
5 Hello world
6 Hello world
7 Hello world
8 Hello world
9 Hello world
A. | String類是final類故不可繼承 |
B. | String類final類故可以繼承 |
C. | String類不是final類故不可繼承 |
D. | String;類不是final類故可以繼承 |
答案:A
|
A. | String temp[ ] = new String{“a”,”b”,”c”}; |
B. | String temp[ ] = {“a”,”b”,”c”}; |
C. | String temp= {“a”,”b”,”c”}; |
D. | String[ ] temp = {“a”,”b”,”c”}; |
答案:BD
|
package com.bjsxt; public class Test { public static void main(String[] args) { String s1 = new String("Hello"); String s2 = new String("Hello"); System.out.print(s1 == s2); String s3 = "Hello"; String s4 = "Hello"; System.out.print(s3 == s4); s1 = s3; s2 = s4; System.out.print(s1 == s2); } }
A. | false true true |
B. | true false true |
C. | true true false |
D. | true true false |
答案:A
|
public class Test { public static void main(String[] args) { //方式一 int num=Integer.parseInt("123"); //方式二 int num2=Integer.valueOf("123"); System.out.println(num+" "+num2); } }
public class Test { public static void main(String[] args) { String result=reverse("abc"); System.out.println(result); } public static String reverse(String str){ StringBuilder result=new StringBuilder(""); char[] chArra=str.toCharArray(); for(int i=chArra.length-1;i>=0;i--){ char ch=chArra[i]; result.append(ch); } return result.toString(); } }
public classDemo1 { publicstaticvoid main(String[] args) { String s="I follow Bill Gate.Tom Gate.John Gate"; System.out.println(s); s=s.replaceAll("Gate","Gates"); System.out.println(s); } }
答: 不是 。Java中的基本數(shù)據(jù)類型只有8個(gè):byte、short、int、long、float、double、char、boolean;除了基本類型(primitive type)和枚舉類型(enumeration type),剩下的都是引用類型(reference type)。
答: Java 平臺(tái)提供了兩種類型的字符串:String和StringBuffer / StringBuilder
相同點(diǎn):
它們都可以儲(chǔ)存和操作字符串,同時(shí)三者都使用final修飾,都屬于終結(jié)類不能派生子類,操作的相關(guān)方法也類似例如獲取字符串長(zhǎng)度等;
不同點(diǎn):
其中String是只讀字符串,也就意味著String引用的字符串內(nèi)容是不能被改變的,而StringBuffer和StringBuilder類表示的字符串對(duì)象可以直接進(jìn)行修改,在修改的同時(shí)地址值不會(huì)發(fā)生改變。StringBuilder是JDK 1.5中引入的,它和StringBuffer的方法完全相同,區(qū)別在于它是在單線程環(huán)境下使用的,因?yàn)樗乃蟹矫娑紱]有被synchronized修飾,因此它的效率也比StringBuffer略高。在此重點(diǎn)說明一下,String、StringBuffer、StringBuilder三者類型不一樣,無法使用equals()方法比較其字符串內(nèi)容是否一樣!
補(bǔ)充1:有一個(gè)面試題問:有沒有哪種情況用+做字符串連接比調(diào)用StringBuffer / StringBuilder對(duì)象的append方法性能更好?如果連接后得到的字符串在靜態(tài)存儲(chǔ)區(qū)中是早已存在的,那么用+做字符串連接是優(yōu)于StringBuffer / StringBuilder的append方法的。
補(bǔ)充2:下面也是一個(gè)面試題,問程序的輸出,看看自己能不能說出正確答案。
package com.bjsxt; public class smallT { public static void main(String[] args) { String a = "Programming"; String b = new String("Programming"); String c = "Program" + "ming"; System.out.println(a == b); System.out.println(a == c); System.out.println(a.equals(b)); System.out.println(a.equals(c)); System.out.println(a.intern() == b.intern()); } }
解析:
String類存在intern()方法,含義如下:返回字符串對(duì)象的規(guī)范化表示形式。它遵循以下規(guī)則:對(duì)于任意兩個(gè)字符串 s 和 t,當(dāng)且僅當(dāng) s.equals(t) 為 true 時(shí),s.intern()?==?t.intern() 才為 true。
字符串比較分為兩種形式,一種使用比較運(yùn)算符”==”比較,他們比較的是各自的字符串在內(nèi)存當(dāng)中的地址值是否相同;一種是使用equals()方法進(jìn)行比較,比較的是兩個(gè)字符串的內(nèi)容是否相同!
結(jié)果如下:
a == b-->false
a == c-->true
a.equals(b)-->true
a.equals(c)-->true
a.intern() == b.intern()-->true
答:1) 為了效率。若允許被繼承,則其高度的被使用率可能會(huì)降低程序的性能。
2)為了安全。JDK中提供的好多核心類比如String,這類的類的內(nèi)部好多方法的實(shí)現(xiàn)都不是java編程語言本身編寫的,好多方法都是調(diào)用的操作系統(tǒng)本地的API,這就是著名的“本地方法調(diào)用”,也只有這樣才能做事,這種類是非常底層的,和操作系統(tǒng)交流頻繁的,那么如果這種類可以被繼承的話,如果我們?cè)侔阉姆椒ㄖ貙懥?,往操作系統(tǒng)內(nèi)部寫入一段具有惡意攻擊性質(zhì)的代碼什么的,這不就成了核心病毒了么?不希望別人改,這個(gè)類就像一個(gè)工具一樣,類的提供者給我們提供了, 就希望我們直接用就完了,不想讓我們隨便能改,其實(shí)說白了還是安全性,如果隨便能改了,那么java編寫的程序肯定就很不穩(wěn)定,你可以保證自己不亂改, 但是將來一個(gè)項(xiàng)目好多人來做,管不了別人,再說有時(shí)候萬一疏忽了呢?他也不是估計(jì)的, 所以這個(gè)安全性是很重要的,java和C++相比,優(yōu)點(diǎn)之一就包括這一點(diǎn)。
1) 基本數(shù)據(jù)類型包括byte、short/char、int、long、float、double、boolean
2 ) java.lang.String類是引用數(shù)據(jù)類型,并且是final類型的,因此不可以繼承這個(gè)類、不能修改這個(gè)類。為了提高效率節(jié)省空間,我們應(yīng)該用StringBuffer類
答:不是對(duì)前面s指向空間內(nèi)容的直接修改。
因?yàn)镾tring被設(shè)計(jì)成不可變(immutable)類,所以它的所有對(duì)象都是不可變對(duì)象。在這段代碼中,s原先指向一個(gè)String對(duì)象,內(nèi)容是 "Hello",然后我們對(duì)s進(jìn)行了+操作,那么s所指向的那個(gè)對(duì)象是否發(fā)生了改變呢?答案是沒有。這時(shí),s不指向原來那個(gè)對(duì)象了,而指向了另一個(gè) String對(duì)象,內(nèi)容為"Hello?world!",原來那個(gè)對(duì)象還存在于內(nèi)存之中,只是s這個(gè)引用變量不再指向它了。
通過上面的說明,我們很容易導(dǎo)出另一個(gè)結(jié)論,如果經(jīng)常對(duì)字符串進(jìn)行各種各樣的修改,或者說,不可預(yù)見的修改,那么使用String來代表字符串的話會(huì)引起很大的內(nèi)存開銷。因?yàn)?String對(duì)象建立之后不能再改變,所以對(duì)于每一個(gè)不同的字符串,都需要一個(gè)String對(duì)象來表示。這時(shí),應(yīng)該考慮使用StringBuffer類,它允許修改,而不是每個(gè)不同的字符串都要生成一個(gè)新的對(duì)象。并且,這兩種類的對(duì)象轉(zhuǎn)換十分容易。
同時(shí),我們還可以知道,如果要使用內(nèi)容相同的字符串,不必每次都new一個(gè)String。例如我們要在構(gòu)造器中對(duì)一個(gè)名叫s的String引用變量進(jìn)行初始化,把它設(shè)置為初始值,應(yīng)當(dāng)這樣做:
public class Demo { private String s; ... public Demo { s = "Initial Value"; } ... }
而非
s?=?new?String("Initial?Value");
后者每次都會(huì)調(diào)用構(gòu)造器,生成新對(duì)象,性能低下且內(nèi)存開銷大,并且沒有意義,因?yàn)镾tring對(duì)象不可改變,所以對(duì)于內(nèi)容相同的字符串,只要一個(gè)String對(duì)象來表示就可以了。也就說,多次調(diào)用上面的構(gòu)造器創(chuàng)建多個(gè)對(duì)象,他們的String類型屬性s都指向同一個(gè)對(duì)象。
上面的結(jié)論還基于這樣一個(gè)事實(shí):對(duì)于字符串常量,如果內(nèi)容相同,Java認(rèn)為它們代表同一個(gè)String對(duì)象。而用關(guān)鍵字new調(diào)用構(gòu)造器,總是會(huì)創(chuàng)建一個(gè)新的對(duì)象,無論內(nèi)容是否相同。
至于為什么要把String類設(shè)計(jì)成不可變類,是它的用途決定的。其實(shí)不只String,很多Java標(biāo)準(zhǔn)類庫(kù)中的類都是不可變的。在開發(fā)一個(gè)系統(tǒng)的時(shí)候,我們有時(shí)候也需要設(shè)計(jì)不可變類,來傳遞一組相關(guān)的值,這也是面向?qū)ο笏枷氲捏w現(xiàn)。不可變類有一些優(yōu)點(diǎn),比如因?yàn)樗膶?duì)象是只讀的,所以多線程并發(fā)訪問也不會(huì)有任何問題。當(dāng)然也有一些缺點(diǎn),比如每個(gè)不同的狀態(tài)都要一個(gè)對(duì)象來代表,可能會(huì)造成性能上的問題。所以Java標(biāo)準(zhǔn)類庫(kù)還提供了一個(gè)可變版本,即 StringBuffer。
答:兩個(gè)或一個(gè),”xyz”對(duì)應(yīng)一個(gè)對(duì)象,這個(gè)對(duì)象放在字符串常量緩沖區(qū),常量”xyz”不管出現(xiàn)多少遍,都是緩沖區(qū)中的那一個(gè)。New String每寫一遍,就創(chuàng)建一個(gè)新的對(duì)象,它一句那個(gè)常量”xyz”對(duì)象的內(nèi)容來創(chuàng)建出一個(gè)新String對(duì)象。如果以前就用過’xyz’,這句代表就不會(huì)創(chuàng)建”xyz”自己了,直接從緩沖區(qū)拿。
答:對(duì)于如下代碼:
String s1 = "a";
String s2 = s1 + "b";
String s3 = "a" + "b";
System.out.println(s2 == "ab");
System.out.println(s3 == "ab");
第一條語句打印的結(jié)果為false,第二條語句打印的結(jié)果為true,這說明javac編譯可以對(duì)字符串常量直接相加的表達(dá)式進(jìn)行優(yōu)化,不必要等到運(yùn)行期去進(jìn)行加法運(yùn)算處理,而是在編譯時(shí)去掉其中的加號(hào),直接將其編譯成一個(gè)這些常量相連的結(jié)果。
題目中的第一行代碼被編譯器在編譯時(shí)優(yōu)化后,相當(dāng)于直接定義一個(gè)”abcd”的字符串,所以,上面的代碼應(yīng)該只創(chuàng)建了一個(gè)String對(duì)象。
寫如下兩行代碼,
String s = "a" + "b" + "c" + "d";
System.out.println(s == "abcd");
最終打印的結(jié)果應(yīng)該為true。
集合:
1、Collection 接口存儲(chǔ)一組不唯一,無序的對(duì)象
2、List 接口存儲(chǔ)一組不唯一,有序(插入順序)的對(duì)象
3、Set 接口存儲(chǔ)一組唯一,無序的對(duì)象
4、Map接口存儲(chǔ)一組鍵值對(duì)象,提供key到value的映射。Key無序,唯一。value不要求有序,允許重復(fù)。(如果只使用key存儲(chǔ),而不使用value,那就是Set)
相同點(diǎn):
1)實(shí)現(xiàn)原理相同---底層都使用數(shù)組
2)功能相同---實(shí)現(xiàn)增刪改查等操作的方法相似
3)都是長(zhǎng)度可變的數(shù)組結(jié)構(gòu),很多情況下可以互用
不同點(diǎn):
1)Vector是早期JDK版本提供,ArrayList是新版本替代Vector的
2)Vector線程安全,ArrayList重速度輕安全,線程非安全長(zhǎng)度需增長(zhǎng)時(shí),Vector默認(rèn)增長(zhǎng)一倍,ArrayList增長(zhǎng)50%
相同點(diǎn):
兩者都實(shí)現(xiàn)了List接口,都具有List中元素有序、不唯一的特點(diǎn)。
不同點(diǎn):
ArrayList實(shí)現(xiàn)了長(zhǎng)度可變的數(shù)組,在內(nèi)存中分配連續(xù)空間。遍歷元素和隨機(jī)訪問元素的效率比較高;
LinkedList采用鏈表存儲(chǔ)方式。插入、刪除元素時(shí)效率比較高
相同點(diǎn):
實(shí)現(xiàn)原理相同,功能相同,底層都是哈希表結(jié)構(gòu),查詢速度快,在很多情況下可以互用
不同點(diǎn):
1、Hashtable是早期提供的接口,HashMap是新版JDK提供的接口
2、Hashtable繼承Dictionary類,HashMap實(shí)現(xiàn)Map接口
3、Hashtable線程安全,HashMap線程非安全
4、Hashtable不允許null值,HashMap允許null值
1)哈希表的查詢速度特別快,時(shí)間復(fù)雜度為O(1)。
2)HashMap、Hashtable、HashSet這些集合采用的是哈希表結(jié)構(gòu),需要用到hashCode哈希碼,hashCode是一個(gè)整數(shù)值。
3)系統(tǒng)類已經(jīng)覆蓋了hashCode方法 自定義類如果要放入hash類集合,必須重寫hashcode。如果不重寫,調(diào)用的是Object的hashcode,而Object的hashCode實(shí)際上是地址。
4)向哈希表中添加數(shù)據(jù)的原理:當(dāng)向集合Set中增加對(duì)象時(shí),首先集合計(jì)算要增加對(duì)象的hashCode碼,根據(jù)該值來得到一個(gè)位置用來存放當(dāng)前對(duì)象,如在該位置沒有一個(gè)對(duì)象存在的話,那么集合Set認(rèn)為該對(duì)象在集合中不存在,直接增加進(jìn)去。如果在該位置有一個(gè)對(duì)象存在的話,接著將準(zhǔn)備增加到集合中的對(duì)象與該位置上的對(duì)象進(jìn)行equals方法比較,如果該equals方法返回false,那么集合認(rèn)為集合中不存在該對(duì)象,在進(jìn)行一次散列,將該對(duì)象放到散列后計(jì)算出的新地址里。如果equals方法返回true,那么集合認(rèn)為集合中已經(jīng)存在該對(duì)象了,不會(huì)再將該對(duì)象增加到集合中了。
5)在哈希表中判斷兩個(gè)元素是否重復(fù)要使用到hashCode()和equals()。hashCode決定數(shù)據(jù)在表中的存儲(chǔ)位置,而equals判斷是否存在相同數(shù)據(jù)。
6) Y=K(X) :K是函數(shù),X是哈希碼,Y是地址
1)TreeSet集合,元素不允許重復(fù)且有序(自然順序)
2)TreeSet采用樹結(jié)構(gòu)存儲(chǔ)數(shù)據(jù),存入元素時(shí)需要和樹中元素進(jìn)行對(duì)比,需要指定比較策略。
3)可以通過Comparable(外部比較器)和Comparator(內(nèi)部比較器)來指定比較策略,實(shí)現(xiàn)了Comparable的系統(tǒng)類可以順利存入TreeSet。自定義類可以實(shí)現(xiàn)Comparable接口來指定比較策略。
4)可創(chuàng)建Comparator接口實(shí)現(xiàn)類來指定比較策略,并通過TreeSet構(gòu)造方法參數(shù)傳入。這種方式尤其對(duì)系統(tǒng)類非常適用。
數(shù)組不是面向?qū)ο蟮?,存在明顯的缺陷,集合完全彌補(bǔ)了數(shù)組的一些缺點(diǎn),比數(shù)組更靈活更實(shí)用,可大大提高軟件的開發(fā)效率而且不同的集合框架類可適用于不同場(chǎng)合。具體如下:
1)數(shù)組的效率高于集合類.
2)數(shù)組能存放基本數(shù)據(jù)類型和對(duì)象,而集合類中只能放對(duì)象。
3)數(shù)組容量固定且無法動(dòng)態(tài)改變,集合類容量動(dòng)態(tài)改變。
4)數(shù)組無法判斷其中實(shí)際存有多少元素,length只告訴了array的容量。
5)集合有多種實(shí)現(xiàn)方式和不同的適用場(chǎng)合,而不像數(shù)組僅采用順序表方式。
6)集合以類的形式存在,具有封裝、繼承、多態(tài)等類的特性,通過簡(jiǎn)單的方法和屬性調(diào)用即可實(shí)現(xiàn)各種復(fù)雜操作,大大提高軟件的開發(fā)效率。
1)Collection是Java提供的集合接口,存儲(chǔ)一組不唯一,無序的對(duì)象。它有兩個(gè)子接口List和Set。
2)Java中還有一個(gè)Collections類,專門用來操作集合類 ,它提供一系列靜態(tài)方法實(shí)現(xiàn)對(duì)各種集合的搜索、排序、線程安全化等操作。
A. | LinkedList繼承自List |
B. | AbstractSet繼承自Set |
C. | HashSet繼承自AbstractSet |
D. | TreeMap繼承自HashMap |
答案: C
分析:A:LinkedList實(shí)現(xiàn)List接口
B:AbstractSet實(shí)現(xiàn)Set接口
D:TreeMap繼承AbstractMap
|
答:HashMap與Hashtable實(shí)現(xiàn)原理相同,功能相同,底層都是哈希表結(jié)構(gòu),查詢速度快,在很多情況下可以互用
兩者的主要區(qū)別如下
1、Hashtable是早期JDK提供的接口,HashMap是新版JDK提供的接口
2、Hashtable繼承Dictionary類,HashMap實(shí)現(xiàn)Map接口
3、Hashtable線程安全,HashMap線程非安全
4、Hashtable不允許null值,HashMap允許null值
HashSet與HashMap的區(qū)別
1、HashSet底層是采用HashMap實(shí)現(xiàn)的。HashSet 的實(shí)現(xiàn)比較簡(jiǎn)單,HashSet 的絕大部分方法都是通過調(diào)用 HashMap 的方法來實(shí)現(xiàn)的,因此 HashSet 和 HashMap 兩個(gè)集合在實(shí)現(xiàn)本質(zhì)上是相同的。
2、HashMap的key就是放進(jìn)HashSet中對(duì)象,value是Object類型的。
3、當(dāng)調(diào)用HashSet的add方法時(shí),實(shí)際上是向HashMap中增加了一行(key-value對(duì)),該行的key就是向HashSet增加的那個(gè)對(duì)象,該行的value就是一個(gè)Object類型的常量
答:Java中集合主要分為兩種:Collection和Map。Collection是List和Set接口的父接口;ArrayList和LinkedList是List的實(shí)現(xiàn)類;HashSet和TreeSet是Set的實(shí)現(xiàn)類;LinkedHashSet是HashSet的子類。HashMap和TreeMap是Map的實(shí)現(xiàn)類;LinkedHashMap是HashMap的子類。
圖中:虛線框中為接口,實(shí)線框中為類。
答:List 接口存儲(chǔ)一組不唯一,有序(插入順序)的對(duì)象。
Set 接口存儲(chǔ)一組唯一,無序的對(duì)象。
Map接口存儲(chǔ)一組鍵值對(duì)象,提供key到value的映射。key無序,唯一。value不要求有序,允許重復(fù)。(如果只使用key存儲(chǔ),而不使用value,那就是Set)。
A. | 0 |
B. | 1 |
C. | 2 |
D. | 3 |
答案:A
分析:已經(jīng)指定了長(zhǎng)度, 所以不擴(kuò)容
|
A. | List Map |
B. | Set Map |
C. | List Set |
D. | List Map Set |
答案:C
分析:Map接口繼承了java.lang.Object類,但沒有實(shí)現(xiàn)任何接口.
|
public class Solution { public ListNode mergeTwoLists(ListNode l1, ListNode l2) { if (l1 == null || l2 == null) { return l1 != null ? l1 : l2; } ListNode head = l1.val < l2.val ? l1 : l2; ListNode other = l1.val >= l2.val ? l1 : l2; ListNode prevHead = head; ListNode prevOther = other; while (prevHead != null) { ListNode next = prevHead.next; if (next != null && next.val > prevOther.val) { prevHead.next = prevOther; prevOther = next; } if(prevHead.next==null){ prevHead.next=prevOther; break; } prevHead=prevHead.next; } return head; } }
/** Definition for singly-linked list. public class ListNode { int val; ListNode next; ListNode(int x) { val = x; } * } */ public class Solution { public ListNode reverseList(ListNode head) { if(head==null||head.next ==null) return head; ListNode prev = reverseList(head.next); head.next.next = head; head.next = null; return prev; } }
public class Solution { public List<List<Integer>> subsets (int[] nums) { List<List<Integer>> res = new ArrayList<ArrayList<Integer>>(); List<Integer> item = new ArrayList<Integer>(); if(nums.length == 0 || nums == null) return res; Arrays.sort(nums); //排序 dfs(nums, 0, item, res); //遞歸調(diào)用 res.add(new ArrayList<Integer>()); //最后加上一個(gè)空集 return res; } public static void dfs(int[] nums, int start, List<Integer> item, List<List<Integer>> res){ for(int i = start; i < nums.length; i ++){ item.add(nums[i]); //item是以整數(shù)為元素的動(dòng)態(tài)數(shù)組,而res是以數(shù)組為元素的數(shù)組,在這一步,當(dāng)item增加完元素后,item所有元素構(gòu)成一個(gè)完整的子串,再由res納入 res.add(new ArrayList<Integer>(item)); dfs(nums, i + 1, item, res); item.remove(item.size() - 1); } } }
A. | HashMap |
B. | ConcurrentHashMap |
C. | WeakHashMap |
D. | TreeMap |
答案:B
分析:
A,C,D都線程不安全,B線程安全,具有同步功能
|
A. | ArrayList |
B. | Linkedlist |
C. | tor |
D. | Collection |
答案:B
分析:
數(shù)組插入、刪除效率差,排除A
tor不是java里面的數(shù)據(jù)結(jié)構(gòu),是一種網(wǎng)絡(luò)路由技術(shù);因此排除C
Collection 是集合的接口,不是某種數(shù)據(jù)結(jié)構(gòu);因此排除D
|
A. | LinkedHashMap |
B. | LinkedHashSet |
C. | LinkedList |
LinkedList
分析:
Stack是先進(jìn)后出的線性結(jié)構(gòu);所以鏈表比較合適;不需要散列表的數(shù)據(jù)結(jié)構(gòu)
|
答:1. Map的實(shí)現(xiàn)類有HashMap,LinkedHashMap,TreeMap
2. HashMap是有無序的,LinkedHashMap和TreeMap都是有序的(LinkedHashMap記錄了添加數(shù)據(jù)的順序;TreeMap默認(rèn)是自然升序)
3. LinkedHashMap底層存儲(chǔ)結(jié)構(gòu)是哈希表+鏈表,鏈表記錄了添加數(shù)據(jù)的順序
4. TreeMap底層存儲(chǔ)結(jié)構(gòu)是二叉樹,二叉樹的中序遍歷保證了數(shù)據(jù)的有序性
5. LinkedHashMap有序性能比較高,因?yàn)榈讓訑?shù)據(jù)存儲(chǔ)結(jié)構(gòu)采用的哈希表
package com.bjsxt; import java.util.LinkedList; public class Stack { LinkedList list = new LinkedList(); public synchronized void push(Object x) { synchronized (list) { list.addLast(x); notify(); } } public synchronized Object pop() throws Exception{ synchronized(list){ if(list.size()<=0){ wait(); } return list.removeLast( ); } } }
答:將if( list.size() <= 0 )改成:while( list.size() <= 0 )
答:TreeSet要求存放的對(duì)象所屬的類必須實(shí)現(xiàn)Comparable接口,該接口提供了比較元素的compareTo()方法,當(dāng)插入元素時(shí)會(huì) 回調(diào)該方法比較元素的大小。TreeMap要求存放的鍵值對(duì)映射的鍵必須實(shí)現(xiàn)Comparable接口從而根據(jù)鍵對(duì)元素進(jìn)行排序。Collections 工具類的sort方法有兩種重載的形式,第一種要求傳入的待排序容器中存放的對(duì)象比較實(shí)現(xiàn)Comparable接口以實(shí)現(xiàn)元素的比較;第二種不強(qiáng)制性的要求容器中的元素必須可比較,但是要求傳入第二個(gè)參數(shù),參數(shù)是Comparator接口的子類型(需要重寫compare方法實(shí)現(xiàn)元素的比較),相當(dāng)于一個(gè)臨時(shí)定義的排序規(guī)則,其實(shí)就是是通過接口注入比較元素大小的算法,也是對(duì)回調(diào)模式的應(yīng)用。
public class Test { public static void main(String[] args) { List<String> li1 = new ArrayList<String>(); li1.add("8"); li1.add("8"); li1.add("9"); li1.add("9"); li1.add("0"); System.out.println(li1); //方法:將List中數(shù)據(jù)取出來來存到Set中 HashSet<String> set = new HashSet<String>(); for(int i=0;i<li1.size();i++){ set.add(li1.get(i)); } System.out.println(set); } }
分析:Java中的java.util.Map的實(shí)現(xiàn)類
1、HashMap
2、Hashtable
3、LinkedHashMap
4、TreeMap
A. | 循環(huán)隊(duì)列有隊(duì)頭和隊(duì)尾兩個(gè)指針,因此,循環(huán)隊(duì)列是非線性結(jié)構(gòu) |
B. | 在循環(huán)隊(duì)列中,只需要隊(duì)頭指針就能反映隊(duì)列中元素的動(dòng)態(tài)變化情況 |
C. | 在循環(huán)隊(duì)列中,只需要隊(duì)尾指針就能反映隊(duì)列中元素的動(dòng)態(tài)變化情況 |
D. | 在循環(huán)隊(duì)列中元素的個(gè)數(shù)是由隊(duì)頭指針和隊(duì)尾指針共同決定的 |
答案:D
分析:循環(huán)隊(duì)列中元素的個(gè)數(shù)是由隊(duì)首指針和隊(duì)尾指針共同決定的,元素的動(dòng)態(tài)變化也是通過隊(duì)首指針和隊(duì)尾指針來反映的,當(dāng)隊(duì)首等于隊(duì)尾時(shí),隊(duì)列為空。
|
答:List、Set 的父接口是Collection,Map 不是其子接口,而是與Collection接口是平行關(guān)系,互不包含。
Map是鍵值對(duì)映射容器,與List和Set有明顯的區(qū)別,而Set存儲(chǔ)的零散的元素且不允許有重復(fù)元素(數(shù)學(xué)中的集合也是如此),List是線性結(jié)構(gòu)的容器,適用于按數(shù)值索引訪問元素的情形。?
答:ArrayList 和Vector都是使用數(shù)組方式存儲(chǔ)數(shù)據(jù),此數(shù)組元素?cái)?shù)大于實(shí)際存儲(chǔ)的數(shù)據(jù)以便增加和插入元素,它們都允許直接按序號(hào)索引元素,但是插入元素要涉及數(shù)組元素移動(dòng)等內(nèi)存操作,所以索引數(shù)據(jù)快而插入數(shù)據(jù)慢,Vector由于使用了synchronized 方法(線程安全),通常性能上較ArrayList 差,而LinkedList 使用雙向鏈表實(shí)現(xiàn)存儲(chǔ)(將內(nèi)存中零散的內(nèi)存單元通過附加的引用關(guān)聯(lián)起來,形成一個(gè)可以按序號(hào)索引的線性結(jié)構(gòu),這種鏈?zhǔn)酱鎯?chǔ)方式與數(shù)組的連續(xù)存儲(chǔ)方式相比,其實(shí)對(duì)內(nèi)存的利用率更高),按序號(hào)索引數(shù)據(jù)需要進(jìn)行前向或后向遍歷,但是插入數(shù)據(jù)時(shí)只需要記錄本項(xiàng)的前后項(xiàng)即可,所以插入速度較快。Vector屬于遺留容器(早期的JDK中使用的容器,除此之外Hashtable、Dictionary、BitSet、Stack、Properties都是遺留容器),現(xiàn)在已經(jīng)不推薦使用,但是由于ArrayList和LinkedListed都是非線程安全的,如果需要多個(gè)線程操作同一個(gè)容器,那么可以通過工具類Collections中的synchronizedList方法將其轉(zhuǎn)換成線程安全的容器后再使用(這其實(shí)是裝潢模式最好的例子,將已有對(duì)象傳入另一個(gè)類的構(gòu)造器中創(chuàng)建新的對(duì)象來增加新功能)。
補(bǔ)充:遺留容器中的Properties類和Stack類在設(shè)計(jì)上有嚴(yán)重的問題,Properties是一個(gè)鍵和值都是字符串的特殊的鍵值對(duì)映射,在設(shè)計(jì)上應(yīng)該是關(guān)聯(lián)一個(gè)Hashtable并將其兩個(gè)泛型參數(shù)設(shè)置為String類型,但是Java API中的Properties直接繼承了Hashtable,這很明顯是對(duì)繼承的濫用。這里復(fù)用代碼的方式應(yīng)該是HAS-A關(guān)系而不是IS-A關(guān)系,另一方面容器都屬于工具類,繼承工具類本身就是一個(gè)錯(cuò)誤的做法,使用工具類最好的方式是HAS-A關(guān)系(關(guān)聯(lián))或USE-A關(guān)系(依賴) 。同理,Stack類繼承Vector也是不正確的。?
答:List以特定索引來存取元素,可有重復(fù)元素。
Set不能存放重復(fù)元素(用對(duì)象的equals()方法來區(qū)分元素是否重復(fù)) 。Map保存鍵值對(duì)(key-value pair)映射,映射關(guān)系可以是一對(duì)一或多對(duì)一。Set和Map容器都有基于哈希存儲(chǔ)和排序樹(紅黑樹)的兩種實(shí)現(xiàn)版本,基于哈希存儲(chǔ)的版本理論存取時(shí)間復(fù)雜度為O(1),而基于排序樹版本的實(shí)現(xiàn)在插入或刪除元素時(shí)會(huì)按照元素或元素的鍵(key)構(gòu)成排序樹從而達(dá)到排序和去重的效果。?
答:TreeSet要求存放的對(duì)象所屬的類必須實(shí)現(xiàn)Comparable接口,該接口提供了比較元素的compareTo()方法,當(dāng)插入元素時(shí)會(huì)回調(diào)該方法比較元素的大小。
TreeMap要求存放的鍵值對(duì)映射的鍵必須實(shí)現(xiàn)Comparable接口從而根據(jù)鍵對(duì)元素進(jìn)行排序。
Collections工具類的sort方法有兩種重載的形式,第一種要求傳入的待排序容器中存放的對(duì)象比較實(shí)現(xiàn)Comparable接口以實(shí)現(xiàn)元素的比較;第二種不強(qiáng)制性的要求容器中的元素必須可比較,但是要求傳入第二個(gè)參數(shù),參數(shù)是Comparator接口的子類型 (需要重寫compare方法實(shí)現(xiàn)元素的比較),相當(dāng)于一個(gè)臨時(shí)定義的排序規(guī)則,其實(shí)就是是通過接口注入比較元素大小的算法,也是對(duì)回調(diào)模式的應(yīng)用。
例子1:
Student.java
package com.bjsxt; public class Student implements Comparable<Student> { private String name; // 姓名 private int age; // 年齡 public Student(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return "Student [name=" + name + ", age=" + age + "]"; } @Override public int compareTo(Student o) { return this.age - o.age; // 比較年齡(年齡的升序) } }
Test01.java
package com.bjsxt; import java.util.Set; import java.util.TreeSet; class Test01 { public static void main(String[] args) { Set<Student> set = new TreeSet<>(); // Java 7的鉆石語法(構(gòu)造器后面的尖括號(hào)中不需要寫類型) set.add(new Student("Hao LUO", 33)); set.add(new Student("XJ WANG", 32)); set.add(new Student("Bruce LEE", 60)); set.add(new Student("Bob YANG", 22)); for(Student stu : set) { System.out.println(stu); } // 輸出結(jié)果: // Student [name=Bob YANG, age=22] // Student [name=XJ WANG, age=32] // Student [name=Hao LUO, age=33] // Student [name=Bruce LEE, age=60] } }
例子2:
Student.java
package com.bjsxt; public class Student { private String name; // 姓名 private int age; // 年齡 public Student(String name, int age) { this.name = name; this.age = age; } /** * 獲取學(xué)生姓名 */ public String getName() { return name; } /** * 獲取學(xué)生年齡 */ public int getAge() { return age; } @Override public String toString() { return "Student [name=" + name + ", age=" + age + "]"; } }
Test02.java
package com.bjsxt; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; class Test02 { public static void main(String[] args) { List<Student> list = new ArrayList<>(); // Java 7的鉆石語法(構(gòu)造器后面的尖括號(hào)中不需要寫類型) list.add(new Student("Hao LUO", 33)); list.add(new Student("XJ WANG", 32)); list.add(new Student("Bruce LEE", 60)); list.add(new Student("Bob YANG", 22)); // 通過sort方法的第二個(gè)參數(shù)傳入一個(gè)Comparator接口對(duì)象 // 相當(dāng)于是傳入一個(gè)比較對(duì)象大小的算法到sort方法中 // 由于Java中沒有函數(shù)指針、仿函數(shù)、委托這樣的概念 // 因此要將一個(gè)算法傳入一個(gè)方法中唯一的選擇就是通過接口回調(diào) Collections.sort(list, new Comparator<Student> () { @Override public int compare(Student o1, Student o2) { return o1.getName().compareTo(o2.getName()); // 比較學(xué)生姓名 } }); for(Student stu : list) { System.out.println(stu); } // 輸出結(jié)果: // Student [name=Bob YANG, age=22] // Student [name=Bruce LEE, age=60] // Student [name=Hao LUO, age=33] // Student [name=XJ WANG, age=32] } }
多線程:
public static void main(String[] args) { Thread t=new Thread(){ public void run(){ pong(); } }; t.run(); System.out.println("ping"); } static void pong(){ System.out.println("pong"); }
A. | pingpong |
B. | pongping |
C. | pingpong和pongping都有可能 |
D. | 都不輸出 |
答案:B
分析:?jiǎn)?dòng)線程需要調(diào)用start()方法,而t.run()方法,則是使用對(duì)象名.分析:?jiǎn)?dòng)線程需要調(diào)用start()方法,而t.run()方法,則是使用對(duì)象名.
|
A. | public class X implements Runnable{public void run() {……}} |
B. | public class X extends Thread{public void run() {……}} |
C. | public class X extends Thread{public int run() {……}} |
D. | public class X implements Runnable{protected void run() {……}} |
答案:AB
分析: 繼承Thread和實(shí)現(xiàn)Runable接口
|
作用:
要編寫一個(gè)多線程安全(Thread-safe)的程序是困難的,為了讓線程共享資源,必須小心地對(duì)共享資源進(jìn)行同步,同步帶來一定的效能延遲,而另一方面,在處理同步的時(shí)候,又要注意對(duì)象的鎖定與釋放,避免產(chǎn)生死結(jié),種種因素都使得編寫多線程程序變得困難。
嘗試從另一個(gè)角度來思考多線程共享資源的問題,既然共享資源這么困難,那么就干脆不要共享,何不為每個(gè)線程創(chuàng)造一個(gè)資源的復(fù)本。將每一個(gè)線程存取數(shù)據(jù)的行為加以隔離,實(shí)現(xiàn)的方法就是給予每個(gè)線程一個(gè)特定空間來保管該線程所獨(dú)享的資源。
比如:在Hibernate中的Session就有使用。
ThreadLocal的原理
ThreadLocal是如何做到為每一個(gè)線程維護(hù)變量的副本的呢?其實(shí)實(shí)現(xiàn)的思路很簡(jiǎn)單,在ThreadLocal類中有一個(gè)Map,用于存儲(chǔ)每一個(gè)線程的變量的副本。
答:悲觀鎖(Pessimistic Lock), 顧名思義,就是很悲觀,每次去拿數(shù)據(jù)的時(shí)候都認(rèn)為別人會(huì)修改,所以每次在拿數(shù)據(jù)的時(shí)候都會(huì)上鎖,這樣別人想拿這個(gè)數(shù)據(jù)就會(huì)block直到它拿到鎖。傳統(tǒng)的關(guān)系型數(shù)據(jù)庫(kù)里邊就用到了很多這種鎖機(jī)制,比如行鎖,表鎖等,讀鎖,寫鎖等,都是在做操作之前先上鎖。
樂觀鎖(Optimistic Lock), 顧名思義,就是很樂觀,每次去拿數(shù)據(jù)的時(shí)候都認(rèn)為別人不會(huì)修改,所以不會(huì)上鎖,但是在更新的時(shí)候會(huì)判斷一下在此期間別人有沒有去更新這個(gè)數(shù)據(jù),可以使用版本號(hào)等機(jī)制。樂觀鎖適用于多讀的應(yīng)用類型,這樣可以提高吞吐量,像數(shù)據(jù)庫(kù)如果提供類似于write_condition機(jī)制的其實(shí)都是提供的樂觀鎖。
兩種鎖各有優(yōu)缺點(diǎn),不可認(rèn)為一種好于另一種,像樂觀鎖適用于寫比較少的情況下,即沖突真的很少發(fā)生的時(shí)候,這樣可以省去了鎖的開銷,加大了系統(tǒng)的整個(gè)吞吐量。但如果經(jīng)常產(chǎn)生沖突,上層應(yīng)用會(huì)不斷的進(jìn)行retry,這樣反倒是降低了性能,所以這種情況下用悲觀鎖就比較合適。
答:當(dāng)多個(gè)線程訪問同一個(gè)數(shù)據(jù)時(shí),容易出現(xiàn)線程安全問題,需要某種方式來確保資源在某一時(shí)刻只被一個(gè)線程使用。需要讓線程同步,保證數(shù)據(jù)安全線程同步的實(shí)現(xiàn)方案: 同步代碼塊和同步方法,均需要使用synchronized關(guān)鍵字
同步代碼塊:public void makeWithdrawal(int amt) {
synchronized (acct) { }
}
同步方法:public synchronized void makeWithdrawal(int amt) { }
線程同步的好處:解決了線程安全問題
線程同步的缺點(diǎn):性能下降,可能會(huì)帶來死鎖
方式1:繼承Java.lang.Thread類,并覆蓋run() 方法。優(yōu)勢(shì):編寫簡(jiǎn)單;劣勢(shì):無法繼承其它父類
public class ThreadDemo1 { public static void main(String args[]) { MyThread1 t = new MyThread1(); t.start(); while (true) { System.out.println("兔子領(lǐng)先了,別驕傲"); } } } class MyThread1 extends Thread { public void run() { while (true) { System.out.println("烏龜領(lǐng)先了,加油"); } } }
方式2:實(shí)現(xiàn)Java.lang.Runnable接口,并實(shí)現(xiàn)run()方法。優(yōu)勢(shì):可繼承其它類,多線程可共享同一個(gè)Thread對(duì)象;劣勢(shì):編程方式稍微復(fù)雜,如需訪問當(dāng)前線程,需調(diào)用Thread.currentThread()方法
public class ThreadDemo2 { public static void main(String args[]) { MyThread2 mt = new MyThread2(); Thread t = new Thread(mt); t.start(); while (true) { System.out.println("兔子領(lǐng)先了,加油"); } } } class MyThread2 implements Runnable { public void run() { while (true) { System.out.println("烏龜超過了,再接再厲"); } } }
答:wait方法是線程通信的方法之一,必須用在 synchronized方法或者synchronized代碼塊中,否則會(huì)拋出異常,這就涉及到一個(gè)“鎖”的概念,而wait方法必須使用上鎖的對(duì)象來調(diào)用,從而持有該對(duì)象的鎖進(jìn)入線程等待狀態(tài),直到使用該上鎖的對(duì)象調(diào)用notify或者notifyAll方法來喚醒之前進(jìn)入等待的線程,以釋放持有的鎖。
答:線程是一個(gè)動(dòng)態(tài)執(zhí)行的過程,它有一個(gè)從產(chǎn)生到死亡的過程,共五種狀態(tài):
新建(new Thread)
當(dāng)創(chuàng)建Thread類的一個(gè)實(shí)例(對(duì)象)時(shí),此線程進(jìn)入新建狀態(tài)(未被啟動(dòng))
例如:Thread t1=new Thread();
就緒(runnable)
線程已經(jīng)被啟動(dòng),正在等待被分配給CPU時(shí)間片,也就是說此時(shí)線程正在就緒隊(duì)列中排隊(duì)等候得到CPU資源。例如:t1.start();
運(yùn)行(running)
線程獲得CPU資源正在執(zhí)行任務(wù)(run()方法),此時(shí)除非此線程自動(dòng)放棄CPU資源或者有優(yōu)先級(jí)更高的線程進(jìn)入,線程將一直運(yùn)行到結(jié)束。
死亡(dead)
當(dāng)線程執(zhí)行完畢或被其它線程殺死,線程就進(jìn)入死亡狀態(tài),這時(shí)線程不可能再進(jìn)入就緒狀態(tài)等待執(zhí)行。
自然終止:正常運(yùn)行run()方法后終止
異常終止:調(diào)用stop()方法讓一個(gè)線程終止運(yùn)行
堵塞(blocked)
由于某種原因?qū)е抡谶\(yùn)行的線程讓出CPU并暫停自己的執(zhí)行,即進(jìn)入堵塞狀態(tài)。
正在睡眠:用sleep(long t) 方法可使線程進(jìn)入睡眠方式。一個(gè)睡眠著的線程在指定的時(shí)間過去可進(jìn)入就緒狀態(tài)。
正在等待:調(diào)用wait()方法。(調(diào)用motify()方法回到就緒狀態(tài))
被另一個(gè)線程所阻塞:調(diào)用suspend()方法。(調(diào)用resume()方法恢復(fù))
A. | sleep() |
B. | Suspend() |
C. | wait() |
D. | yield() |
答案:D
分析:yield會(huì)是線程進(jìn)入就緒狀態(tài)
|
答:不能。雖然volatile提供了同步的機(jī)制,但是知識(shí)一種弱的同步機(jī)制,如需要強(qiáng)線程安全,還需要使用synchronized。
Java語言提供了一種稍弱的同步機(jī)制,即volatile變量,用來確保將變量的更新操作通知到其他線程。當(dāng)把變量聲明為volatile類型后,編譯器與運(yùn)行時(shí)都會(huì)注意到這個(gè)變量是共享的,因此不會(huì)將該變量上的操作與其他內(nèi)存操作一起重排序。volatile變量不會(huì)被緩存在寄存器或者對(duì)其他處理器不可見的地方,因此在讀取volatile類型的變量時(shí)總會(huì)返回最新寫入的值。
一、volatile的內(nèi)存語義是:
當(dāng)寫一個(gè)volatile變量時(shí),JMM會(huì)把該線程對(duì)應(yīng)的本地內(nèi)存中的共享變量值立即刷新到主內(nèi)存中。
當(dāng)讀一個(gè)volatile變量時(shí),JMM會(huì)把該線程對(duì)應(yīng)的本地內(nèi)存設(shè)置為無效,直接從主內(nèi)存中讀取共享變量。
二、volatile底層的實(shí)現(xiàn)機(jī)制
如果把加入volatile關(guān)鍵字的代碼和未加入volatile關(guān)鍵字的代碼都生成匯編代碼,會(huì)發(fā)現(xiàn)加入volatile關(guān)鍵字的代碼會(huì)多出一個(gè)lock前綴指令。
1 、重排序時(shí)不能把后面的指令重排序到內(nèi)存屏障之前的位置
2、使得本CPU的Cache寫入內(nèi)存
3、寫入動(dòng)作也會(huì)引起別的CPU或者別的內(nèi)核無效化其Cache,相當(dāng)于讓新寫入的值對(duì)別的線程可見。
(1) 繼承Thread類
public class java_thread extends Thread{ public static void main(String args[]) { new java_thread().run(); System.out.println("main thread run "); } public synchronized void run() { System.out.println("sub thread run "); } }
(2) 實(shí)現(xiàn)Runnable接口
public class java_thread implements Runnable{ public static void main(String args[]) { new Thread(new java_thread()).start(); System.out.println("main thread run "); } public void run() { System.out.println("sub thread run "); } }
在Executor框架下,利用Executors的靜態(tài)方法可以創(chuàng)建三種類型的常用線程池:
1)FixedThreadPool這個(gè)線程池可以創(chuàng)建固定線程數(shù)的線程池。
2)SingleThreadExecutor是使用單個(gè)worker線程的Executor。
3)CachedThreadPool是一個(gè)”無限“容量的線程池,它會(huì)根據(jù)需要?jiǎng)?chuàng)建新線程。
A. | sleep是線程類(Thread)的方法,wait是Object類的方法 |
B. | Sleep不釋放對(duì)象鎖,wait放棄對(duì)象鎖 |
C. | Sleep暫停線程、但監(jiān)控狀態(tài)任然保持,結(jié)束后會(huì)自動(dòng)恢復(fù) |
D. | Wait后進(jìn)入等待鎖定池,只針對(duì)此對(duì)象發(fā)出notify方法后獲取對(duì)象鎖進(jìn)入運(yùn)行狀態(tài)。 |
答案:D
分析:針對(duì)此對(duì)象的notify方法后獲取對(duì)象鎖并進(jìn)入就緒狀態(tài),而不是運(yùn)行狀態(tài)。另外針對(duì)此對(duì)象的notifyAll方法后也可能獲取對(duì)象鎖并進(jìn)入就緒狀態(tài),而不是運(yùn)行狀態(tài)
|
進(jìn)程是具有一定獨(dú)立功能的程序關(guān)于某個(gè)數(shù)據(jù)集合上的一次運(yùn)行活動(dòng),進(jìn)程是系統(tǒng)進(jìn)行資源分配和調(diào)度的一個(gè)獨(dú)立單位.
線程是進(jìn)程的一個(gè)實(shí)體,是CPU調(diào)度和分派的基本單位,它是比進(jìn)程更小的能獨(dú)立運(yùn)行的基本單位.線程自己基本上不擁有系統(tǒng)資源,只擁有一點(diǎn)在運(yùn)行中必不可少的資源(如程序計(jì)數(shù)器,一組寄存器和棧),但是它可與同屬一個(gè)進(jìn)程的其他的線程共享進(jìn)程所擁有的全部資源.
區(qū)別 | 進(jìn)程 | 線程 |
根本區(qū)別? | 作為資源分配的單位? | 調(diào)度和執(zhí)行的單位 |
開銷? | 每個(gè)進(jìn)程都有獨(dú)立的代碼和數(shù)據(jù)空間(進(jìn)程上下文),進(jìn)程間的切換會(huì)有較大的開銷。? | 線程可以看成時(shí)輕量級(jí)的進(jìn)程,同一類線程共享代碼和數(shù)據(jù)空間,每個(gè)線程有獨(dú)立的運(yùn)行棧和程序計(jì)數(shù)器(PC),線程切換的開銷小。? |
所處環(huán)境? | 系統(tǒng)在運(yùn)行的時(shí)候會(huì)為每個(gè)進(jìn)程分配不同的內(nèi)存區(qū)域? | 除了CPU之外,不會(huì)為線程分配內(nèi)存(線程所使用的資源是它所屬的進(jìn)程的資源),線程組只能共享資源? |
分配內(nèi)存? | 系統(tǒng)在運(yùn)行的時(shí)候會(huì)為每個(gè)進(jìn)程分配不同的內(nèi)存區(qū)域? | 除了CPU之外,不會(huì)為線程分配內(nèi)存(線程所使用的資源是它所屬的進(jìn)程的資源),線程組只能共享資源? |
包含關(guān)系? | 沒有線程的進(jìn)程是可以被看作單線程的,如果一個(gè)進(jìn)程內(nèi)擁有多個(gè)線程,則執(zhí)行過程不是一條線的,而是多條線(線程)共同完成的。? | 線程是進(jìn)程的一部分,所以線程有的時(shí)候被稱為是輕權(quán)進(jìn)程或者輕量級(jí)進(jìn)程。? |
A. | Lock |
B. | Synchronized |
C. | Volatile |
答案:C
|
答:用一個(gè)for循環(huán)創(chuàng)建線程對(duì)象,同時(shí)調(diào)用wait()方法,讓所有線程等待;直到最后一個(gè)線程也準(zhǔn)備就緒后,調(diào)用notifyAll(), 同時(shí)啟動(dòng)所有線程。
比如:給你n個(gè)賽車,讓他們都在起跑線上就緒后,同時(shí)出發(fā),Java多線程如何寫代碼?
思路是,來一輛賽車就加上一把鎖,并修改對(duì)應(yīng)的操作數(shù),如果沒有全部就緒就等待,并釋放鎖,直到最后一輛賽車到場(chǎng)后喚醒所有的賽車線程。代碼參考如下:
public class CarCompetion { // 參賽賽車的數(shù)量 protected final int totalCarNum = 10; // 當(dāng)前在起跑線的賽車數(shù)量 protected int nowCarNum = 0; }
public class Car implements Runnable{ private int carNum; private CarCompetion competion = null; public Car(int carNum, CarCompetion competion) { this.carNum = carNum; this.competion = competion; } @Override public void run() { synchronized (competion) { competion.nowCarNum++; while (competion.nowCarNum < competion.totalCarNum) { try { competion.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } competion.notifyAll(); } startCar(); } private void startCar() { System.out.println("Car num " + this.carNum + " start to run."); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Car num " + this.carNum + " get to the finish line."); } }
public static void main(String[] args) { CarCompetion carCompetion = new CarCompetion(); final ExecutorService carPool = Executors.newFixedThreadPool(carCompetion.totalCarNum); for (int i = 0; i < carCompetion.totalCarNum; i++) { carPool.execute(new Car(i, carCompetion)); }
答:1.如果數(shù)據(jù)將在線程間共享。例如正在寫的數(shù)據(jù)以后可能被另一個(gè)線程讀到,或者正在讀的數(shù)據(jù)可能已經(jīng)被另一個(gè)線程寫過了,那么這些數(shù)據(jù)就是共享數(shù)據(jù),必須進(jìn)行同步存取。
2.當(dāng)應(yīng)用程序在對(duì)象上調(diào)用了一個(gè)需要花費(fèi)很長(zhǎng)時(shí)間來執(zhí)行的方法,并且不希望讓程序等待方法的返回時(shí),就應(yīng)該使用異步編程,在很多情況下采用異步途徑往往更有效率。
3.舉個(gè)例子: 打電話是同步 發(fā)消息是異步
答:sleep是線程類(Thread)的方法;作用是導(dǎo)致此線程暫停執(zhí)行指定時(shí)間,給執(zhí)行機(jī)會(huì)給其他線程,但是監(jiān)控狀態(tài)依然保持,到時(shí)后會(huì)自動(dòng)恢復(fù);調(diào)用sleep()不會(huì)釋放對(duì)象鎖。
wait是Object類的方法;對(duì)此對(duì)象調(diào)用wait方法導(dǎo)致本線程放棄對(duì)象鎖,進(jìn)入等 待此對(duì)象的等待鎖定池。只有針對(duì)此對(duì)象發(fā)出notify方法(或notifyAll)后本線程才進(jìn)入對(duì)象鎖定池,準(zhǔn)備獲得對(duì)象鎖進(jìn)行運(yùn)行狀態(tài)。
A. | 由調(diào)度程序?yàn)檫M(jìn)程分配CPU |
B. | 建立一個(gè)進(jìn)程控制塊 |
C. | 為進(jìn)程分配內(nèi)存 |
D. | 為進(jìn)程分配文件描述符 |
答案:BC
|
A. | 針對(duì)計(jì)數(shù)器,可以使用原子加 |
B. | 只有一個(gè)生產(chǎn)者和一個(gè)消費(fèi)者,那么就可以做到免鎖訪問環(huán)形緩沖區(qū)(Ring Buffer) |
C. | RCU(Read-Copy-Update),新舊副本切換機(jī)制,對(duì)于舊副本可以采用延遲釋放的做法 |
D. | CAS(Compare-and-Swap),如無鎖棧,無鎖隊(duì)列等待 |
答案:D
分析:A 這方法雖然不太好,但是常見
B ProducerConsumerQueue就是這個(gè),到處都是
C linux kernel里面大量使用
D 本質(zhì)上其實(shí)就是樂觀鎖,操作起來很困難。。單生產(chǎn)者多消費(fèi)者或者多生產(chǎn)者單消費(fèi)者的情況下比較常見,也不容易遇到ABA問題。
|
答:① sleep()方法給其他線程運(yùn)行機(jī)會(huì)時(shí)不考慮線程的優(yōu)先級(jí),因此會(huì)給低優(yōu)先級(jí)的線程以運(yùn)行的機(jī)會(huì);yield()方法只會(huì)給相同優(yōu)先級(jí)或更高優(yōu)先級(jí)的線程以運(yùn)行的機(jī)會(huì);
② 線程執(zhí)行sleep()方法后轉(zhuǎn)入阻塞(blocked)狀態(tài),而執(zhí)行yield()方法后轉(zhuǎn)入就緒(ready)狀態(tài);
③ sleep()方法聲明拋出InterruptedException,而yield()方法沒有聲明任何異常;
④ sleep()方法比yield()方法(跟操作系統(tǒng)相關(guān))具有更好的可移植性。?
答:不能。其它線程只能訪問該對(duì)象的非同步方法,同步方法則不能進(jìn)入。?只有等待當(dāng)前線程執(zhí)行完畢釋放鎖資源之后,其他線程才有可能進(jìn)行執(zhí)行該同步方法!
延伸 對(duì)象鎖分為三種:共享資源、this、當(dāng)前類的字節(jié)碼文件對(duì)象
答:1. wait():使一個(gè)線程處于等待(阻塞)狀態(tài),并且釋放所持有的對(duì)象的鎖;
2. sleep():使一個(gè)正在運(yùn)行的線程處于睡眠狀態(tài),是一個(gè)靜態(tài)方法,調(diào)用此方法要捕捉InterruptedException 異常;
3. notify():喚醒一個(gè)處于等待狀態(tài)的線程,當(dāng)然在調(diào)用此方法的時(shí)候,并不能確切的喚醒某一個(gè)等待狀態(tài)的線程,而是由JVM確定喚醒哪個(gè)線程,而且與優(yōu)先級(jí)無關(guān);
4. notityAll():喚醒所有處入等待狀態(tài)的線程,注意并不是給所有喚醒線程一個(gè)對(duì)象的鎖,而是讓它們競(jìng)爭(zhēng);
5. JDK 1.5通過Lock接口提供了顯式(explicit)的鎖機(jī)制,增強(qiáng)了靈活性以及對(duì)線程的協(xié)調(diào)。Lock接口中定義了加鎖(lock())和解鎖(unlock())的方法,同時(shí)還提供了newCondition()方法來產(chǎn)生用于線程之間通信的Condition對(duì)象;
6. JDK 1.5還提供了信號(hào)量(semaphore)機(jī)制,信號(hào)量可以用來限制對(duì)某個(gè)共享資源進(jìn)行訪問的線程的數(shù)量。在對(duì)資源進(jìn)行訪問之前,線程必須得到信號(hào)量的許可(調(diào)用Semaphore對(duì)象的acquire()方法);在完成對(duì)資源的訪問后,線程必須向信號(hào)量歸還許可(調(diào)用Semaphore對(duì)象的release()方法)。
下面的例子演示了100個(gè)線程同時(shí)向一個(gè)銀行賬戶中存入1元錢,在沒有使用同步機(jī)制和使用同步機(jī)制情況下的執(zhí)行情況。
銀行賬戶類:
package com.bjsxt; /** * 銀行賬戶 * @author sxt * */ public class Account { private double balance; // 賬戶余額 /** * 存款 * @param money 存入金額 */ public void deposit(double money) { double newBalance = balance + money; try { Thread.sleep(10); // 模擬此業(yè)務(wù)需要一段處理時(shí)間 } catch(InterruptedException ex) { ex.printStackTrace(); } balance = newBalance; } /** * 獲得賬戶余額 */ public double getBalance() { return balance; } }
存錢線程類:
package com.bjsxt; /** * 存錢線程 * @author sxt李端陽 * */ public class AddMoneyThread implements Runnable { private Account account; // 存入賬戶 private double money; // 存入金額 public AddMoneyThread(Account account, double money) { this.account = account; this.money = money; } @Override public void run() { account.deposit(money); } }
測(cè)試類:
package com.bjsxt; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Test01 { public static void main(String[] args) { Account account = new Account(); ExecutorService service = Executors.newFixedThreadPool(100); for(int i = 1; i <= 100; i++) { service.execute(new AddMoneyThread(account, 1)); } service.shutdown(); while(!service.isTerminated()) {} System.out.println("賬戶余額: " + account.getBalance()); } }
在沒有同步的情況下,執(zhí)行結(jié)果通常是顯示賬戶余額在10元以下,出現(xiàn)這種狀況的原因是,當(dāng)一個(gè)線程A試圖存入1元的時(shí)候,另外一個(gè)線程B也能夠進(jìn)入存款的方法中,線程B讀取到的賬戶余額仍然是線程A存入1元錢之前的賬戶余額,因此也是在原來的余額0上面做了加1元的操作,同理線程C也會(huì)做類似的事情,所以最后100個(gè)線程執(zhí)行結(jié)束時(shí),本來期望賬戶余額為100元,但實(shí)際得到的通常在10元以下。解決這個(gè)問題的辦法就是同步,當(dāng)一個(gè)線程對(duì)銀行賬戶存錢時(shí),需要將此賬戶鎖定,待其操作完成后才允許其他的線程進(jìn)行操作,代碼有如下幾種調(diào)整方案:
1. 在銀行賬戶的存款(deposit)方法上同步(synchronized)關(guān)鍵字
package com.bjsxt; /** * 銀行賬戶 * @author SXT李端陽 */ public class Account { private double balance; // 賬戶余額 /** * 存款 * @param money 存入金額 */ public synchronized void deposit(double money) { double newBalance = balance + money; try { Thread.sleep(10); // 模擬此業(yè)務(wù)需要一段處理時(shí)間 } catch(InterruptedException ex) { ex.printStackTrace(); } balance = newBalance; } /** * 獲得賬戶余額 */ public double getBalance() { return balance; } }
2. 在線程調(diào)用存款方法時(shí)對(duì)銀行賬戶進(jìn)行同步
package com.bjsxt; /** * 存錢線程 * @author SXT * */ public class AddMoneyThread implements Runnable { private Account account; // 存入賬戶 private double money; // 存入金額 public AddMoneyThread(Account account, double money) { this.account = account; this.money = money; } @Override public void run() { synchronized (account) { account.deposit(money); } } }
3. 通過JDK 1.5顯示的鎖機(jī)制,為每個(gè)銀行賬戶創(chuàng)建一個(gè)鎖對(duì)象,在存款操作進(jìn)行加鎖和解鎖的操作
package com.bjsxt; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * 銀行賬戶 * * @author SXT李端陽 * */ public class Account { private Lock accountLock = new ReentrantLock(); private double balance; // 賬戶余額 /** * 存款 * * @param money * 存入金額 */ public void deposit(double money) { accountLock.lock(); try { double newBalance = balance + money; try { Thread.sleep(10); // 模擬此業(yè)務(wù)需要一段處理時(shí)間 } catch (InterruptedException ex) { ex.printStackTrace(); } balance = newBalance; } finally { accountLock.unlock(); } } /** * 獲得賬戶余額 */ public double getBalance() { return balance; } }
按照上述三種方式對(duì)代碼進(jìn)行修改后,重寫執(zhí)行測(cè)試代碼Test01,將看到最終的賬戶余額為100元。?
答:Java 5以前實(shí)現(xiàn)多線程有兩種實(shí)現(xiàn)方法:一種是繼承Thread類;另一種是實(shí)現(xiàn)Runnable接口。兩種方式都要通過重寫run()方法來定義線程的行為,推薦使用后者,因?yàn)镴ava中的繼承是單繼承,一個(gè)類有一個(gè)父類,如果繼承了Thread類就無法再繼承其他類了,同時(shí)也可以實(shí)現(xiàn)資源共享,顯然使用Runnable接口更為靈活。
補(bǔ)充:Java 5以后創(chuàng)建線程還有第三種方式:實(shí)現(xiàn)Callable接口,該接口中的call方法可以在線程執(zhí)行結(jié)束時(shí)產(chǎn)生一個(gè)返回值,代碼如下所示:
package com.bjsxt; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; class MyTask implements Callable<Integer> { private int upperBounds; public MyTask(int upperBounds) { this.upperBounds = upperBounds; } @Override public Integer call() throws Exception { int sum = 0; for(int i = 1; i <= upperBounds; i++) { sum += i; } return sum; } } public class Test { public static void main(String[] args) throws Exception { List<Future<Integer>> list = new ArrayList<>(); ExecutorService service = Executors.newFixedThreadPool(10); for(int i = 0; i < 10; i++) { list.add(service.submit(new MyTask((int) (Math.random() * 100)))); } int sum = 0; for(Future<Integer> future : list) { while(!future.isDone()) ; sum += future.get(); } System.out.println(sum); } }
答:synchronized關(guān)鍵字可以將對(duì)象或者方法標(biāo)記為同步,以實(shí)現(xiàn)對(duì)對(duì)象和方法的互斥訪問,可以用synchronized(對(duì)象) { … }定義同步代碼塊,或者在聲明方法時(shí)將synchronized作為方法的修飾符。在第60題的例子中已經(jīng)展示了synchronized關(guān)鍵字的用法。?
答:?jiǎn)?dòng)一個(gè)線程是調(diào)用start()方法,使線程所代表的虛擬處理機(jī)處于可運(yùn)行狀態(tài),這意味著它可以由JVM 調(diào)度并執(zhí)行,這并不意味著線程就會(huì)立即運(yùn)行。run()方法是線程啟動(dòng)后要進(jìn)行回調(diào)(callback)的方法。?
API解釋如下:
答:在面向?qū)ο缶幊讨校瑒?chuàng)建和銷毀對(duì)象是很費(fèi)時(shí)間的,因?yàn)閯?chuàng)建一個(gè)對(duì)象要獲取內(nèi)存資源或者其它更多資源。在Java中更是如此,虛擬機(jī)將試圖跟蹤每一個(gè)對(duì)象,以便能夠在對(duì)象銷毀后進(jìn)行垃圾回收。所以提高服務(wù)程序效率的一個(gè)手段就是盡可能減少創(chuàng)建和銷毀對(duì)象的次數(shù),特別是一些很耗資源的對(duì)象創(chuàng)建和銷毀,這就是"池化資源"技術(shù)產(chǎn)生的原因。線程池顧名思義就是事先創(chuàng)建若干個(gè)可執(zhí)行的線程放入一個(gè)池(容器)中,需要的時(shí)候從池中獲取線程不用自行創(chuàng)建,使用完畢不需要銷毀線程而是放回池中,從而減少創(chuàng)建和銷毀線程對(duì)象的開銷。
Java 5+中的Executor接口定義一個(gè)執(zhí)行線程的工具。它的子類型即線程池接口是ExecutorService。要配置一個(gè)線程池是比較復(fù)雜的,尤其是對(duì)于線程池的原理不是很清楚的情況下,因此在工具類Executors面提供了一些靜態(tài)工廠方法,生成一些常用的線程池,如下所示:
newSingleThreadExecutor:創(chuàng)建一個(gè)單線程的線程池。這個(gè)線程池只有一個(gè)線程在工作,也就是相當(dāng)于單線程串行執(zhí)行所有任務(wù)。如果這個(gè)唯一的線程因?yàn)楫惓=Y(jié)束,那么會(huì)有一個(gè)新的線程來替代它。此線程池保證所有任務(wù)的執(zhí)行順序按照任務(wù)的提交順序執(zhí)行。
newFixedThreadPool:創(chuàng)建固定大小的線程池。每次提交一個(gè)任務(wù)就創(chuàng)建一個(gè)線程,直到線程達(dá)到線程池的最大大小。線程池的大小一旦達(dá)到最大值就會(huì)保持不變,如果某個(gè)線程因?yàn)閳?zhí)行異常而結(jié)束,那么線程池會(huì)補(bǔ)充一個(gè)新線程。
newCachedThreadPool:創(chuàng)建一個(gè)可緩存的線程池。如果線程池的大小超過了處理任務(wù)所需要的線程,那么就會(huì)回收部分空閑(60秒不執(zhí)行任務(wù))的線程,當(dāng)任務(wù)數(shù)增加時(shí),此線程池又可以智能的添加新線程來處理任務(wù)。此線程池不會(huì)對(duì)線程池大小做限制,線程池大小完全依賴于操作系統(tǒng)(或者說JVM)能夠創(chuàng)建的最大線程大小。
newScheduledThreadPool:創(chuàng)建一個(gè)大小無限的線程池。此線程池支持定時(shí)以及周期性執(zhí)行任務(wù)的需求。
newSingleThreadExecutor:創(chuàng)建一個(gè)單線程的線程池。此線程池支持定時(shí)以及周期性執(zhí)行任務(wù)的需求。
有通過Executors工具類創(chuàng)建線程池并使用線程池執(zhí)行線程的代碼。如果希望在服務(wù)器上使用線程池,強(qiáng)烈建議使用newFixedThreadPool方法來創(chuàng)建線程池,這樣能獲得更好的性能。?
除去起始(new)狀態(tài)和結(jié)束(finished)狀態(tài),線程有三種狀態(tài),分別是:就緒(ready)、運(yùn)行(running)和阻塞(blocked)。其中就緒狀態(tài)代表線程具備了運(yùn)行的所有條件,只等待CPU調(diào)度(萬事俱備,只欠東風(fēng));處于運(yùn)行狀態(tài)的線程可能因?yàn)镃PU調(diào)度(時(shí)間片用完了)的原因回到就緒狀態(tài),也有可能因?yàn)檎{(diào)用了線程的yield方法回到就緒狀態(tài),此時(shí)線程不會(huì)釋放它占有的資源的鎖,坐等CPU以繼續(xù)執(zhí)行;運(yùn)行狀態(tài)的線程可能因?yàn)镮/O中斷、線程休眠、調(diào)用了對(duì)象的wait方法而進(jìn)入阻塞狀態(tài)(有的地方也稱之為等待狀態(tài));而進(jìn)入阻塞狀態(tài)的線程會(huì)因?yàn)樾菝呓Y(jié)束、調(diào)用了對(duì)象的notify方法或notifyAll方法或其他線程執(zhí)行結(jié)束而進(jìn)入就緒狀態(tài)。注意:調(diào)用wait方法會(huì)讓線程進(jìn)入等待池中等待被喚醒,notify方法或notifyAll方法會(huì)讓等待鎖中的線程從等待池進(jìn)入等鎖池,在沒有得到對(duì)象的鎖之前,線程仍然無法獲得CPU的調(diào)度和執(zhí)行。
答:Lock是Java 5以后引入的新的API,和關(guān)鍵字synchronized相比主要相同點(diǎn):Lock 能完成synchronized所實(shí)現(xiàn)的所有功能;主要不同點(diǎn):Lock 有比synchronized 更精確的線程語義和更好的性能。synchronized 會(huì)自動(dòng)釋放鎖,而Lock 一定要求程序員手工釋放,并且必須在finally 塊中釋放(這是釋放外部資源的最好的地方)。?
方式1:繼承Java.lang.Thread類,并覆蓋run() 方法。
優(yōu)勢(shì):編寫簡(jiǎn)單;
劣勢(shì):?jiǎn)卫^承的限制----無法繼承其它父類,同時(shí)不能實(shí)現(xiàn)資源共享。
package com.bjsxt; public class ThreadDemo1 { public static void main(String args[]) { MyThread1 t = new MyThread1(); t.start(); while (true) { System.out.println("兔子領(lǐng)先了,別驕傲"); } } } class MyThread1 extends Thread { public void run() { while (true) { System.out.println("烏龜領(lǐng)先了,加油"); } } }
方式2:實(shí)現(xiàn)Java.lang.Runnable接口,并實(shí)現(xiàn)run()方法。
優(yōu)勢(shì):可繼承其它類,多線程可共享同一個(gè)Thread對(duì)象;
劣勢(shì):編程方式稍微復(fù)雜,如需訪問當(dāng)前線程,需調(diào)用Thread.currentThread()方法
package com.bjsxt; public class ThreadDemo2 { public static void main(String args[]) { MyThread2 mt = new MyThread2(); Thread t = new Thread(mt); t.start(); while (true) { System.out.println("兔子領(lǐng)先了,加油"); } } } class MyThread2 implements Runnable { public void run() { while (true) { System.out.println("烏龜超過了,再接再厲"); } } }
兩種方法的區(qū)別
1) start方法:
用start方法來啟動(dòng)線程,真正實(shí)現(xiàn)了多線程運(yùn)行,這時(shí)無需等待run方法體代碼執(zhí)行完畢而直接繼續(xù)執(zhí)行下面的代碼。通過調(diào)用Thread類的start()方法來啟動(dòng)一個(gè)線程,這時(shí)此線程處于就緒(可運(yùn)行)狀態(tài),并沒有運(yùn)行,一旦得到cpu時(shí)間片,就開始執(zhí)行run()方法,這里方法run()稱為線程體,它包含了要執(zhí)行的這個(gè)線程的內(nèi)容,Run方法運(yùn)行結(jié)束,此線程隨即終止。
2) run():
run()方法只是類的一個(gè)普通方法而已,如果直接調(diào)用run方法,程序中依然只有主線程這一個(gè)線程,其程序執(zhí)行路徑還是只有一條,還是要順序執(zhí)行,還是要等待,run方法體執(zhí)行完畢后才可繼續(xù)執(zhí)行下面的代碼,這樣就沒有達(dá)到寫線程的目的。
總結(jié):調(diào)用start方法方可啟動(dòng)線程,而run方法只是thread的一個(gè)普通方法調(diào)用,還是在主線程里執(zhí)行。這兩個(gè)方法應(yīng)該都比較熟悉,把需要并行處理的代碼放在run()方法中,start()方法啟動(dòng)線程將自動(dòng)調(diào)用 run()方法,這是由jvm的內(nèi)存機(jī)制規(guī)定的。并且run()方法必須是public訪問權(quán)限,返回值類型為void。
兩種方式的比較 :
實(shí)際中往往采用實(shí)現(xiàn)Runable接口,一方面因?yàn)閖ava只支持單繼承,繼承了Thread類就無法再繼續(xù)繼承其它類,而且Runable接口只有一個(gè)run方法;另一方面通過結(jié)果可以看出實(shí)現(xiàn)Runable接口才是真正的多線程。
線程是一個(gè)動(dòng)態(tài)執(zhí)行的過程,它也有一個(gè)從產(chǎn)生到死亡的過程。
生命周期的五種狀態(tài)
新建(new Thread)
當(dāng)創(chuàng)建Thread類的一個(gè)實(shí)例(對(duì)象)時(shí),此線程進(jìn)入新建狀態(tài)(未被啟動(dòng))
例如:Thread t1=new Thread();
就緒(runnable)
線程已經(jīng)被啟動(dòng),正在等待被分配給CPU時(shí)間片,也就是說此時(shí)線程正在就緒隊(duì)列中排隊(duì)等候得到CPU資源。例如:t1.start();
運(yùn)行(running)
線程獲得CPU資源正在執(zhí)行任務(wù)(run()方法),此時(shí)除非此線程自動(dòng)放棄CPU資源或者有優(yōu)先級(jí)更高的線程進(jìn)入,線程將一直運(yùn)行到結(jié)束。
死亡(dead)
當(dāng)線程執(zhí)行完畢或被其它線程殺死,線程就進(jìn)入死亡狀態(tài),這時(shí)線程不可能再進(jìn)入就緒狀態(tài)等待執(zhí)行。
自然終止:正常運(yùn)行run()方法后終止
異常終止:調(diào)用stop()方法讓一個(gè)線程終止運(yùn)行
堵塞(blocked)
由于某種原因?qū)е抡谶\(yùn)行的線程讓出CPU并暫停自己的執(zhí)行,即進(jìn)入堵塞狀態(tài)。
正在睡眠:用sleep(long t) 方法可使線程進(jìn)入睡眠方式。一個(gè)睡眠著的線程在指定的時(shí)間過去可進(jìn)入就緒狀態(tài)。
正在等待:調(diào)用wait()方法。(調(diào)用motify()方法回到就緒狀態(tài))
被另一個(gè)線程所阻塞:調(diào)用suspend()方法。(調(diào)用resume()方法恢復(fù))
當(dāng)多個(gè)線程訪問同一個(gè)數(shù)據(jù)時(shí),容易出現(xiàn)線程安全問題,需要某種方式來確保資源在某一時(shí)刻只被一個(gè)線程使用。需要讓線程同步,保證數(shù)據(jù)安全
線程同步的實(shí)現(xiàn)方案:
1)同步代碼塊,使用synchronized關(guān)鍵字
同步代碼塊:
synchronized (同步鎖) {
授課代碼;
}
同步方法:
public synchronized void makeWithdrawal(int amt) { }
線程同步的好處:解決了線程安全問題
線程同步的缺點(diǎn):性能下降,可能會(huì)帶來死鎖
注意: 同步代碼塊,所使用的同步鎖可以是三種,
1、this 2、 共享資源 3、 字節(jié)碼文件對(duì)象
同步方法所使用的同步鎖,默認(rèn)的是this
答:Java中每個(gè)對(duì)象都有一個(gè)內(nèi)置鎖。
當(dāng)程序運(yùn)行到非靜態(tài)的synchronized同步方法上時(shí),自動(dòng)獲得與正在執(zhí)行代碼類的當(dāng)前實(shí)例(this實(shí)例)有關(guān)的鎖。獲得一個(gè)對(duì)象的鎖也稱為獲取鎖、鎖定對(duì)象、在對(duì)象上鎖定或在對(duì)象上同步。
當(dāng)程序運(yùn)行到synchronized同步方法或代碼塊時(shí)才該對(duì)象鎖才起作用。
一個(gè)對(duì)象只有一個(gè)鎖。所以,如果一個(gè)線程獲得該鎖,就沒有其他線程可以獲得鎖,直到第一個(gè)線程釋放(或返回)鎖。這也意味著任何其他線程都不能進(jìn)入該對(duì)象上的synchronized方法或代碼塊,直到該鎖被釋放。
釋放鎖是指持鎖線程退出了synchronized同步方法或代碼塊。
關(guān)于鎖和同步,有一下幾個(gè)要點(diǎn):
1)只能同步方法,而不能同步變量和類;
2)每個(gè)對(duì)象只有一個(gè)鎖;當(dāng)提到同步時(shí),應(yīng)該清楚在什么上同步?也就是說,在哪個(gè)對(duì)象上同步?
3)不必同步類中所有的方法,類可以同時(shí)擁有同步和非同步方法。
4)如果兩個(gè)線程要執(zhí)行一個(gè)類中的synchronized方法,并且兩個(gè)線程使用相同的實(shí)例來調(diào)用方法,那么一次只能有一個(gè)線程能夠執(zhí)行方法,另一個(gè)需要等待,直到鎖被釋放。也就是說:如果一個(gè)線程在對(duì)象上獲得一個(gè)鎖,就沒有任何其他線程可以進(jìn)入(該對(duì)象的)類中的任何一個(gè)同步方法。
5)如果線程擁有同步和非同步方法,則非同步方法可以被多個(gè)線程自由訪問而不受鎖的限制。
6)線程睡眠時(shí),它所持的任何鎖都不會(huì)釋放。
7)線程可以獲得多個(gè)鎖。比如,在一個(gè)對(duì)象的同步方法里面調(diào)用另外一個(gè)對(duì)象的同步方法,則獲取了兩個(gè)對(duì)象的同步鎖。
8)同步損害并發(fā)性,應(yīng)該盡可能縮小同步范圍。同步不但可以同步整個(gè)方法,還可以同步方法中一部分代碼塊。
9)在使用同步代碼塊時(shí)候,應(yīng)該指定在哪個(gè)對(duì)象上同步,也就是說要獲取哪個(gè)對(duì)象的鎖。
Java提供了3個(gè)方法解決線程之間的通信問題,均是java.lang.Object類的方法,都只能在同步方法或者同步代碼塊中使用,否則會(huì)拋出異常。
方法名 | 作 用 |
final void wait() | 表示線程一直等待,直到其它線程通知 |
void wait(long timeout) | 線程等待指定毫秒?yún)?shù)的時(shí)間 |
final void wait(long timeout,int nanos) | 線程等待指定毫秒、微妙的時(shí)間 |
final void notify() | 喚醒一個(gè)處于等待狀態(tài)的線程。注意的是在調(diào)用此方法的時(shí)候,并不能確切的喚醒某一個(gè)等待狀態(tài)的線程,而是由JVM確定喚醒哪個(gè)線程,而且不是按優(yōu)先級(jí)。 |
final void notifyAll() | 喚醒同一個(gè)對(duì)象上所有調(diào)用wait()方法的線程,注意并不是給所有喚醒線程一個(gè)對(duì)象的鎖,而是讓它們競(jìng)爭(zhēng) |
A. | BufferedWriter |
B. | FileInputStream |
C. | ObjectInputStream |
D. | InputStreamReader |
答案:D
分析:A:字符輸出的緩沖流
B:字節(jié)輸入流
C:對(duì)象輸入流
|
A. |
FileInputStream in=new FileInputStream("file.dat");
in.skip(9);
int c=in.read();
|
B. |
FileInputStream in=new FileInputStream("file.dat");
in.skip(10);
int c=in.read();
|
C. |
FileInputStream in=new FileInputStream("file.dat");
int c=in.read();
|
D. |
RandomAccessFile in=new RandomAccessFile("file.dat");
in.skip(7);
int c=in.readByte();
|
答案:A
分析: skip(long n)該方法中的n指的是要跳過的字節(jié)數(shù)
|
A. | new BufferedWriter(new FileWriter(“a.txt”)); |
B. | new BufferedReader (new FileInputStream(“a.dat”)); |
C. | new GZIPOutputStream(new FileOutputStream(“a.zip”)); |
D. | new ObjectInputStream(new FileInputStream(“a.dat”)); |
答案:B
分析:BufferedReader類的參數(shù)只能是Reader類型的,不能是InputStream類型。
|
A. | BufferedWriter |
B. | FileInputStream |
C. | ObjectInputStream |
D. | InputStreamReader |
答案:D
以InputStream(輸入流)/OutputStream(輸出流)為后綴的是字節(jié)流;
以Reader(輸入流)/Writer(輸出流)為后綴的是字符流。
|
A. | Java.io.FileOutputStream |
B. | java.ByteArrayOutputStream |
C. | java.io.BufferedOutputStream |
D. | java,.io.DataOutputStream |
答案:B
分析: ACD都是io到文件
|
public class test { public static void main(String[] args) { String str = "bjsxt"; writeFile(str); } public static void writeFile(String str) { File file = new File("c:/test.txt"); PrintStream ps = null; try { OutputStream fos = new FileOutputStream(file); ps = new PrintStream(fos); ps.print(str); } catch (FileNotFoundException e) { e.printStackTrace(); } finally { ps.close(); } } }
A. | BufferedWriter |
B. | FileInputStream |
C. | ObjectInputStream |
D. | InputStreamReader |
答案:D
|
答:序列化就是一種用來處理對(duì)象流的機(jī)制,所謂對(duì)象流也就是將對(duì)象的內(nèi)容進(jìn)行流化。可以對(duì)流化后的對(duì)象進(jìn)行讀寫操作,也可將流化后的對(duì)象傳輸于網(wǎng)絡(luò)之間。序列化是為了解決對(duì)象流讀寫操作時(shí)可能引發(fā)的問題(如果不進(jìn)行序列化可能會(huì)存在數(shù)據(jù)亂序的問題)。
要實(shí)現(xiàn)序列化,需要讓一個(gè)類實(shí)現(xiàn)Serializable接口,該接口是一個(gè)標(biāo)識(shí)性接口,標(biāo)注該類對(duì)象是可被序列化的,然后使用一個(gè)輸出流來構(gòu)造一個(gè)對(duì)象輸出流并通過writeObject(Object obj)方法就可以將實(shí)現(xiàn)對(duì)象寫出(即保存其狀態(tài));如果需要反序列化則可以用一個(gè)輸入流建立對(duì)象輸入流,然后通過readObject方法從流中讀取對(duì)象。序列化除了能夠?qū)崿F(xiàn)對(duì)象的持久化之外,還能夠用于對(duì)象的深度克?。▍⒁奐ava面試題集1-29題)?
答:兩種流分別是字節(jié)流,字符流。
字節(jié)流繼承于InputStream、OutputStream,字符流繼承于Reader、Writer。在java.io 包中還有許多其他的流,主要是為了提高性能和使用方便。
補(bǔ)充:關(guān)于Java的IO需要注意的有兩點(diǎn):一是兩種對(duì)稱性(輸入和輸出的對(duì)稱性,字節(jié)和字符的對(duì)稱性);二是兩種設(shè)計(jì)模式(適配器模式和裝潢模式)。另外Java中的流不同于C#的是它只有一個(gè)維度一個(gè)方向。
補(bǔ)充:下面用IO和NIO兩種方式實(shí)現(xiàn)文件拷貝,這個(gè)題目在面試的時(shí)候是經(jīng)常被問到的。
package com.bjsxt; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; public class MyUtil { private MyUtil() { throw new AssertionError(); } public static void fileCopy(String source, String target) throws IOException { try (InputStream in = new FileInputStream(source)) { try (OutputStream out = new FileOutputStream(target)) { byte[] buffer = new byte[4096]; int bytesToRead; while((bytesToRead = in.read(buffer)) != -1) { out.write(buffer, 0, bytesToRead); } } } } public static void fileCopyNIO(String source, String target) throws IOException { try (FileInputStream in = new FileInputStream(source)) { try (FileOutputStream out = new FileOutputStream(target)) { FileChannel inChannel = in.getChannel(); FileChannel outChannel = out.getChannel(); ByteBuffer buffer = ByteBuffer.allocate(4096); while(inChannel.read(buffer) != -1) { buffer.flip(); outChannel.write(buffer); buffer.clear(); } } } } }
注意:上面用到Java 7的TWR,使用TWR后可以不用在finally中釋放外部資源 ,從而讓代碼更加優(yōu)雅。
答:代碼如下:
package com.bjsxt; import java.io.BufferedReader; import java.io.FileReader; public class Account { // 工具類中的方法都是靜態(tài)方式訪問的因此將構(gòu)造器私有不允許創(chuàng)建對(duì)象(絕對(duì)好習(xí)慣) private Account() { throw new AssertionError(); } /** * 統(tǒng)計(jì)給定文件中給定字符串的出現(xiàn)次數(shù) * @param filename 文件名 * @param word 字符串 * @return 字符串在文件中出現(xiàn)的次數(shù) */ public static int countWordInFile(String filename, String word) { int counter = 0; try (FileReader fr = new FileReader(filename)) { try (BufferedReader br = new BufferedReader(fr)) { String line = null; while ((line = br.readLine()) != null) { int index = -1; while (line.length() >= word.length() && (index = line.indexOf(word)) >= 0) { counter++; line = line.substring(index + word.length()); } } } } catch (Exception ex) { ex.printStackTrace(); } return counter; } }
首先,你要明白什么是“流”。直觀地講,流就像管道一樣,在程序和文件之間,輸入輸出的方向是針對(duì)程序而言,向程序中讀入東西,就是輸入流,從程序中向外讀東西,就是輸出流。
輸入流是得到數(shù)據(jù),輸出流是輸出數(shù)據(jù),而節(jié)點(diǎn)流,處理流是流的另一種劃分,按照功能不同進(jìn)行的劃分。節(jié)點(diǎn)流,可以從或向一個(gè)特定的地方(節(jié)點(diǎn))讀寫數(shù)據(jù)。處理流是對(duì)一個(gè)已存在的流的連接和封裝,通過所封裝的流的功能調(diào)用實(shí)現(xiàn)數(shù)據(jù)讀寫。如BufferedReader。處理流的構(gòu)造方法總是要帶一個(gè)其他的流對(duì)象做參數(shù)。一個(gè)流對(duì)象經(jīng)過其他流的多次包裝,稱為流的鏈接。
字符流和字節(jié)流是流的一種劃分,按處理照流的數(shù)據(jù)單位進(jìn)行的劃分。兩類都分為輸入和輸出操作。在字節(jié)流中輸出數(shù)據(jù)主要是使用OutputStream完成,輸入使的是InputStream,在字符流中輸出主要是使用Writer類完成,輸入流主要使用Reader類完成。這四個(gè)都是抽象類。
字符流處理的單元為2個(gè)字節(jié)的Unicode字符,分別操作字符、字符數(shù)組或字符串,而字節(jié)流處理單元為1個(gè)字節(jié),操作字節(jié)和字節(jié)數(shù)組。字節(jié)流是最基本的,所有的InputStrem和OutputStream的子類都是,主要用在處理二進(jìn)制數(shù)據(jù),它是按字節(jié)來處理的 但實(shí)際中很多的數(shù)據(jù)是文本,又提出了字符流的概念,它是按虛擬機(jī)的編碼來處理,也就是要進(jìn)行字符集的轉(zhuǎn)化 這兩個(gè)之間通過 InputStreamReader,OutputStreamWriter來關(guān)聯(lián),實(shí)際上是通過byte[]和String來關(guān)聯(lián)的。
FileInputStream 從文件系統(tǒng)中的某個(gè)文件中獲得輸入字節(jié)。
FileOutputStream 從程序當(dāng)中的數(shù)據(jù),寫入到指定文件。
ObjectInputStream 對(duì)以前使用 ObjectOutputStream 寫入的基本數(shù)據(jù)和對(duì)象進(jìn)行反序列化。 ObjectOutputStream 和ObjectInputStream 分別與FileOutputStream 和 FileInputStream 一起使用時(shí),可以為應(yīng)用程序提供對(duì)對(duì)象圖形的持久存儲(chǔ)。ObjectInputStream 用于恢復(fù)那些以前序列化的對(duì)象。其他用途包括使用套接字流在主機(jī)之間傳遞對(duì)象,或者用于編組和解組遠(yuǎn)程通信系統(tǒng)中的實(shí)參和形參。
ByteArrayInputStream 包含一個(gè)內(nèi)部緩沖區(qū),該緩沖區(qū)包含從流中讀取的字節(jié)。內(nèi)部計(jì)數(shù)器跟蹤 read 方法要提供的下一個(gè)字節(jié)。
FilterInputStream 包含其他一些輸入流,它將這些流用作其基本數(shù)據(jù)源,它可以直接傳輸數(shù)據(jù)或提供一些額外的功能。FilterInputStream 類本身只是簡(jiǎn)單地重寫那些將所有請(qǐng)求傳遞給所包含輸入流的 InputStream 的所有方法。FilterInputStream 的子類可進(jìn)一步重寫這些方法中的一些方法,并且還可以提供一些額外的方法和字段。
StringBufferInputStream此類允許應(yīng)用程序創(chuàng)建輸入流,在該流中讀取的字節(jié)由字符串內(nèi)容提供。應(yīng)用程序還可以使用ByteArrayInputStream 從 byte 數(shù)組中讀取字節(jié)。 只有字符串中每個(gè)字符的低八位可以由此類使用。
ByteArrayOutputStream此類實(shí)現(xiàn)了一個(gè)輸出流,其中的數(shù)據(jù)被寫入一個(gè) byte 數(shù)組。緩沖區(qū)會(huì)隨著數(shù)據(jù)的不斷寫入而自動(dòng)增長(zhǎng)。可使用 toByteArray() 和 toString() 獲取數(shù)據(jù)。
FileOutputStream文件輸出流是用于將數(shù)據(jù)寫入 File 或FileDescriptor 的輸出流。文件是否可用或能否可以被創(chuàng)建取決于基礎(chǔ)平臺(tái)。特別是某些平臺(tái)一次只允許一個(gè) FileOutputStream(或其他文件寫入對(duì)象)打開文件進(jìn)行寫入。在這種情況下,如果所涉及的文件已經(jīng)打開,則此類中的構(gòu)造方法將失敗。
FilterOutputStream類是過濾輸出流的所有類的超類。這些流位于已存在的輸出流(基礎(chǔ) 輸出流)之上,它們將已存在的輸出流作為其基本數(shù)據(jù)接收器,但可能直接傳輸數(shù)據(jù)或提供一些額外的功能。 FilterOutputStream 類本身只是簡(jiǎn)單地重寫那些將所有請(qǐng)求傳遞給所包含輸出流的 OutputStream 的所有方法。FilterOutputStream 的子類可進(jìn)一步地重寫這些方法中的一些方法,并且還可以提供一些額外的方法和字段。
ObjectOutputStream 將 Java 對(duì)象的基本數(shù)據(jù)類型和圖形寫入 OutputStream。可以使用 ObjectInputStream 讀?。ㄖ貥?gòu))對(duì)象。通過在流中使用文件可以實(shí)現(xiàn)對(duì)象的持久存儲(chǔ)。如果流是網(wǎng)絡(luò)套接字流,則可以在另一臺(tái)主機(jī)上或另一個(gè)進(jìn)程中重構(gòu)對(duì)象。
PipedOutputStream可以將管道輸出流連接到管道輸入流來創(chuàng)建通信管道。管道輸出流是管道的發(fā)送端。通常,數(shù)據(jù)由某個(gè)線程寫入 PipedOutputStream 對(duì)象,并由其他線程從連接的 PipedInputStream 讀取。不建議對(duì)這兩個(gè)對(duì)象嘗試使用單個(gè)線程,因?yàn)檫@樣可能會(huì)造成該線程死鎖。如果某個(gè)線程正從連接的管道輸入流中讀取數(shù)據(jù)字節(jié),但該線程不再處于活動(dòng)狀態(tài),則該管道被視為處于毀壞狀態(tài)。
不帶緩沖的流的工作原理:
它讀取到一個(gè)字節(jié)/字符,就向用戶指定的路徑寫出去,讀一個(gè)寫一個(gè),所以就慢了。
帶緩沖的流的工作原理:
讀取到一個(gè)字節(jié)/字符,先不輸出,等湊足了緩沖的最大容量后一次性寫出去,從而提高了工作效率
優(yōu)點(diǎn):減少對(duì)硬盤的讀取次數(shù),降低對(duì)硬盤的損耗。
想把一個(gè)對(duì)象寫在硬盤上或者網(wǎng)絡(luò)上,對(duì)其進(jìn)行序列化,把他序列化成為一個(gè)字節(jié)流。
實(shí)現(xiàn)和注意事項(xiàng):
1)實(shí)現(xiàn)接口Serializable Serializable接口中沒有任何的方法,實(shí)現(xiàn)該接口的類不需要實(shí)現(xiàn)額外的方法。
2)如果對(duì)象中的某個(gè)屬性是對(duì)象類型,必須也實(shí)現(xiàn)Serializable接口才可以,序列化對(duì)靜態(tài)變量無效
3)如果不希望某個(gè)屬性參與序列化,不是將其static,而是transient串行化保存的只是變量的值,對(duì)于變量的任何修飾符,都不能保存序列化版本不兼容
(結(jié)合遞歸)
package com.bjsxt; import java.io.*; /** * CopyDocJob定義了實(shí)際執(zhí)行的任務(wù),即 * 從源目錄拷貝文件到目標(biāo)目錄 */ public class CopyDir2 { public static void main(String[] args) { try { copyDirectiory("d:/301sxt","d:/301sxt2"); } catch (IOException e) { e.printStackTrace(); } } /** * 復(fù)制單個(gè)文件 * @param sourceFile 源文件 * @param targetFile 目標(biāo)文件 * @throws IOException */ private static void copyFile(File sourceFile, File targetFile) throws IOException { BufferedInputStream inBuff = null; BufferedOutputStream outBuff = null; try { // 新建文件輸入流 inBuff = new BufferedInputStream(new FileInputStream(sourceFile)); // 新建文件輸出流 outBuff = new BufferedOutputStream(new FileOutputStream(targetFile)); // 緩沖數(shù)組 byte[] b = new byte[1024 * 5]; int len; while ((len = inBuff.read(b)) != -1) { outBuff.write(b, 0, len); } // 刷新此緩沖的輸出流 outBuff.flush(); } finally { // 關(guān)閉流 if (inBuff != null) inBuff.close(); if (outBuff != null) outBuff.close(); } } /** * 復(fù)制目錄 * @param sourceDir 源目錄 * @param targetDir 目標(biāo)目錄 * @throws IOException */ private static void copyDirectiory(String sourceDir, String targetDir) throws IOException { // 檢查源目錄 File fSourceDir = new File(sourceDir); if(!fSourceDir.exists() || !fSourceDir.isDirectory()){ return; } //檢查目標(biāo)目錄,如不存在則創(chuàng)建 File fTargetDir = new File(targetDir); if(!fTargetDir.exists()){ fTargetDir.mkdirs(); } // 遍歷源目錄下的文件或目錄 File[] file = fSourceDir.listFiles(); for (int i = 0; i < file.length; i++) { if (file[i].isFile()) { // 源文件 File sourceFile = file[i]; // 目標(biāo)文件 File targetFile = new File(fTargetDir, file[i].getName()); copyFile(sourceFile, targetFile); } //遞歸復(fù)制子目錄 if (file[i].isDirectory()) { // 準(zhǔn)備復(fù)制的源文件夾 String subSourceDir = sourceDir + File.separator + file[i].getName(); // 準(zhǔn)備復(fù)制的目標(biāo)文件夾 String subTargetDir = targetDir + File.separator + file[i].getName(); // 復(fù)制子目錄 copyDirectiory(subSourceDir, subTargetDir); } } } }
Java BIO: 同步并阻塞,服務(wù)器實(shí)現(xiàn)模式為一個(gè)連接一個(gè)線程,即客戶端有連接請(qǐng)求時(shí)服務(wù)器端就需要啟動(dòng)一個(gè)線程進(jìn)行處理,如果這個(gè)連接不做任何事情會(huì)造成不必要的線程開銷,當(dāng)然可以通過線程池機(jī)制改善。
Java NIO: 同步非阻塞,服務(wù)器實(shí)現(xiàn)模式為一個(gè)請(qǐng)求一個(gè)線程,即客戶端發(fā)送的連接請(qǐng)求都會(huì)注冊(cè)到多路復(fù)用器上,多路復(fù)用器輪詢到連接有I/O請(qǐng)求時(shí)才啟動(dòng)一個(gè)線程進(jìn)行處理。
Java AIO: 異步非阻塞,服務(wù)器實(shí)現(xiàn)模式為一個(gè)有效請(qǐng)求一個(gè)線程,客戶端的I/O請(qǐng)求都是由OS先完成了再通知服務(wù)器應(yīng)用去啟動(dòng)線程進(jìn)行處理。
NIO比BIO的改善之處是把一些無效的連接擋在了啟動(dòng)線程之前,減少了這部分資源的浪費(fèi)(因?yàn)槲覀兌贾烂縿?chuàng)建一個(gè)線程,就要為這個(gè)線程分配一定的內(nèi)存空間)
AIO比NIO的進(jìn)一步改善之處是將一些暫時(shí)可能無效的請(qǐng)求擋在了啟動(dòng)線程之前,比如在NIO的處理方式中,當(dāng)一個(gè)請(qǐng)求來的話,開啟線程進(jìn)行處理,但這個(gè)請(qǐng)求所需要的資源還沒有就緒,此時(shí)必須等待后端的應(yīng)用資源,這時(shí)線程就被阻塞了。
適用場(chǎng)景分析:
BIO方式適用于連接數(shù)目比較小且固定的架構(gòu),這種方式對(duì)服務(wù)器資源要求比較高,并發(fā)局限于應(yīng)用中,JDK1.4以前的唯一選擇,但程序直觀簡(jiǎn)單易理解,如之前在Apache中使用。
NIO方式適用于連接數(shù)目多且連接比較短(輕操作)的架構(gòu),比如聊天服務(wù)器,并發(fā)局限于應(yīng)用中,編程比較復(fù)雜,JDK1.4開始支持,如在 Nginx,Netty中使用。
AIO方式使用于連接數(shù)目多且連接比較長(zhǎng)(重操作)的架構(gòu),比如相冊(cè)服務(wù)器,充分調(diào)用OS參與并發(fā)操作,編程比較復(fù)雜,JDK7開始支持,在成長(zhǎng)中,Netty曾經(jīng)使用過,后來放棄。
網(wǎng)絡(luò)編程:
1)IP地址
用來標(biāo)志網(wǎng)絡(luò)中的一個(gè)通信實(shí)體的地址。通信實(shí)體可以是計(jì)算機(jī),路由器等。
2)IP地址分類
IPV4:32位地址,以點(diǎn)分十進(jìn)制表示,如192.168.0.1
IPV6:128位(16個(gè)字節(jié))寫成8個(gè)16位的無符號(hào)整數(shù),每個(gè)整數(shù)用四個(gè)十六進(jìn)制位表示,數(shù)之間用冒號(hào)(:)分開,如:3ffe:3201:1401:1280:c8ff:fe4d:db39:1984
3)特殊的IP地址
127.0.0.1 本機(jī)地址
192.168.0.0--192.168.255.255私有地址,屬于非注冊(cè)地址,專門為組織機(jī)構(gòu)內(nèi)部使用。
4)端口:port
IP地址用來標(biāo)志一臺(tái)計(jì)算機(jī),但是一臺(tái)計(jì)算機(jī)上可能提供多種應(yīng)用程序,使用端口來區(qū)分這些應(yīng)用程序。 端口是虛擬的概念,并不是說在主機(jī)上真的有若干個(gè)端口。通過端口,可以在一個(gè)主機(jī)上運(yùn)行多個(gè)網(wǎng)絡(luò)應(yīng)用程序。 端口范圍0---65535,16位整數(shù)
5)端口分類
公認(rèn)端口 0—1023 比如80端口分配給WWW,21端口分配給FTP,22端口分配給SSH,23端口分配給telnet,25端口分配給smtp
注冊(cè)端口 1024—49151 分配給用戶進(jìn)程或應(yīng)用程序
動(dòng)態(tài)/私有端口 49152--65535
6)理解IP和端口的關(guān)系
IP地址好比每個(gè)人的地址(門牌號(hào)),端口好比是房間號(hào)。必須同時(shí)指定IP地址和端口號(hào)才能夠正確的發(fā)送數(shù)據(jù)
IP地址好比為電話號(hào)碼,而端口號(hào)就好比為分機(jī)號(hào)。
OSI(Open System Interconnection),開放式系統(tǒng)互聯(lián)參考模型 。是一個(gè)邏輯上的定義,一個(gè)規(guī)范,它把網(wǎng)絡(luò)協(xié)議從邏輯上分為了7層。每一層都有相關(guān)、相對(duì)應(yīng)的物理設(shè)備,比如常規(guī)的路由器是三層交換設(shè)備,常規(guī)的交換機(jī)是二層交換設(shè)備。OSI七層模型是一種框架性的設(shè)計(jì)方法,建立七層模型的主要目的是為解決異種網(wǎng)絡(luò)互連時(shí)所遇到的兼容性問題,其最主要的功能就是幫助不同類型的主機(jī)實(shí)現(xiàn)數(shù)據(jù)傳輸。它的最大優(yōu)點(diǎn)是將服務(wù)、接口和協(xié)議這三個(gè)概念明確地區(qū)分開來,通過七個(gè)層次化的結(jié)構(gòu)模型使不同的系統(tǒng)不同的網(wǎng)絡(luò)之間實(shí)現(xiàn)可靠的通訊。
TCP/IP協(xié)議是Internet最基本的協(xié)議、Internet國(guó)際互聯(lián)網(wǎng)絡(luò)的基礎(chǔ),主要由網(wǎng)絡(luò)層的IP協(xié)議和傳輸層的TCP協(xié)議組成。TCP/IP 定義了電子設(shè)備如何連入因特網(wǎng),以及數(shù)據(jù)如何在它們之間傳輸?shù)臉?biāo)準(zhǔn)。協(xié)議采用了4層的層級(jí)結(jié)構(gòu),每一層都呼叫它的下一層所提供的協(xié)議來完成自己的需求。
ISO制定的OSI參考模型的過于龐大、復(fù)雜招致了許多批評(píng)。伴隨著互聯(lián)網(wǎng)的流行,其本身所采用的TCP/IP協(xié)議棧獲得了更為廣泛的應(yīng)用和認(rèn)可。在TCP/IP參考模型中,去掉了OSI參考模型中的會(huì)話層和表示層(這兩層的功能被合并到應(yīng)用層實(shí)現(xiàn))。同時(shí)將OSI參考模型中的數(shù)據(jù)鏈路層和物理層合并為主機(jī)到網(wǎng)絡(luò)層。
TCP和UDP是TCP/IP協(xié)議棧中傳輸層的兩個(gè)協(xié)議,它們使用IP路由功能把數(shù)據(jù)包發(fā)送到目的地,從而為應(yīng)用程序及應(yīng)用層協(xié)議(包括:HTTP、SMTP、SNMP、FTP和Telnet)提供網(wǎng)絡(luò)服務(wù)。
TCP的server和client之間通信就好比兩個(gè)人打電話,需要互相知道對(duì)方的電話號(hào)碼,然后開始對(duì)話。所以在兩者的連接過程中間需要指定端口和地址。
UDP的server和client之間的通信就像兩個(gè)人互相發(fā)信。我只需要知道對(duì)方的地址,然后就發(fā)信過去。對(duì)方是否收到我不知道,也不需要專門對(duì)口令似的來建立連接。具體區(qū)別如下:
1)TCP是面向連接的傳輸。UDP是無連接的傳輸
2)TCP有流量控制、擁塞控制,檢驗(yàn)數(shù)據(jù)數(shù)據(jù)按序到達(dá),而UDP則相反。
3)TCP的路由選擇只發(fā)生在建立連接的時(shí)候,而UDP的每個(gè)報(bào)文都要進(jìn)行路由選擇
4)TCP是可靠性傳輸,他的可靠性是由超時(shí)重發(fā)機(jī)制實(shí)現(xiàn)的,而UDP則是不可靠傳輸
5)UDP因?yàn)樯倭撕芏嗫刂菩畔ⅲ詡鬏斔俣缺萒CP速度快
6)TCP適合用于傳輸大量數(shù)據(jù),UDP適合用于傳輸小量數(shù)據(jù)
Socket編程的定義如下:
所謂socket通常也稱作"套接字",用于描述IP地址和端口,是一個(gè)通信鏈的句柄。應(yīng)用程序通常通過"套接字"向網(wǎng)絡(luò)發(fā)出請(qǐng)求或者應(yīng)答網(wǎng)絡(luò)請(qǐng)求。
我們開發(fā)的網(wǎng)絡(luò)應(yīng)用程序位于應(yīng)用層,TCP和UDP屬于傳輸層協(xié)議,在應(yīng)用層如何使用傳輸層的服務(wù)呢?在應(yīng)用層和傳輸層之間,則是使用套接字來進(jìn)行分離。
套接字就像是傳輸層為應(yīng)用層開的一個(gè)小口,應(yīng)用程序通過這個(gè)小口向遠(yuǎn)程發(fā)送數(shù)據(jù),或者接收遠(yuǎn)程發(fā)來的數(shù)據(jù);而這個(gè)小口以內(nèi),也就是數(shù)據(jù)進(jìn)入這個(gè)口之后,或者數(shù)據(jù)從這個(gè)口出來之前,是不知道也不需要知道的,也不會(huì)關(guān)心它如何傳輸,這屬于網(wǎng)絡(luò)其它層次的工作。
Socket實(shí)際是傳輸層供給應(yīng)用層的編程接口。傳輸層則在網(wǎng)絡(luò)層的基礎(chǔ)上提供進(jìn)程到進(jìn)程問的邏輯通道,而應(yīng)用層的進(jìn)程則利用傳輸層向另一臺(tái)主機(jī)的某一進(jìn)程通信。Socket就是應(yīng)用層與傳輸層之間的橋梁
使用Socket編程可以開發(fā)客戶機(jī)和服務(wù)器應(yīng)用程序,可以在本地網(wǎng)絡(luò)上進(jìn)行通信,也可通過Internet在全球范圍內(nèi)通信。
生活案例1如果你想寫封郵件發(fā)給遠(yuǎn)方的朋友,如何寫信、將信打包,屬于應(yīng)用層。信怎么寫,怎么打包完全由我們做主;而當(dāng)我們將信投入郵筒時(shí),郵筒的那個(gè)口就是套接字,在進(jìn)入套接字之后,就是傳輸層、網(wǎng)絡(luò)層等(郵局、公路交管或者航線等)其它層次的工作了。我們從來不會(huì)去關(guān)心信是如何從西安發(fā)往北京的,我們只知道寫好了投入郵筒就OK了。
生活案例2:可以把Socket比作是一個(gè)港口碼頭,應(yīng)用程序只要將數(shù)據(jù)交給Socket,就算完成了數(shù)據(jù)的發(fā)送,具體細(xì)節(jié)由Socket來完成,細(xì)節(jié)不必了解。同理,對(duì)于接收方,應(yīng)用程序也要?jiǎng)?chuàng)建一個(gè)碼頭,等待數(shù)據(jù)的到達(dá),并獲取數(shù)據(jù)。
Java分別為TCP和UDP 兩種通信協(xié)議提供了相應(yīng)的Socket編程類,這些類存放在java.net包中。與TCP對(duì)應(yīng)的是服務(wù)器的ServerSocket和客戶端的Socket,與UDP對(duì)應(yīng)的是DatagramSocket。
基于TCP創(chuàng)建的套接字可以叫做流套接字,服務(wù)器端相當(dāng)于一個(gè)監(jiān)聽器,用來監(jiān)聽端口。?服務(wù)器與客服端之間的通訊都是輸入輸出流來實(shí)現(xiàn)的?;赨DP的套接字就是數(shù)據(jù)報(bào)套接字,?? 兩個(gè)都要先構(gòu)造好相應(yīng)的數(shù)據(jù)包。
基于TCP協(xié)議的Socket編程的主要步驟
服務(wù)器端(server):
1. 構(gòu)建一個(gè)ServerSocket實(shí)例,指定本地的端口。這個(gè)socket就是用來監(jiān)聽指定端口的連接請(qǐng)求的。
2. 重復(fù)如下幾個(gè)步驟:
a. 調(diào)用socket的accept()方法來獲得下面客戶端的連接請(qǐng)求。通過accept()方法返回的socket實(shí)例,建立了一個(gè)和客戶端的新連接。
b. 通過這個(gè)返回的socket實(shí)例獲取InputStream和OutputStream,可以通過這兩個(gè)stream來分別讀和寫數(shù)據(jù)。
c. 結(jié)束的時(shí)候調(diào)用socket實(shí)例的close()方法關(guān)閉socket連接。
客戶端(client):
1.構(gòu)建Socket實(shí)例,通過指定的遠(yuǎn)程服務(wù)器地址和端口來建立連接。
2.通過Socket實(shí)例包含的InputStream和OutputStream來進(jìn)行數(shù)據(jù)的讀寫。
3.操作結(jié)束后調(diào)用socket實(shí)例的close方法,關(guān)閉。
UDP
服務(wù)器端(server):
1. 構(gòu)造DatagramSocket實(shí)例,指定本地端口。
2. 通過DatagramSocket實(shí)例的receive方法接收DatagramPacket.DatagramPacket中間就包含了通信的內(nèi)容。
3. 通過DatagramSocket的send和receive方法來收和發(fā)DatagramPacket.
客戶端(client):
1. 構(gòu)造DatagramSocket實(shí)例。
2. 通過DatagramSocket實(shí)例的send和receive方法發(fā)送DatagramPacket報(bào)文。
3. 結(jié)束后,調(diào)用DatagramSocket的close方法關(guān)閉。
異常處理:
A. | NullPointerException |
B. | ClassCastException |
C. | FileNotFoundException |
D. | IndexOutOfBoundsException |
答案:C
分析:NullPointerException空指針異常
ClassCastException類型轉(zhuǎn)換異常
IndexOutOfBoundsException索引超出邊界的異常
以上這些異常都是程序在運(yùn)行時(shí)發(fā)生的異常,所以不需要在編寫程序時(shí)聲明
|
答:OutOf MemoryError這種錯(cuò)誤可以細(xì)分為多種不同的錯(cuò)誤,每種錯(cuò)誤都有自身的原因和解決辦法,如下所示:
java.lang.OutOfMemoryError: Java heap space
錯(cuò)誤原因:此OOM是由于JVM中heap的最大值不滿足需要。
解決方法:1) 調(diào)高h(yuǎn)eap的最大值,即-Xmx的值調(diào)大。2) 如果你的程序存在內(nèi)存泄漏,一味的增加heap空間也只是推遲該錯(cuò)誤出現(xiàn)的時(shí)間而已,所以要檢查程序是否存在內(nèi)存泄漏。
java.lang.OutOfMemoryError: GC overhead limit exceeded
錯(cuò)誤原因:此OOM是由于JVM在GC時(shí),對(duì)象過多,導(dǎo)致內(nèi)存溢出,建議調(diào)整GC的策略,在一定比例下開始GC而不要使用默認(rèn)的策略,或者將新代和老代設(shè)置合適的大小,需要進(jìn)行微調(diào)存活率。
解決方法:改變GC策略,在老代80%時(shí)就是開始GC,并且將-XX:SurvivorRatio(-XX:SurvivorRatio=8)和-XX:NewRatio(-XX:NewRatio=4)設(shè)置的更合理。
java.lang.OutOfMemoryError: Java perm space
錯(cuò)誤原因:此OOM是由于JVM中perm的最大值不滿足需要。
解決方法:調(diào)高h(yuǎn)eap的最大值,即-XX:MaxPermSize的值調(diào)大。
另外,注意一點(diǎn),Perm一般是在JVM啟動(dòng)時(shí)加載類進(jìn)來,如果是JVM運(yùn)行較長(zhǎng)一段時(shí)間而不是剛啟動(dòng)后溢出的話,很有可能是由于運(yùn)行時(shí)有類被動(dòng)態(tài)加載進(jìn)來,此時(shí)建議用CMS策略中的類卸載配置。如:-XX:+UseConcMarkSweepGC -XX:+CMSClassUnloadingEnabled。
java.lang.OutOfMemoryError: unable to create new native thread
錯(cuò)誤原因:當(dāng)JVM向OS請(qǐng)求創(chuàng)建一個(gè)新線程時(shí),而OS卻由于內(nèi)存不足無法創(chuàng)建新的native線程。
解決方法:如果JVM內(nèi)存調(diào)的過大或者可利用率小于20%,可以建議將heap及perm的最大值下調(diào),并將線程棧調(diào)小,即-Xss調(diào)小,如:-Xss128k。
java.lang.OutOfMemoryError: Requested array size exceeds VM limit
錯(cuò)誤原因:此類信息表明應(yīng)用程序(或者被應(yīng)用程序調(diào)用的APIs)試圖分配一個(gè)大于堆大小的數(shù)組。例如,如果應(yīng)用程序new一個(gè)數(shù)組對(duì)象,大小為512M,但是最大堆大小為256M,因此OutOfMemoryError會(huì)拋出,因?yàn)閿?shù)組的大小超過虛擬機(jī)的限制。
解決方法:1) 首先檢查heap的-Xmx是不是設(shè)置的過小。2) 如果heap的-Xmx已經(jīng)足夠大,那么請(qǐng)檢查應(yīng)用程序是不是存在bug,例如:應(yīng)用程序可能在計(jì)算數(shù)組的大小時(shí),存在算法錯(cuò)誤,導(dǎo)致數(shù)組的size很大,從而導(dǎo)致巨大的數(shù)組被分配。
java.lang.OutOfMemoryError: request < size> bytes for < reason>. Out of swap space
錯(cuò)誤原因:拋出這類錯(cuò)誤,是由于從native堆中分配內(nèi)存失敗,并且堆內(nèi)存可能接近耗盡。這類錯(cuò)誤可能跟應(yīng)用程序沒有關(guān)系,例如下面兩種原因也會(huì)導(dǎo)致錯(cuò)誤的發(fā)生:1) 操作系統(tǒng)配置了較小的交換區(qū)。2)系統(tǒng)的另外一個(gè)進(jìn)程正在消耗所有的內(nèi)存。
解決辦法:1) 檢查os的swap是不是沒有設(shè)置或者設(shè)置的過小。2) 檢查是否有其他進(jìn)程在消耗大量的內(nèi)存,從而導(dǎo)致當(dāng)前的JVM內(nèi)存不夠分配。
注意:雖然有時(shí)< reason>部分顯示導(dǎo)致OOM的原因,但大多數(shù)情況下,< reason>顯示的是提示分配失敗的源模塊的名稱,所以有必要查看日志文件,如crash時(shí)的hs文件。
答:ClassCastException(類轉(zhuǎn)換異常)
比如 Object obj=new Object(); String s=(String)obj;?
IndexOutOfBoundsException(下標(biāo)越界異常)
NullPointerException(空指針異常)
ArrayStoreException(數(shù)據(jù)存儲(chǔ)異常,操作數(shù)組時(shí)類型不一致)
BufferOverflowException(IO操作時(shí)出現(xiàn)的緩沖區(qū)上溢異常)
InputMismatchException(輸入類型不匹配異常)
ArithmeticException(算術(shù)異常)
注意:運(yùn)行時(shí)異常都是RuntimeException子類異常。
A. | 繼承自 Throwable |
B. | 不支持Serializable |
C. | 繼承自 AbstractSet |
D. | 繼承自FitelnputStream |
答案:A
分析:Throwable是Exception和Error的父類,Exception雖然沒有實(shí)現(xiàn)Serializable接口,但是其父類Throwable已經(jīng)實(shí)現(xiàn)了該接口,因此Exception也支持Serializable。
|
答:?jiǎn)栴}的根本原因是工程中某個(gè)jar包的版本(jar包編譯時(shí)的所用的jdk版本)高于工程build path中jdk的版本,這個(gè)是不兼容的! 編程中遇到此異常Unsupported major.minor version 52.0(根據(jù)版本號(hào),這里可以為其他數(shù)值,52是1.8jdk jar包與 1.8以下低版本jdk不匹配),在將build path中jdk的版本調(diào)整與jar包匹配后,解決異常。
答:會(huì)執(zhí)行,在方法返回調(diào)用者前執(zhí)行。Java允許在finally中改變返回值的做法是不好的,因?yàn)槿绻嬖趂inally代碼塊,try中的return語句不會(huì)立馬返回調(diào)用者,而是記錄下返回值待finally代碼塊執(zhí)行完畢之后再向調(diào)用者返回其值,然后如果在finally中修改了返回值,這會(huì)對(duì)程序造成很大的困擾,C#中就從語法上規(guī)定不能做這樣的事。?
(也許你的答案是在return之前,但往更細(xì)地說,我的答案是在return中間執(zhí)行,請(qǐng)看下面程序代碼的運(yùn)行結(jié)果:
public classTest { /** * @paramargs add by zxx ,Dec 9, 2008 */ public static voidmain(String[] args) { // TODO Auto-generated method stub System.out.println(newTest().test());; } static int test() { int x = 1; try { returnx; } finally { ++x; } } }
執(zhí)行結(jié)果
運(yùn)行結(jié)果是1,為什么呢?主函數(shù)調(diào)用子函數(shù)并得到結(jié)果的過程,好比主函數(shù)準(zhǔn)備一個(gè)空罐子,當(dāng)子函數(shù)要返回結(jié)果時(shí),先把結(jié)果放在罐子里,然后再將程序邏輯返回到主函數(shù)。所謂返回,就是子函數(shù)說,我不運(yùn)行了,你主函數(shù)繼續(xù)運(yùn)行吧,這沒什么結(jié)果可言,結(jié)果是在說這話之前放進(jìn)罐子里的。
答:Java 通過面向?qū)ο蟮姆椒ㄟM(jìn)行異常處理,把各種不同的異常進(jìn)行分類,并提供了良好的接口。在Java 中,每個(gè)異常都是一個(gè)對(duì)象,它是Throwable 類或其子類的實(shí)例。當(dāng)一個(gè)方法出現(xiàn)異常后便拋出一個(gè)異常對(duì)象,該對(duì)象中包含有異常信息,調(diào)用這個(gè)對(duì)象的方法可以捕獲到這個(gè)異常并進(jìn)行處理。Java 的異常處理是通過5 個(gè)關(guān)鍵詞來實(shí)現(xiàn)的:try、catch、throw、throws和finally。一般情況下是用try來執(zhí)行一段程序,如果出現(xiàn)異常,系統(tǒng)會(huì)拋出(throw)一個(gè)異常,這時(shí)候你可以通過它的類型來捕捉(catch)它,或最后(finally)由缺省處理器來處理;try用來指定一塊預(yù)防所有“異?!钡某绦?;catch 子句緊跟在try塊后面,用來指定你想要捕捉的“異?!钡念愋?;throw 語句用來明確地拋出一個(gè)“異?!?;throws用來標(biāo)明一個(gè)成員函數(shù)可能拋出的各種“異?!保籪inally 為確保一段代碼不管發(fā)生什么“異?!倍急粓?zhí)行一段代碼;可以在一個(gè)成員函數(shù)調(diào)用的外面寫一個(gè)try語句,在這個(gè)成員函數(shù)內(nèi)部寫另一個(gè)try語句保護(hù)其他代碼。每當(dāng)遇到一個(gè)try 語句,“異?!钡目蚣芫头诺綏I厦?,直到所有的try語句都完成。如果下一級(jí)的try語句沒有對(duì)某種“異?!边M(jìn)行處理,棧就會(huì)展開,直到遇到有處理這種“異?!钡膖ry 語句。?
答:異常表示程序運(yùn)行過程中可能出現(xiàn)的非正常狀態(tài),運(yùn)行時(shí)異常表示虛擬機(jī)的通常操作中可能遇到的異常,是一種常見運(yùn)行錯(cuò)誤,只要程序設(shè)計(jì)得沒有問題通常就不會(huì)發(fā)生。受檢異常跟程序運(yùn)行的上下文環(huán)境有關(guān),即使程序設(shè)計(jì)無誤,仍然可能因使用的問題而引發(fā)。Java編譯器要求方法必須聲明拋出可能發(fā)生的受檢異常,但是并不要求必須聲明拋出未被捕獲的運(yùn)行時(shí)異常。異常和繼承一樣,是面向?qū)ο蟪绦蛟O(shè)計(jì)中經(jīng)常被濫用的東西,神作《Effective Java》中對(duì)異常的使用給出了以下指導(dǎo)原則:
不要將異常處理用于正常的控制流(設(shè)計(jì)良好的API不應(yīng)該強(qiáng)迫它的調(diào)用者為了正常的控制流而使用異常)
對(duì)可以恢復(fù)的情況使用受檢異常,對(duì)編程錯(cuò)誤使用運(yùn)行時(shí)異常
避免不必要的使用受檢異常(可以通過一些狀態(tài)檢測(cè)手段來避免異常發(fā)生)
優(yōu)先使用標(biāo)準(zhǔn)的異常
每個(gè)方法拋出的異常都要有文檔
保持異常的原子性
不要在catch中忽略掉捕獲到的異常?
(異常表示程序運(yùn)行過程中可能出現(xiàn)的非正常狀態(tài),運(yùn)行時(shí)異常表示虛擬機(jī)的通常操作中可能遇到的異常,是一種常見運(yùn)行錯(cuò)誤。java編譯器要求方法必須聲明拋出可能發(fā)生的非運(yùn)行時(shí)異常,但是并不要求必須聲明拋出未被捕獲的運(yùn)行時(shí)異常。)
有如下代碼片斷:
try{ throw new ExampleB("b") }catch(ExampleA e){ System.out.println("ExampleA"); }catch(Exception e){ System.out.println("Exception"); } }
請(qǐng)問執(zhí)行此段代碼的輸出是什么?
答:輸出:ExampleA。(根據(jù)里氏代換原則[能使用父類型的地方一定能使用子類型],抓取ExampleA類型異常的catch塊能夠抓住try塊中拋出的ExampleB類型的異常)
補(bǔ)充: 比此題略復(fù)雜的一道面試題如下所示(此題的出處是《Java編程思想》),說出你的答案吧!
package com.bjsxt; class Annoyance extends Exception {} class Sneeze extends Annoyance {} class Human { public static void main(String[] args) throws Exception { try { try { throw new Sneeze(); } catch ( Annoyance a ) { System.out.println("Caught Annoyance"); throw a; } } catch ( Sneeze s ) { System.out.println("Caught Sneeze"); return ; } finally { System.out.println("Hello World!"); } } }
輸出為:
Caught Annoyance
Caught Sneeze
Hello World!
Error類,表示僅靠程序本身無法恢復(fù)的嚴(yán)重錯(cuò)誤,比如說內(nèi)存溢出、動(dòng)態(tài)鏈接異常、虛擬機(jī)錯(cuò)誤。應(yīng)用程序不應(yīng)該拋出這種類型的對(duì)象。假如出現(xiàn)這種錯(cuò)誤,除了盡力使程序安全退出外,在其他方面是無能為力的。所以在進(jìn)行程序設(shè)計(jì)時(shí),應(yīng)該更關(guān)注Exception類。
Exception類,由Java應(yīng)用程序拋出和處理的非嚴(yán)重錯(cuò)誤,比如所需文件沒有找到、零作除數(shù),數(shù)組下標(biāo)越界等。它的各種不同子類分別對(duì)應(yīng)不同類型異常??煞譃閮深悾篊hecked異常和Runtime異常
try-catch-finally程序塊的執(zhí)行流程以及執(zhí)行結(jié)果比較復(fù)雜。
基本執(zhí)行過程如下:
1)程序首先執(zhí)行可能發(fā)生異常的try語句塊。
2)如果try語句沒有出現(xiàn)異常則執(zhí)行完后跳至finally語句塊執(zhí)行;
3)如果try語句出現(xiàn)異常,則中斷執(zhí)行并根據(jù)發(fā)生的異常類型跳至相應(yīng)的catch語句塊執(zhí)行處理。
4)catch語句塊可以有多個(gè),分別捕獲不同類型的異常。
5)catch語句塊執(zhí)行完后程序會(huì)繼續(xù)執(zhí)行finally語句塊。
finally語句是可選的,如果有的話,則不管是否發(fā)生異常,finally語句都會(huì)被執(zhí)行。需要注意的是即使try和catch塊中存在return語句,finally語句也會(huì)執(zhí)行,是在執(zhí)行完finally語句后再通過return退出。
1)作用不同:
throw用于程序員自行產(chǎn)生并拋出異常;
throws用于聲明在該方法內(nèi)拋出了異常
2) 使用的位置不同:
throw位于方法體內(nèi)部,可以作為單獨(dú)語句使用;
throws必須跟在方法參數(shù)列表的后面,不能單獨(dú)使用。
3)內(nèi)容不同:
throw拋出一個(gè)異常對(duì)象,且只能是一個(gè);
throws后面跟異常類,而且可以有多個(gè)。
答:.class文件放在WEB-INF/classes文件下,.jar文件放在WEB-INF/lib文件夾下
答:document.getElementById(“username”).value;
區(qū)別:
JSP是在HTML代碼里寫JAVA代碼,框架是HTML;而Servlet是在JAVA代碼中寫HTML代碼,本身是個(gè)JAVA類。
JSP使人們把顯示和邏輯分隔成為可能,這意味著兩者的開發(fā)可并行進(jìn)行;而Servlet并沒有把兩者分開。
Servlet獨(dú)立地處理靜態(tài)表示邏輯與動(dòng)態(tài)業(yè)務(wù)邏輯.這樣,任何文件的變動(dòng)都需要對(duì)此服務(wù)程序重新編譯;JSP允許用特殊標(biāo)簽直接嵌入到HTML頁面, HTML內(nèi)容與JAVA內(nèi)容也可放在單獨(dú)文件中,HTML內(nèi)容的任何變動(dòng)會(huì)自動(dòng)編譯裝入到服務(wù)程序.
Servlet需要在web.xml中配置,而JSP無需配置。
目前JSP主要用在視圖層,負(fù)責(zé)顯示,而Servlet主要用在控制層,負(fù)責(zé)調(diào)度
聯(lián)系:
都是Sun公司推出的動(dòng)態(tài)網(wǎng)頁技術(shù)。
先有Servlet,針對(duì)Servlet缺點(diǎn)推出JSP。JSP是Servlet的一種特殊形式,每個(gè)JSP頁面就是一個(gè)Servlet實(shí)例——JSP頁面由系統(tǒng)翻譯成Servlet,Servlet再負(fù)責(zé)響應(yīng)用戶請(qǐng)求。
JavaScript 高級(jí)程序設(shè)計(jì)(特別是對(duì)瀏覽器差異的復(fù)雜處理),通常很困難也很耗時(shí)。為了應(yīng)對(duì)這些調(diào)整,許多的 JavaScript庫(kù)應(yīng)運(yùn)而生。這些 JavaScript 庫(kù)常被稱為 JavaScript 框架。
jQuery:
Ext JS - 可定制的 widget,用于構(gòu)建富因特網(wǎng)應(yīng)用程序(rich Internet applications)。
Prototype
MooTools。
YUI - Yahoo! User Interface Framework,涵蓋大量函數(shù)的大型庫(kù),從簡(jiǎn)單的 JavaScript 功能到完整的 internet widget。
1、什么是HTML(超文本標(biāo)記語言 Hyper Text Markup Language),HTML 是用來描述網(wǎng)頁的一種語言。
2、CSS(層疊樣式表 Cascading Style Sheets),樣式定義如何顯示 HTML 元素,語法為:selector {property:value} (選擇符 {屬性:值})
3、JavaScript是一種腳本語言,其源代碼在發(fā)往客戶端運(yùn)行之前不需經(jīng)過編譯,而是將文本格式的字符代碼發(fā)送給瀏覽器由瀏覽器解釋運(yùn)行
對(duì)于一個(gè)網(wǎng)頁,HTML定義網(wǎng)頁的結(jié)構(gòu),CSS描述網(wǎng)頁的樣子,JavaScript設(shè)置一個(gè)很經(jīng)典的例子是說HTML就像 一個(gè)人的骨骼、器官,而CSS就是人的皮膚,有了這兩樣也就構(gòu)成了一個(gè)植物人了,加上javascript這個(gè)植物人就可以對(duì)外界刺激做出反應(yīng),可以思 考、運(yùn)動(dòng)、可以給自己整容化妝(改變CSS)等等,成為一個(gè)活生生的人。
如果說HTML是肉身、CSS就是皮相、Javascript就是靈魂。沒有Javascript,HTML+CSS是植物人,沒有Javascript、CSS是個(gè)毀容的植物人。
如果說HTML是建筑師,CSS就是干裝修的,Javascript是魔術(shù)師。
A. | JQuery(expression, [context]) |
B. | JQuery(html, [ownerDocument]) |
C. | JQuery(callback) |
答案:C
|
答:1. DOM(Document Object Model)
DOM是用與平臺(tái)和語言無關(guān)的方式表示XML文檔的官方W3C標(biāo)準(zhǔn)。DOM是以層次結(jié)構(gòu)組織的節(jié)點(diǎn)或信息片斷的集合。這個(gè)層次結(jié)構(gòu)允許開發(fā)人員在樹中尋找特定信息。分析該結(jié)構(gòu)通常需要加載整個(gè)文檔和構(gòu)造層次結(jié)構(gòu),然后才能做任何工作。由于它是基于信息層次的,因而DOM被認(rèn)為是基于樹或基于對(duì)象的。
【優(yōu)點(diǎn)】
①允許應(yīng)用程序?qū)?shù)據(jù)和結(jié)構(gòu)做出更改。
②訪問是雙向的,可以在任何時(shí)候在樹中上下導(dǎo)航,獲取和操作任意部分的數(shù)據(jù)。
【缺點(diǎn)】
①通常需要加載整個(gè)XML文檔來構(gòu)造層次結(jié)構(gòu),消耗資源大。
2. SAX(Simple API for XML)
SAX處理的優(yōu)點(diǎn)非常類似于流媒體的優(yōu)點(diǎn)。分析能夠立即開始,而不是等待所有的數(shù)據(jù)被處理。而且,由于應(yīng)用程序只是在讀取數(shù)據(jù)時(shí)檢查數(shù)據(jù),因此不需要將數(shù)據(jù)存儲(chǔ)在內(nèi)存中。這對(duì)于大型文檔來說是個(gè)巨大的優(yōu)點(diǎn)。事實(shí)上,應(yīng)用程序甚至不必解析整個(gè)文檔;它可以在某個(gè)條件得到滿足時(shí)停止解析。一般來說,SAX還比它的替代者DOM快許多。
選擇DOM還是選擇SAX? 對(duì)于需要自己編寫代碼來處理XML文檔的開發(fā)人員來說, 選擇DOM還是SAX解析模型是一個(gè)非常重要的設(shè)計(jì)決策。 DOM采用建立樹形結(jié)構(gòu)的方式訪問XML文檔,而SAX采用的是事件模型。
DOM解析器把XML文檔轉(zhuǎn)化為一個(gè)包含其內(nèi)容的樹,并可以對(duì)樹進(jìn)行遍歷。用DOM解析模型的優(yōu)點(diǎn)是編程容易,開發(fā)人員只需要調(diào)用建樹的指令,然后利用navigation APIs訪問所需的樹節(jié)點(diǎn)來完成任務(wù)??梢院苋菀椎奶砑雍托薷臉渲械脑?。然而由于使用DOM解析器的時(shí)候需要處理整個(gè)XML文檔,所以對(duì)性能和內(nèi)存的要求比較高,尤其是遇到很大的XML文件的時(shí)候。由于它的遍歷能力,DOM解析器常用于XML文檔需要頻繁的改變的服務(wù)中。
SAX解析器采用了基于事件的模型,它在解析XML文檔的時(shí)候可以觸發(fā)一系列的事件,當(dāng)發(fā)現(xiàn)給定的tag的時(shí)候,它可以激活一個(gè)回調(diào)方法,告訴該方法制定的標(biāo)簽已經(jīng)找到。SAX對(duì)內(nèi)存的要求通常會(huì)比較低,因?yàn)樗岄_發(fā)人員自己來決定所要處理的tag.特別是當(dāng)開發(fā)人員只需要處理文檔中所包含的部分?jǐn)?shù)據(jù)時(shí),SAX這種擴(kuò)展能力得到了更好的體現(xiàn)。但用SAX解析器的時(shí)候編碼工作會(huì)比較困難,而且很難同時(shí)訪問同一個(gè)文檔中的多處不同數(shù)據(jù)。
【優(yōu)勢(shì)】
①不需要等待所有數(shù)據(jù)都被處理,分析就能立即開始。
②只在讀取數(shù)據(jù)時(shí)檢查數(shù)據(jù),不需要保存在內(nèi)存中。
③可以在某個(gè)條件得到滿足時(shí)停止解析,不必解析整個(gè)文檔。
④效率和性能較高,能解析大于系統(tǒng)內(nèi)存的文檔。
【缺點(diǎn)】
①需要應(yīng)用程序自己負(fù)責(zé)TAG的處理邏輯(例如維護(hù)父/子關(guān)系等),文檔越復(fù)雜程序就越復(fù)雜。
②單向?qū)Ш?,無法定位文檔層次,很難同時(shí)訪問同一文檔的不同部分?jǐn)?shù)據(jù),不支持XPath。
3. JDOM(Java-based Document Object Model)
JDOM的目的是成為Java特定文檔模型,它簡(jiǎn)化與XML的交互并且比使用DOM實(shí)現(xiàn)更快。由于是第一個(gè)Java特定模型,JDOM一直得到大力推廣和促進(jìn)。正在考慮通過“Java規(guī)范請(qǐng)求JSR-102”將它最終用作“Java標(biāo)準(zhǔn)擴(kuò)展”。從2000年初就已經(jīng)開始了JDOM開發(fā)。
JDOM與DOM主要有兩方面不同。首先,JDOM僅使用具體類而不使用接口。這在某些方面簡(jiǎn)化了API,但是也限制了靈活性。第二,API大量使用了Collections類,簡(jiǎn)化了那些已經(jīng)熟悉這些類的Java開發(fā)者的使用。
JDOM文檔聲明其目的是“使用20%(或更少)的精力解決80%(或更多)Java/XML問題”(根據(jù)學(xué)習(xí)曲線假定為20%)。JDOM對(duì)于大多數(shù)Java/XML應(yīng)用程序來說當(dāng)然是有用的,并且大多數(shù)開發(fā)者發(fā)現(xiàn)API比DOM容易理解得多。JDOM還包括對(duì)程序行為的相當(dāng)廣泛檢查以防止用戶做任何在XML中無意義的事。然而,它仍需要您充分理解XML以便做一些超出基本的工作(或者甚至理解某些情況下的錯(cuò)誤)。這也許是比學(xué)習(xí)DOM或JDOM接口都更有意義的工作。
JDOM自身不包含解析器。它通常使用SAX2解析器來解析和驗(yàn)證輸入XML文檔(盡管它還可以將以前構(gòu)造的DOM表示作為輸入)。它包含一些轉(zhuǎn)換器以將JDOM表示輸出成SAX2事件流、DOM模型或XML文本文檔。JDOM是在Apache許可證變體下發(fā)布的開放源碼。
【優(yōu)點(diǎn)】
①使用具體類而不是接口,簡(jiǎn)化了DOM的API。
②大量使用了Java集合類,方便了Java開發(fā)人員。
【缺點(diǎn)】
①?zèng)]有較好的靈活性。
②性能較差。
4. DOM4J(Document Object Model for Java)
雖然DOM4J代表了完全獨(dú)立的開發(fā)結(jié)果,但最初,它是JDOM的一種智能分支。它合并了許多超出基本XML文檔表示的功能,包括集成的XPath支持、XML Schema支持以及用于大文檔或流化文檔的基于事件的處理。它還提供了構(gòu)建文檔表示的選項(xiàng),它通過DOM4J API和標(biāo)準(zhǔn)DOM接口具有并行訪問功能。從2000下半年開始,它就一直處于開發(fā)之中。
為支持所有這些功能,DOM4J使用接口和抽象基本類方法。DOM4J大量使用了API中的Collections類,但是在許多情況下,它還提供一些替代方法以允許更好的性能或更直接的編碼方法。直接好處是,雖然DOM4J付出了更復(fù)雜的API的代價(jià),但是它提供了比JDOM大得多的靈活性。
在添加靈活性、XPath集成和對(duì)大文檔處理的目標(biāo)時(shí),DOM4J的目標(biāo)與JDOM是一樣的:針對(duì)Java開發(fā)者的易用性和直觀操作。它還致力于成為比JDOM更完整的解決方案,實(shí)現(xiàn)在本質(zhì)上處理所有Java/XML問題的目標(biāo)。在完成該目標(biāo)時(shí),它比JDOM更少?gòu)?qiáng)調(diào)防止不正確的應(yīng)用程序行為。
DOM4J是一個(gè)非常非常優(yōu)秀的Java XML API,具有性能優(yōu)異、功能強(qiáng)大和極端易用使用的特點(diǎn),同時(shí)它也是一個(gè)開放源代碼的軟件。如今你可以看到越來越多的Java軟件都在使用DOM4J來讀寫XML,特別值得一提的是連Sun的JAXM也在用DOM4J.
【優(yōu)點(diǎn)】
①大量使用了Java集合類,方便Java開發(fā)人員,同時(shí)提供一些提高性能的替代方法。
②支持XPath。
③有很好的性能。
【缺點(diǎn)】
①大量使用了接口,API較為復(fù)雜。
二、比較
1. DOM4J性能最好,連Sun的JAXM也在用DOM4J。目前許多開源項(xiàng)目中大量采用DOM4J,例如大名鼎鼎的Hibernate也用DOM4J來讀取XML配置文件。如果不考慮可移植性,那就采用DOM4J.
2. JDOM和DOM在性能測(cè)試時(shí)表現(xiàn)不佳,在測(cè)試10M文檔時(shí)內(nèi)存溢出,但可移植。在小文檔情況下還值得考慮使用DOM和JDOM.雖然JDOM的開發(fā)者已經(jīng)說明他們期望在正式發(fā)行版前專注性能問題,但是從性能觀點(diǎn)來看,它確實(shí)沒有值得推薦之處。另外,DOM仍是一個(gè)非常好的選擇。DOM實(shí)現(xiàn)廣泛應(yīng)用于多種編程語言。它還是許多其它與XML相關(guān)的標(biāo)準(zhǔn)的基礎(chǔ),因?yàn)樗将@得W3C推薦(與基于非標(biāo)準(zhǔn)的Java模型相對(duì)),所以在某些類型的項(xiàng)目中可能也需要它(如在JavaScript中使用DOM)。
3. SAX表現(xiàn)較好,這要依賴于它特定的解析方式-事件驅(qū)動(dòng)。一個(gè)SAX檢測(cè)即將到來的XML流,但并沒有載入到內(nèi)存(當(dāng)然當(dāng)XML流被讀入時(shí),會(huì)有部分文檔暫時(shí)隱藏在內(nèi)存中)。
我的看法:如果XML文檔較大且不考慮移植性問題建議采用DOM4J;如果XML文檔較小則建議采用JDOM;如果需要及時(shí)處理而不需要保存數(shù)據(jù)則考慮SAX。但無論如何,還是那句話:適合自己的才是最好的,如果時(shí)間允許,建議大家講這四種方法都嘗試一遍然后選擇一種適合自己的即可。
答:1.java采用unicode編碼,2個(gè)字節(jié)(16位)來表示一個(gè)字符, 無論是漢字還是數(shù)字,字母,或其他語言都可以存儲(chǔ)。
2.char 在java中是2個(gè)字節(jié),所以可以存儲(chǔ)中文
下面接著再說說兩者在應(yīng)用上的區(qū)別:
接口更多的是在系統(tǒng)架構(gòu)設(shè)計(jì)方法發(fā)揮作用,主要用于定義模塊之間的通信契約。而抽象類在代碼實(shí)現(xiàn)方面發(fā)揮作用,可以實(shí)現(xiàn)代碼的重用,例如,模板方法設(shè)計(jì)模式是抽象類的一個(gè)典型應(yīng)用,假設(shè)某個(gè)項(xiàng)目的所有Servlet類都要用相同的方式進(jìn)行權(quán)限判斷、記錄訪問日志和處理異常,那么就可以定義一個(gè)抽象的基類,讓所有的Servlet都繼承這個(gè)抽象基類,在抽象基類的service方法中完成權(quán)限判斷、記錄訪問日志和處理異常的代碼,在各個(gè)子類中只是完成各自的業(yè)務(wù)邏輯代碼,偽代碼如下:
public abstract classBaseServlet extends HttpServlet{ public final void service(HttpServletRequest request,HttpServletResponse response) throws IOExcetion,ServletException { 記錄訪問日志 進(jìn)行權(quán)限判斷 if(具有權(quán)限){ try{ doService(request,response); } catch(Excetpion e) { 記錄異常信息 } } } protected abstract void doService(HttpServletRequest request,HttpServletResponse response) throws IOExcetion,ServletException; //注意訪問權(quán)限定義成protected,顯得既專業(yè),又嚴(yán)謹(jǐn),因?yàn)樗菍iT給子類用的 } public class MyServlet1 extendsBaseServlet { protected voiddoService(HttpServletRequest request, HttpServletResponse response) throwsIOExcetion,ServletException { 本Servlet只處理的具體業(yè)務(wù)邏輯代碼 } }
父類方法中間的某段代碼不確定,留給子類干,就用模板方法設(shè)計(jì)模式。
備注:這道題的思路是先從總體解釋抽象類和接口的基本概念,然后再比較兩者的語法細(xì)節(jié),最后再說兩者的應(yīng)用區(qū)別。比較兩者語法細(xì)節(jié)區(qū)別的條理是:先從一個(gè)類中的構(gòu)造方法、普通成員變量和方法(包括抽象方法),靜態(tài)變量和方法,繼承性等6個(gè)方面逐一去比較回答,接著從第三者繼承的角度的回答,特別是最后用了一個(gè)典型的例子來展現(xiàn)自己深厚的技術(shù)功底。
答:JavaScript 與Java是兩個(gè)公司開發(fā)的不同的兩個(gè)產(chǎn)品。Java 是原Sun 公司推出的面向?qū)ο蟮某绦蛟O(shè)計(jì)語言,特別適合于互聯(lián)網(wǎng)應(yīng)用程序開發(fā);而JavaScript是Netscape公司的產(chǎn)品,為了擴(kuò)展Netscape瀏覽器的功能而開發(fā)的一種可以嵌入Web頁面中運(yùn)行的基于對(duì)象和事件驅(qū)動(dòng)的解釋性語言,它的前身是LiveScript;而Java 的前身是Oak語言。
下面對(duì)兩種語言間的異同作如下比較:
1)基于對(duì)象和面向?qū)ο螅篔ava是一種真正的面向?qū)ο蟮恼Z言,即使是開發(fā)簡(jiǎn)單的程序,必須設(shè)計(jì)對(duì)象;JavaScript是種腳本語言,它可以用來制作與網(wǎng)絡(luò)無關(guān)的,與用戶交互作用的復(fù)雜軟件。它是一種基于對(duì)象(Object-Based)和事件驅(qū)動(dòng)(Event-Driven)的編程語言。因而它本身提供了非常豐富的內(nèi)部對(duì)象供設(shè)計(jì)人員使用;
2)解釋和編譯:Java 的源代碼在執(zhí)行之前,必須經(jīng)過編譯;JavaScript 是一種解釋性編程語言,其源代碼不需經(jīng)過編譯,由瀏覽器解釋執(zhí)行;
3)強(qiáng)類型變量和類型弱變量:Java采用強(qiáng)類型變量檢查,即所有變量在編譯之前必須作聲明;JavaScript中變量聲明,采用其弱類型。即變量在使用前不需作聲明,而是解釋器在運(yùn)行時(shí)檢查其數(shù)據(jù)類型;
4)代碼格式不一樣。
補(bǔ)充:上面列出的四點(diǎn)是原來所謂的標(biāo)準(zhǔn)答案中給出的。其實(shí)Java和JavaScript最重要的區(qū)別是一個(gè)是靜態(tài)語言,一個(gè)是動(dòng)態(tài)語言。目前的編程語言的發(fā)展趨勢(shì)是函數(shù)式語言和動(dòng)態(tài)語言。在Java中類(class)是一等公民,而JavaScript中函數(shù)(function)是一等公民。對(duì)于這種問題,在面試時(shí)還是用自己的語言回答會(huì)更加靠譜。?
答:assertion(斷言)在軟件開發(fā)中是一種常用的調(diào)試方式,很多開發(fā)語言中都支持這種機(jī)制。一般來說,assertion用于保證程序最基本、關(guān)鍵的正確性。assertion檢查通常在開發(fā)和測(cè)試時(shí)開啟。為了提高性能,在軟件發(fā)布后, assertion檢查通常是關(guān)閉的。在實(shí)現(xiàn)中,斷言是一個(gè)包含布爾表達(dá)式的語句,在執(zhí)行這個(gè)語句時(shí)假定該表達(dá)式為true;如果表達(dá)式計(jì)算為false,那么系統(tǒng)會(huì)報(bào)告一個(gè)AssertionError。
斷言用于調(diào)試目的:
assert(a > 0); // throws an AssertionError if a <= 0
斷言可以有兩種形式:
assert Expression1;
assert Expression1 : Expression2 ;
Expression1 應(yīng)該總是產(chǎn)生一個(gè)布爾值。
Expression2 可以是得出一個(gè)值的任意表達(dá)式;這個(gè)值用于生成顯示更多調(diào)試信息的字符串消息。
斷言在默認(rèn)情況下是禁用的,要在編譯時(shí)啟用斷言,需使用source 1.4 標(biāo)記:
javac -source 1.4 Test.java
要在運(yùn)行時(shí)啟用斷言,可使用-enableassertions 或者-ea 標(biāo)記。
要在運(yùn)行時(shí)選擇禁用斷言,可使用-da 或者-disableassertions 標(biāo)記。
要在系統(tǒng)類中啟用斷言,可使用-esa 或者-dsa 標(biāo)記。還可以在包的基礎(chǔ)上啟用或者禁用斷言。可以在預(yù)計(jì)正常情況下不會(huì)到達(dá)的任何位置上放置斷言。斷言可以用于驗(yàn)證傳遞給私有方法的參數(shù)。不過,斷言不應(yīng)該用于驗(yàn)證傳遞給公有方法的參數(shù),因?yàn)椴还苁欠駟⒂昧藬嘌?,公有方法都必須檢查其參數(shù)。不過,既可以在公有方法中,也可以在非公有方法中利用斷言測(cè)試后置條件。另外,斷言不應(yīng)該以任何方式改變程序的狀態(tài)。?
答:UML是統(tǒng)一建模語言(Unified Modeling Language)的縮寫,它發(fā)表于1997年,綜合了當(dāng)時(shí)已經(jīng)存在的面向?qū)ο蟮慕UZ言、方法和過程,是一個(gè)支持模型化和軟件系統(tǒng)開發(fā)的圖形化語言,為軟件開發(fā)的所有階段提供模型化和可視化支持。使用UML可以幫助溝通與交流,輔助應(yīng)用設(shè)計(jì)和文檔的生成,還能夠闡釋系統(tǒng)的結(jié)構(gòu)和行為。UML定義了多種圖形化的符號(hào)來描述軟件系統(tǒng)部分或全部的靜態(tài)結(jié)構(gòu)和動(dòng)態(tài)結(jié)構(gòu),包括:用例圖(use case diagram)、類圖(class diagram)、時(shí)序圖(sequence diagram)、協(xié)作圖(collaboration diagram)、狀態(tài)圖(statechart diagram)、活動(dòng)圖(activity diagram)、構(gòu)件圖(component diagram)、部署圖(deployment diagram)等。在這些圖形化符號(hào)中,有三種圖最為重要,分別是:用例圖(用來捕獲需求,描述系統(tǒng)的功能,通過該圖可以迅速的了解系統(tǒng)的功能模塊及其關(guān)系)、類圖(描述類以及類與類之間的關(guān)系,通過該圖可以快速了解系統(tǒng))、時(shí)序圖(描述執(zhí)行特定任務(wù)時(shí)對(duì)象之間的交互關(guān)系以及執(zhí)行順序,通過該圖可以了解對(duì)象能接收的消息也就是說對(duì)象能夠向外界提供的服務(wù))。
用例圖:
答: XML文檔定義分為DTD和Schema兩種形式;其本質(zhì)區(qū)別在于Schema本身也是一個(gè)XML文件,可以被XML解析器解析。對(duì)XML的解析主要有DOM(文檔對(duì)象模型)、SAX、StAX(JDK 1.6中引入的新的解析XML的方式,Streaming API for XML) 等,其中DOM處理大型文件時(shí)其性能下降的非常厲害,這個(gè)問題是由DOM 的樹結(jié)構(gòu)所造成的,這種結(jié)構(gòu)占用的內(nèi)存較多,而且DOM 必須在解析文件之前把整個(gè)文檔裝入內(nèi)存,適合對(duì)XML 的隨機(jī)訪問(典型的用空間換取時(shí)間的策略);SAX是事件驅(qū)動(dòng)型的XML解析方式,它順序讀取XML文件,不需要一次全部裝載整個(gè)文件。當(dāng)遇到像文件開頭,文檔結(jié)束,或者標(biāo)簽開頭與標(biāo)簽結(jié)束時(shí),它會(huì)觸發(fā)一個(gè)事件,用戶通過在其回調(diào)事件中寫入處理代碼來處理XML文件,適合對(duì)XML 的順序訪問;如其名稱所暗示的那樣,StAX把重點(diǎn)放在流上。實(shí)際上,StAX與其他方法的區(qū)別就在于應(yīng)用程序能夠把XML作為一個(gè)事件流來處理。將XML作為一組事件來處理的想法并不新穎(事實(shí)上 SAX 已經(jīng)提出來了),但不同之處在于StAX允許應(yīng)用程序代碼把這些事件逐個(gè)拉出來,而不用提供在解析器方便時(shí)從解析器中接收事件的處理程序。?
答: XML的主要作用有兩個(gè)方面:數(shù)據(jù)交換(曾經(jīng)被稱為業(yè)界數(shù)據(jù)交換的事實(shí)標(biāo)準(zhǔn),現(xiàn)在此項(xiàng)功能在很多時(shí)候都被JSON取代)和信息配置。在做數(shù)據(jù)交換時(shí),XML將數(shù)據(jù)用標(biāo)簽組裝成起來,然后壓縮打包加密后通過網(wǎng)絡(luò)傳送給接收者,接收解密與解壓縮后再?gòu)腦ML文件中還原相關(guān)信息進(jìn)行處理。目前很多軟件都使用XML來存儲(chǔ)配置信息,很多項(xiàng)目中我們通常也會(huì)將作為配置的硬代碼(hard code)寫在XML文件中,Java的很多框架也是這么做的。?
Function testE(ss){ var reg=/^[1-9][0-9]{5}$/; if(req.test(ss)){ alert(“郵編OK”) }else{ alert(“郵編格式不正確”); } }
$(“*”).css(“border”,”2px dashed”)
答案:調(diào)用jQuery中的ajax函數(shù),設(shè)置其async屬性來表明是異步還是同步,如下:
$.ajax({
async:true//表示異步,false表示同步
})
答案:兼容firefox的 outerHTML,F(xiàn)F中沒有outerHtml的方法
IE下,可以使用()或[]獲取集合類對(duì)象;Firefox下,只能使用[]獲取集合類對(duì)象.解決方法:統(tǒng)一使用[]獲取集合類對(duì)象.
IE下,可以使用獲取常規(guī)屬性的方法來獲取自定義屬性,也可以使用getAttribute()獲取自定義屬性;Firefox下,只能使用getAttribute()獲取自定義屬性.解決方法:統(tǒng)一通過getAttribute()獲取自定義屬性
$.post(“show”,{uname=”張三”,pwd=”123”},function(data){ alert(data) })
答案:ready 事件的觸發(fā),表示文檔結(jié)構(gòu)已經(jīng)加載完成(不包含圖片等非文字媒體文件)
onload 事件的觸發(fā),表示頁面包含圖片等文件在內(nèi)的所有元素都加載完成。
答案:
基本選擇器
層次選擇器
基本過濾選擇器
內(nèi)容過濾選擇器
可見性過濾選擇器
屬性過濾選擇器
子元素過濾選擇器
表單選擇器
表單過濾選擇器
答案:使用reload()即可
Div居中:
margin:auto 0px;
內(nèi)容居中:
text-align:center;
答案:
存儲(chǔ)角度:
Session是服務(wù)器端的數(shù)據(jù)存儲(chǔ)技術(shù),cookie是客戶端的數(shù)據(jù)存儲(chǔ)技術(shù)
解決問題角度:
Session解決的是一個(gè)用戶不同請(qǐng)求的數(shù)據(jù)共享問題,cookie解決的是不同請(qǐng)求的請(qǐng)求數(shù)據(jù)的共享問題
生命周期角度:
Session的id是依賴于cookie來進(jìn)行存儲(chǔ)的,瀏覽器關(guān)閉id就會(huì)失效
Cookie可以單獨(dú)的設(shè)置其在瀏覽器的存儲(chǔ)時(shí)間。
答案:
賦值角度說明:
null 表示此處沒有值,undefined表示此處定義了但是沒有賦值
從數(shù)據(jù)轉(zhuǎn)換角度:
Null在做數(shù)值轉(zhuǎn)換時(shí)會(huì)被轉(zhuǎn)換為0,undefined會(huì)被轉(zhuǎn)換為NaN
答案:
區(qū)別:doPost用來處理post請(qǐng)求,doGet用來處理get請(qǐng)求,獲取參數(shù):獲取的參數(shù)是相同的都是HttpServletRequest \HttpServletResponse
答案:$(“a[class=view-link]”).attr(“target”,”_blank”)
var scope ="global scope"; function checkscope() { var scope ="local scope”; return function() { return scope} } console.log (checkscope()());
eq返回的是一個(gè)jquery對(duì)象 get返回的是一個(gè)html對(duì)象
在啟動(dòng)Weblogic的腳本中(位于所在Domian對(duì)應(yīng)服務(wù)器目錄下的startServerName),增加set MEM_ARGS=-Xms32m -Xmx200m,可以調(diào)整最小內(nèi)存為32M,最大200M
三次握手是為了防止已失效的連接請(qǐng)求再次傳送到服務(wù)器端。 二次握手不可行,因?yàn)椋喝绻捎诰W(wǎng)絡(luò)不穩(wěn)定,雖然客戶端以前發(fā)送的連接請(qǐng)求以到達(dá)服務(wù)方,但服務(wù)方的同意連接的應(yīng)答未能到達(dá)客戶端。則客戶方要重新發(fā)送連接請(qǐng)求,若采用二次握手,服務(wù)方收到重傳的請(qǐng)求連接后,會(huì)以為是新的請(qǐng)求,就會(huì)發(fā)送同意連接報(bào)文,并新開進(jìn)程提供服務(wù),這樣會(huì)造成服務(wù)方資源的無謂浪費(fèi)
A. | 200ok表示請(qǐng)求成功 |
B. | 400不良請(qǐng)求表示服務(wù)器未發(fā)現(xiàn)與請(qǐng)求URL匹配內(nèi)容 |
C. | 404未發(fā)現(xiàn)表示由于語法錯(cuò)誤兒導(dǎo)致服務(wù)器無法理解請(qǐng)求信息 |
D. | 500內(nèi)部服務(wù)器錯(cuò)誤,無法處理請(qǐng)求 |
答案:D
分析:
A 200ok 表示的意思是一切正常。一般用于相應(yīng)GET和POST請(qǐng)求。這個(gè)狀態(tài)碼對(duì)servlet是缺省的;如果沒有調(diào)用setStatus方法的話,就會(huì)得到200。
B 400 表示指出客戶端請(qǐng)求中的語法錯(cuò)誤
C 404 客戶端所給的地址無法找到任何資源
|
A. | JSP命令 |
B. | JSP Action |
C. | JSP腳本 |
D. | JSP控件 |
答案:C
分析:JSP頁面元素構(gòu)成如下,因此ABD錯(cuò)誤
A 200ok 表示的意思是一切正常。一般用于相應(yīng)GET和POST請(qǐng)求。這個(gè)狀態(tài)碼對(duì)servlet是缺省的;如果沒有調(diào)用setStatus方法的話,就會(huì)得到200。
B 400 表示指出客戶端請(qǐng)求中的語法錯(cuò)誤
C 404 客戶端所給的地址無法找到任何資源
|
A. | DOM |
B. | CSS |
C. | JavaScript |
D. | XmlHttpRequest |
答案:A
|
A. | HttpSession session=new HttpSession(); |
B. | String haha=session getParameler(:haha”); |
C. | session.removeAttribute(“haha”); |
D. | session.setAttribute(:haha:);XmlHttpRequest |
答案:A
|
答案:1、request對(duì)象
request 對(duì)象是 javax.servlet.httpServletRequest類型的對(duì)象。 該對(duì)象代表了客戶端的請(qǐng)求信息,主要用于接受通過HTTP協(xié)議傳送到服務(wù)器的數(shù)據(jù)。(包括頭信息、系統(tǒng)信息、請(qǐng)求方式以及請(qǐng)求參數(shù)等)。request對(duì)象的作用域?yàn)橐淮握?qǐng)求。
2、response對(duì)象
response 代表的是對(duì)客戶端的響應(yīng),主要是將JSP容器處理過的對(duì)象傳回到客戶端。response對(duì)象也具有作用域,它只在JSP頁面內(nèi)有效。
3、session對(duì)象
session 對(duì)象是由服務(wù)器自動(dòng)創(chuàng)建的與用戶請(qǐng)求相關(guān)的對(duì)象。服務(wù)器為每個(gè)用戶都生成一個(gè)session對(duì)象,用于保存該用戶的信息,跟蹤用戶的操作狀態(tài)。session對(duì)象內(nèi)部使用Map類來保存數(shù)據(jù),因此保存數(shù)據(jù)的格式為 “Key/value”。 session對(duì)象的value可以使復(fù)雜的對(duì)象類型,而不僅僅局限于字符串類型。
4、application對(duì)象
?application 對(duì)象可將信息保存在服務(wù)器中,直到服務(wù)器關(guān)閉,否則application對(duì)象中保存的信息會(huì)在整個(gè)應(yīng)用中都有效。與session對(duì)象相比,application對(duì)象生命周期更長(zhǎng),類似于系統(tǒng)的“全局變量”。
5、out 對(duì)象
out 對(duì)象用于在Web瀏覽器內(nèi)輸出信息,并且管理應(yīng)用服務(wù)器上的輸出緩沖區(qū)。在使用 out 對(duì)象輸出數(shù)據(jù)時(shí),可以對(duì)數(shù)據(jù)緩沖區(qū)進(jìn)行操作,及時(shí)清除緩沖區(qū)中的殘余數(shù)據(jù),為其他的輸出讓出緩沖空間。待數(shù)據(jù)輸出完畢后,要及時(shí)關(guān)閉輸出流。
6、pageContext 對(duì)象
pageContext 對(duì)象的作用是取得任何范圍的參數(shù),通過它可以獲取 JSP頁面的out、request、reponse、session、application 等對(duì)象。pageContext對(duì)象的創(chuàng)建和初始化都是由容器來完成的,在JSP頁面中可以直接使用 pageContext對(duì)象。
7、config 對(duì)象
config 對(duì)象的主要作用是取得服務(wù)器的配置信息。通過 pageConext對(duì)象的 getServletConfig() 方法可以獲取一個(gè)config對(duì)象。當(dāng)一個(gè)Servlet 初始化時(shí),容器把某些信息通過 config對(duì)象傳遞給這個(gè) Servlet。 開發(fā)者可以在web.xml 文件中為應(yīng)用程序環(huán)境中的Servlet程序和JSP頁面提供初始化參數(shù)。
8、page 對(duì)象
page 對(duì)象代表JSP本身,只有在JSP頁面內(nèi)才是合法的。 page隱含對(duì)象本質(zhì)上包含當(dāng)前 Servlet接口引用的變量,類似于Java編程中的 this 指針。
9、exception 對(duì)象
exception 對(duì)象的作用是顯示異常信息,只有在包含 isErrorPage="true" 的頁面中才可以被使用,在一般的JSP頁面中使用該對(duì)象將無法編譯JSP文件。excepation對(duì)象和Java的所有對(duì)象一樣,都具有系統(tǒng)提供的繼承結(jié)構(gòu)。exception 對(duì)象幾乎定義了所有異常情況。在Java程序中,可以使用try/catch關(guān)鍵字來處理異常情況; 如果在JSP頁面中出現(xiàn)沒有捕獲到的異常,就會(huì)生成 exception 對(duì)象,并把 exception 對(duì)象傳送到在page指令中設(shè)定的錯(cuò)誤頁面中,然后在錯(cuò)誤頁面中處理相應(yīng)的 exception 對(duì)象。
在web.xml中使用如下標(biāo)簽:
<servlet> <servlet-name></servlet-name> <servlet-class></servlet-class> </servlet> <servlet-mapping> <servlet-name></servlet-name> <url-pattern></url-pattern> </servlet-mapping> 或者使用注解方式: @WebServlet(name="servlet", urlPatterns={"/*"})
答: var arr=[1,2,3,4,5,6,7,8]
A. | var obj=( ); |
B. | var obj=[ ]; |
C. | var obj=//; |
D. | var obj=1; |
答案:AC
|
A. | <% %> |
B. | <% ! %> |
C. | <%@ %> |
D. | <%=%> |
答案:B
分析:B <% ! %> 可用作聲明
A不正確
C為引用xxx,比如<% @page xxxxx%>
D為表達(dá)式
|
HTML含義:
Hyper Text Markup Language 超文本標(biāo)記語言,是一種用來制作“網(wǎng)頁”的簡(jiǎn)單標(biāo)記語言;用HTML編寫的超文本文檔稱為HTML文檔,HTML文檔的擴(kuò)展名是html或者h(yuǎn)tm
版本變化:
HTML1.0——在1993年6月作為IETF工作草案發(fā)布(并非標(biāo)準(zhǔn))
HTML 2.0——1995年11月作為RFC 1866發(fā)布
HTML 3.2——1997年1月14日,W3C推薦標(biāo)準(zhǔn)
HTML 4.0——1997年12月18日,W3C推薦標(biāo)準(zhǔn)
HTML 4.01(微小改進(jìn))——1999年12月24日,W3C推薦標(biāo)準(zhǔn)
HTML 5—2014年10月28日,W3C推薦標(biāo)準(zhǔn)HTML文檔結(jié)構(gòu);
HTML 5.1 - 2016年
HTML 5.2 – 2018年最新版本
HTML 5.3 is coming…
錨鏈接是帶有文本的超鏈接??梢蕴D(zhuǎn)到頁面的某個(gè)位置,適用于頁面內(nèi)容較多,超過一屏的場(chǎng)合 。分為頁面內(nèi)的錨鏈接和頁面間的錨鏈接 。
說明:
1.在標(biāo)記位置利用a標(biāo)簽的name屬性設(shè)置標(biāo)記。
2.在導(dǎo)航位置通過a標(biāo)簽的href屬性用#開頭加name屬性值即可跳轉(zhuǎn)錨點(diǎn)位置。
有些字符,比如說“<”字符,在HTML中有特殊的含義,因此不能在文本中使用。想要在HTML中顯示一個(gè)小于號(hào)“<”,需要用到字符實(shí)體:<或者<
字符實(shí)體擁有三個(gè)部分:一個(gè)and符號(hào)(&),一個(gè)實(shí)體名或者一個(gè)實(shí)體號(hào),最后是一個(gè)分號(hào)(;)
常用字符實(shí)體:
顯示結(jié)果 | 描述 | 實(shí)體 | 實(shí)體號(hào) |
空格 | |||
< | 小于 | < | < |
> | 大于 | > | |
& | and符號(hào) | & | & |
' | 單引號(hào) | ' (IE不支持) | ' |
" | 引號(hào) | " | " |
£ | 英鎊 | £ | £ |
¥ | 人民幣元 | ¥ | ¥ |
§ | 章節(jié) | ¥ | ¥ |
? | 版權(quán) | © | © |
表單的作用:
利用表單可以收集客戶端提交的有關(guān)信息。
常用表單項(xiàng)類型:
input標(biāo)簽 type屬性 |
功能 | input標(biāo)簽 type屬性 |
功能 |
text | 單行本框 | reset | 重置按鈕 |
password | 密碼框 | submit | 提交按鈕 |
radio | 單選按鈕 | textarea | 文本域 |
checkbox | 復(fù)選框 | select | 下拉框 |
button | 普通按鈕 | hidden | 隱藏域 |
335.表格、框架、div三種HTML布局方式的特點(diǎn)
優(yōu)點(diǎn) | 缺點(diǎn) | 應(yīng)用場(chǎng)合 | |
表格 | 方便排列有規(guī)律、結(jié)構(gòu)均勻的內(nèi)容或數(shù)據(jù) | 產(chǎn)生垃圾代碼、影響頁面下載時(shí)間、靈活性不大難于修改 | 內(nèi)容或數(shù)據(jù)整齊的頁面 |
框架 | 支持滾動(dòng)條、方便導(dǎo)航 節(jié)省頁面下載時(shí)間等 | 兼容性不好,保存時(shí)不方便、應(yīng)用范圍有限 | 小型商業(yè)網(wǎng)站、論壇后臺(tái)管理 |
Div | 代碼精簡(jiǎn)、提高頁面下載速度、表現(xiàn)和內(nèi)容分離 | 比較靈活、難于控制 | 復(fù)雜的不規(guī)則頁面、業(yè)務(wù)種類較多的大型商業(yè)網(wǎng)站 |
336.form中input設(shè)置為readonly和disabled的區(qū)別
readonly | disabled | |
有效對(duì)象 | .只針對(duì)type為text/password有效 | 對(duì)所有表單元素有效 |
表單提交 | 當(dāng)表單元素設(shè)置readonly后,表單提交能將該表單元素的值傳遞出去。 | 當(dāng)表單元素設(shè)置disabled后,表單提交不能將該表單元素的值傳遞出去。 |
337.CSS的定義和作用
CSS的定義:CSS是Cascading Style Sheets(層疊樣式表)的簡(jiǎn)稱。
CSS是一系列格式規(guī)則,它們控制網(wǎng)頁內(nèi)容的外觀。CSS簡(jiǎn)單來說就是用來美化網(wǎng)頁用的。
CSS的具體作用包括:
使網(wǎng)頁豐富多彩,易于控制。
頁面的精確控制,實(shí)現(xiàn)精美、復(fù)雜頁面 。
338.CSS2常用選擇器類型及其含義
選擇器名稱 | 案例 | 語法格式 |
標(biāo)簽選擇器 | h3{font-size:24px;font-family:"隸書“; }< h3>JSP< /h3> | 元素標(biāo)簽名{樣式屬性} |
類選擇器 | .red {color:#F00;} < li class="red">Oracle< /li> | . 元素標(biāo)簽class屬性值{樣式屬性} |
ID選擇器 | #p1 {background-color:#0F0;} < p id="p1">content< /p> | #元素標(biāo)簽id屬性值{樣式屬性} |
包含選擇器 | div h3{color:red;} < div> < h3>CSS層疊樣式表< /h3> < /div> | 父元素標(biāo)簽 子元素標(biāo)簽{ 樣式屬性 } |
子選擇器 | div>ul{color:blue;} < div> < ul> < li>測(cè)試1 < ol> < li>嵌套元素< /li> < li>嵌套元素< /li> < li>嵌套元素< /li> < li>嵌套元素< /li> < /ol> < /li> < li>測(cè)試1< /li> < li>測(cè)試1< /li> < /ul> < /div> | 父元素標(biāo)簽名>子元素名{ 樣式屬性 } |
339.引入樣式的三種方式及其優(yōu)先級(jí)別
三種引用方式:
1. 外部樣式表(存放.css文件中)
不需要style標(biāo)簽
< link rel=”stylesheet” href=”引用文件地址” />
2. 嵌入式樣式表
< style type=“text/css”>
p{color:red;}
< /style>
3.內(nèi)聯(lián)樣式
標(biāo)簽屬性名為style
< p style=“color:red;”>< /p>
優(yōu)先級(jí)級(jí)別:內(nèi)聯(lián)定義最高、內(nèi)部CSS次之、外部CSS優(yōu)先級(jí)最低。。
340.盒子模型
盒子模型類似于生活中的盒子,具有4個(gè)屬性,外邊距,內(nèi)邊距,邊框,內(nèi)容。
外邊距:margin,用于設(shè)置元素和其他元素之間的距離。
內(nèi)邊距:padding,用于設(shè)置元素內(nèi)容和邊框之間的距離。
邊框:border,用于設(shè)置元素邊框粗細(xì),顏色,線型。
內(nèi)容:width,height,用于設(shè)置元素內(nèi)容顯示的大小。
例如:
<style> body{ margin: 0; /*取消body默認(rèn)的外邊距*/ } #img1{ width:200px; /*設(shè)置圖片的寬度*/ border: 2px solid black; /*設(shè)置圖片邊框*/ margin: 5px; /*設(shè)置圖片外邊距(表示該圖片與其他圖片的距離為5px)*/ padding:10px; /*設(shè)置圖片與邊框之間的距離*/ } #img2{ height: 200px; /* 設(shè)置圖片的高度*/ border: 2px solid black; /*設(shè)置圖片的邊框*/ margin: 5px; /*設(shè)置圖片外邊距*/ padding: 20px; /*設(shè)置圖片與邊框之間的距離*/ } </style> <img id="img1" src="img/2.jpg" /> <img id="img2" src="img/lss.jpg" />
341.JavaScript語言及其特點(diǎn)
Javascript一種基于對(duì)象(object-based)和事件驅(qū)動(dòng)(Event Driven)的簡(jiǎn)單的并具有安全性能的腳本語言。特點(diǎn):
解釋性: JavaScript不同于一些編譯性的程序語言,例如C、C++等,它是一種解釋性的程序語言,它的源代碼不需要經(jīng)過編譯,而直接在瀏覽器中運(yùn)行時(shí)被解釋。
基于對(duì)象:?JavaScript是一種基于對(duì)象的語言。這意味著它能運(yùn)用自己已經(jīng)創(chuàng)建的對(duì)象。因此,許多功能可以來自于腳本環(huán)境中對(duì)象的方法與腳本的相互作用。
事件驅(qū)動(dòng): JavaScript可以直接對(duì)用戶或客戶輸入做出響應(yīng),無須經(jīng)過Web服務(wù)程序。它對(duì)用戶的響應(yīng),是以事件驅(qū)動(dòng)的方式進(jìn)行的。所謂事件驅(qū)動(dòng),就是指在主頁中執(zhí)行了某種操作所產(chǎn)生的動(dòng)作,此動(dòng)作稱為“事件”。比如按下鼠標(biāo)、移動(dòng)窗口、選擇菜單等都可以視為事件。當(dāng)事件發(fā)生后,可能會(huì)引起相應(yīng)的事件響應(yīng)。
跨平臺(tái):JavaScript依賴于瀏覽器本身,與操作環(huán)境無關(guān),只要能運(yùn)行瀏覽器的計(jì)算機(jī),并支持JavaScript的瀏覽器就可正確執(zhí)行。
342.JavaScript常用數(shù)據(jù)類型有哪些
1、數(shù)值型(Number):整數(shù)和浮點(diǎn)數(shù)統(tǒng)稱為數(shù)值。例如85或3.1415926等。
2、字符串型(String):由0個(gè),1個(gè)或多個(gè)字符組成的序列。在JavaScript中,用雙引號(hào)或單引號(hào)括起來表示,如“您好”、‘學(xué)習(xí)JavaScript’等。 不區(qū)分單引號(hào)、雙引號(hào)。
3、邏輯(布爾)型(Boolean):用true或false來表示。
4、空(null)值(Null):表示沒有值,用于定義空的或不存在的引用。
要注意,空值不等同于空字符串""或0。
5、未定義(Undefined)值:它也是一個(gè)保留字。表示變量雖然已經(jīng)聲明,但卻沒有賦值。
除了以上五種基本的數(shù)據(jù)類型之外,JavaScript還支持復(fù)合數(shù)據(jù)類型,包括對(duì)象和數(shù)組兩種。
343.html語法中哪條命令用于使一行文本折行,而不是插入一個(gè)新的段落? (B)
A. | < TD> |
B. | < BR> |
C. | < P> |
D. | < H1> |
分析:
A < td>定義標(biāo)準(zhǔn)表格
C < p>表示文本一個(gè)段落
D < h1>表示對(duì)文本標(biāo)題進(jìn)行強(qiáng)調(diào)的一種標(biāo)簽
|
344.Ajax的優(yōu)點(diǎn)和缺點(diǎn)
優(yōu)點(diǎn):減輕服務(wù)器的負(fù)擔(dān),按需取數(shù)據(jù),最大程度的減少冗余請(qǐng)求,局部刷新頁面,減少用戶心理和實(shí)際的等待時(shí)間,帶來更好的用戶體驗(yàn),基于xml標(biāo)準(zhǔn)化,并被廣泛支持,不需安裝插件等,進(jìn)一步促進(jìn)頁面和數(shù)據(jù)的分離
缺點(diǎn):AJAX大量的使用了javascript和ajax引擎,這些取決于瀏覽器的支持.在編寫的時(shí)候考慮對(duì)瀏覽器的兼容性.
345.怎樣防止表單刷新重復(fù)提交問題?(說出思路即可)
JS腳本方式:
第一種:定義全局變量,在form提交前判斷是否已有提交過
<script> var checkSubmitFlg = false; function checkSubmit(){ if(checkSubmitFlg == true){ return false; } checkSubmitFlg = true; return true; } </script> <form action="" onsubmit="return checkSubmit();"> </form>
第二種:?jiǎn)螕籼峤话粹o后,立刻禁用改按鈕
第三種:?jiǎn)螕籼峤话粹o后,彈出屏蔽層,防止用戶第二次點(diǎn)擊
346.JQuery.get()和JQuery.ajax()方法之間的區(qū)別是什么?
JQuery.ajax()是對(duì)原生的javaScript的ajax的封裝,簡(jiǎn)化了ajax的步驟,用戶可用JQuery.ajax()發(fā)送get或者post方式請(qǐng)求,Jquery.get()是對(duì)ajax的get方式的封裝,只能發(fā)送get方式的請(qǐng)求。
347.Jquery里的緩存問題如何解決?例如($.ajax()以及$.get())
$.ajax()請(qǐng)求時(shí)候加上cache:false的參數(shù),如:
$.ajax({ type : "get", url : "XX", dataType : "json", cache:false, success : function(json) { } });
$.get()請(qǐng)求時(shí)候加上時(shí)間,如:
$.get("url","data"+new Date(),function(data){});
348.Javascript是面向?qū)ο蟮?,怎么體現(xiàn)Javascript的繼承關(guān)系?
Javascript里面沒有像java那樣的繼承,javascript中的繼承機(jī)制僅僅是靠模擬的,可以使用prototype原型來實(shí)現(xiàn)
349.Javascript的有幾種種變量。變量范圍有什么不同?
可以分為三種
1、原生類型(string,number,boolean)
2、對(duì)象(Date,Array)
3、特殊類型(var vara;(只什么沒有定義),var varb = null;(定義一個(gè)變量并賦值為null))
350.Js如何獲取頁面的dom對(duì)象
1、直接獲取
//1.1 -- id方式獲取
var varid = document.getElementById("unameid");
//1.2 -- name獲取(獲取的是數(shù)組對(duì)象)
var varname = document.getElementsByName("sex");
//1.3 -- 元素獲取(獲取的是數(shù)組對(duì)象)
var varinput = document.getElementsByTagName("input");
2、間接方式獲取
//2.1 父子關(guān)系 --childNodes
var varchilds = document.getElementById("div01").childNodes;
//2.2 子父關(guān)系--parentNode
var varfather2 = document.getElementById("unameid").parentNode;
//2.3 兄弟之間相互獲取 nextSibling:下一個(gè)節(jié)點(diǎn) previousSibling:上一個(gè)節(jié)點(diǎn)
351.Servlet API中forward() 與redirect()的區(qū)別?
答:為實(shí)現(xiàn)程序的模塊化,就需要保證在不同的Servlet之間可以相互跳轉(zhuǎn),而Servlet中主要有兩種實(shí)現(xiàn)跳轉(zhuǎn)的方式:FORWARD方式與redirect方式。?
Forward() : 是服務(wù)器內(nèi)部的重定向,服務(wù)器直接訪問目標(biāo)地址的URL,把那個(gè)URL的響應(yīng)內(nèi)容讀取出來,而客戶端并不知道,因此在客戶端瀏覽器的地址欄里不會(huì)顯示跳轉(zhuǎn)后的地址,還是原來的地址。由于在整個(gè)定向的過程中用的是同一個(gè)Request,因此FORWARD會(huì)將Request的信息帶到被定向的JSP或Servlet中使用。
Redirect():則是客戶端的重定向,是完全的跳轉(zhuǎn),即客戶端瀏覽器會(huì)獲取跳轉(zhuǎn)后的地址,然后重新發(fā)送請(qǐng)求,因此瀏覽器中會(huì)顯示跳轉(zhuǎn)后的地址。同時(shí),由于這種方式比FORWARD方式多了一次網(wǎng)絡(luò)請(qǐng)求,因此其效率低于FORWARD方式,需要注意到的是,客戶端的重定向可以通過設(shè)置特定的HTTP 頭或?qū)慗avaScript腳本來實(shí)現(xiàn)。
鑒于以上的區(qū)別,一般當(dāng)FORWARD方式可以滿足需求時(shí),盡可能的使用FORWARD方式。但在有些情況下,例如,需要跳轉(zhuǎn)到一個(gè)其他服務(wù)器上的資源時(shí),則必須使用redirect 方式。
352.Session域和request域什么區(qū)別?
作用域:存放數(shù)據(jù),獲取數(shù)據(jù)(傳遞數(shù)據(jù))
有效的作用域:生命周期,作用范圍
httpServeltRequest:
生命周期:一次請(qǐng)求之間
作用范圍:所有被請(qǐng)求轉(zhuǎn)發(fā)過的servlet都能獲取到
httpSession:
生命周期:一次會(huì)話
作用范圍:所有的servlet都可以獲取到
servletContex:
生命周期:從項(xiàng)目開始運(yùn)行到服務(wù)器關(guān)閉
作用范圍:所有的servlet都可以獲取到?
作用域如何選用?
httpServeltRequest:和當(dāng)前請(qǐng)求有關(guān)的信息
httpSession:和當(dāng)前用戶有關(guān)的信息
servletContex:訪問量比較大,不易更改
353.頁面中有一個(gè)命名為bankNo的下拉列表,寫js腳本獲取當(dāng)前選項(xiàng)的索引值,如果用jquery如何獲取
var a = document.getElementsByName("bankNo")[0].value;
var b = $("select[name=bankNo]").val();
354.寫出要求11位數(shù)字的正則表達(dá)式
^[1-9]\d{10}$
355.分別獲取指定name、Id的javascript對(duì)象,如果用jquey如何獲取
js: id--document.getElementById("id"); name--document.getElementsByName("name"); jquery id--$("#id"); name--$("元素名稱[name="name值"]");
356.一個(gè)頁面有兩個(gè)form,如何獲取第一個(gè)form
用id方式獲?。籨ocument.getElementById("id");
357.如何設(shè)置一個(gè)層的可見/隱藏
可見 : document.getElementById("divid").style.display = "block";
隱藏 : document.getElementById("divid").style.display = "none";
358.描述JSP中動(dòng)態(tài)INCLUDE與靜態(tài)INCLUDE的區(qū)別?
動(dòng)態(tài)導(dǎo)入
1、會(huì)將多個(gè)jsp頁面分別再編寫成java文件,編譯成class文件
2、jsp文件中允許有相同的變量名,每個(gè)頁面互不影響
3、當(dāng)java代碼比較多優(yōu)先選用動(dòng)態(tài)導(dǎo)入
4、效率相對(duì)較低,耦合性低
靜態(tài)導(dǎo)入
1、會(huì)將多個(gè)jsp頁面合成一個(gè)jsp頁面,再編寫成java文件,編譯成class文件
2、jsp文件中不允許有相同的變量名
3、當(dāng)java代碼比較少或者沒有java代碼是優(yōu)先選用靜態(tài)導(dǎo)入
4、效率相對(duì)較高,耦合性高
359.列舉JSP的內(nèi)置對(duì)象及方法
request表示HttpServletRequest對(duì)象。它包含了有關(guān)瀏覽器請(qǐng)求的信息,并且提供了幾個(gè)用于獲取cookie,?header,?和session數(shù)據(jù)的有用的方法。?
response表示HttpServletResponse對(duì)象,并提供了幾個(gè)用于設(shè)置送回?瀏覽器的響應(yīng)的方法(如cookies,頭信息等)?
out對(duì)象是javax.jsp.JspWriter的一個(gè)實(shí)例,提供了幾個(gè)方法使你能用于向?yàn)g覽器回送輸出結(jié)果
pageContext表示一個(gè)javax.servlejt.sp.PageContext對(duì)象。它是用于方便存取各種范圍的名字空間、servlet相關(guān)的對(duì)象的API,并且包裝了通用的servlet相關(guān)功能的方法。?
session表示一個(gè)請(qǐng)求的javax.servlet.http.HttpSession對(duì)象。Session可以存貯用戶的狀態(tài)信息
applicaton?表示一個(gè)javax.servle.ServletContext對(duì)象。這有助于查找有關(guān)servlet引擎和servlet環(huán)境的信息?
config表示一個(gè)javax.servlet.ServletConfig對(duì)象。該對(duì)象用于存取servlet實(shí)例的初始化參數(shù)。?
page表示從該頁面產(chǎn)生的一個(gè)servlet實(shí)例
Exception異常
360.列舉jsp的四大作用域
page、request、session、application
361.html和xhtml的區(qū)別是什么?
HTML與XHTML之間的差別,粗略可以分為兩大類比較:一個(gè)是功能上的差別,另外是書寫習(xí)慣的差別。關(guān)于功能上的差別,主要是XHTML可兼容各大瀏覽器、手機(jī)以及PDA,并且瀏覽器也能快速正確地編譯網(wǎng)頁。
因?yàn)閄HTML的語法較為嚴(yán)謹(jǐn), 所以如果你是習(xí)慣松散結(jié)構(gòu)的HTML編寫者,那需要特別注意XHTML的規(guī)則。但也不必太過擔(dān)心,因?yàn)閄HTML的規(guī)則并不太難。下面列出了幾條容易犯的錯(cuò)誤,供大家引用。
1:所有標(biāo)簽都必須小寫
在XHTML中,所有的標(biāo)簽都必須小寫,不能大小寫穿插其中,也不能全部都是大寫。看一個(gè)例子。
錯(cuò)誤:< Head>< /Head>< Body>< /Body>
正確:< head>< /head>< body>< /body>
2:標(biāo)簽必須成雙成對(duì)
像是< p>...< /p>、< a>...< /a>、< div>...< /div>標(biāo)簽等,當(dāng)出現(xiàn)一個(gè)標(biāo)簽時(shí),必須要有對(duì)應(yīng)的結(jié)束標(biāo)簽,缺一不可,就像在任何程序語言中的括號(hào)一樣。
錯(cuò)誤:大家好< p>我是muki
正確:< p>大家好< /p>< p>我是muki< /p>
3:標(biāo)簽順序必須正確
標(biāo)簽由外到內(nèi),一層層包覆著,所以假設(shè)你先寫div后寫h1,結(jié)尾就要先寫h1后寫div。只要記住一個(gè)原則“先進(jìn)后出”,先彈出的標(biāo)簽要后結(jié)尾。
錯(cuò)誤:< div>< h1>大家好< /div>< /h1>
正確:< div>< h1>大家好< /h1>< /div>
4:所有屬性都必須使用雙引號(hào)
在XHTML 1.0中規(guī)定連單引號(hào)也不能使用,所以全程都得用雙引號(hào)。
錯(cuò)誤:< div style=font-size:11px>hello< /div>
正確:< div style="font-size:11px">hello< /div
5:不允許使用target="_blank"
從XHTML 1.1開始全面禁止target屬性,如果想要有開新窗口的功能,就必須改寫為rel="external",并搭配JavaScript實(shí)現(xiàn)此效果。
錯(cuò)誤:< a target="_blank">MUKI space< /a>
正確:< a rel="external">MUKI space< /a>
362.你做的頁面用哪些瀏覽器測(cè)試過?這些測(cè)試的內(nèi)核分別是什么?
1、Trident內(nèi)核代表產(chǎn)品Internet Explorer,又稱其為IE內(nèi)核。?Trident(又稱為MSHTML),是微軟開發(fā)的一種排版引擎。使用Trident渲染引擎的瀏覽器包括:IE、傲游、世界之窗瀏覽器、Avant、騰訊TT、Netscape 8、NetCaptor、Sleipnir、GOSURF、GreenBrowser和KKman等。?
2、Gecko內(nèi)核代表作品Mozilla?,FirefoxGecko是一套開放源代碼的、以C++編寫的網(wǎng)頁排版引擎。Gecko是最流行的排版引擎之一,僅次于Trident。使用它的最著名瀏覽器有Firefox、Netscape6至9
3、WebKit內(nèi)核代表作品Safari、Chromewebkit?, 是一個(gè)開源項(xiàng)目,包含了來自KDE項(xiàng)目和蘋果公司的一些組件,主要用于Mac OS系統(tǒng),它的特點(diǎn)在于源碼結(jié)構(gòu)清晰、渲染速度極快。缺點(diǎn)是對(duì)網(wǎng)頁代碼的兼容性不高,導(dǎo)致一些編寫不標(biāo)準(zhǔn)的網(wǎng)頁無法正常顯示。主要代表作品有Safari和Google的瀏覽器Chrome。?
4、Presto內(nèi)核代表作品OperaPresto,?是由Opera Software開發(fā)的瀏覽器排版引擎,供Opera 7.0及以上使用。它取代了舊版Opera 4至6版本使用的Elektra排版引擎,包括加入動(dòng)態(tài)功能,例如網(wǎng)頁或其部分可隨著DOM及Script語法的事件而重新排版。
363.你遇到了哪些瀏覽器的兼容性問題?怎么解決的?
答:因?yàn)椴煌臑g覽器對(duì)同一段代碼有不同的解析,造成頁面顯示效果不統(tǒng)一的情況;這是我們常見的兼容性問題。
解決方法:
1、針對(duì)不同的瀏覽器寫不同的代碼
2、使用jquery屏蔽瀏覽器差異
遇到不同的兼容問題,需要針對(duì)前端進(jìn)行兼容適配;
364.你知道的常用的js庫(kù)有哪些?
1.moment.js
舉個(gè)例子:
用js轉(zhuǎn)換時(shí)間戳為日期
let date = new Date(1437925575663); let year = date.getFullYear() + '-'; let month = ( date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1 ) + '-'; let day = date.getDate(); ... return year + month + day; 用moment.js return moment(1437925575663).format('YYYY-MM-DD HH:mm:ss')
2.chart.js
繪制簡(jiǎn)單的柱狀圖,曲線圖,蛛網(wǎng)圖,環(huán)形圖,餅圖等完全夠用,用法比較簡(jiǎn)單。
3.D3.js
功能太強(qiáng)大了,看首頁就知道了,感覺沒有什么圖d3繪不出來的。
4.Rx.js
很好的解決了異步和事件組合的問題。
5.lodash.js
365.Js中的三種彈出式消息提醒(警告窗口、確認(rèn)窗口、信息輸入窗口)的命令是什么?
alter(),confirm(),prompt()
366.談?wù)刯s的閉包
答:閉包無處不在,比如:jQuery、zepto的核心代碼都包含在一個(gè)大的閉包中,所以下面我先寫一個(gè)最簡(jiǎn)單最原始的閉包,以便讓你在大腦里產(chǎn)生閉包的畫面:
function A(){ function B(){ console.log("Hello Closure!"); } return B; } var C = A(); C();//Hello Closure!
這是最簡(jiǎn)單的閉包。
有了初步認(rèn)識(shí)后,我們簡(jiǎn)單分析一下它和普通函數(shù)有什么不同,上面代碼翻譯成自然語言如下:
(1)定義普通函數(shù) A
(2)在 A 中定義普通函數(shù) B
(3)在 A 中返回 B
(4)執(zhí)行 A, 并把 A 的返回結(jié)果賦值給變量 C
(5)執(zhí)行 C
把這5步操作總結(jié)成一句話就是:
函數(shù)A的內(nèi)部函數(shù)B被函數(shù)A外的一個(gè)變量 c 引用。
把這句話再加工一下就變成了閉包的定義:
當(dāng)一個(gè)內(nèi)部函數(shù)被其外部函數(shù)之外的變量引用時(shí),就形成了一個(gè)閉包。
因此,當(dāng)你執(zhí)行上述5步操作時(shí),就已經(jīng)定義了一個(gè)閉包!
這就是閉包。
367.寫一段js,遍歷所有的li,將每個(gè)li的內(nèi)容逐個(gè)alert出來
<body> <ul> <li>張三:123</li> <li>李四:456</li> <li>王五:789</li> <li>趙六:147</li> <ul> <body>
function test(){ var varli = document.getElementsByTagName("li"); for (var i=0;i<varli.length;i++) { alert(varli[i].innerText); } }
368.頁面上如何用JavaScript對(duì)多個(gè)checkbox全選
//全選 function checkAll(){ //獲取復(fù)選框?qū)ο?-數(shù)組對(duì)象 var varcheck = document.getElementsByName("name"); //alert(varcheck.length); //遍歷for for(var i=0;i<varcheck.length;i++){ varcheck[i].checked = true; } }
369.寫一個(gè)簡(jiǎn)單的JQuery的ajax
<script type="text/javascript" src="js/jquery-1.9.1.js" charset="utf-8"></script> <script type="text/javascript"> function testJqAjax(){ //url :請(qǐng)求地址 //type :請(qǐng)求的方式 get/post //data :請(qǐng)求的參數(shù)(json/String) //cache:true(走緩存 ) false(不走緩存) //result:當(dāng)ajax發(fā)送成功后會(huì)調(diào)用success后面的函數(shù),result:相當(dāng)于形參,返回的數(shù)據(jù) //async:是否為異步請(qǐng)求 默認(rèn)true異步 , false同步 $.ajax({ url:"TestJqAjax", type:"get", /* data:"uname=zhangsan&realname=張三豐", */ data:{uname:"zhangsan",realname:"張三豐"}, cache:false, async:false, success:function(result){ alert(result); } }); } //ajax的get方式的請(qǐng)求 function jqAjaxGet(){ //url,[data],[callback](當(dāng)ajax發(fā)送成功后調(diào)用的函數(shù)) $.get("TestJqAjax",{uname:"zhangsan",realname:"張三豐"},function(result){ alert(result); }); } function jqAjaxPost() { //url,[data],[callback](當(dāng)ajax發(fā)送成功后調(diào)用的函數(shù)) $.post("TestJqAjax",{uname:"zhangsan",realname:"張三豐"},function(result){ alert(result); }); } </script>
370.Js截取字符串a(chǎn)bcdefg的efg
function test2(){ var str = "abcdefg"; var substr = str.substring(4); alert(substr); }
371.http的請(qǐng)求頭信息包含了什么?
請(qǐng)求行(請(qǐng)求方式,資源路徑,協(xié)議和協(xié)議版本號(hào))
若干請(qǐng)求頭
請(qǐng)求實(shí)體內(nèi)容
372.http的響應(yīng)碼200,404,302,500表示的含義分別是?
200 - 確定??蛻舳苏?qǐng)求已成功
302 - 臨時(shí)移動(dòng)轉(zhuǎn)移,請(qǐng)求的內(nèi)容已臨時(shí)移動(dòng)新的位置
404 - 未找到文件或目錄
500 - 服務(wù)器內(nèi)部錯(cuò)誤
373.Servlet中request對(duì)象的方法有?
/獲取網(wǎng)絡(luò)信息 private void getNet(HttpServletRequest req, HttpServletResponse resp) { System.out.println("TestHttpRequest.getNet(獲取客戶端的ip):"+req.getRemoteAddr()); System.out.println("TestHttpRequest.getNet(獲取客戶端的端口):"+req.getRemotePort()); System.out.println("TestHttpRequest.getNet(獲取服務(wù)器的ip):"+req.getLocalAddr()); System.out.println("TestHttpRequest.getNet(獲取服務(wù)器的端口):"+req.getLocalPort()); } //獲取實(shí)體內(nèi)容 private void getContent(HttpServletRequest req, HttpServletResponse resp) { //獲取單條信息 String uname = req.getParameter("uname"); //獲取多條信息,數(shù)組格式 String[] favs = req.getParameterValues("fav"); //遍歷數(shù)組 //判斷 if(favs!=null&&favs.length>0){ for (int i = 0; i < favs.length; i++) { System.out.println("TestHttpRequest.getContent(fav):"+favs[i]); } } String un = req.getParameter("un"); System.out.println("TestHttpRequest.getContent():"+uname+"--"+favs+"--"+un); } //獲取請(qǐng)求頭信息 private void getHeads(HttpServletRequest req, HttpServletResponse resp) { //獲取單條頭信息 //System.out.println("TestHttpRequest.getHeads(獲取請(qǐng)求頭信息-瀏覽器頭信息):"+req.getHeader("User-Agent")); //獲取所有頭信息--返回枚舉類型 Enumeration strHeads = req.getHeaderNames(); //遍歷枚舉類型 while (strHeads.hasMoreElements()) { String strhead = (String) strHeads.nextElement(); System.out.println("TestHttpRequest.getHeads(獲取頭信息):"+req.getHeader(strhead)); } } //獲取請(qǐng)求行的信息 private void getLines(HttpServletRequest req, HttpServletResponse resp) { System.out.println("TestHttpRequest.getLines(請(qǐng)求方式***):"+req.getMethod()); System.out.println("TestHttpRequest.getLines(資源路徑):"+req.getRequestURI()); System.out.println("TestHttpRequest.getLines(地址):"+req.getRequestURL()); System.out.println("TestHttpRequest.getLines(協(xié)議):"+req.getScheme()); System.out.println("TestHttpRequest.getLines(協(xié)議的版本號(hào)):"+req.getProtocol()); System.out.println("TestHttpRequest.getLines(獲取參數(shù)信息):"+req.getQueryString()); System.out.println("TestHttpRequest.getLines(項(xiàng)目名稱***):"+req.getContextPath()); }
374.Javascript的常用對(duì)象有哪些
常用對(duì)象包括日期對(duì)象Date,字符串對(duì)象String,數(shù)組對(duì)象Array
//獲取并顯示系統(tǒng)當(dāng)前時(shí)間
function testDate(){ var date = new Date(); var fmtDate = date.getFullYear()+"-"+(date.getMonth()+1)+ "-"+date.getDate()+"-"+date.getHours() +":"+date.getMinutes()+":"+date.getSeconds(); alert(fmtDate); }
//獲取出’sxt’的下標(biāo)位置
function testString(){ var str = 'welcome to beijingsxt'; alert(str.indexOf('sxt')); }
//遍歷數(shù)組信息
function testArray(){ var arr = new Array('a',123,'c',true,'e'); for(var item in arr){ document.write(arr[item]+" "); } }
375.DOM和BOM及其關(guān)系
BOM瀏覽器對(duì)象模型,由一系列對(duì)象組成,是訪問、控制、修改瀏覽器的屬性的方法。
DOM文檔對(duì)象模型,由一系列對(duì)象組成,是訪問、檢索、修改XHTML文檔內(nèi)容與結(jié)構(gòu)的標(biāo)準(zhǔn)方法。
關(guān)系:
–BOM描述了與瀏覽器進(jìn)行交互的方法和接口
–DOM描述了處理網(wǎng)頁內(nèi)容的方法和接口
–DOM屬于BOM的一個(gè)屬性
376.JavaScript中獲取某個(gè)元素的三種方式JavaScript中的三種彈出式消息提醒命令是什么?
window.alert() 顯示一個(gè)提示信息
window.confirm() 顯示一個(gè)帶有提示信息、確定和取消按鈕的對(duì)話框
window.prompt() 顯示可提示用戶輸入的對(duì)話框
setTimeout與setInterval 的區(qū)別
setTimeout和setInterval的語法相同。它們都有兩個(gè)參數(shù),一個(gè)是將要執(zhí)行的代碼字符串,還有一個(gè)是以毫秒為單位的時(shí)間間隔,當(dāng)過了那個(gè)時(shí)間段之后就將執(zhí)行那段代碼。
不過這兩個(gè)函數(shù)還是有區(qū)別的,setInterval在執(zhí)行完一次代碼之后,經(jīng)過了那個(gè)固定的時(shí)間間隔,它還會(huì)自動(dòng)重復(fù)執(zhí)行代碼,而setTimeout只執(zhí)行一次那段代碼。
window.setTimeout("function",time);//設(shè)置一個(gè)超時(shí)對(duì)象,只執(zhí)行一次,無周期
window.setInterval("function",time);//設(shè)置一個(gè)超時(shí)對(duì)象,周期='交互時(shí)間'
377.JavaScript操作CSS的兩種方式
第一種方式:操作元素的屬性(對(duì)象.style.樣式名=樣式值;)
//改變直接樣式
var child2 = document.createElement("div"); child2.innerHTML = "child2"; child2.style.fontWeight = "bold"; parent.appendChild(child2);
第二種方式:操作元素的類(對(duì)象.className=類;)
例如:
var parent = document.getElementById("parent"); //改變className var child0 = document.createElement("div"); child0.innerHTML = "child0"; child0.className = "newDiv"; parent.appendChild(child0);
378.靜態(tài)網(wǎng)頁和動(dòng)態(tài)網(wǎng)頁的聯(lián)系和區(qū)別
聯(lián)系:
1)靜態(tài)網(wǎng)頁是網(wǎng)站建設(shè)的基礎(chǔ),靜態(tài)網(wǎng)頁和動(dòng)態(tài)網(wǎng)頁都要使用到HTMl語言。
2)靜態(tài)網(wǎng)頁是相對(duì)于動(dòng)態(tài)網(wǎng)頁而言,指沒有后臺(tái)數(shù)據(jù)庫(kù)、不含程序和不可交互的網(wǎng)頁、是標(biāo)準(zhǔn)的HTML文件,它的文件擴(kuò)展名是.htm或.html。你編的是什么它顯示的就是什么、不會(huì)有任何改變。
3)靜態(tài)網(wǎng)頁和動(dòng)態(tài)網(wǎng)頁之間并不矛盾,為了網(wǎng)站適應(yīng)搜索引擎檢索的需要,動(dòng)態(tài)網(wǎng)站可以采用靜動(dòng)結(jié)合的原則,適合采用動(dòng)態(tài)網(wǎng)頁的地方用動(dòng)態(tài)網(wǎng)頁,如果必要使用靜態(tài)網(wǎng)頁,則可以考慮用靜態(tài)網(wǎng)頁的方法來實(shí)現(xiàn),在同一個(gè)網(wǎng)站上,動(dòng)態(tài)網(wǎng)頁內(nèi)容和靜態(tài)網(wǎng)頁內(nèi)容同時(shí)存在也是很常見的事情。
區(qū)別:
1)程序是否在服務(wù)器端運(yùn)行,是重要標(biāo)志。在服務(wù)器端運(yùn)行的程序、網(wǎng)頁、組件,屬于動(dòng)態(tài)網(wǎng)頁,它們會(huì)隨不同客戶、不同時(shí)間,返回不同的網(wǎng)頁,例如ASP、PHP、JSP、ASP.net、CGI等。運(yùn)行于客戶端的程序、網(wǎng)頁、插件、組件,屬于靜態(tài)網(wǎng)頁,例如html頁、Flash、javascript、VBscript等等,它們是永遠(yuǎn)不變的。
2)編程技術(shù)不同。靜態(tài)網(wǎng)頁和動(dòng)態(tài)網(wǎng)頁主要根據(jù)網(wǎng)頁制作的語言來區(qū)分。靜態(tài)網(wǎng)頁使用語言:HTML。 動(dòng)態(tài)網(wǎng)頁使用語言:HTML+ASP 或 HTML+PHP 或 HTML+JSP 等其它網(wǎng)站動(dòng)態(tài)語言。
3)被搜索引擎收錄情況不同。由于編程技術(shù)不容,靜態(tài)網(wǎng)頁是純粹HTML格式的網(wǎng)頁,頁面內(nèi)容穩(wěn)定,不論是網(wǎng)頁是否被訪問,頁面都被保存在網(wǎng)站服務(wù)器上,很容易被搜索引擎收錄。而動(dòng)態(tài)網(wǎng)頁的內(nèi)容是當(dāng)用戶點(diǎn)擊請(qǐng)求時(shí)才從數(shù)據(jù)庫(kù)中調(diào)出返回給用戶一個(gè)網(wǎng)頁的內(nèi)容,并不是存放在服務(wù)器上的獨(dú)立文件,相比較于靜態(tài)網(wǎng)頁而言,動(dòng)態(tài)網(wǎng)頁很難被搜索引擎收錄。
4)用戶訪問速度不同。用戶訪問動(dòng)態(tài)網(wǎng)頁時(shí),網(wǎng)頁在獲得搜索指令后經(jīng)過數(shù)據(jù)庫(kù)的調(diào)查匹配,再將與指令相符的內(nèi)容傳遞給服務(wù)器,通過服務(wù)器的編譯將網(wǎng)頁編譯成標(biāo)準(zhǔn)的HTML代碼,從而傳遞給用戶瀏覽器,多個(gè)讀取過程大大降低了用戶的訪問速度。而靜態(tài)網(wǎng)頁不同,由于網(wǎng)頁內(nèi)容直接存取在服務(wù)器上,省去了服務(wù)器的編譯過程,用戶訪問網(wǎng)頁速度很快。
5)制作和后期維護(hù)工作量不同。動(dòng)態(tài)網(wǎng)頁的設(shè)計(jì)以數(shù)據(jù)庫(kù)技術(shù)為基礎(chǔ),可以實(shí)現(xiàn)多種功能,降低了網(wǎng)站維護(hù)的工作量。而靜態(tài)網(wǎng)頁由于沒有數(shù)據(jù)庫(kù)的支持,網(wǎng)頁內(nèi)容更改時(shí)需要直接修改代碼,在網(wǎng)站內(nèi)容制作和維護(hù)中,所需的工作量更大。動(dòng)態(tài)網(wǎng)頁與靜態(tài)網(wǎng)頁各有特點(diǎn),網(wǎng)站設(shè)計(jì)師在網(wǎng)頁設(shè)計(jì)時(shí),主要根據(jù)網(wǎng)站的功能需求和網(wǎng)站內(nèi)容多少選擇不同網(wǎng)頁。如,網(wǎng)站包含信息量太大時(shí),就需要選擇動(dòng)態(tài)網(wǎng)頁,反之,則選擇靜態(tài)網(wǎng)頁。
379.JSP/ASP/PHP的比較
ASP(Active Server Pages),JSP(JavaServer Pages),PHP(Hypertext Preprocessor)是目前主流的三種動(dòng)態(tài)網(wǎng)頁語言。
ASP是微軟(Microsoft)所開發(fā)的一種后臺(tái)腳本語言,它的語法和Visual BASIC類似,可以像SSI(Server Side Include)那樣把后臺(tái)腳本代碼內(nèi)嵌到HTML頁面中。雖然ASP簡(jiǎn)單易用,但是它自身存在著許多缺陷,最重要的就是安全性問題。
PHP是一種跨平臺(tái)的服務(wù)器端的嵌入式腳本語言。它大量地借用C,Java和Perl語言的語法, 并耦合PHP自己的特性,使WEB開發(fā)者能夠快速地寫出動(dòng)態(tài)產(chǎn)生頁面。它支持目前絕大多數(shù)數(shù)據(jù)庫(kù)。
JSP是一個(gè)簡(jiǎn)化的Servlet,它是由Sun公司倡導(dǎo)、許多公司參與一起建立的一種動(dòng)態(tài)網(wǎng)頁技術(shù)標(biāo)準(zhǔn)。JSP技術(shù)有點(diǎn)類似ASP技術(shù),它是在傳統(tǒng)的網(wǎng)頁HTML中插入Java程序段和JSP標(biāo)記(tag),從而形成JSP文件,后綴名為(*.jsp)。 用JSP開發(fā)的Web應(yīng)用是跨平臺(tái)的,既能在Linux下運(yùn)行,也能在其他操作系統(tǒng)上運(yùn)行。
ASP優(yōu)點(diǎn): 無需編譯、易于生成、獨(dú)立于瀏覽器、面向?qū)ο蟆⑴c任何ActiveX scripting 語言兼容、源程序碼不會(huì)外漏。
缺點(diǎn):
1)Windows本身的所有問題都會(huì)一成不變的也累加到了它的身上。安全性、穩(wěn)定性、跨平臺(tái)性都會(huì)因?yàn)榕cNT的捆綁而顯現(xiàn)出來。
2)ASP由于使用了COM組件所以它會(huì)變的十分強(qiáng)大,但是這樣的強(qiáng)大由于Windows NT系統(tǒng)最初的設(shè)計(jì)問題而會(huì)引發(fā)大量的安全問題。只要在這樣的組件或是操作中一不注意,那么外部攻擊就可以取得相當(dāng)高的權(quán)限而導(dǎo)致網(wǎng)站癱瘓或者數(shù)據(jù)丟失。
3)還無法完全實(shí)現(xiàn)一些企業(yè)級(jí)的功能:完全的集群、負(fù)載均橫。
PHP優(yōu)點(diǎn):
1)一種能快速學(xué)習(xí)、跨平臺(tái)、有良好數(shù)據(jù)庫(kù)交互能力的開發(fā)語言。
2)簡(jiǎn)單輕便,易學(xué)易用。
3 ) 與Apache及其它擴(kuò)展庫(kù)結(jié)合緊密。
缺點(diǎn):
1 ) 數(shù)據(jù)庫(kù)支持的極大變化。
2 ) 不適合應(yīng)用于大型電子商務(wù)站點(diǎn)。
JSP優(yōu)點(diǎn):
1 ) 一處編寫隨處運(yùn)行。
2 ) 系統(tǒng)的多臺(tái)平支持。
3 ) 強(qiáng)大的的可伸縮性。
4 ) 多樣化和功能強(qiáng)大的開發(fā)工具支持。
缺點(diǎn):
1) 與ASP一樣,Java的一些優(yōu)勢(shì)正是它致命的問題所在。
2 ) 開發(fā)速度慢
380.CGI/Servlet/JSP的比較
CGI(Common Gateway Interface),通用網(wǎng)關(guān)接口,是一種根據(jù)請(qǐng)求信息動(dòng)態(tài)產(chǎn)生回應(yīng)內(nèi)容的技術(shù)。
通過CGI,Web 服務(wù)器可以將根據(jù)請(qǐng)求不同啟動(dòng)不同的外部程序,并將請(qǐng)求內(nèi)容轉(zhuǎn)發(fā)給該程序,在程序執(zhí)行結(jié)束后,將執(zhí)行結(jié)果作為回應(yīng)返回給客戶端。也就是說,對(duì)于每個(gè)請(qǐng)求,都要產(chǎn)生一個(gè)新的進(jìn)程進(jìn)行處理。
Servlet 是在服務(wù)器上運(yùn)行的小程序。在實(shí)際運(yùn)行的時(shí)候Java Servlet與Web服務(wù)器會(huì)融為一體。與CGI不同的是,Servlet對(duì)每個(gè)請(qǐng)求都是單獨(dú)啟動(dòng)一個(gè)線程,而不是進(jìn)程。這種處理方式大幅度地降低了系統(tǒng)里的進(jìn)程數(shù)量,提高了系統(tǒng)的并發(fā)處理能力。
比較:
1) JSP從本質(zhì)上說就是Servlet。JSP技術(shù)產(chǎn)生于Servlet之后,兩者分工協(xié)作,Servlet側(cè)重于解決運(yùn)算和業(yè)務(wù)邏輯問題,JSP則側(cè)重于解決展示問題。
2 ) 與CGI相比,Servlet效率更高。Servlet處于服務(wù)器進(jìn)程中,它通過多線程方式運(yùn)行其service方法,一個(gè)實(shí)例可以服務(wù)于多個(gè)請(qǐng)求,并且其實(shí)例一般不會(huì)銷毀。而CGI對(duì)每個(gè)請(qǐng)求都產(chǎn)生新的進(jìn)程,服務(wù)完成后就銷毀,所以效率上低于Servlet 。
3)與CGI相比,Servlet更容易使用,功能更強(qiáng)大,具有更好的可移植性,更節(jié)省投資。在未來的技術(shù)發(fā)展過程中,Servlet有可能徹底取代CGI。
381.HTTP協(xié)議工作原理及其特點(diǎn)
超文本傳輸協(xié)議(HTTP:Hypertext Transport Protocol)是萬維網(wǎng)應(yīng)用層的協(xié)議,它通過兩個(gè)程序?qū)崿F(xiàn):一個(gè)是客戶端程序(各種瀏覽器),另一個(gè)是服務(wù)器 (常稱Web服務(wù)器) 。這兩個(gè)通常運(yùn)行在不同的主機(jī)上,通過交換報(bào)文來完成網(wǎng)頁請(qǐng)求和響應(yīng),報(bào)文可簡(jiǎn)單分為請(qǐng)求報(bào)文和響應(yīng)報(bào)文。
工作原理(流程):
客戶機(jī)與服務(wù)器建立連接后,瀏覽器可以向web服務(wù)器發(fā)送請(qǐng)求并顯示收到的網(wǎng)頁,當(dāng)用戶在瀏覽器地址欄中輸入一個(gè)URL或點(diǎn)擊一個(gè)超連接時(shí),瀏覽器就向服務(wù)器發(fā)出了HTTP請(qǐng)求,請(qǐng)求方式的格式為:統(tǒng)一資源標(biāo)識(shí)符、協(xié)議版本號(hào),后邊是MIME(Multipurpose Internet Mail Extensions)信息包括請(qǐng)求修飾符、客戶機(jī)信息和可能的內(nèi)容。該請(qǐng)求被送往由URL指定的WEB服務(wù)器,WEB服務(wù)器接收到請(qǐng)求后,進(jìn)行相應(yīng)反映,其格式為:一個(gè)狀態(tài)行包括信息的協(xié)議版本號(hào)、一個(gè)成功或錯(cuò)誤的代碼,后邊服務(wù)器信息、實(shí)體信息和可能的內(nèi)容。即以HTTP規(guī)定的格式送回所要求的文件或其他相關(guān)信息,再由用戶計(jì)算機(jī)上的瀏覽器負(fù)責(zé)解釋和顯示。
特點(diǎn):
1)支持客戶/服務(wù)器模式。
2)簡(jiǎn)單快速:客戶向服務(wù)器請(qǐng)求服務(wù)時(shí),只需傳送請(qǐng)求方法和路徑。請(qǐng)求方法常用的有GET、HEAD、POST。每種方法規(guī)定了客戶與服務(wù)器聯(lián)系的類型不同。由于HTTP協(xié)議簡(jiǎn)單,使得HTTP服務(wù)器的程序規(guī)模小,因而通信速度很快。
3)靈活:HTTP允許傳輸任意類型的數(shù)據(jù)對(duì)象。正在傳輸?shù)念愋陀蒀ontent-Type加以標(biāo)記。
4)無連接:無連接的含義是限制每次連接只處理一個(gè)請(qǐng)求。服務(wù)器處理完客戶的請(qǐng)求,并收到客戶的應(yīng)答后,即斷開連接。采用這種方式可以節(jié)省傳輸時(shí)間。
5)無狀態(tài):HTTP協(xié)議是無狀態(tài)協(xié)議。無狀態(tài)是指協(xié)議對(duì)于事務(wù)處理沒有記憶能力。缺少狀態(tài)意味著如果后續(xù)處理需要前面的信息,則它必須重傳,這樣可能導(dǎo)致每次連接傳送的數(shù)據(jù)量增大。另一方面,在服務(wù)器不需要先前信息時(shí)它的應(yīng)答就較快。
382.get和post的區(qū)別
1. Get是不安全的,因?yàn)樵趥鬏斶^程,數(shù)據(jù)被放在請(qǐng)求的URL中;Post的所有操作對(duì)用戶來說都是不可見的。
2. Get傳送的數(shù)據(jù)量較小,這主要是因?yàn)槭躑RL長(zhǎng)度限制;Post傳送的數(shù)據(jù)量較大,一般被默認(rèn)為不受限制。
3. Get限制Form表單的數(shù)據(jù)集的值必須為ASCII字符;而Post支持整個(gè)ISO10646字符集。
4. Get執(zhí)行效率卻比Post方法好。Get是form提交的默認(rèn)方法。
383.如何解決表單提交的中文亂碼問題
1)設(shè)置頁面編碼,若是jsp頁面,需編寫代碼
<%@page language="java" pageEncoding="UTF-8" contentType="text/html;charset=UTF-8" %>
若是html頁面,在網(wǎng)頁頭部(< head>< /head>)中添加下面這段代碼
< meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
2)將form表單提交方式變?yōu)閜ost方式,即添加method="post";)在Servlet類中編寫代碼request.setCharacterEncoding("UTF-8"),而且必須寫在第一行。
3)如果是get請(qǐng)求,在Servlet類中編寫代碼
byte [] bytes = str.getBytes("iso-8859-1");
String cstr = new String(bytes,"utf-8");
或者直接修改Tomcat服務(wù)器配置文件server.xml增加內(nèi)容:
URIEncoding="utf-8"
384.絕對(duì)路徑、根路徑、相對(duì)路徑的含義及其區(qū)別
絕對(duì)路徑指對(duì)站點(diǎn)的根目錄而言某文件的位置,相對(duì)路徑指以當(dāng)前文件所處目錄而言某文件的位置,相對(duì)路徑-以引用文件之網(wǎng)頁所在位置為參考基礎(chǔ),而建立出的目錄路徑。絕對(duì)路徑-以Web站點(diǎn)根目錄為參考基礎(chǔ)的目錄路徑。
先給出一個(gè)網(wǎng)站結(jié)構(gòu)圖做實(shí)例加深理解,A網(wǎng)站(域名為http://www.a.com):/include/a-test.html,/img/a-next.jpg;B網(wǎng)站(域名為http://www.b.com):/include/b-test.html,/img/b-next.jpg。
相對(duì)路徑是從引用的網(wǎng)頁文件本身開始構(gòu)建的,如果在A網(wǎng)站中的a-test.html中要插入圖片a-next.jpg,可以這樣做:< img src="../img/a-next.jpg" />,重點(diǎn)是img前面的../,表示從html處于的include開始起步,輸入一個(gè)../表示回到上面一級(jí)父文件夾下,然后再接著img/表示又從父級(jí)文件夾下的img文件開始了,最后定位img下面的next.jpg。
根路徑是從網(wǎng)站的最底層開始起,一般的網(wǎng)站的根目錄就是域名下對(duì)應(yīng)的文件夾,就如D盤是一個(gè)網(wǎng)站,雙擊D盤進(jìn)入到D盤看到的就是網(wǎng)站的根目錄,這種路徑的鏈接樣式是這樣的:如果在A網(wǎng)站中的a-test.html中要插入圖片a-next.jpg,可以這樣做:< img src="/img/a-next.jpg" >,以/開頭表示從網(wǎng)站根目錄算起,找到根目錄下面的img文件夾下的next.jpg。
絕對(duì)路徑就很好理解了,這種路徑一般帶有網(wǎng)站的域名,如果在A網(wǎng)站中的a-test.html中要插入圖片a-next.jpg,需要這樣這樣寫:< img src="http://www.a.com/img/a-next.jpg" >,將圖片路徑上帶有了域名信息,再打個(gè)比方:如果在A網(wǎng)站中的a-test.html中要插入B網(wǎng)站的圖片b-next.jpg,就需要這樣寫:< img src="http://www.b.com/img/b-next.jpg" >,這種方法適用與在不同網(wǎng)站之間插入外部網(wǎng)站的圖片。
385.如實(shí)現(xiàn)servlet的單線程模式
實(shí)現(xiàn)servlet的單線程的jsp命令是: <%@ page isThreadSafe=”false”%>。默認(rèn)isThreadSafe值為true。
屬性isThreadSafe=false模式表示它是以Singleton模式運(yùn)行,該模式implements了接口SingleThreadMode, 該模式同一時(shí)刻只有一個(gè)實(shí)例,不會(huì)出現(xiàn)信息同步與否的概念。若多個(gè)用戶同時(shí)訪問一個(gè)這種模式的頁面,那么先訪問者完全執(zhí)行完該頁面后,后訪問者才開始執(zhí)行。
屬性isThreadSafe=true模式表示它以多線程方式運(yùn)行。該模式的信息同步,需訪問同步方法(用synchronized標(biāo)記的)來實(shí)現(xiàn)。 一般格式如下:
public synchronized void syncmethod(...){ while(...) { this.wait(); } this.notifyAll(); }
386.Servlet的生命周期
1、加載:在下列時(shí)刻加載 Servlet:(1)如果已配置自動(dòng)加載選項(xiàng),則在啟動(dòng)服務(wù)器時(shí)自動(dòng)
2、加載 (web.xml中設(shè)置< load-on-start>);(2)在服務(wù)器啟動(dòng)后,客戶機(jī)首次向 Servlet 發(fā)出請(qǐng)求時(shí);(3)重新加載 Servlet 時(shí)(只執(zhí)行一次)
3、實(shí)例化:加載 Servlet 后,服務(wù)器創(chuàng)建一個(gè) Servlet 實(shí)例。(只執(zhí)行一次)
4、初始化:調(diào)用 Servlet 的 init() 方法。在初始化階段,Servlet 初始化參數(shù)被傳遞給 Servlet 配置對(duì)象ServletConfig。 (只執(zhí)行一次)
5、請(qǐng)求處理:對(duì)于到達(dá)服務(wù)器的客戶機(jī)請(qǐng)求,服務(wù)器創(chuàng)建針對(duì)此次請(qǐng)求的一個(gè)“請(qǐng)求”對(duì)象和一個(gè)“響應(yīng)”對(duì)象。服務(wù)器調(diào)用 Servlet 的 service() 方法,該方法用于傳遞“請(qǐng)求”和“響應(yīng)”對(duì)象。service() 方法從“請(qǐng)求”對(duì)象獲得請(qǐng)求信息、處理該請(qǐng)求并用“響應(yīng)”對(duì)象的方法以將響應(yīng)傳回客戶機(jī)。service() 方法可以調(diào)用其它方法來處理請(qǐng)求,例如 doGet()、doPost() 或其它的方法。(每次請(qǐng)求都執(zhí)行該步驟)
6、銷毀:當(dāng)服務(wù)器不再需要 Servlet, 或重新裝入 Servlet 的新實(shí)例時(shí),服務(wù)器會(huì)調(diào)用 Servlet 的 destroy() 方法。(只執(zhí)行一次)
387.轉(zhuǎn)發(fā)和重定向的區(qū)別
轉(zhuǎn)發(fā)是在服務(wù)端直接做的事情,是對(duì)客戶端的同一個(gè)request進(jìn)行傳遞,瀏覽器并不知道。重定向是由瀏覽器來做的事情。重定向時(shí),服務(wù)端返回一個(gè)response,里面包含了跳轉(zhuǎn)的地址,由瀏覽器獲得后,自動(dòng)發(fā)送一個(gè)新request。轉(zhuǎn)發(fā)像呼叫轉(zhuǎn)移或者110報(bào)警中心,重定向似114查號(hào)臺(tái)。
a) 區(qū)別1:跳轉(zhuǎn)效率的不同
轉(zhuǎn)發(fā)效率相對(duì)高;重定向效率相對(duì)低
b) 區(qū)別2:實(shí)現(xiàn)語句不同
轉(zhuǎn)發(fā) request.getRequestDispatcher("xxxx").forward(request,response) ;
重定向 response.sendRedirect("xxxx")
c) 區(qū)別3:是否共有同一個(gè)request的數(shù)據(jù)
轉(zhuǎn)發(fā)源組件與目標(biāo)組件共有同一個(gè)request數(shù)據(jù)
重定向源組件與目標(biāo)組件不共有同一個(gè)request數(shù)據(jù)(可使用session共有數(shù)據(jù))
d) 區(qū)別4:瀏覽器URL地址的不同
轉(zhuǎn)發(fā)后瀏覽器URL地址保持不變(源組件地址)
重定向后瀏覽器URL地址改變?yōu)橹囟ㄏ蚝蟮牡刂罚繕?biāo)組件地址)
e) 區(qū)別5:"/"路徑的含義不同
轉(zhuǎn)發(fā)時(shí)"/"代表當(dāng)前項(xiàng)目的根路徑 ;重定向時(shí)"/"代表當(dāng)前服務(wù)器的根路徑
f) 區(qū)別6:跳轉(zhuǎn)范圍的不同
只能轉(zhuǎn)發(fā)到同一應(yīng)用中的URL(默認(rèn)) ;可以重定向任何服務(wù)器、任何應(yīng)用的URL
g) 區(qū)別7:刷新是否導(dǎo)致重復(fù)提交
轉(zhuǎn)發(fā)會(huì)導(dǎo)致重復(fù)提交(可以通過同步令牌解決);重定向不會(huì)導(dǎo)致重復(fù)提交
h) 區(qū)別8:是否經(jīng)過過濾器
轉(zhuǎn)發(fā)不經(jīng)過過濾器(默認(rèn)情況);重定向經(jīng)過過濾器
388.JSP的執(zhí)行過程
在JSP運(yùn)行過程中,首先由客戶端發(fā)出請(qǐng)求,Web服務(wù)器接收到請(qǐng)求后,如果是第一次訪問某個(gè)jsp頁面,Web服務(wù)器對(duì)它進(jìn)行以下3個(gè)操作。
1)翻譯:由.jsp變?yōu)?java,由JSP引擎實(shí)現(xiàn)。
2)編譯:由.java變?yōu)?class,由 Java編譯器實(shí)現(xiàn)。
3)執(zhí)行:由.class變?yōu)?html,用Java虛擬機(jī)執(zhí)行編譯文件,然后將執(zhí)行結(jié)果返回給Web服務(wù)器,并最終返回給客戶端
如果不是第一次訪問某個(gè)JSP頁面,則只執(zhí)行第三步。所以第一次訪問JSP較慢。
389.JSP動(dòng)作有哪些,簡(jiǎn)述作用?
jsp:include:在頁面被請(qǐng)求的時(shí)候引入一個(gè)文件。
jsp:useBean:尋找或者實(shí)例化一個(gè)JavaBean。 jsp:setProperty:設(shè)置JavaBean的屬性。
jsp:getProperty:輸出某個(gè)JavaBean的屬性。
jsp:forward:把請(qǐng)求轉(zhuǎn)到一個(gè)新的頁面。 jsp:plugin:根據(jù)瀏覽器類型為Java插件生成OBJECT或EMBED標(biāo)記。
390.page/request/session/application作用域區(qū)別
page:當(dāng)前頁面范圍
request:當(dāng)前頁面范圍+轉(zhuǎn)發(fā)頁面(forward)+包含頁面(include)
session:當(dāng)前會(huì)話:session在以下幾種情況下失效
1)銷毀session:Session.invalidate();
2)超過最大非活動(dòng)間隔時(shí)間
3)手動(dòng)關(guān)閉瀏覽器(session并沒有立刻失效,因?yàn)榉?wù)器端session仍舊存在,超過最大非活動(dòng)間隔時(shí)間后真正失效)
application:當(dāng)前應(yīng)用;服務(wù)器重新啟動(dòng)前一直有效
391.JSP和Servlet的區(qū)別和聯(lián)系
區(qū)別:
1)JSP是在HTML代碼里寫JAVA代碼,框架是HTML;而Servlet是在JAVA代碼中寫HTML代碼,本身是個(gè)JAVA類。
2)JSP使人們把顯示和邏輯分隔成為可能,這意味著兩者的開發(fā)可并行進(jìn)行;而Servlet并沒有把兩者分開。
3)Servlet獨(dú)立地處理靜態(tài)表示邏輯與動(dòng)態(tài)業(yè)務(wù)邏輯.這樣,任何文件的變動(dòng)都需要對(duì)此服務(wù)程序重新編譯;JSP允許用特殊標(biāo)簽直接嵌入到HTML頁面, HTML內(nèi)容與JAVA內(nèi)容也可放在單獨(dú)文件中,HTML內(nèi)容的任何變動(dòng)會(huì)自動(dòng)編譯裝入到服務(wù)程序.
4)Servlet需要在web.xml中配置,而JSP無需配置。
5)目前JSP主要用在視圖層,負(fù)責(zé)顯示,而Servlet主要用在控制層,負(fù)責(zé)調(diào)度
聯(lián)系:
1)都是Sun公司推出的動(dòng)態(tài)網(wǎng)頁技術(shù)。
2)先有Servlet,針對(duì)Servlet缺點(diǎn)推出JSP。JSP是Servlet的一種特殊形式,每個(gè)JSP頁面就是一個(gè)Servlet實(shí)例——JSP頁面由系統(tǒng)翻譯成Servlet,Servlet再負(fù)責(zé)響應(yīng)用戶請(qǐng)求。
392.談?wù)勥^濾器原理及其作用?
原理:
?過濾器是運(yùn)行在服務(wù)器端的一個(gè)攔截作用的web組件,一個(gè)請(qǐng)求來到時(shí),web容器會(huì)判斷是否有過濾器與該信息資源相關(guān)聯(lián),如果有則交給過濾器處理,然后再交給目標(biāo)資源,響應(yīng)的時(shí)候則以相反的順序交給過濾器處理,最后再返回給用戶瀏覽器
?一般用于日志記錄、性能、安全、權(quán)限管理等公共模塊。
過濾器開發(fā):
?過濾器是一個(gè)實(shí)現(xiàn)了javax.servlet.Filter接口的java類
?主要業(yè)務(wù)代碼放在doFilter方法中
?業(yè)務(wù)代碼完成后要將請(qǐng)求向后傳遞,即調(diào)用FilterChain對(duì)象的doFilter方法
配置:
在web.xml中增加如下代碼 <filter> <filter-name>MyFilter</filter-name> <filter-class>Filter完整類名</filter-class> </filter> <filter-mapping> <filter-name>MyFilter</filter-name> <url-pattern>/*(要過慮的url,此處*表示過慮所有的url)</url-pattern> </filter-mapping>
談?wù)劚O(jiān)聽器作用及其分類?
監(jiān)聽器也叫Listener,是一個(gè)實(shí)現(xiàn)特定接口的java類,使用時(shí)需要在web.xml中配置,它是web服務(wù)器端的一個(gè)組件,它們用于監(jiān)聽的事件源分別為SerlvetConext,HttpSession和ServletRequest這三個(gè)域?qū)ο?/p>
主要有以下三種操作:
–監(jiān)聽三個(gè)域?qū)ο髣?chuàng)建和銷毀的事件監(jiān)聽器
–監(jiān)聽域?qū)ο笾袑傩缘脑黾雍蛣h除的事件監(jiān)聽器
–監(jiān)聽綁定到HttpSession域中的某個(gè)對(duì)象的狀態(tài)的時(shí)間監(jiān)聽器
接口分類:
–ServletContextListener
HttpSessionListener
–ServletRequestListener
–ServletContextAttributeListener
–HttpSessionAttributeListener
ServletRequestAttributeListener
–HttpSessionBindingListener(不需要配置)
–HttpSessionActivationListener(不需要配置)
配置:
< listener>< listener-class>實(shí)現(xiàn)以上任意接口的java類全名< /listener-class>< /listener>
393.jQuery相比JavaScript的優(yōu)勢(shì)在哪里
jQuery的語法更加簡(jiǎn)單。
jQuery消除了JavaScript跨平臺(tái)兼容問題。
相比其他JavaScript和JavaScript庫(kù),jQuery更容易使用。
jQuery有一個(gè)龐大的庫(kù)/函數(shù)。
jQuery有良好的文檔和幫助手冊(cè)。
jQuery支持AJAX
394.DOM對(duì)象和jQuery對(duì)象的區(qū)別及其轉(zhuǎn)換
DOM對(duì)象,是我們用傳統(tǒng)的方法(javascript)獲得的對(duì)象,jQuery對(duì)象即是用jQuery類庫(kù)的選擇器獲得的對(duì)象,它是對(duì)DOM對(duì)象的一種封裝,jQuery對(duì)象不能使用DOM對(duì)象的方法,只能使用jQuery對(duì)象自己的方法。
普通的dom對(duì)象一般可以通過$()轉(zhuǎn)換成jquery對(duì)象
如:var cr=document.getElementById("cr"); //dom對(duì)象
var $cr = $(cr); //轉(zhuǎn)換成jquery對(duì)象
由于jquery對(duì)象本身是一個(gè)集合。所以如果jquery對(duì)象要轉(zhuǎn)換為dom對(duì)象則必須取出其中的某一項(xiàng),一般可通過索引取出
如:$("#msg")[0],$("div").eq(1)[0],$("div").get()[1],$("td")[5]這幾種語法在jQuery中都是合法的
395.jQuery中$的作用主要有哪些
1)$用作選擇器
例如:根據(jù)id獲得頁面元素$("#元素ID")
2)$相當(dāng)于window.onload 和 $(document).ready(...)
例如:$(function(){...}); function(){...}會(huì)在DOM樹加載完畢之后執(zhí)行。
3)$用作JQuery的工具函數(shù)的前綴
例如: var str = ' Welcome to shanghai.com ';
str = $.trim(str);去掉空格
4)$(element):把DOM節(jié)點(diǎn)轉(zhuǎn)化成jQuery節(jié)點(diǎn)
例如:var cr=document.getElementById("cr"); //dom對(duì)象
var $cr = $(cr); //轉(zhuǎn)換成jquery對(duì)象
5)$(html):使用HTML字符串創(chuàng)建jQuery節(jié)點(diǎn)
例如:var obj = $("< div>尚學(xué)堂,實(shí)戰(zhàn)化教學(xué)第一品牌< /div>")
396.Ajax含義及其主要技術(shù)
Ajax (Asynchronous JavaScript and XML 阿賈克斯)不是一個(gè)新的技術(shù),事實(shí)上,它是一些舊有的成熟的技術(shù)以一種全新的更加強(qiáng)大的方式整合在一起。
Ajax的關(guān)鍵技術(shù):
1)使用CSS構(gòu)建用戶界面樣式,負(fù)責(zé)頁面排版和美工
2)使用DOM進(jìn)行動(dòng)態(tài)顯示和交互,對(duì)頁面進(jìn)行局部修改
3)使用XMLHttpRequest異步獲取數(shù)據(jù)
4)使用JavaScript將所有元素綁定在一起
397.Ajax的工作原理
Ajax的原理簡(jiǎn)單來說通過XmlHttpRequest對(duì)象來向服務(wù)器發(fā)異步請(qǐng)求,從服務(wù)器獲得數(shù)據(jù),然后用javascript來操作DOM而更新頁面。這其中最關(guān)鍵的一步就是從服務(wù)器獲得請(qǐng)求數(shù)據(jù)。要清楚這個(gè)過程和原理,我們必須對(duì) XMLHttpRequest有所了解。
XMLHttpRequest是ajax的核心機(jī)制,它是在IE5中首先引入的,是一種支持異步請(qǐng)求的技術(shù)。簡(jiǎn)單的說,也就是javascript可以及時(shí)向服務(wù)器提出請(qǐng)求和處理響應(yīng),而不阻塞用戶。達(dá)到無刷新的效果。
398.JSON及其作用
JSON(JavaScript Object Notation) 是一種輕量級(jí)的數(shù)據(jù)交換格式,采用完全獨(dú)立于語言的文本格式,是理想的數(shù)據(jù)交換格式。同時(shí),JSON是 JavaScript 原生格式,這意味著在 JavaScript 中處理 JSON數(shù)據(jù)不須要任何特殊的 API 或工具包。
在JSON中,有兩種結(jié)構(gòu):對(duì)象和數(shù)組。
?{} 對(duì)象
?[] 數(shù)組
?, 分隔屬性
: 左邊為屬性名,右邊為屬性值?
屬性名可用可不用引號(hào)括起,屬性值為字符串一定要用引號(hào)括起
舉例:
varo={ "xlid": "cxh", "xldigitid": 123456, "topscore": 2000, "topplaytime": "2009-08-20" }; jsonranklist=[ { "xlid": "cxh", "xldigitid": 123456, "topscore": 2000, "topplaytime": "2009-08-20" }, { "xlid": "zd", "xldigitid": 123456, "topscore": 1500, "topplaytime": "2009-11-20" } ];
399.文件上傳組件Common-fileUpload的常用類及其作用?
DiskFileItemFactory:磁盤文件工廠類,設(shè)置上傳文件保存的磁盤目錄,緩沖區(qū)大小。
ServletFileUpload:上傳處理類,此類真正讀取客戶上傳的文件,同時(shí)可以設(shè)置最大接收大小。
FileItem:上傳的文件對(duì)象,可以是多個(gè)文件,每個(gè)上傳的文件都是一個(gè)單獨(dú)的FileItem對(duì)象。
400.說出Servlet的生命周期,并說出Servlet和CGI的區(qū)別?
答:Web容器加載Servlet并將其實(shí)例化后,Servlet生命周期開始,容器運(yùn)行其init()方法進(jìn)行Servlet的初始化;請(qǐng)求到達(dá)時(shí)調(diào)用Servlet的service方法,service方法會(huì)調(diào)用與請(qǐng)求對(duì)應(yīng)的doGet或doPost等方法;當(dāng)服務(wù)器關(guān)閉會(huì)項(xiàng)目被卸載時(shí)服務(wù)器會(huì)將Servlet實(shí)例銷毀,此時(shí)會(huì)調(diào)用Servlet的destroy方法。Servlet與CGI的區(qū)別在于Servlet處于服務(wù)器進(jìn)程中,它通過多線程方式運(yùn)行其service方法,一個(gè)實(shí)例可以服務(wù)于多個(gè)請(qǐng)求,并且其實(shí)例一般不會(huì)銷毀,而CGI 對(duì)每個(gè)請(qǐng)求都產(chǎn)生新的進(jìn)程,服務(wù)完成后就銷毀,所以效率上低于Servlet。
【補(bǔ)充1】SUN公司在1996年發(fā)布Servlet技術(shù)就是為了和CGI進(jìn)行競(jìng)爭(zhēng),Servlet是一個(gè)特殊的Java程序,一個(gè)基于Java的Web應(yīng)用通常包含一個(gè)或多個(gè)Servlet類。 Servlet不能夠自行創(chuàng)建并執(zhí)行,它是在Servlet容器中運(yùn)行的,容器將用戶的請(qǐng)求傳遞給Servlet程序,此外將Servlet的響應(yīng)回傳給用戶。通常一個(gè)Servlet會(huì)關(guān)聯(lián)一個(gè)或多個(gè)JSP頁面。以前CGI經(jīng)常因?yàn)樾阅荛_銷上的問題被詬病,然而Fast CGI早就已經(jīng)解決了CGI效率上的問題,所以面試的時(shí)候大可不必詬病CGI,騰訊的網(wǎng)站就使用了CGI技術(shù),相信你也沒感覺它哪里不好。
【補(bǔ)充2】Servlet接口定義了5個(gè)方法,其中前三個(gè)方法與Servlet生命周期相關(guān):
void init(ServletConfig config) throws ServletException
void service(ServletRequest req, ServletResponse resp) throws ServletException, java.io.IOException
void destory()
java.lang.String getServletInfo()
ServletConfig getServletConfig()
401.JSP 和Servlet 有有什么關(guān)系?
答:其實(shí)這個(gè)問題在上面已經(jīng)闡述過了,Servlet是一個(gè)特殊的Java程序,它運(yùn)行于服務(wù)器的JVM中,能夠依靠服務(wù)器的支持向?yàn)g覽器提供顯示內(nèi)容。JSP本質(zhì)上是Servlet的一種簡(jiǎn)易形式, JSP會(huì)被服務(wù)器處理成一個(gè)類似于Servlet的Java程序,可以簡(jiǎn)化頁面內(nèi)容的生成。Servlet和JSP最主要的不同點(diǎn)在于,Servlet 的應(yīng)用邏輯是在Java 文件中,并且完全從表示層中的HTML分離開來。而JSP的情況是Java和HTML可以組合成一個(gè)擴(kuò)展名為.jsp 的文件(有人說,Servlet就是在Java中寫HTML,而JSP就是在HTML中寫Java代碼,當(dāng)然,這個(gè)說法還是很片面的)。JSP側(cè)重于視圖,Servlet更側(cè)重于控制邏輯,在MVC架構(gòu)模式中,JSP適合充當(dāng)視圖(view)而Servlet適合充當(dāng)控制器(controller)。
402.JSP中的四種作用域?
答:page、request、session和application,具體如下:
①page 代表與一個(gè)頁面相關(guān)的對(duì)象和屬性。
②request 代表與Web客戶機(jī)發(fā)出的一個(gè)請(qǐng)求相關(guān)的對(duì)象和屬性。一個(gè)請(qǐng)求可能跨越多個(gè)頁面,涉及多個(gè)Web 組件;需要在頁面顯示的臨時(shí)數(shù)據(jù)可以置于此作用域
③session代表與某個(gè)用戶與服務(wù)器建立的一次會(huì)話相關(guān)的對(duì)象和屬性。跟某個(gè)用戶相關(guān)的數(shù)據(jù)應(yīng)該放在用戶自己的session中
④application代表與整個(gè)Web應(yīng)用程序相關(guān)的對(duì)象和屬性,它實(shí)質(zhì)上是跨越整個(gè)Web應(yīng)用程序,包括多個(gè)頁面、請(qǐng)求和會(huì)話的一個(gè)全局作用域。
403.如何實(shí)現(xiàn)JSP或Servlet的單線程模式?
<%@page isThreadSafe=”false”%>
【補(bǔ)充】Servlet默認(rèn)的工作模式是單實(shí)例多線程,如果Servlet實(shí)現(xiàn)了標(biāo)識(shí)接口SingleThreadModel又或是JSP頁面通過page指令設(shè)置isThreadSafe屬性為false,那么它們生成的Java代碼會(huì)以單線程多實(shí)例方式工作。顯然,這樣做會(huì)導(dǎo)致每個(gè)請(qǐng)求創(chuàng)建一個(gè)Servlet實(shí)例,這種實(shí)踐將導(dǎo)致嚴(yán)重的性能問題。
404.實(shí)現(xiàn)會(huì)話跟蹤的技術(shù)有哪些?
答:由于HTTP協(xié)議本身是無狀態(tài)的,服務(wù)器為了區(qū)分不同的用戶,就需要對(duì)用戶會(huì)話進(jìn)行跟蹤,簡(jiǎn)單的說就是為用戶進(jìn)行登記,為用戶分配唯一的ID,下一次用戶在請(qǐng)求中包含此ID,服務(wù)器據(jù)此判斷到底是哪一個(gè)用戶。
①URL 重寫:在URL中添加用戶會(huì)話的信息作為請(qǐng)求的參數(shù),或者將唯一的會(huì)話ID添加到URL結(jié)尾以標(biāo)識(shí)一個(gè)會(huì)話。
②設(shè)置表單隱藏域:將和會(huì)話跟蹤相關(guān)的字段添加到隱式表單域中,這些信息不會(huì)在瀏覽器中顯示但是提交表單時(shí)會(huì)提交給服務(wù)器。
這兩種方式很難處理跨越多個(gè)頁面的信息傳遞,因?yàn)槿绻看味家薷腢RL或在頁面中添加隱式表單域來存儲(chǔ)用戶會(huì)話相關(guān)信息,事情將變得非常麻煩。
③cookie:cookie有兩種,一種是基于窗口的,瀏覽器窗口關(guān)閉后,cookie就沒有了;另一種是將信息存儲(chǔ)在一個(gè)臨時(shí)文件中,并設(shè)置存在的時(shí)間。當(dāng)用戶通過瀏覽器和服務(wù)器建立一次會(huì)話后,會(huì)話ID就會(huì)隨響應(yīng)信息返回存儲(chǔ)在基于窗口的cookie中,那就意味著只要瀏覽器沒有關(guān)閉,會(huì)話沒有超時(shí),下一次請(qǐng)求時(shí)這個(gè)會(huì)話ID又會(huì)提交給服務(wù)器讓服務(wù)器識(shí)別用戶身份。會(huì)話中可以為用戶保存信息。會(huì)話對(duì)象是在服務(wù)器內(nèi)存中的,而基于窗口的cookie是在客戶端內(nèi)存中的。如果瀏覽器禁用了cookie,那么就需要通過下面兩種方式進(jìn)行會(huì)話跟蹤。當(dāng)然,在使用cookie時(shí)要注意幾點(diǎn):首先不要在cookie中存放敏感信息;其次cookie存儲(chǔ)的數(shù)據(jù)量有限(4k),不能將過多的內(nèi)容存儲(chǔ)cookie中;再者瀏覽器通常只允許一個(gè)站點(diǎn)最多存放20個(gè)cookie。當(dāng)然,和用戶會(huì)話相關(guān)的其他信息(除了會(huì)話ID)也可以存在cookie方便進(jìn)行會(huì)話跟蹤。
④HttpSession:在所有會(huì)話跟蹤技術(shù)中,HttpSession對(duì)象是最強(qiáng)大也是功能最多的。當(dāng)一個(gè)用戶第一次訪問某個(gè)網(wǎng)站時(shí)會(huì)自動(dòng)創(chuàng)建HttpSession,每個(gè)用戶可以訪問他自己的HttpSession。可以通過HttpServletRequest對(duì)象的getSession方法獲得HttpSession,通過HttpSession的setAttribute方法可以將一個(gè)值放在HttpSession中,通過調(diào)用HttpSession對(duì)象的getAttribute方法,同時(shí)傳入屬性名就可以獲取保存在HttpSession中的對(duì)象。與上面三種方式不同的是,HttpSession放在服務(wù)器的內(nèi)存中,因此不要將過大的對(duì)象放在里面,即使目前的Servlet容器可以在內(nèi)存將滿時(shí)將HttpSession中的對(duì)象移到其他存儲(chǔ)設(shè)備中,但是這樣勢(shì)必影響性能。添加到HttpSession中的值可以是任意Java對(duì)象,這個(gè)對(duì)象最好實(shí)現(xiàn)了Serializable接口,這樣Servlet容器在必要的時(shí)候可以將其序列化到文件中,否則在序列化時(shí)就會(huì)出現(xiàn)異常。
405.過濾器有哪些作用和用法?
答: Java Web開發(fā)中的過濾器(filter)是從Servlet 2.3規(guī)范開始增加的功能,并在Servlet 2.4規(guī)范中得到增強(qiáng)。對(duì)Web應(yīng)用來說,過濾器是一個(gè)駐留在服務(wù)器端的Web組件,它可以截取客戶端和服務(wù)器之間的請(qǐng)求與響應(yīng)信息,并對(duì)這些信息進(jìn)行過濾。當(dāng)Web容器接受到一個(gè)對(duì)資源的請(qǐng)求時(shí),它將判斷是否有過濾器與這個(gè)資源相關(guān)聯(lián)。如果有,那么容器將把請(qǐng)求交給過濾器進(jìn)行處理。在過濾器中,你可以改變請(qǐng)求的內(nèi)容,或者重新設(shè)置請(qǐng)求的報(bào)頭信息,然后再將請(qǐng)求發(fā)送給目標(biāo)資源。當(dāng)目標(biāo)資源對(duì)請(qǐng)求作出響應(yīng)時(shí)候,容器同樣會(huì)將響應(yīng)先轉(zhuǎn)發(fā)給過濾器,再過濾器中,你可以對(duì)響應(yīng)的內(nèi)容進(jìn)行轉(zhuǎn)換,然后再將響應(yīng)發(fā)送到客戶端。
常見的過濾器用途主要包括:對(duì)用戶請(qǐng)求進(jìn)行統(tǒng)一認(rèn)證、對(duì)用戶的訪問請(qǐng)求進(jìn)行記錄和審核、對(duì)用戶發(fā)送的數(shù)據(jù)進(jìn)行過濾或替換、轉(zhuǎn)換圖象格式、對(duì)響應(yīng)內(nèi)容進(jìn)行壓縮以減少傳輸量、對(duì)請(qǐng)求或響應(yīng)進(jìn)行加解密處理、觸發(fā)資源訪問事件、對(duì)XML的輸出應(yīng)用XSLT等。
和過濾器相關(guān)的接口主要有:Filter、FilterConfig、FilterChain
406.監(jiān)聽器有哪些作用和用法?
答:Java Web開發(fā)中的監(jiān)聽器(listener)就是application、session、request三個(gè)對(duì)象創(chuàng)建、銷毀或者往其中添加修改刪除屬性時(shí)自動(dòng)執(zhí)行代碼的功能組件,如下所示:
①ServletContextListener:對(duì)Servlet上下文的創(chuàng)建和銷毀進(jìn)行監(jiān)聽。
②ServletContextAttributeListener:監(jiān)聽Servlet上下文屬性的添加、刪除和替換。
③HttpSessionListener:對(duì)Session的創(chuàng)建和銷毀進(jìn)行監(jiān)聽。
補(bǔ)充:session的銷毀有兩種情況:1session超時(shí)(可以在web.xml中通過< session-config>/< session-timeout>標(biāo)簽配置超時(shí)時(shí)間);2通過調(diào)用session對(duì)象的invalidate()方法使session失效。
④HttpSessionAttributeListener:對(duì)Session對(duì)象中屬性的添加、刪除和替換進(jìn)行監(jiān)聽。
⑤ServletRequestListener:對(duì)請(qǐng)求對(duì)象的初始化和銷毀進(jìn)行監(jiān)聽。
⑥ServletRequestAttributeListener:對(duì)請(qǐng)求對(duì)象屬性的添加、刪除和替換進(jìn)行監(jiān)聽。
407.你的項(xiàng)目中使用過哪些JSTL標(biāo)簽?
答:項(xiàng)目中主要使用了JSTL的核心標(biāo)簽庫(kù),包括< c:if>、< c:choose>、< c: when>、< c: otherwise>、< c:forEach>等,主要用于構(gòu)造循環(huán)和分支結(jié)構(gòu)以控制顯示邏輯。
【說明】雖然JSTL標(biāo)簽庫(kù)提供了core、sql、fmt、xml等標(biāo)簽庫(kù),但是實(shí)際開發(fā)中建議只使用核心標(biāo)簽庫(kù)(core),而且最好只使用分支和循環(huán)標(biāo)簽并輔以表達(dá)式語言(EL),這樣才能真正做到數(shù)據(jù)顯示和業(yè)務(wù)邏輯的分離,這才是最佳實(shí)踐。
408.使用標(biāo)簽庫(kù)有什么好處?如何自定義JSP標(biāo)簽?
答:使用標(biāo)簽庫(kù)的好處包括以下幾個(gè)方面:
分離JSP頁面的內(nèi)容和邏輯,簡(jiǎn)化了Web開發(fā);
開發(fā)者可以創(chuàng)建自定義標(biāo)簽來封裝業(yè)務(wù)邏輯和顯示邏輯;
標(biāo)簽具有很好的可移植性、可維護(hù)性和可重用性;
避免了對(duì)Scriptlet(小腳本)的使用(很多公司的項(xiàng)目開發(fā)都不允許在JSP中書寫小腳本)
自定義JSP標(biāo)簽包括以下幾個(gè)步驟:
編寫一個(gè)Java類實(shí)現(xiàn)實(shí)現(xiàn)Tag/BodyTag/IterationTag接口(通常不直接實(shí)現(xiàn)這些接口而是繼承TagSupport/BodyTagSupport/SimpleTagSupport類,這是對(duì)適配器模式中缺省適配模式的應(yīng)用)
重寫doStartTag()、doEndTag()等方法,定義標(biāo)簽要完成的功能
編寫擴(kuò)展名為tld的標(biāo)簽描述文件對(duì)自定義標(biāo)簽進(jìn)行部署,tld文件通常放在WEB-INF文件夾或其子目錄
在JSP頁面中使用taglib指令引用該標(biāo)簽庫(kù)
下面是一個(gè)例子:
package com.bjsxt; package com.lovo.tags; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; import javax.servlet.jsp.JspException; import javax.servlet.jsp.JspWriter; import javax.servlet.jsp.tagext.TagSupport; public class TimeTag extends TagSupport { private static final long serialVersionUID = 1L; private String format = "yyyy-MM-dd hh:mm:ss"; private String foreColor = "black"; private String backColor = "white"; public int doStartTag() throws JspException { SimpleDateFormat sdf = new SimpleDateFormat(format); JspWriter writer = pageContext.getOut(); StringBuilder sb = new StringBuilder(); sb.append(String.format("<span style='color:%s;background-color:%s'>%s</span>", foreColor, backColor, sdf.format(new Date()))); try { writer.print(sb.toString()); } catch(IOException e) { e.printStackTrace(); } return SKIP_BODY; } public void setFormat(String format) { this.format = format; } public void setForeColor(String foreColor) { this.foreColor = foreColor; } public void setBackColor(String backColor) { this.backColor = backColor; } }
標(biāo)簽庫(kù)描述文件(該文件通常放在WEB-INF目錄或其子目錄下)
<?xml version="1.0" encoding="UTF-8" ?> <taglib xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd" version="2.0"> <description>定義標(biāo)簽庫(kù)</description> <tlib-version>1.0</tlib-version> <short-name>MyTag</short-name> <tag> <name>time</name> <tag-class>com.lovo.tags.TimeTag</tag-class> <body-content>empty</body-content> <attribute> <name>format</name> <required>false</required> </attribute> <attribute> <name>foreColor</name> </attribute> <attribute> <name>backColor</name> </attribute> </tag> </taglib>
JSP頁面
<%@ page pageEncoding="UTF-8"%> <%@ taglib prefix="my" uri="/WEB-INF/tld/my.tld" %> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE html> <html> <head> <base href="<%=basePath%>"> <title>首頁</title> <style type="text/css"> * { font-family: "Arial"; font-size:72px; } </style> </head> <body> <my:time format="yyyy-MM-dd" backColor="blue" foreColor="yellow"/> </body> </html>
運(yùn)行結(jié)果
【注意】如果要將自定義的標(biāo)簽庫(kù)發(fā)布成JAR文件,需要將標(biāo)簽庫(kù)描述文件(tld文件)放在JAR文件的META-INF目錄下,可以JDK自帶的jar工具完成JAR文件的生成。
409.表達(dá)式語言(EL)的隱式對(duì)象及其作用?
答: pageContext、initParam(訪問上下文參數(shù))、param(訪問請(qǐng)求參數(shù))、paramValues、header(訪問請(qǐng)求頭)、headerValues、cookie(訪問cookie)、applicationScope(訪問application作用域)、sessionScope(訪問session作用域)、requestScope(訪問request作用域)、pageScope(訪問page作用域)。用法如下所示:
${pageContext.request.method}
${pageContext["request"]["method"]}
${pageContext.request["method"]}
${pageContext["request"].method}
${initParam.defaultEncoding}
${header["accept-language"]}
${headerValues["accept-language"][0]}
${cookie.jsessionid.value}
${sessionScope.loginUser.username}
【補(bǔ)充】表達(dá)式語言的.和[]運(yùn)算作用是一致的,唯一的差別在于如果訪問的屬性名不符合Java標(biāo)識(shí)符命名規(guī)則,例如上面的accept-language就不是一個(gè)有效的Java標(biāo)識(shí)符,那么這時(shí)候就只能用[]運(yùn)算符而不能使用.獲取它的值
410.表達(dá)式語言(EL)支持哪些運(yùn)算符?
答:除了.和[]運(yùn)算符,EL還提供了:
算術(shù)運(yùn)算符:+、-、*、/或div、%或mod
關(guān)系運(yùn)算符:==或eq、!=或ne、>或gt、>=或ge、< 或lt、< =或le
邏輯運(yùn)算符:&&或and、||或or、!或not
條件運(yùn)算符:${statement? A : B}(跟Java的條件運(yùn)算符類似)
empty運(yùn)算符:檢查一個(gè)值是否為null或者空(數(shù)組長(zhǎng)度為0或集合中沒有元素也返回true)
411.Servlet 3中的異步處理指的是什么?
答:在Servlet 3中引入了一項(xiàng)新的技術(shù)可以讓Servlet異步處理請(qǐng)求。有人可能會(huì)質(zhì)疑,既然都有多線程了,還需要異步處理請(qǐng)求嗎?答案是肯定的,因?yàn)槿绻粋€(gè)任務(wù)處理時(shí)間相當(dāng)長(zhǎng),那么Servlet或Filter會(huì)一直占用著請(qǐng)求處理線程直到任務(wù)結(jié)束,隨著并發(fā)用戶的增加,容器將會(huì)遭遇線程超出的風(fēng)險(xiǎn),這這種情況下很多的請(qǐng)求將會(huì)被堆積起來而后續(xù)的請(qǐng)求可能會(huì)遭遇拒絕服務(wù),直到有資源可以處理請(qǐng)求為止。異步特性可以幫助應(yīng)用節(jié)省容器中的線程,特別適合執(zhí)行時(shí)間長(zhǎng)而且用戶需要得到結(jié)果的任務(wù),如果用戶不需要得到結(jié)果則直接將一個(gè)Runnable對(duì)象交給Executor(如果不清楚請(qǐng)查看前文關(guān)于多線程和線程池的部分)并立即返回即可。
【補(bǔ)充】多線程在Java誕生初期無疑是一個(gè)亮點(diǎn),而Servlet單實(shí)例多線程的工作方式也曾為其贏得美名,然而技術(shù)的發(fā)展往往會(huì)顛覆我們很多的認(rèn)知,就如同當(dāng)年愛因斯坦的相對(duì)論顛覆了牛頓的經(jīng)典力學(xué)一般。事實(shí)上,異步處理絕不是Serlvet 3首創(chuàng),如果你了解Node.js的話,對(duì)Servlet 3的這個(gè)重要改進(jìn)就不以為奇了。
412.如何在基于Java的Web項(xiàng)目中實(shí)現(xiàn)文件上傳和下載?
答:(稍后呈現(xiàn),我準(zhǔn)備用HTML5寫一個(gè)帶進(jìn)度條的客戶端,然后再用Servlet 3提供的文件上傳支持來做一個(gè)多文件上傳的例子)
413.簡(jiǎn)述值棧(Value-Stack)的原理和生命周期
答: Value-Stack貫穿整個(gè) Action 的生命周期,保存在request作用域中,所以它和request的生命周期一樣。當(dāng)Struts 2接受一個(gè)請(qǐng)求時(shí),會(huì)創(chuàng)建ActionContext、Value-Stack和Action對(duì)象,然后把Action存放進(jìn)Value-Stack,所以Action的實(shí)例變量可以通過OGNL訪問。由于Action是多實(shí)例的,和使用單例的Servlet不同, 每個(gè)Action都有一個(gè)對(duì)應(yīng)的Value-Stack,Value-Stack存放的數(shù)據(jù)類型是該Action的實(shí)例,以及該Action中的實(shí)例變量,Action對(duì)象默認(rèn)保存在棧頂。
414.闡述Session加載實(shí)體對(duì)象的過程。
答:Session加載實(shí)體對(duì)象的步驟是:
① Session在調(diào)用數(shù)據(jù)庫(kù)查詢功能之前, 首先會(huì)在緩存中進(jìn)行查詢, 在一級(jí)緩存中, 通過實(shí)體類型和主鍵進(jìn)行查找, 如果一級(jí)緩存查找命中且數(shù)據(jù)狀態(tài)合法, 則直接返回
② 如果一級(jí)緩存沒有命中, 接下來Session會(huì)在當(dāng)前NonExists記錄(相當(dāng)于一個(gè)查詢黑名單, 如果出現(xiàn)重復(fù)的無效查詢可以迅速判斷, 從而提升性能)中進(jìn)行查找, 如果NonExists中存在同樣的查詢條件,則返回null
③ 對(duì)于load方法, 如果一級(jí)緩存查詢失敗則查詢二級(jí)緩存, 如果二級(jí)緩存命中則直接返回
④ 如果之前的查詢都未命中, 則發(fā)出SQL語句, 如果查詢未發(fā)現(xiàn)對(duì)應(yīng)記錄則將此次查詢添加到Session的NonExists中加以記錄, 并返回null
⑤ 根據(jù)映射配置和SQL語句得到ResultSet,并創(chuàng)建對(duì)應(yīng)的實(shí)體對(duì)象
⑥ 將對(duì)象納入Session(一級(jí)緩存)管理
⑦ 執(zhí)行攔截器的onLoad方法(如果有對(duì)應(yīng)的攔截器)
⑧ 將數(shù)據(jù)對(duì)象納入二級(jí)緩存
⑨ 返回?cái)?shù)據(jù)對(duì)象
415.怎么防止重復(fù)提交
1.禁掉提交按鈕。表單提交后使用Javascript使提交按鈕disable。這種方法防止心急的用戶多次點(diǎn)擊按鈕。但有個(gè)問題,如果客戶端把Javascript給禁止掉,這種方法就無效了。
2.Post/Redirect/Get模式。在提交后執(zhí)行頁面重定向,這就是所謂的Post-Redirect-Get (PRG)模式。簡(jiǎn)言之,當(dāng)用戶提交了表單后,你去執(zhí)行一個(gè)客戶端的重定向,轉(zhuǎn)到提交成功信息頁面。
這能避免用戶按F5導(dǎo)致的重復(fù)提交,而其也不會(huì)出現(xiàn)瀏覽器表單重復(fù)提交的警告,也能消除按瀏覽器前進(jìn)和后退按導(dǎo)致的同樣問題。
3.在session中存放一個(gè)特殊標(biāo)志。當(dāng)表單頁面被請(qǐng)求時(shí),生成一個(gè)特殊的字符標(biāo)志串,存在session中,同時(shí)放在表單的隱藏域里。接受處理表單數(shù)據(jù)時(shí),檢查標(biāo)識(shí)字串是否存在,并立即從session中刪除它,然后正常處理數(shù)據(jù)。
如果發(fā)現(xiàn)表單提交里沒有有效的標(biāo)志串,這說明表單已經(jīng)被提交過了,忽略這次提交。
4.在數(shù)據(jù)庫(kù)里添加約束。在數(shù)據(jù)庫(kù)里添加唯一約束或創(chuàng)建唯一索引,防止出現(xiàn)重復(fù)數(shù)據(jù)。這是最有效的防止重復(fù)提交數(shù)據(jù)的方法。
416.$(document).ready(function(){}) jQuery(document).ready(function(){}); 有什么區(qū)別?
window.jQuery = window.$ = jQuery;
這兩者可以互換使用。一般建議優(yōu)先使用$
417.寫出輸出結(jié)果
<script> function Foo() { getName = function (){alert(1);}; return this; } Foo.getName = function() {alert (2);}; Foo.prototype.getName = function (){ alert (3);}; var getName = function (){alert (4);}; function getName(){alert (5);} </script>
//請(qǐng)寫出以下輸出結(jié)果:
Foo.getName(); // 2
getName(); // 4
Foo().getName(); // 1
getName(); // 1
new Foo.getName(); // 2
new Foo().getName(); // 3
new new Foo().getName(); // 3
418.web項(xiàng)目從瀏覽器發(fā)起交易響應(yīng)緩慢,請(qǐng)簡(jiǎn)述從哪些方面如數(shù)分析
從前端后端分別取考慮,后臺(tái)是不是數(shù)據(jù)庫(kù)死鎖等。
前臺(tái)看看是不是js 錯(cuò)誤,或者圖片過大,dom 渲染dom樹,畫面優(yōu)化。cmd amd 規(guī)范等
答:工廠設(shè)計(jì)模式:程序在接口和子類之間加入了一個(gè)過渡端,通過此過渡端可以動(dòng)態(tài)取得實(shí)現(xiàn)了共同接口的子類實(shí)例化對(duì)象。
代理設(shè)計(jì)模式:指由一個(gè)代理主題來操作真實(shí)主題,真實(shí)主題執(zhí)行具體的業(yè)務(wù)操作,而代理主題負(fù)責(zé)其他相關(guān)業(yè)務(wù)的處理。比如生活中的通過代理訪問網(wǎng)絡(luò),客戶通過網(wǎng)絡(luò)代理連接網(wǎng)絡(luò)(具體業(yè)務(wù)),由代理服務(wù)器完成用戶權(quán)限和訪問限制等與上網(wǎng)相關(guān)的其他操作(相關(guān)業(yè)務(wù))
適配器模式:如果一個(gè)類要實(shí)現(xiàn)一個(gè)具有很多抽象方法的接口,但是本身只需要實(shí)現(xiàn)接口中的部分方法便可以達(dá)成目的,所以此時(shí)就需要一個(gè)中間的過渡類,但此過渡類又不希望直接使用,所以將此類定義為抽象類最為合適,再讓以后的子類直接繼承該抽象類便可選擇性的覆寫所需要的方法,而此抽象類便是適配器類。
工廠設(shè)計(jì)模式:
思路說明:由一個(gè)工廠類根據(jù)傳入的參數(shù)(一般是字符串參數(shù)),動(dòng)態(tài)決定應(yīng)該創(chuàng)建哪一個(gè)產(chǎn)品子類(這些產(chǎn)品子類繼承自同一個(gè)父類或接口)的實(shí)例,并以父類形式返回
優(yōu)點(diǎn):客戶端不負(fù)責(zé)對(duì)象的創(chuàng)建,而是由專門的工廠類完成;客戶端只負(fù)責(zé)對(duì)象的調(diào)用,實(shí)現(xiàn)了創(chuàng)建和調(diào)用的分離,降低了客戶端代碼的難度;
缺點(diǎn):如果增加和減少產(chǎn)品子類,需要修改簡(jiǎn)單工廠類,違背了開閉原則;如果產(chǎn)品子類過多,會(huì)導(dǎo)致工廠類非常的龐大,違反了高內(nèi)聚原則,不利于后期維護(hù)。
public class SimpleFactory { public static Product createProduct(String pname){ Product product=null; if("p1".equals(pname)){ product = new Product1(); }else if("p2".equals(pname)){ product = new Product2(); }else if("pn".equals(pname)){ product = new ProductN(); } return product; } }
單例模式
/** * 餓漢式的單例模式 * 在類加載的時(shí)候創(chuàng)建單例實(shí)例,而不是等到第一次請(qǐng)求實(shí)例的時(shí)候的時(shí)候創(chuàng)建 * 1、私有 的無參數(shù)構(gòu)造方法Singleton(),避免外部創(chuàng)建實(shí)例 * 2、私有靜態(tài)屬性instance * 3、公有靜態(tài)方法getInstance() */ public class Singleton { private static Singleton instance = new Singleton(); private Singleton(){ } public static Singleton getInstance(){ return instance; } } /** * 懶漢式的單例模式 *在類加載的時(shí)候不創(chuàng)建單例實(shí)例,只有在第一次請(qǐng)求實(shí)例的時(shí)候的時(shí)候創(chuàng)建 */ public class Singleton { private static Singleton instance; private Singleton(){ } /** * 多線程情況的單例模式,避免創(chuàng)建多個(gè)對(duì)象 */ public static Singleton getInstance(){ if(instance ==null){//避免每次加鎖,只有第一次沒有創(chuàng)建對(duì)象時(shí)才加鎖 synchronized(Singleton.class){//加鎖,只允許一個(gè)線程進(jìn)入 if(instance==null){ //只創(chuàng)建一次對(duì)象 instance = new Singleton(); } } } return instance; }}
答:工廠模式:工廠模式是 Java 中最常用的設(shè)計(jì)模式之一。這種類型的設(shè)計(jì)模式屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對(duì)象的最佳方式。在工廠模式中,我們?cè)趧?chuàng)建對(duì)象時(shí)不會(huì)對(duì)客戶端暴露創(chuàng)建邏輯,并且是通過使用一個(gè)共同的接口來指向新創(chuàng)建的對(duì)象。
適配器模式:適配器模式是作為兩個(gè)不兼容的接口之間的橋梁。這種類型的設(shè)計(jì)模式屬于結(jié)構(gòu)型模式,它結(jié)合了兩個(gè)獨(dú)立接口的功能。這種模式涉及到一個(gè)單一的類,該類負(fù)責(zé)加入獨(dú)立的或不兼容的接口功能。
模板模式:在模板模式中,一個(gè)抽象類公開定義了執(zhí)行它的方法的方式/模板。它的子類可以按需要重寫方法實(shí)現(xiàn),但調(diào)用將以抽象類中定義的方式進(jìn)行。
答:struts2中action是多例的,即一個(gè)session產(chǎn)生一個(gè)action
背景:
1) Struts2會(huì)對(duì)每一個(gè)請(qǐng)求,產(chǎn)生一個(gè)Action的實(shí)例來處理.
2) Spring的Ioc容器管理的bean默認(rèn)是單實(shí)例的.
首先從數(shù)據(jù)安全性的問題上考慮,我們的Action應(yīng)該保證是多例的,這樣才不會(huì)出現(xiàn)數(shù)據(jù)問題。但是如果有的action比如只有admin才能操作,或者某些action,全站公用一個(gè)來提高性能,這樣的話,就可以使用單例模式。
不過幸好,Spring的bean可以針對(duì)每一個(gè)設(shè)置它的scope,所以,上面的問題就不是問題了。如果用單例,就在spring的action bean配置的時(shí)候設(shè)置scope=”prototype”
如果是單例的話,若出現(xiàn)兩個(gè)用戶都修改一個(gè)對(duì)象的屬性值,則會(huì)因?yàn)橛脩粜薷臅r(shí)間不同,兩個(gè)用戶訪問得到的屬性不一樣,操作得出的結(jié)果不一樣.
舉個(gè)例子:有一塊布長(zhǎng)度300cm,能做一件上衣(用掉100cm)和一件褲子(用掉200cm);甲和乙同時(shí)訪問得到的長(zhǎng)度都是300cm,
甲想做上衣和褲子,他先截取100cm去做上衣,等上衣做完再去做褲子,而乙這時(shí)正好也拿100cm去做上衣,那好,等甲做完上衣再做褲子的時(shí)候發(fā)現(xiàn)剩下的布(100cm)已經(jīng)不夠做褲子了…..這就是影響系統(tǒng)的性能,解決的辦法就是給甲和乙一人一塊300cm的布,就不會(huì)出現(xiàn)布被別人偷用的事情,也是就單實(shí)例和多實(shí)例的區(qū)別
如果設(shè)置成單例,那么多個(gè)線程會(huì)共享一個(gè)ActionContext和ValueStack,這樣并發(fā)訪問的時(shí)候就會(huì)出現(xiàn)問題了
struts 2的Action是多實(shí)例的并非單例,也就是每次請(qǐng)求產(chǎn)生一個(gè)Action的對(duì)象。原因是:struts 2的Action中包含數(shù)據(jù),例如你在頁面填寫的數(shù)據(jù)就會(huì)包含在Action的成員變量里面。如果Action是單實(shí)例的話,這些數(shù)據(jù)在多線程的環(huán)境下就會(huì)相互影響,例如造成別人填寫的數(shù)據(jù)被你看到了。所以Struts2的Action是多例模式的。
問題出現(xiàn)了,可以讓Struts2的action變成單例模式么?
Struts2中,可以使用注解開發(fā),在Action上@Scope(“prototype”) 指定為多例 , 默認(rèn)為singleton()單例)
基本上action的scope需要是prototype,就是每次請(qǐng)求都建立新的線程
不寫的話,默認(rèn)是singleton了
答:?jiǎn)卫J街饕饔檬潜WC在Java應(yīng)用程序中,一個(gè)類只有一個(gè)實(shí)例存在。下面給出兩種不同形式的單例:
第一種形式:餓漢式單例?
package com.bjsxt; public class Singleton { private Singleton(){} private static Singleton instance = new Singleton(); public static Singleton getInstance(){ return instance; } }
第二種形式:懶漢式單例
package com.bjsxt; public class Singleton { private static Singleton instance = null; private Singleton() {} public static synchronized Singleton getInstance(){ if (instance==null) instance=newSingleton(); return instance; } }
單例的特點(diǎn):外界無法通過構(gòu)造器來創(chuàng)建對(duì)象,該類必須提供一個(gè)靜態(tài)方法向外界提供該類的唯一實(shí)例。
【補(bǔ)充】用Java進(jìn)行服務(wù)器端編程時(shí),使用單例模式的機(jī)會(huì)還是很多的,服務(wù)器上的資源都是很寶貴的,對(duì)于那些無狀態(tài)的對(duì)象其實(shí)都可以單例化或者靜態(tài)化(在內(nèi)存中僅有唯一拷貝),如果使用了spring這樣的框架來進(jìn)行對(duì)象托管,Spring的IoC容器在默認(rèn)情況下對(duì)所有托管對(duì)象都是進(jìn)行了單例化處理的。?
答:在GoF的《Design Patterns: Elements of Reusable Object-Oriented Software》中給出了三類(創(chuàng)建型[對(duì)類的實(shí)例化過程的抽象化]、結(jié)構(gòu)型[描述如何將類或?qū)ο蠼Y(jié)合在一起形成更大的結(jié)構(gòu)]、行為型[對(duì)在不同的對(duì)象之間劃分責(zé)任和算法的抽象化])共23種設(shè)計(jì)模式,包括:Abstract Factory(抽象工廠模式),Builder(建造者模式),F(xiàn)actory Method(工廠方法模式),Prototype(原始模型模式),Singleton(單例模式);Facade(門面模式),Adapter(適配器模式),Bridge(橋梁模式),Composite(合成模式),Decorator(裝飾模式),F(xiàn)lyweight(享元模式),Proxy(代理模式);Command(命令模式),Interpreter(解釋器模式),Visitor(訪問者模式),Iterator(迭代子模式),Mediator(調(diào)停者模式),Memento(備忘錄模式),Observer(觀察者模式),State(狀態(tài)模式),Strategy(策略模式),Template Method(模板方法模式), Chain Of Responsibility(責(zé)任鏈模式)。
所謂設(shè)計(jì)模式,就是一套被反復(fù)使用的代碼設(shè)計(jì)經(jīng)驗(yàn)的總結(jié)(情境中一個(gè)問題經(jīng)過證實(shí)的一個(gè)解決方案)。使用設(shè)計(jì)模式是為了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性。設(shè)計(jì)模式使人們可以更加簡(jiǎn)單方便的復(fù)用成功的設(shè)計(jì)和體系結(jié)構(gòu)。將已證實(shí)的技術(shù)表述成設(shè)計(jì)模式也會(huì)使新系統(tǒng)開發(fā)者更加容易理解其設(shè)計(jì)思路。
【補(bǔ)充】設(shè)計(jì)模式并不是像某些地方吹噓的那樣是遙不可及的編程理念,說白了設(shè)計(jì)模式就是對(duì)面向?qū)ο蟮木幊淘瓌t的實(shí)踐,面向?qū)ο蟮木幊淘瓌t包括:
單一職責(zé)原則:一個(gè)類只做它該做的事情。(單一職責(zé)原則想表達(dá)的就是“高內(nèi)聚”,寫代碼最終極的原則只有六個(gè)字“高內(nèi)聚、低耦合”,就如同葵花寶典或辟邪劍譜的中心思想就八個(gè)字“欲練此功必先自宮”,所謂的高內(nèi)聚就是一個(gè)代碼模塊只完成一項(xiàng)功能,在面向?qū)ο笾?,如果只讓一個(gè)類完成它該做的事,而不涉及與它無關(guān)的領(lǐng)域就是踐行了高內(nèi)聚的原則,這個(gè)類就只有單一職責(zé)。我們都知道一句話叫“因?yàn)閷Wⅲ詫I(yè)”,一個(gè)對(duì)象如果承擔(dān)太多的職責(zé),那么注定它什么都做不好。這個(gè)世界上任何好的東西都有兩個(gè)特征,一個(gè)是功能單一,好的相機(jī)絕對(duì)不是電視購(gòu)物里面賣的那種一個(gè)機(jī)器有一百多種功能的,它基本上只能照相;另一個(gè)是模塊化,好的自行車是組裝車,從減震叉、剎車到變速器,所有的部件都是可以拆卸和重新組裝的,好的乒乓球拍也不是成品拍,一定是底板和膠皮可以拆分和自行組裝的,一個(gè)好的軟件系統(tǒng),它里面的每個(gè)功能模塊也應(yīng)該是可以輕易的拿到其他系統(tǒng)中使用的,這樣才能實(shí)現(xiàn)軟件復(fù)用的目標(biāo)。)
開閉原則:軟件實(shí)體應(yīng)當(dāng)對(duì)擴(kuò)展開放,對(duì)修改關(guān)閉。(在理想的狀態(tài)下,當(dāng)我們需要為一個(gè)軟件系統(tǒng)增加新功能時(shí),只需要從原來的系統(tǒng)派生出一些新類就可以,不需要修改原來的任何一行代碼。要做到開閉有兩個(gè)要點(diǎn):①抽象是關(guān)鍵,一個(gè)系統(tǒng)中如果沒有抽象類或接口系統(tǒng)就沒有擴(kuò)展點(diǎn);②封裝可變性,將系統(tǒng)中的各種可變因素封裝到一個(gè)繼承結(jié)構(gòu)中,如果多個(gè)可變因素混雜在一起,系統(tǒng)將變得復(fù)雜而換亂,如果不清楚如何封裝可變性,可以參考《設(shè)計(jì)模式精解》一書中對(duì)橋梁模式的講解的章節(jié)。)
依賴倒轉(zhuǎn)原則:面向接口編程。(該原則說得直白和具體一些就是聲明方法的參數(shù)類型、方法的返回類型、變量的引用類型時(shí),盡可能使用抽象類型而不用具體類型,因?yàn)槌橄箢愋涂梢员凰娜魏我粋€(gè)子類型所替代,請(qǐng)參考下面的里氏替換原則。)
里氏替換原則:任何時(shí)候都可以用子類型替換掉父類型。(關(guān)于里氏替換原則的描述,Barbara Liskov女士的描述比這個(gè)要復(fù)雜得多,但簡(jiǎn)單的說就是能用父類型的地方就一定能使用子類型。里氏替換原則可以檢查繼承關(guān)系是否合理,如果一個(gè)繼承關(guān)系違背了里氏替換原則,那么這個(gè)繼承關(guān)系一定是錯(cuò)誤的,需要對(duì)代碼進(jìn)行重構(gòu)。例如讓貓繼承狗,或者狗繼承貓,又或者讓正方形繼承長(zhǎng)方形都是錯(cuò)誤的繼承關(guān)系,因?yàn)槟愫苋菀渍业竭`反里氏替換原則的場(chǎng)景。需要注意的是:子類一定是增加父類的能力而不是減少父類的能力,因?yàn)樽宇惐雀割惖哪芰Ω?,把能力多的?duì)象當(dāng)成能力少的對(duì)象來用當(dāng)然沒有任何問題。)
接口隔離原則:接口要小而專,絕不能大而全。(臃腫的接口是對(duì)接口的污染,既然接口表示能力,那么一個(gè)接口只應(yīng)該描述一種能力,接口也應(yīng)該是高度內(nèi)聚的。例如,琴棋書畫就應(yīng)該分別設(shè)計(jì)為四個(gè)接口,而不應(yīng)設(shè)計(jì)成一個(gè)接口中的四個(gè)方法,因?yàn)槿绻O(shè)計(jì)成一個(gè)接口中的四個(gè)方法,那么這個(gè)接口很難用,畢竟琴棋書畫四樣都精通的人還是少數(shù),而如果設(shè)計(jì)成四個(gè)接口,會(huì)幾項(xiàng)就實(shí)現(xiàn)幾個(gè)接口,這樣的話每個(gè)接口被復(fù)用的可能性是很高的。Java中的接口代表能力、代表約定、代表角色,能否正確的使用接口一定是編程水平高低的重要標(biāo)識(shí)。)
合成聚合復(fù)用原則:優(yōu)先使用聚合或合成關(guān)系復(fù)用代碼。(通過繼承來復(fù)用代碼是面向?qū)ο蟪绦蛟O(shè)計(jì)中被濫用得最多的東西,因?yàn)樗械慕炭茣紵o一例外的對(duì)繼承進(jìn)行了鼓吹從而誤導(dǎo)了初學(xué)者,類與類之間簡(jiǎn)單的說有三種關(guān)系,IS-A關(guān)系、HAS-A關(guān)系、USE-A關(guān)系,分別代表繼承、關(guān)聯(lián)和依賴。其中,關(guān)聯(lián)關(guān)系根據(jù)其關(guān)聯(lián)的強(qiáng)度又可以進(jìn)一步劃分為關(guān)聯(lián)、聚合和合成,但說白了都是HAS-A關(guān)系,合成聚合復(fù)用原則想表達(dá)的是優(yōu)先考慮HAS-A關(guān)系而不是IS-A關(guān)系復(fù)用代碼,原因嘛可以自己從百度上找到一萬個(gè)理由,需要說明的是,即使在Java的API中也有不少濫用繼承的例子,例如Properties類繼承了Hashtable類,Stack類繼承了Vector類,這些繼承明顯就是錯(cuò)誤的,更好的做法是在Properties類中放置一個(gè)Hashtable類型的成員并且將其鍵和值都設(shè)置為字符串來存儲(chǔ)數(shù)據(jù),而Stack類的設(shè)計(jì)也應(yīng)該是在Stack類中放一個(gè)Vector對(duì)象來存儲(chǔ)數(shù)據(jù)。記住:任何時(shí)候都不要繼承工具類,工具是可以擁有并可以使用的(HAS/USE),而不是拿來繼承的。)
迪米特法則:迪米特法則又叫最少知識(shí)原則,一個(gè)對(duì)象應(yīng)當(dāng)對(duì)其他對(duì)象有盡可能少的了解。(迪米特法則簡(jiǎn)單的說就是如何做到“低耦合”,門面模式和調(diào)停者模式就是對(duì)迪米特法則的踐行。對(duì)于門面模式可以舉一個(gè)簡(jiǎn)單的例子,你去一家公司洽談業(yè)務(wù),你不需要了解這個(gè)公司內(nèi)部是如何運(yùn)作的,你甚至可以對(duì)這個(gè)公司一無所知,去的時(shí)候只需要找到公司入口處的前臺(tái)美女,告訴她們你要做什么,她們會(huì)找到合適的人跟你接洽,前臺(tái)的美女就是公司這個(gè)系統(tǒng)的門面。再?gòu)?fù)雜的系統(tǒng)都可以為用戶提供一個(gè)簡(jiǎn)單的門面,Java Web開發(fā)中作為前端控制器的Servlet或Filter不就是一個(gè)門面嗎,瀏覽器對(duì)服務(wù)器的運(yùn)作方式一無所知,但是通過前端控制器就能夠根據(jù)你的請(qǐng)求得到相應(yīng)的服務(wù)。調(diào)停者模式也可以舉一個(gè)簡(jiǎn)單的例子來說明,例如一臺(tái)計(jì)算機(jī),CPU、內(nèi)存、硬盤、顯卡、聲卡各種設(shè)備需要相互配合才能很好的工作,但是如果這些東西都直接連接到一起,計(jì)算機(jī)的布線將異常復(fù)雜,在這種情況下,主板作為一個(gè)調(diào)停者的身份出現(xiàn),它將各個(gè)設(shè)備連接在一起而不需要每個(gè)設(shè)備之間直接交換數(shù)據(jù),這樣就減小了系統(tǒng)的耦合度和復(fù)雜度。迪米特法則用通俗的話來將就是不要和陌生人打交道,如果真的需要,找一個(gè)自己的朋友,讓他替你和陌生人打交道。)
答: 按照分層開發(fā)的觀點(diǎn),可以將應(yīng)用劃分為:表示層、業(yè)務(wù)邏輯層和持久層,每一層都有屬于自己類別的設(shè)計(jì)模式。
表示層設(shè)計(jì)模式:
1) Interceptor Filter:攔截過濾器,提供請(qǐng)求預(yù)處理和后處理的方案,可以對(duì)請(qǐng)求和響應(yīng)進(jìn)行過濾。/p>
2) Front Controller:通過中央控制器提供請(qǐng)求管理和處理,管理內(nèi)容讀取、安全性、視圖管理和導(dǎo)航等功能。Struts 2中的StrutsPrepareAndExecuteFilter、Spring MVC中的DispatcherServlet都是前端控制器,后者如下圖所示:
3) View Helper:視圖幫助器,負(fù)責(zé)將顯示邏輯和業(yè)務(wù)邏輯分開。顯示的部分放在視圖組件中,業(yè)務(wù)邏輯代碼放在幫助器中,典型的功能是內(nèi)容讀取、驗(yàn)證與適配。
4) Composite View:復(fù)合視圖。
業(yè)務(wù)邏輯層設(shè)計(jì)模式:
1) Business Delegate:業(yè)務(wù)委托,減少表示層和業(yè)務(wù)邏輯層之間的耦合。
2) Value Object:值對(duì)象,解決層之間交換數(shù)據(jù)的開銷問題。
3) Session Fa?ade:會(huì)話門面,隱藏業(yè)務(wù)邏輯組件的細(xì)節(jié),集中工作流程。
4) Value Object Assembler:靈活的組裝不同的值對(duì)象
5) Value List Handler:提供執(zhí)行查詢和處理結(jié)果的解決方案,還可以緩存查詢結(jié)果,從而達(dá)到提升性能的目的。
6) Service Locator:服務(wù)定位器,可以查找、創(chuàng)建和定位服務(wù)工廠,封裝其實(shí)現(xiàn)細(xì)節(jié),減少?gòu)?fù)雜性,提供單個(gè)控制點(diǎn),通過緩存提高性能。
持久層設(shè)計(jì)模式:
Data Access Object:數(shù)據(jù)訪問對(duì)象,以面向?qū)ο蟮姆绞酵瓿蓪?duì)數(shù)據(jù)的增刪改查。
【補(bǔ)充】如果想深入的了解Java企業(yè)級(jí)應(yīng)用的設(shè)計(jì)模式和架構(gòu)模式,可以參考這些書籍:?《Pro Java EE Spring Patterns》、《POJO in Action》、《Patterns of Enterprise Application Architecture》。
答:面試被問到關(guān)于設(shè)計(jì)模式的知識(shí)時(shí),可以揀最常用的作答,例如:
1) 工廠模式:工廠類可以根據(jù)條件生成不同的子類實(shí)例,這些子類有一個(gè)公共的抽象父類并且實(shí)現(xiàn)了相同的方法,但是這些方法針對(duì)不同的數(shù)據(jù)進(jìn)行了不同的操作(多態(tài)方法)。當(dāng)?shù)玫阶宇惖膶?shí)例后,開發(fā)人員可以調(diào)用基類中的方法而不必考慮到底返回的是哪一個(gè)子類的實(shí)例。
2) 代理模式:給一個(gè)對(duì)象提供一個(gè)代理對(duì)象,并由代理對(duì)象控制原對(duì)象的引用。實(shí)際開發(fā)中,按照使用目的的不同,代理可以分為:遠(yuǎn)程代理、虛擬代理、保護(hù)代理、Cache代理、防火墻代理、同步化代理、智能引用代理。
3) 適配器模式:把一個(gè)類的接口變換成客戶端所期待的另一種接口,從而使原本因接口不匹配而無法在一起使用的類能夠一起工作。
4) 模板方法模式:提供一個(gè)抽象類,將部分邏輯以具體方法或構(gòu)造器的形式實(shí)現(xiàn),然后聲明一些抽象方法來迫使子類實(shí)現(xiàn)剩余的邏輯。不同的子類可以以不同的方式實(shí)現(xiàn)這些抽象方法(多態(tài)實(shí)現(xiàn)),從而實(shí)現(xiàn)不同的業(yè)務(wù)邏輯。
除此之外,還可以講講上面提到的門面模式、橋梁模式、單例模式、裝潢模式(Collections工具類里面的synchronizedXXX方法把一個(gè)線程不安全的容器變成線程安全容器就是對(duì)裝潢模式的應(yīng)用,而Java IO里面的過濾流(有的翻譯成處理流)也是應(yīng)用裝潢模式的經(jīng)典例子)等,反正原則就是揀自己最熟悉的用得最多的作答,以免言多必失。?
設(shè)計(jì)模式是一套被反復(fù)使用的、多數(shù)人知曉、經(jīng)過分類編目的優(yōu)秀代碼設(shè)計(jì)經(jīng)驗(yàn)的總結(jié)。特定環(huán)境下特定問題的處理方法。
1)重用設(shè)計(jì)和代碼 重用設(shè)計(jì)比重用代碼更有意義,自動(dòng)帶來代碼重用
2)提高擴(kuò)展性 大量使用面向接口編程,預(yù)留擴(kuò)展插槽,新的功能或特性很容易加入到系統(tǒng)中來
3)提高靈活性 通過組合提高靈活性,可允許代碼修改平穩(wěn)發(fā)生,對(duì)一處修改不會(huì)波及到其他模塊
4) 提高開發(fā)效率 正確使用設(shè)計(jì)模式,可以節(jié)省大量的時(shí)間
package com.bjsxt; public class SimpleFactory { public static Product createProduct(String pname){ Product product=null; if("p1".equals(pname)){ product = new Product(); }else if("p2".equals(pname)){ product = new Product(); }else if("pn".equals(pname)){ product = new Product(); } return product; } }
基本原理:由一個(gè)工廠類根據(jù)傳入的參數(shù)(一般是字符串參數(shù)),動(dòng)態(tài)決定應(yīng)該創(chuàng)建哪一個(gè)產(chǎn)品子類(這些產(chǎn)品子類繼承自同一個(gè)父類或接口)的實(shí)例,并以父類形式返回
優(yōu)點(diǎn):客戶端不負(fù)責(zé)對(duì)象的創(chuàng)建,而是由專門的工廠類完成;客戶端只負(fù)責(zé)對(duì)象的調(diào)用,實(shí)現(xiàn)了創(chuàng)建和調(diào)用的分離,降低了客戶端代碼的難度;
缺點(diǎn):如果增加和減少產(chǎn)品子類,需要修改簡(jiǎn)單工廠類,違背了開閉原則;如果產(chǎn)品子類過多,會(huì)導(dǎo)致工廠類非常的龐大,違反了高內(nèi)聚原則,不利于后期維護(hù)
分析:建議挑選有一定技術(shù)難度,并且在實(shí)際開發(fā)中應(yīng)用較多的設(shè)計(jì)模式。可以挑選裝飾模式和動(dòng)態(tài)代理模式。此處挑選動(dòng)態(tài)代理設(shè)計(jì)模式。
講解思路:生活案例引入、技術(shù)講解、優(yōu)缺點(diǎn)分析、典型應(yīng)用。
1、生活案例引入:送生日蛋糕:
MM們要過生日了,怎么也得表示下吧。最起碼先送個(gè)蛋糕。蛋糕多種多樣了。巧克力,冰淇淋,奶油等等。這都是基本的了,再加點(diǎn)額外的裝飾,如蛋糕里放點(diǎn)花、放賀卡、放點(diǎn)干果吃著更香等等。
分析:
方案1:如果采用繼承會(huì)造成大量的蛋糕子類
方案2:蛋糕作為主體,花,賀卡,果仁等是裝飾者,需要時(shí)加到蛋糕上。要啥我就加啥。
技術(shù)講解
裝飾模式(別名Wrapper)是在不必改變?cè)愇募褪褂美^承的情況下,動(dòng)態(tài)的擴(kuò)展一個(gè)對(duì)象的功能。它通過創(chuàng)建一個(gè)包裝對(duì)象,也就是裝飾來包裹真實(shí)對(duì)象,提供了比繼承更具彈性的代替方案。
裝飾模式一般涉及到的角色
抽象構(gòu)建角色(Component):給出一個(gè)抽象的接口,以規(guī)范準(zhǔn)備接受附加責(zé)任的對(duì)象。
具體的構(gòu)建角色(ConcreteComponent):定義一個(gè)將要接受附加責(zé)任的類。
抽象的裝飾角色 (Decorator):持有一個(gè)抽象構(gòu)建(Component)角色的引用,并定義一個(gè)與抽象構(gòu)件一致的接口。
具體的裝飾角色(ConcreteDecorator):負(fù)責(zé)給構(gòu)建對(duì)象“貼上”附加的責(zé)任。
3、優(yōu)缺點(diǎn)分析
優(yōu)點(diǎn)
1)Decorator模式與繼承關(guān)系的目的都是要擴(kuò)展對(duì)象的功能,但是Decorato更多的靈活性。
2)把類中的裝飾功能從類中搬移出去,這樣可以簡(jiǎn)化原有的類。有效地把類的核心功能和裝飾功能區(qū)分開了。
3)通過使用不同的具體裝飾類以及這些裝飾類的排列組合,可創(chuàng)造出很多不同行為的組合。
缺點(diǎn)
這種比繼承更加靈活機(jī)動(dòng)的特性,也同時(shí)意味著更加多的復(fù)雜性。
裝飾模式會(huì)導(dǎo)致設(shè)計(jì)中出現(xiàn)許多小類,如果過度使用,會(huì)使程序變得很復(fù)雜。
符合的設(shè)計(jì)原則:
多用組合,少用繼承。利用繼承設(shè)計(jì)子類的行為是在編譯時(shí)靜態(tài)決定的,且所有的子類都會(huì)繼承到相同的行為。如能夠利用組合擴(kuò)展對(duì)象的行為,就可在運(yùn)行時(shí)動(dòng)態(tài)進(jìn)行擴(kuò)展。
類應(yīng)設(shè)計(jì)的對(duì)擴(kuò)展開放,對(duì)修改關(guān)閉。
4、典型應(yīng)用
java IO中需要完成對(duì)不同輸入輸出源的操作,如果單純的使用繼承這一方式,無疑需要很多的類。比如說,我們操作文件需要一個(gè)類,實(shí)現(xiàn)文件的字節(jié)讀取需要一個(gè)類,實(shí)現(xiàn)文件的字符讀取又需要一個(gè)類....一次類推每個(gè)特定的操作都需要一個(gè)特定的類。這無疑會(huì)導(dǎo)致大量的IO繼承類的出現(xiàn)。顯然對(duì)于編程是很不利的。而是用裝飾模式則可以很好的解決這一問題,在裝飾模式中:節(jié)點(diǎn)流(如FileInputStream)直接與輸入源交互,之后通過過濾流(FilterInputStream)進(jìn)行裝飾,這樣獲得的io對(duì)象便具有某幾個(gè)的功能,很好的拓展了IO的功能。
高級(jí)框架
Maven使用項(xiàng)目對(duì)象模型(POM)的概念,可以通過一小段描述信息來管理項(xiàng)目的構(gòu)建,報(bào)告和文檔的軟件項(xiàng)目管理工具。
Maven 除了以程序構(gòu)建能力為特色之外,還提供高級(jí)項(xiàng)目管理工具。由于 Maven 的缺省構(gòu)建規(guī)則有較高的可重用性,所以常常用兩三行 Maven 構(gòu)建腳本就可以構(gòu)建簡(jiǎn)單的項(xiàng)目。由于 Maven 的面向項(xiàng)目的方法,許多 Apache Jakarta 項(xiàng)目發(fā)布時(shí)使用 Maven,而且公司項(xiàng)目采用 Maven 的比例在持續(xù)增長(zhǎng)。
Maven的出現(xiàn),解決了開發(fā)過程中的jar包升級(jí)及依賴的難題。它可以對(duì)項(xiàng)目依賴的jar包進(jìn)行管理,可以讓你的項(xiàng)目保持基本的依賴,排除冗余jar包,并且可以讓你非常輕松的對(duì)依賴的jar包進(jìn)行版本升級(jí)。而這些僅僅是Maven最基本的功能,它可以在這基礎(chǔ)上對(duì)項(xiàng)目進(jìn)行清理、編譯、測(cè)試、打包、發(fā)布等等構(gòu)建項(xiàng)目的工作。?
可以說,Maven是現(xiàn)在Java社區(qū)中最強(qiáng)大的項(xiàng)目管理和項(xiàng)目構(gòu)建工具,而更加值得慶幸的是,這樣一個(gè)強(qiáng)大的工具,它的使用也是非常簡(jiǎn)單的。
現(xiàn)在,JavaEE項(xiàng)目使用的開源軟件都可以通過Maven來獲取,并且,越來越多的公司也開始使用Maven來管理構(gòu)建項(xiàng)目了。
1.maven&ant同屬apach是流行的構(gòu)建工具。
都是為了簡(jiǎn)化軟件開發(fā)而存在的。但是maven因?yàn)樽陨砉芾硪粋€(gè)項(xiàng)目對(duì)象模型(project object model),這個(gè)模型其實(shí)就是抽象了一個(gè)項(xiàng)目的開發(fā)流程,它包含了一個(gè)項(xiàng)目的生命周期的各個(gè)階段,并將這個(gè)周期固定下來,這也就是約定大于配置。約定大于配置的意思就是,我maven將項(xiàng)目開發(fā)的各個(gè)階段固定起來了,每個(gè)文件的存放位置,每個(gè)階段要生成什么文件、保存為什么格式并且要把它放在什么位置,我都固定好了。我知道一個(gè)軟件是怎么開發(fā)出來,如果一個(gè)項(xiàng)目要使用maven,可以,但你要遵循我的規(guī)則,文件目錄不要亂建亂放,只有這樣maven才會(huì)將源碼用起來。這就是約定大于配置,因?yàn)閙aven已經(jīng)將流程固定下來了,只要遵守約定,就不需要自己手動(dòng)去配置了,這將大大地提高開發(fā)效率。就像是開車一樣,只要知道點(diǎn)火、油門、方向、剎車,就可以將車子開東起來(當(dāng)然出于安全和法律考慮,還是要考駕照的。),關(guān)于車子內(nèi)部的傳動(dòng)原理,電氣原理,工程原理,普通人并不需要了解多少,日常夠用就好了。這也是約定大于配置的一個(gè)例子。配置就是自己造一輛車去開,有必要,有能力,有時(shí)間嗎?
2.maven的中央倉(cāng)庫(kù)和pom.xml文件。中央倉(cāng)庫(kù)統(tǒng)一存放了開發(fā)用到的各種jar包,要用時(shí)只需要添加依賴到pom文件中,maven就會(huì)自動(dòng)下載,當(dāng)然為了方便一般會(huì)在本地建一個(gè)倉(cāng)庫(kù),減少下載時(shí)間。pom文件是maven的配置文件,maven就是通過管理pom文件和一些核心插件來管理項(xiàng)目。當(dāng)然我前面將maven擬人化了,其實(shí)maven是沒有智力的,一切都是封裝好的流程,只是maven將很多操作隱藏起來了。
3.ant的build.xml文件。build文件是ant的配置文件,ant依靠它來執(zhí)行操作,與maven不同的是ant沒有固定一條程序鏈。你想要執(zhí)行什么操作以及操作之間的順序和依賴關(guān)系,都需要手動(dòng)添加到build文件中,一點(diǎn)一滴都要寫清楚,否則ant就不會(huì)執(zhí)行。
4.maven和ant區(qū)別
Maven 擁有約定,只要遵守約定,它就知道你的源代碼在哪里。Maven 是聲明式的。你需要做的只是創(chuàng)建一個(gè) pom.xml 文件然后將源代碼放到默認(rèn)的目錄。Maven 會(huì)幫你處理其它的事情。Maven 有一個(gè)生命周期,當(dāng)你運(yùn)行 mvn install 的時(shí)候被調(diào)用。這條命令告訴 Maven 執(zhí)行一系列的有序的步驟,直到到達(dá)你指定的生命周期。缺點(diǎn)是運(yùn)行許多默認(rèn)目標(biāo)。
而ant沒有約定,項(xiàng)目生命周期,它是命令式的。所有操作都要手動(dòng)去創(chuàng)建、布置。甚至連build.xml文件都需要手動(dòng)創(chuàng)建。
Maven倉(cāng)庫(kù)是基于簡(jiǎn)單文件系統(tǒng)存儲(chǔ)的,集中化管理Java API資源(構(gòu)件)的一個(gè)服務(wù)。倉(cāng)庫(kù)中的任何一個(gè)構(gòu)件都有其唯一的坐標(biāo),根據(jù)這個(gè)坐標(biāo)可以定義其在倉(cāng)庫(kù)中的唯一存儲(chǔ)路徑。得益于 Maven 的坐標(biāo)機(jī)制,任何 Maven項(xiàng)目使用任何一個(gè)構(gòu)件的方式都是完全相同的,Maven 可以在某個(gè)位置統(tǒng)一存儲(chǔ)所有的 Maven 項(xiàng)目共享的構(gòu)件,這個(gè)統(tǒng)一的位置就是倉(cāng)庫(kù),項(xiàng)目構(gòu)建完畢后生成的構(gòu)件也可以安裝或者部署到倉(cāng)庫(kù)中,供其它項(xiàng)目使用。
對(duì)于Maven來說,倉(cāng)庫(kù)分為兩類:本地倉(cāng)庫(kù)和遠(yuǎn)程倉(cāng)庫(kù)。
POM工程
POM工程是邏輯工程。用在父級(jí)工程或聚合工程中。用來做jar包的版本控制。
JAR工程
將會(huì)打包成jar用作jar包使用。即常見的本地工程 - Java Project。
WAR工程
將會(huì)打包成war,發(fā)布在服務(wù)器上的工程。如網(wǎng)站或服務(wù)。即常見的網(wǎng)絡(luò)工程 - Dynamic Web Project。war工程默認(rèn)沒有WEB-INF目錄及web.xml配置文件,IDE通常會(huì)顯示工程錯(cuò)誤,提供完整工程結(jié)構(gòu)可以解決。
install
本地安裝, 包含編譯,打包,安裝到本地倉(cāng)庫(kù)
編譯 - javac
打包 - jar, 將java代碼打包為jar文件
安裝到本地倉(cāng)庫(kù) - 將打包的jar文件,保存到本地倉(cāng)庫(kù)目錄中。
clean
清除已編譯信息。
刪除工程中的target目錄。
compile
只編譯。 javac命令
deploy
部署。 常見于結(jié)合私服使用的命令。
相當(dāng)于是install+上傳jar到私服。
包含編譯,打包,安裝到本地倉(cāng)庫(kù),上傳到私服倉(cāng)庫(kù)。
package
打包。 包含編譯,打包兩個(gè)功能。
配置管理
在我們的應(yīng)用中除了代碼外,還有一些就是各種配置。比如數(shù)據(jù)庫(kù)連接等。一般我們都是使用配置文件的方式,在代碼中引入這些配置文件。當(dāng)我們只有一種配置,只有一臺(tái)服務(wù)器,并且不經(jīng)常修改的時(shí)候,使用配置文件是一個(gè)很好的做法,但是如果我們配置非常多,有很多服務(wù)器都需要這個(gè)配置,這時(shí)使用配置文件就不是個(gè)好主意了。這個(gè)時(shí)候往往需要尋找一種集中管理配置的方法,我們?cè)谶@個(gè)集中的地方修改了配置,所有對(duì)這個(gè)配置感興趣的都可以獲得變更。Zookeeper就是這種服務(wù),它使用Zab這種一致性協(xié)議來提供一致性?,F(xiàn)在有很多開源項(xiàng)目使用Zookeeper來維護(hù)配置,比如在HBase中,客戶端就是連接一個(gè)Zookeeper,獲得必要的HBase集群的配置信息,然后才可以進(jìn)一步操作。還有在開源的消息隊(duì)列Kafka中,也使用Zookeeper來維護(hù)broker的信息。在Alibaba開源的SOA框架Dubbo中也廣泛的使用Zookeeper管理一些配置來實(shí)現(xiàn)服務(wù)治理。
名字服務(wù)
名字服務(wù)這個(gè)就很好理解了。比如為了通過網(wǎng)絡(luò)訪問一個(gè)系統(tǒng),我們得知道對(duì)方的IP地址,但是IP地址對(duì)人非常不友好,這個(gè)時(shí)候我們就需要使用域名來訪問。但是計(jì)算機(jī)是不能是域名的。怎么辦呢?如果我們每臺(tái)機(jī)器里都備有一份域名到IP地址的映射,這個(gè)倒是能解決一部分問題,但是如果域名對(duì)應(yīng)的IP發(fā)生變化了又該怎么辦呢?于是我們有了DNS這個(gè)東西。我們只需要訪問一個(gè)大家熟知的(known)的點(diǎn),它就會(huì)告訴你這個(gè)域名對(duì)應(yīng)的IP是什么。在我們的應(yīng)用中也會(huì)存在很多這類問題,特別是在我們的服務(wù)特別多的時(shí)候,如果我們?cè)诒镜乇4娣?wù)的地址的時(shí)候?qū)⒎浅2环奖?,但是如果我們只需要訪問一個(gè)大家都熟知的訪問點(diǎn),這里提供統(tǒng)一的入口,那么維護(hù)起來將方便得多了。
分布式鎖
其實(shí)在第一篇文章中已經(jīng)介紹了Zookeeper是一個(gè)分布式協(xié)調(diào)服務(wù)。這樣我們就可以利用Zookeeper來協(xié)調(diào)多個(gè)分布式進(jìn)程之間的活動(dòng)。比如在一個(gè)分布式環(huán)境中,為了提高可靠性,我們的集群的每臺(tái)服務(wù)器上都部署著同樣的服務(wù)。但是,一件事情如果集群中的每個(gè)服務(wù)器都進(jìn)行的話,那相互之間就要協(xié)調(diào),編程起來將非常復(fù)雜。而如果我們只讓一個(gè)服務(wù)進(jìn)行操作,那又存在單點(diǎn)。通常還有一種做法就是使用分布式鎖,在某個(gè)時(shí)刻只讓一個(gè)服務(wù)去干活,當(dāng)這臺(tái)服務(wù)出問題的時(shí)候鎖釋放,立即fail over到另外的服務(wù)。這在很多分布式系統(tǒng)中都是這么做,這種設(shè)計(jì)有一個(gè)更好聽的名字叫Leader Election(leader選舉)。比如HBase的Master就是采用這種機(jī)制。但要注意的是分布式鎖跟同一個(gè)進(jìn)程的鎖還是有區(qū)別的,所以使用的時(shí)候要比同一個(gè)進(jìn)程里的鎖更謹(jǐn)慎的使用。
集群管理
在分布式的集群中,經(jīng)常會(huì)由于各種原因,比如硬件故障,軟件故障,網(wǎng)絡(luò)問題,有些節(jié)點(diǎn)會(huì)進(jìn)進(jìn)出出。有新的節(jié)點(diǎn)加入進(jìn)來,也有老的節(jié)點(diǎn)退出集群。這個(gè)時(shí)候,集群中其他機(jī)器需要感知到這種變化,然后根據(jù)這種變化做出對(duì)應(yīng)的決策。比如我們是一個(gè)分布式存儲(chǔ)系統(tǒng),有一個(gè)中央控制節(jié)點(diǎn)負(fù)責(zé)存儲(chǔ)的分配,當(dāng)有新的存儲(chǔ)進(jìn)來的時(shí)候我們要根據(jù)現(xiàn)在集群目前的狀態(tài)來分配存儲(chǔ)節(jié)點(diǎn)。這個(gè)時(shí)候我們就需要?jiǎng)討B(tài)感知到集群目前的狀態(tài)。還有,比如一個(gè)分布式的SOA架構(gòu)中,服務(wù)是一個(gè)集群提供的,當(dāng)消費(fèi)者訪問某個(gè)服務(wù)時(shí),就需要采用某種機(jī)制發(fā)現(xiàn)現(xiàn)在有哪些節(jié)點(diǎn)可以提供該服務(wù)(這也稱之為服務(wù)發(fā)現(xiàn),比如Alibaba開源的SOA框架Dubbo就采用了Zookeeper作為服務(wù)發(fā)現(xiàn)的底層機(jī)制)。還有開源的Kafka隊(duì)列就采用了Zookeeper作為Cosnumer的上下線管理。
在Zookeeper中,znode是一個(gè)跟Unix文件系統(tǒng)路徑相似的節(jié)點(diǎn),可以往這個(gè)節(jié)點(diǎn)存儲(chǔ)或獲取數(shù)據(jù)。
Zookeeper底層是一套數(shù)據(jù)結(jié)構(gòu)。這個(gè)存儲(chǔ)結(jié)構(gòu)是一個(gè)樹形結(jié)構(gòu),其上的每一個(gè)節(jié)點(diǎn),我們稱之為“znode”
zookeeper中的數(shù)據(jù)是按照“樹”結(jié)構(gòu)進(jìn)行存儲(chǔ)的。而且znode節(jié)點(diǎn)還分為4中不同的類型。
每一個(gè)znode默認(rèn)能夠存儲(chǔ)1MB的數(shù)據(jù)(對(duì)于記錄狀態(tài)性質(zhì)的數(shù)據(jù)來說,夠了)
可以使用zkCli命令,登錄到zookeeper上,并通過ls、create、delete、get、set等命令操作這些znode節(jié)點(diǎn)
答:(1)PERSISTENT 持久化節(jié)點(diǎn): 所謂持久節(jié)點(diǎn),是指在節(jié)點(diǎn)創(chuàng)建后,就一直存在,直到有刪除操作來主動(dòng)清除這個(gè)節(jié)點(diǎn)。否則不會(huì)因?yàn)閯?chuàng)建該節(jié)點(diǎn)的客戶端會(huì)話失效而消失。
(2)PERSISTENT_SEQUENTIAL 持久順序節(jié)點(diǎn):這類節(jié)點(diǎn)的基本特性和上面的節(jié)點(diǎn)類型是一致的。額外的特性是,在ZK中,每個(gè)父節(jié)點(diǎn)會(huì)為他的第一級(jí)子節(jié)點(diǎn)維護(hù)一份時(shí)序,會(huì)記錄每個(gè)子節(jié)點(diǎn)創(chuàng)建的先后順序?;谶@個(gè)特性,在創(chuàng)建子節(jié)點(diǎn)的時(shí)候,可以設(shè)置這個(gè)屬性,那么在創(chuàng)建節(jié)點(diǎn)過程中,ZK會(huì)自動(dòng)為給定節(jié)點(diǎn)名加上一個(gè)數(shù)字后綴,作為新的節(jié)點(diǎn)名。這個(gè)數(shù)字后綴的范圍是整型的最大值。?在創(chuàng)建節(jié)點(diǎn)的時(shí)候只需要傳入節(jié)點(diǎn) “/test_”,這樣之后,zookeeper自動(dòng)會(huì)給”test_”后面補(bǔ)充數(shù)字。
(3)EPHEMERAL 臨時(shí)節(jié)點(diǎn):和持久節(jié)點(diǎn)不同的是,臨時(shí)節(jié)點(diǎn)的生命周期和客戶端會(huì) 話綁定。也就是說,如果客戶端會(huì)話失效,那么這個(gè)節(jié)點(diǎn)就會(huì)自動(dòng)被清除掉。注意,這里提到的是會(huì)話失效,而非連接斷開。另外,在臨時(shí)節(jié)點(diǎn)下面不能創(chuàng)建子節(jié)點(diǎn)。?
這里還要注意一件事,就是當(dāng)你客戶端會(huì)話失效后,所產(chǎn)生的節(jié)點(diǎn)也不是一下子就消失了,也要過一段時(shí)間,大概是10秒以內(nèi),可以試一下,本機(jī)操作生成節(jié)點(diǎn),在服務(wù)器端用命令來查看當(dāng)前的節(jié)點(diǎn)數(shù)目,你會(huì)發(fā)現(xiàn)客戶端已經(jīng)stop,但是產(chǎn)生的節(jié)點(diǎn)還在。
EPHEMERAL_SEQUENTIAL 臨時(shí)自動(dòng)編號(hào)節(jié)點(diǎn):此節(jié)點(diǎn)是屬于臨時(shí)節(jié)點(diǎn),不過帶有順序,客戶端會(huì)話結(jié)束節(jié)點(diǎn)就消失。
Dubbo是阿里巴巴公司開源的一個(gè)高性能優(yōu)秀的服務(wù)框架,使得應(yīng)用可通過高性能的 RPC 實(shí)現(xiàn)服務(wù)的輸出和輸入功能,可以和Spring框架無縫集成。Dubbo框架,是基于容器運(yùn)行的.。容器是Spring。
其核心部分包含:
1. 遠(yuǎn)程通訊: 提供對(duì)多種基于長(zhǎng)連接的NIO框架抽象封裝,包括多種線程模型,序列化,以及“請(qǐng)求-響應(yīng)”模式的信息交換方式。
2. 集群容錯(cuò): 提供基于接口方法的透明遠(yuǎn)程過程調(diào)用,包括多協(xié)議支持,以及軟負(fù)載均衡,失敗容錯(cuò),地址路由,動(dòng)態(tài)配置等集群支持。
3. 自動(dòng)發(fā)現(xiàn): 基于注冊(cè)中心目錄服務(wù),使服務(wù)消費(fèi)方能動(dòng)態(tài)的查找服務(wù)提供方,使地址透明,使服務(wù)提供方可以平滑增加或減少機(jī)器。
Dubbo能做什么?
1.透明化的遠(yuǎn)程方法調(diào)用,就像調(diào)用本地方法一樣調(diào)用遠(yuǎn)程方法,只需簡(jiǎn)單配置,沒有任何API侵入。 ? ? ?
2.軟負(fù)載均衡及容錯(cuò)機(jī)制,可在內(nèi)網(wǎng)替代F5等硬件負(fù)載均衡器,降低成本,減少單點(diǎn)。
3. 服務(wù)自動(dòng)注冊(cè)與發(fā)現(xiàn),不再需要寫死服務(wù)提供方地址,注冊(cè)中心基于接口名查詢服務(wù)提供者的IP地址,并且能夠平滑添加或刪除服務(wù)提供者。
Dubbo的存在簡(jiǎn)單來說就是要減小service層的壓力。
遠(yuǎn)程過程調(diào)用協(xié)議,它是一種通過網(wǎng)絡(luò)從遠(yuǎn)程計(jì)算機(jī)程序上請(qǐng)求服務(wù),而不需要了解底層網(wǎng)絡(luò)技術(shù)的協(xié)議。RPC協(xié)議假定某些傳輸協(xié)議的存在,如TCP或UDP,為通信程序之間攜帶信息數(shù)據(jù)。在OSI網(wǎng)絡(luò)通信模型中,RPC跨越了傳輸層和應(yīng)用層。RPC使得開發(fā)包括網(wǎng)絡(luò)分布式多程序在內(nèi)的應(yīng)用程序更加容易。
registry
注冊(cè)中心. 是用于發(fā)布和訂閱服務(wù)的一個(gè)平臺(tái).用于替代SOA結(jié)構(gòu)體系框架中的ESB服務(wù)總線的。
發(fā)布
開發(fā)服務(wù)端代碼完畢后, 將服務(wù)信息發(fā)布出去. 實(shí)現(xiàn)一個(gè)服務(wù)的公開.
訂閱
客戶端程序,從注冊(cè)中心下載服務(wù)內(nèi)容 這個(gè)過程是訂閱.
訂閱服務(wù)的時(shí)候, 會(huì)將發(fā)布的服務(wù)所有信息,一次性下載到客戶端.
客戶端也可以自定義, 修改部分服務(wù)配置信息. 如: 超時(shí)的時(shí)長(zhǎng), 調(diào)用的重試次數(shù)等.
Consumer
服務(wù)的消費(fèi)者, 就是服務(wù)的客戶端.
消費(fèi)者必須使用Dubbo技術(shù)開發(fā)部分代碼. 基本上都是配置文件定義.
provider
服務(wù)的提供者, 就是服務(wù)端.
服務(wù)端必須使用Dubbo技術(shù)開發(fā)部分代碼. 以配置文件為主.
container
容器. Dubbo技術(shù)的服務(wù)端(Provider), 在啟動(dòng)執(zhí)行的時(shí)候, 必須依賴容器才能正常啟動(dòng).
默認(rèn)依賴的就是spring容器. 且Dubbo技術(shù)不能脫離spring框架.
在2.5.3版本的dubbo中, 默認(rèn)依賴的是spring2.5版本技術(shù). 可以選用spring4.5以下版本.
在2.5.7版本的dubbo中, 默認(rèn)依賴的是spring4.3.10版本技術(shù). 可以選擇任意的spring版本.
monitor
監(jiān)控中心. 是Dubbo提供的一個(gè)jar工程.
主要功能是監(jiān)控服務(wù)端(Provider)和消費(fèi)端(Consumer)的使用數(shù)據(jù)的. 如: 服務(wù)端是什么,有多少接口,多少方法, 調(diào)用次數(shù), 壓力信息等. 客戶端有多少, 調(diào)用過哪些服務(wù)端, 調(diào)用了多少次等.
0 start: 啟動(dòng)Spring容器時(shí),自動(dòng)啟動(dòng)Dubbo的Provider
1、register: Dubbo的Provider在啟動(dòng)后自動(dòng)會(huì)去注冊(cè)中心注冊(cè)內(nèi)容.注冊(cè)的內(nèi)容包括:
1.1 Provider的 IP
1.2 Provider 的端口.
1.3 Provider 對(duì)外提供的接口列表.哪些方法.哪些接口類
1.4 Dubbo 的版本.
1.5 訪問Provider的協(xié)議.
2、subscribe: 訂閱.當(dāng)Consumer啟動(dòng)時(shí),自動(dòng)去Registry獲取到所已注冊(cè)的服務(wù)的信息.
3、notify: 通知.當(dāng)Provider的信息發(fā)生變化時(shí), 自動(dòng)由Registry向Consumer推送通知.
4、invoke: 調(diào)用. Consumer 調(diào)用Provider中方法
4.1 同步請(qǐng)求.消耗一定性能.但是必須是同步請(qǐng)求,因?yàn)樾枰邮照{(diào)用方法后的結(jié)果.
5、count:次數(shù). 每隔2分鐘,provoider和consumer自動(dòng)向Monitor發(fā)送訪問次數(shù).Monitor進(jìn)行統(tǒng)計(jì).
1、Dubbo協(xié)議(官方推薦協(xié)議)
優(yōu)點(diǎn):
采用NIO復(fù)用單一長(zhǎng)連接,并使用線程池并發(fā)處理請(qǐng)求,減少握手和加大并發(fā)效率,性能較好(推薦使用)
缺點(diǎn):
大文件上傳時(shí),可能出現(xiàn)問題(不使用Dubbo文件上傳)
2、RMI(Remote Method Invocation)協(xié)議
優(yōu)點(diǎn):
JDK自帶的能力。可與原生RMI互操作,基于TCP協(xié)議
缺點(diǎn):
偶爾連接失敗.
3、Hessian協(xié)議
優(yōu)點(diǎn):
可與原生Hessian互操作,基于HTTP協(xié)議
缺點(diǎn):
需hessian.jar支持,http短連接的開銷大
1、Zookeeper(官方推薦)
優(yōu)點(diǎn):支持分布式.很多周邊產(chǎn)品.
缺點(diǎn): 受限于Zookeeper軟件的穩(wěn)定性.Zookeeper專門分布式輔助軟件,穩(wěn)定較優(yōu)
2、Multicast
優(yōu)點(diǎn):去中心化,不需要單獨(dú)安裝軟件.
缺點(diǎn):Provider和Consumer和Registry不能跨機(jī)房(路由)
3、Redis
優(yōu)點(diǎn):支持集群,性能高
缺點(diǎn):要求服務(wù)器時(shí)間同步.否則可能出現(xiàn)集群失敗問題.
4、Simple
優(yōu)點(diǎn): 標(biāo)準(zhǔn)RPC服務(wù).沒有兼容問題
缺點(diǎn): 不支持集群.
答:SessionFactory對(duì)應(yīng)Hibernate的一個(gè)數(shù)據(jù)存儲(chǔ)的概念,它是線程安全的,可以被多個(gè)線程并發(fā)訪問。SessionFactory一般只會(huì)在啟動(dòng)的時(shí)候構(gòu)建。對(duì)于應(yīng)用程序,最好將SessionFactory通過單例的模式進(jìn)行封裝以便于訪問。Session是一個(gè)輕量級(jí)非線程安全的對(duì)象(線程間不能共享session),它表示與數(shù)據(jù)庫(kù)進(jìn)行交互的一個(gè)工作單元。Session是由SessionFactory創(chuàng)建的,在任務(wù)完成之后它會(huì)被關(guān)閉。Session是持久層服務(wù)對(duì)外提供的主要接口。Session會(huì)延遲獲取數(shù)據(jù)庫(kù)連接(也就是在需要的時(shí)候才會(huì)獲?。榱吮苊鈩?chuàng)建太多的session,可以使用ThreadLocal來取得當(dāng)前的session,無論你調(diào)用多少次getCurrentSession()方法,返回的都是同一個(gè)session。
答:主要有以下三項(xiàng)區(qū)別:
1)如果沒有找到符合條件的記錄, get方法返回null,load方法拋出異常
2)get方法直接返回實(shí)體類對(duì)象, load方法返回實(shí)體類對(duì)象的代理
3)在Hibernate 3之前,get方法只在一級(jí)緩存(內(nèi)部緩存)中進(jìn)行數(shù)據(jù)查找, 如果沒有找到對(duì)應(yīng)的數(shù)據(jù)則越過二級(jí)緩存, 直接發(fā)出SQL語句完成數(shù)據(jù)讀取; load方法則可以充分利用二級(jí)緩存中的現(xiàn)有數(shù)據(jù);當(dāng)然從Hibernate 3開始,get方法不再是對(duì)二級(jí)緩存只寫不讀,它也是可以訪問二級(jí)緩存的
簡(jiǎn)單的說,對(duì)于load()方法Hibernate認(rèn)為該數(shù)據(jù)在數(shù)據(jù)庫(kù)中一定存在可以放心的使用代理來實(shí)現(xiàn)延遲加載,如果沒有數(shù)據(jù)就拋出異常,而通過get()方法去取的數(shù)據(jù)可以不存在。
答:Hibernate的對(duì)象有三種狀態(tài):瞬態(tài)、持久態(tài)和游離態(tài)。游離狀態(tài)的實(shí)例可以通過調(diào)用save()、persist()或者saveOrUpdate()方法進(jìn)行持久化;脫管狀態(tài)的實(shí)例可以通過調(diào)用 update()、0saveOrUpdate()、lock()或者replicate()進(jìn)行持久化。save()和persist()將會(huì)引發(fā)SQL的INSERT語句,而update()或merge()會(huì)引發(fā)UPDATE語句。save()和update()的區(qū)別在于一個(gè)是將瞬態(tài)對(duì)象變成持久態(tài),一個(gè)是將游離態(tài)對(duì)象變?yōu)槌志脩B(tài)。merge方法可以完成save()和update()方法的功能,它的意圖是將新的狀態(tài)合并到已有的持久化對(duì)象上或創(chuàng)建新的持久化對(duì)象。按照官方文檔的說明:(1)persist()方法把一個(gè)瞬態(tài)的實(shí)例持久化,但是并"不保證"標(biāo)識(shí)符被立刻填入到持久化實(shí)例中,標(biāo)識(shí)符的填入可能被推遲到flush的時(shí)間;(2) persist"保證",當(dāng)它在一個(gè)事務(wù)外部被調(diào)用的時(shí)候并不觸發(fā)一個(gè)Insert語句,當(dāng)需要封裝一個(gè)長(zhǎng)會(huì)話流程的時(shí)候,一個(gè)persist這樣的函數(shù)是需要的。(3)save"不保證"第2條,它要返回標(biāo)識(shí)符,所以它會(huì)立即執(zhí)行Insert語句,不管是不是在事務(wù)內(nèi)部還是外部。update()方法是把一個(gè)已經(jīng)更改過的脫管狀態(tài)的對(duì)象變成持久狀態(tài);lock()方法是把一個(gè)沒有更改過的脫管狀態(tài)的對(duì)象變成持久狀態(tài)。
vsftpd 是“very secure FTP daemon”的縮寫,安全性是它的一個(gè)最大的特點(diǎn)。vsftpd 是一個(gè) UNIX 類操作系統(tǒng)上運(yùn)行的服務(wù)器的名字,它可以運(yùn)行在諸如 Linux、BSD、Solaris、 HP-UNIX等系統(tǒng)上面,是一個(gè)完全免費(fèi)的、開放源代碼的ftp服務(wù)器軟件,支持很多其他的 FTP 服務(wù)器所不支持的特征。
Nginx?(engine x) 是一個(gè)高性能的HTTP和反向代理服務(wù)。Nginx是由伊戈?duì)枴べ愃饕驗(yàn)槎砹_斯訪問量第二的Rambler.ru站點(diǎn)(俄文:Рамблер)開發(fā)的,第一個(gè)公開版本0.1.0發(fā)布于2004年10月4日。
Nginx 是一個(gè)很強(qiáng)大的高性能Web和反向代理服務(wù),它具有很多非常優(yōu)越的特性:在連接高并發(fā)的情況下,Nginx是Apache服務(wù)不錯(cuò)的替代品:Nginx在美國(guó)是做虛擬主機(jī)生意的老板們經(jīng)常選擇的軟件平臺(tái)之一。
答:http協(xié)議代理
搭建虛擬主機(jī)
服務(wù)的反向代理
在反向代理中配置集群的負(fù)載均衡
正向代理,意思是一個(gè)位于客戶端和原始服務(wù)器(origin server)之間的服務(wù)器,為了從原始服務(wù)器取得內(nèi)容,客戶端向代理發(fā)送一個(gè)請(qǐng)求并指定目標(biāo)(原始服務(wù)器),然后代理向原始服務(wù)器轉(zhuǎn)交請(qǐng)求并將獲得的內(nèi)容返回給客戶端??蛻舳瞬拍苁褂谜虼?。
反向代理(Reverse Proxy)方式是指以代理服務(wù)器來接受internet上的連接請(qǐng)求,然后將請(qǐng)求轉(zhuǎn)發(fā)給內(nèi)部網(wǎng)絡(luò)上的服務(wù)器,并將從服務(wù)器上得到的結(jié)果返回給internet上請(qǐng)求連接的客戶端,此時(shí)代理服務(wù)器對(duì)外就表現(xiàn)為一個(gè)反向代理服務(wù)器。
答:Remote Dictionary Server(Redis)是一個(gè)開源的使用ANSI?C語言編寫、支持網(wǎng)絡(luò)、可基于內(nèi)存亦可持久化的日志型、Key-Value數(shù)據(jù)庫(kù),并提供多種語言的API。
它通常被稱為數(shù)據(jù)結(jié)構(gòu)服務(wù)器,因?yàn)橹担╲alue)可以是 字符串(String), 哈希(Map), 列表(list), 集合(sets) 和 有序集合(sorted sets)等類型。
1. 支持多種數(shù)據(jù)結(jié)構(gòu),如 string(字符串)、 list(雙向鏈表)、dict(hash表)、set(集合)、zset(排序set)、hyperloglog(基數(shù)估算)
2. 支持持久化操作,可以進(jìn)行aof及rdb數(shù)據(jù)持久化到磁盤,從而進(jìn)行數(shù)據(jù)備份或數(shù)據(jù)恢復(fù)等操作,較好的防止數(shù)據(jù)丟失的手段。
3. 支持通過Replication進(jìn)行數(shù)據(jù)復(fù)制,通過master-slave機(jī)制,可以實(shí)時(shí)進(jìn)行數(shù)據(jù)的同步復(fù)制,支持多級(jí)復(fù)制和增量復(fù)制,master-slave機(jī)制是Redis進(jìn)行HA的重要手段。
單進(jìn)程請(qǐng)求,所有命令串行執(zhí)行,并發(fā)情況下不需要考慮數(shù)據(jù)一致性問題。
答:String(字符串)
Hash(hash表)
List(鏈表)
Set(集合)
SortedSet(有序集合zset)
incr 讓當(dāng)前鍵值以1的數(shù)量遞增,并返回遞增后的值
incrby 可以指定參數(shù)一次增加的數(shù)值,并返回遞增后的值
incrby 可以指定參數(shù)一次增加的數(shù)值,并返回遞增后的值
decrby 可以指定參數(shù)一次遞減的數(shù)值,并返回遞減后的值
incrbyfloat 可以遞增一個(gè)雙精度浮點(diǎn)數(shù)
append 作用是向鍵值的末尾追加value。如果鍵不存在則將該鍵的值設(shè)置為value。返回值是追加后字符串的總長(zhǎng)度。
mget/mset 作用與get/set相似,不過mget/mset可以同時(shí)獲得/設(shè)置多個(gè)鍵的鍵值
del 根據(jù)key來刪除value
flushdb 清除當(dāng)前庫(kù)的所有數(shù)據(jù)
hset 存儲(chǔ)一個(gè)哈希鍵值對(duì)的集合
hget獲取一個(gè)哈希鍵的值
hmset 存儲(chǔ)一個(gè)或多個(gè)哈希是鍵值對(duì)的集合
hmget 獲取多個(gè)指定的鍵的值
hexists 判斷哈希表中的字段名是否存在 如果存在返回1 否則返回0
hdel 刪除一個(gè)或多個(gè)字段
hgetall 獲取一個(gè)哈希是鍵值對(duì)的集合
hvals 只返回字段值
hkeys 只返回字段名
hlen 返回key的hash的元素個(gè)數(shù)
lpush key value向鏈表左側(cè)添加
rpush key value向鏈表右側(cè)添加
lpop key 從左邊移出一個(gè)元素
rpop key 從右邊移出一個(gè)元素
llen key 返回鏈表中元素的個(gè)數(shù) 相當(dāng)于關(guān)系型數(shù)據(jù)庫(kù)中 select count(*)
lrange key start end lrange命令將返回索引從start到stop之間的所有元素。Redis的列表起始索引為0。
lrange也支持負(fù)索引 lrange nn -2 -1 如 -1表示最右邊第一個(gè)元素 -2表示最右邊第二個(gè)元素,依次類推。
lindex key indexnumber 如果要將列表類型當(dāng)做數(shù)組來用,lindex命令是必不可少的。lindex命令用來返回指定索引的元素,索引從0開始
如果是負(fù)數(shù)表示從右邊開始計(jì)算的索引,最右邊元素的索引是-1。
Lset key indexnumber value 是另一個(gè)通過索引操作列表的命令,它會(huì)將索引為index的元素賦值為value。
sadd?key value?添加一個(gè)string元素到,key對(duì)應(yīng)的set集合中,成功返回1,如果元素已經(jīng)在集合中返回0
scard?key?返回set的元素個(gè)數(shù),如果set是空或者key不存在返回0
smembers?key?返回key對(duì)應(yīng)set的所有元素,結(jié)果是無序的
sismember?key value?判斷value 是否在set中,存在返回1,0表示不存在或者key不存在
srem key value 從key對(duì)應(yīng)set中移除給定元素,成功返回1,如果value 在集合中不存在或者key不存在返回0
zadd key score value 將一個(gè)或多個(gè)value及其socre加入到set中
zrange key start end 0和-1表示從索引為0的元素到最后一個(gè)元素(同LRANGE命令相似)
zrange key 0 -1 withscores 也可以連同score一塊輸出,使用WITHSCORES參數(shù)
zremrangebyscore key start end 可用于范圍刪除操作
ping 測(cè)試redis是否鏈接 如果已鏈接返回 PONG
echo value測(cè)試redis是否鏈接 如果已鏈接返回 echo命令后給定的值
keys * 返回所有的key 可以加*通配
exists key判斷string類型一個(gè)key是否存在 如果存在返回1 否則返回0
expire key time(s) 設(shè)置一個(gè)key的過期時(shí)間 單位秒。時(shí)間到達(dá)后會(huì)刪除key及value
ttl key 查詢已設(shè)置過期時(shí)間的key的剩余時(shí)間 如果返回-2表示該鍵值對(duì)已經(jīng)被刪除
persist 移除給定key的過期時(shí)間
select dbindex 選擇數(shù)據(jù)庫(kù)(0-15)
move key dbIndex 將當(dāng)前數(shù)據(jù)庫(kù)中的key轉(zhuǎn)移到其他數(shù)據(jù)庫(kù)中
dbsize 返回當(dāng)前數(shù)據(jù)庫(kù)中的key的數(shù)目
info 獲取服務(wù)器的信息和統(tǒng)計(jì)
flushdb 刪除當(dāng)前選擇的數(shù)據(jù)庫(kù)中的key
flushall 刪除所有數(shù)據(jù)庫(kù)中的所有key
quit 退出連接
答:以下兩種
RDB方式
AOF方式
答:是RDB是對(duì)內(nèi)存中數(shù)據(jù)庫(kù)狀態(tài)進(jìn)行快照
RDB方式:將Redis在內(nèi)存中的數(shù)據(jù)庫(kù)狀態(tài)保存到磁盤里面,RDB文件是一個(gè)經(jīng)過壓縮的二進(jìn)制文件,通過該文件可以還原生成RDB文件時(shí)的數(shù)據(jù)庫(kù)狀態(tài)(默認(rèn)下,持久化到dump.rdb文件,并且在redis重啟后,自動(dòng)讀取其中文件,據(jù)悉,通常情況下一千萬的字符串類型鍵,1GB的快照文件,同步到內(nèi)存中的 時(shí)間是20-30秒)
RDB的生成方式:
1、執(zhí)行命令手動(dòng)生成
有兩個(gè)Redis命令可以用于生成RDB文件,一個(gè)是SAVE,另一個(gè)是BGSAVE SAVE命令會(huì)阻塞Redis服務(wù)器進(jìn)程,直到RDB文件創(chuàng)建完畢為止,在服務(wù)器進(jìn)程阻塞期間,服務(wù)器不能處理任何命令請(qǐng)求,BGSAVE命令會(huì)派生出一個(gè)子進(jìn)程,然后由子進(jìn)程負(fù)責(zé)創(chuàng)建RDB文件,服務(wù)器進(jìn)程(父進(jìn)程)繼續(xù)處理命令請(qǐng)求,創(chuàng)建RDB文件結(jié)束之前,客戶端發(fā)送的BGSAVE和SAVE命令會(huì)被服務(wù)器拒絕
2、通過配置自動(dòng)生成
可以設(shè)置服務(wù)器配置的save選項(xiàng),讓服務(wù)器每隔一段時(shí)間自動(dòng)執(zhí)行一次BGSAVE命令,可以通過save選項(xiàng)設(shè)置多個(gè)保存條件,但只要其中任意一個(gè)條件被滿足,服務(wù)器就會(huì)執(zhí)行BGSAVE命令
例如:
save 900 1
save 300 10
save 60 10000
那么只要滿足以下三個(gè)條件中的任意一個(gè),BGSAVE命令就會(huì)被執(zhí)行
服務(wù)器在900秒之內(nèi),對(duì)數(shù)據(jù)庫(kù)進(jìn)行了至少1次修改
服務(wù)器在300秒之內(nèi),對(duì)數(shù)據(jù)庫(kù)進(jìn)行了至少10次修改
服務(wù)器在60秒之內(nèi),對(duì)數(shù)據(jù)庫(kù)進(jìn)行了至少10000次修改
AOF持久化方式在redis中默認(rèn)是關(guān)閉的,需要修改配置文件開啟該方式。
AOF:把每條命令都寫入文件,類似mysql的binlog日志
AOF方式:是通過保存Redis服務(wù)器所執(zhí)行的寫命令來記錄數(shù)據(jù)庫(kù)狀態(tài)的文件。
AOF文件刷新的方式,有三種:
appendfsync always - 每提交一個(gè)修改命令都調(diào)用fsync刷新到AOF文件,非常非常慢,但也非常安全
appendfsync everysec - 每秒鐘都調(diào)用fsync刷新到AOF文件,很快,但可能會(huì)丟失一秒以內(nèi)的數(shù)據(jù)
appendfsync no - 依靠OS進(jìn)行刷新,redis不主動(dòng)刷新AOF,這樣最快,但安全性就差
默認(rèn)并推薦每秒刷新,這樣在速度和安全上都做到了兼顧
AOF數(shù)據(jù)恢復(fù)方式
服務(wù)器在啟動(dòng)時(shí),通過載入和執(zhí)行AOF文件中保存的命令來還原服務(wù)器關(guān)閉之前的數(shù)據(jù)庫(kù)狀態(tài),具體過程:
載入AOF文件
創(chuàng)建模擬客戶端
從AOF文件中讀取一條命令
使用模擬客戶端執(zhí)行命令
循環(huán)讀取并執(zhí)行命令,直到全部完成
如果同時(shí)啟用了RDB和AOF方式,AOF優(yōu)先,啟動(dòng)時(shí)只加載AOF文件恢復(fù)數(shù)據(jù)
答:什么叫做全文檢索呢?這要從我們生活中的數(shù)據(jù)說起。
我們生活中的數(shù)據(jù)總體分為兩種:結(jié)構(gòu)化數(shù)據(jù)和非結(jié)構(gòu)化數(shù)據(jù)。
1)結(jié)構(gòu)化數(shù)據(jù):指具有固定格式或有限長(zhǎng)度的數(shù)據(jù),如數(shù)據(jù)庫(kù),元數(shù)據(jù)等。
2)非結(jié)構(gòu)化數(shù)據(jù):指不定長(zhǎng)或無固定格式的數(shù)據(jù),如郵件,word文檔等。
非結(jié)構(gòu)化數(shù)據(jù)又一種叫法叫全文數(shù)據(jù)。
?按照數(shù)據(jù)的分類,搜索也分為兩種:
1)對(duì)結(jié)構(gòu)化數(shù)據(jù)的搜索:如對(duì)數(shù)據(jù)庫(kù)的搜索,用SQL語句。
2)對(duì)非結(jié)構(gòu)化數(shù)據(jù)的搜索:如利用windows的搜索也可以搜索文件內(nèi)容,
全文檢索: 就是一種將文件中所有文本與檢索項(xiàng)匹配的文字資料檢索方法。全文檢索首先將要查詢的目標(biāo)文檔中的詞提取出來,組成索引,通過查詢索引達(dá)到搜索目標(biāo)文檔的目的。這種先建立索引,再對(duì)索引進(jìn)行搜索的過程就叫全文檢索(Full-text Search)。
Lucene是一個(gè)高效的,基于Java的全文檢索庫(kù)。
Lucene是apache軟件基金會(huì)4 jakarta項(xiàng)目組的一個(gè)子項(xiàng)目,是一個(gè)開放源代碼的全文檢索引擎工具包,但它不是一個(gè)完整的全文檢索引擎,而是一個(gè)全文檢索引擎的架構(gòu),Lucene的目的是為軟件開發(fā)人員提供一個(gè)簡(jiǎn)單易用的工具包,以方便的在目標(biāo)系統(tǒng)中實(shí)現(xiàn)全文檢索的功能,或者是以此為基礎(chǔ)建立起完整的全文檢索引擎。Lucene是一套用于全文檢索和搜尋的開源程序庫(kù),由Apache軟件基金會(huì)支持和提供。Lucene提供了一個(gè)簡(jiǎn)單卻強(qiáng)大的應(yīng)用程序接口,能夠做全文索引和搜尋。在Java開發(fā)環(huán)境里L(fēng)ucene是一個(gè)成熟的免費(fèi)開源工具。就其本身而言,Lucene是當(dāng)前以及最近幾年最受歡迎的免費(fèi)Java信息檢索程序庫(kù)。
答:Solr是一個(gè)獨(dú)立的企業(yè)級(jí)搜索應(yīng)用服務(wù)器,它對(duì)外提供類似于Web-service的API接口。
Solr是一個(gè)高性能,采用Java開發(fā),基于Lucene的全文搜索服務(wù)器。同時(shí)對(duì)其進(jìn)行了擴(kuò)展,提供了比Lucene更為豐富的查詢語言,同時(shí)實(shí)現(xiàn)了可配置、可擴(kuò)展并對(duì)查詢性能進(jìn)行了優(yōu)化,并且提供了一個(gè)完善的功能管理界面,是一款非常優(yōu)秀的全文檢索引擎。
文檔通過Http利用XML 加到一個(gè)搜索集合中。查詢?cè)摷弦彩峭ㄟ^http收到一個(gè)XML/JSON響應(yīng)來實(shí)現(xiàn)。它的主要特性包括:高效、靈活的緩存功能,垂直搜索功能,高亮顯示搜索結(jié)果,通過索引復(fù)制來提高可用性,提供一套強(qiáng)大Data Schema來定義字段,類型和設(shè)置文本分析,提供基于Web的管理界面等。
答:如下兩個(gè)部分
Solr的web服務(wù)
Solr的索引庫(kù)
正排索引是以文檔的ID為關(guān)鍵字,索引文檔中每個(gè)字的位置信息,查找時(shí)掃描索引中每個(gè)文檔中字的信息直到找出所有包含查詢關(guān)鍵字的文檔。
但是在查詢的時(shí)候需對(duì)所有的文檔進(jìn)行掃描以確保沒有遺漏,這樣就使得檢索時(shí)間大大延長(zhǎng),檢索效率低下。 ? ??
盡管正排索引的工作原理非常的簡(jiǎn)單,但是由于其檢索效率太低,除非在特定情況下,否則實(shí)用性價(jià)值不大。
對(duì)數(shù)據(jù)進(jìn)行分析,抽取出數(shù)據(jù)中的詞條,以詞條作為key,對(duì)應(yīng)數(shù)據(jù)的存儲(chǔ)位置作為value,實(shí)現(xiàn)索引的存儲(chǔ)。這種索引稱為倒排索引。
當(dāng)solr存儲(chǔ)文檔時(shí),solr會(huì)首先對(duì)文檔數(shù)據(jù)進(jìn)行分詞,創(chuàng)建索引庫(kù)和文檔數(shù)據(jù)庫(kù)。所謂的分詞是指:將一段字符文本按照一定的規(guī)則分成若干個(gè)單詞。
ActiveMQ是一種開源的,實(shí)現(xiàn)了JMS1.1規(guī)范的,面向消息(MOM)的中間件,為應(yīng)用程序提供高效的、可擴(kuò)展的、穩(wěn)定的和安全的企業(yè)級(jí)消息通信。ActiveMQ使用Apache提供的授權(quán),任何人都可以對(duì)其實(shí)現(xiàn)代碼進(jìn)行修改。
ActiveMQ的設(shè)計(jì)目標(biāo)是提供標(biāo)準(zhǔn)的,面向消息的,能夠跨越多語言和多系統(tǒng)的應(yīng)用集成消息通信中間件。
ActiveMQ實(shí)現(xiàn)了JMS標(biāo)準(zhǔn)并提供了很多附加的特性。這些附加的特性包括,JMX管理(java Management Extensions,即java管理擴(kuò)展),主從管理(master/salve,這是集群模式的一種,主要體現(xiàn)在可靠性方面,當(dāng)主中介(代理)出現(xiàn)故障,那么從代理會(huì)替代主代理的位置,不至于使消息系統(tǒng)癱瘓)、消息組通信(同一組的消息,僅會(huì)提交給一個(gè)客戶進(jìn)行處理)、有序消息管理(確保消息能夠按照發(fā)送的次序被接受者接收)。消息優(yōu)先級(jí)(優(yōu)先級(jí)高的消息先被投遞和處理)、訂閱消息的延遲接收(訂閱消息在發(fā)布時(shí),如果訂閱者沒有開啟連接,那么當(dāng)訂閱者開啟連接時(shí),消息中介將會(huì)向其提交之前的,其未處理的消息)、接收者處理過慢(可以使用動(dòng)態(tài)負(fù)載平衡,將多數(shù)消息提交到處理快的接收者,這主要是對(duì)PTP消息所說)、虛擬接收者(降低與中介的連接數(shù)目)、成熟的消息持久化技術(shù)(部分消息需要持久化到數(shù)據(jù)庫(kù)或文件系統(tǒng)中,當(dāng)中介崩潰時(shí),信息不會(huì)丟失)、支持游標(biāo)操作(可以處理大消息)、支持消息的轉(zhuǎn)換、通過使用Apache的Camel可以支持EIP、使用鏡像隊(duì)列的形式輕松的對(duì)消息隊(duì)列進(jìn)行監(jiān)控等。
答:如下3個(gè)場(chǎng)景都可以使用消息服務(wù)
1、異步處理
2、應(yīng)用的解耦
3、流量的削峰
JMS(Java Messaging Service)是Java平臺(tái)上有關(guān)面向消息中間件的技術(shù)規(guī)范,它便于消息系統(tǒng)中的Java應(yīng)用程序進(jìn)行消息交換,并且通過提供標(biāo)準(zhǔn)的產(chǎn)生、發(fā)送、接收消息的接口,簡(jiǎn)化企業(yè)應(yīng)用的開發(fā)。
答:JMS消息機(jī)制主要分為兩種模型:PTP模型和Pub/Sub模型。
1、PTP模型:(Point? to Point 對(duì)點(diǎn)模型) 每一個(gè)消息傳遞給一個(gè)消息消費(fèi)者,保證消息傳遞給消息消費(fèi)者,且消息不會(huì)同時(shí)被多個(gè)消費(fèi)者接收。如果消息消費(fèi)者暫時(shí)不在連接范圍內(nèi),JMS會(huì)自動(dòng)保證消息不會(huì)丟失,直到消息消費(fèi)者進(jìn)入連接,消息將自動(dòng)送達(dá)。因此,JMS需要將消息保存到永久性介質(zhì)上,例如數(shù)據(jù)庫(kù)或者文件。
2、Pub-Sub模型:(publish-subscription 發(fā)布者訂閱者模型)每個(gè)主題可以擁有多個(gè)訂閱者。JMS系統(tǒng)負(fù)責(zé)將消息的副本傳給該主題的每個(gè)訂閱者。
如果希望每一條消息都能夠被處理,那么應(yīng)該使用PTP消息模型。如果并不要求消息都必須被消息消費(fèi)者接收到的情況下,可使用pub-sub消息模型。Pub-Sub模型可以在一對(duì)多的消息廣播時(shí)使用。
Jsonp(JSON with Padding) 是 json 的一種"使用模式",可以讓網(wǎng)頁從別的域名(網(wǎng)站)那獲取資料,即跨域讀取數(shù)據(jù)。
跨域是指一個(gè)域(網(wǎng)站)下的文檔或腳本試圖去請(qǐng)求另一個(gè)域(網(wǎng)站)下的資源。
同源策略/SOP(Same origin policy)是一種約定,由Netscape公司1995年引入瀏覽器,它是瀏覽器最核心也最基本的安全功能,現(xiàn)在所有支持JavaScript 的瀏覽器都會(huì)使用這個(gè)策略。如果缺少了同源策略,瀏覽器很容易受到XSS、CSFR等攻擊。所謂同源是指"協(xié)議+域名+端口"三者相同,即便兩個(gè)不同的域名指向同一個(gè)ip地址,也非同源
MyCat是目前最流行的基于java語言編寫的數(shù)據(jù)庫(kù)中間件,是一個(gè)實(shí)現(xiàn)了MySQL協(xié)議的服務(wù)器,前端用戶可以把它看作是一個(gè)數(shù)據(jù)庫(kù)代理,用MySQL客戶端工具和命令行訪問,而其后端可以用MySQL原生協(xié)議與多個(gè)MySQL服務(wù)器通信,也可以用JDBC協(xié)議與大多數(shù)主流數(shù)據(jù)庫(kù)服務(wù)器通信,其核心功能是分庫(kù)分表。配合數(shù)據(jù)庫(kù)的主從模式還可實(shí)現(xiàn)讀寫分離。
MyCat是基于阿里開源的Cobar產(chǎn)品而研發(fā),Cobar的穩(wěn)定性、可靠性、優(yōu)秀的架構(gòu)和性能以及眾多成熟的使用案例使得MyCat變得非常的強(qiáng)大。
MyCat發(fā)展到目前的版本,已經(jīng)不是一個(gè)單純的MySQL代理了,它的后端可以支持MySQL、SQL Server、Oracle、DB2、PostgreSQL等主流數(shù)據(jù)庫(kù),也支持MongoDB這種新型NoSQL方式的存儲(chǔ),未來還會(huì)支持更多類型的存儲(chǔ)。而在最終用戶看來,無論是那種存儲(chǔ)方式,在MyCat里,都是一個(gè)傳統(tǒng)的數(shù)據(jù)庫(kù)表,支持標(biāo)準(zhǔn)的SQL語句進(jìn)行數(shù)據(jù)的操作,這樣一來,對(duì)前端業(yè)務(wù)系統(tǒng)來說,可以大幅降低開發(fā)難度,提升開發(fā)速度。
就是把原本存儲(chǔ)于一個(gè)庫(kù)的數(shù)據(jù)存儲(chǔ)到多個(gè)庫(kù)上。
由于對(duì)數(shù)據(jù)庫(kù)的讀寫都是對(duì)同一個(gè)庫(kù)進(jìn)行操作,所以單庫(kù)并不能解決大規(guī)模并發(fā)寫入的問題。
例如,我們會(huì)建立定義數(shù)據(jù)庫(kù)workDB、商品數(shù)據(jù)庫(kù)payDB、用戶數(shù)據(jù)庫(kù)userDB、日志數(shù)據(jù)庫(kù)logDB等,分別用于存儲(chǔ)項(xiàng)目數(shù)據(jù)定義表、商品定義表、用戶數(shù)據(jù)表、日志數(shù)據(jù)表等。
優(yōu)點(diǎn)
1)減少增量數(shù)據(jù)寫入時(shí)的鎖對(duì)查詢的影響。
2)由于單表數(shù)量下降,常見的查詢操作由于減少了需要掃描的記錄,使得單表單次查詢所需的檢索行數(shù)變少,減少了磁盤IO,時(shí)延變短。
缺點(diǎn):
無法解決單表數(shù)據(jù)量太大的問題。
橫向切分/水平切分
把原本存儲(chǔ)于一個(gè)表的數(shù)據(jù)分塊存儲(chǔ)到多個(gè)表上。當(dāng)一個(gè)表中的數(shù)據(jù)量過大時(shí),我們可以把該表的數(shù)據(jù)按照某種規(guī)則,進(jìn)行劃分,然后存儲(chǔ)到多個(gè)結(jié)構(gòu)相同的表,和不同的庫(kù)上。
例如,我們userDB中的userTable中數(shù)據(jù)量很大,那么可以把userDB切分為結(jié)構(gòu)相同的多個(gè)userDB:part0DB、part1DB等,再將userDB上的userTable,切分為很多userTable:userTable0、userTable1等,然后將這些表按照一定的規(guī)則存儲(chǔ)到多個(gè)userDB上。
優(yōu)點(diǎn):
1)單表的并發(fā)能力提高了,磁盤I/O性能也提高了。
2)如果出現(xiàn)高并發(fā)的話,總表可以根據(jù)不同的查詢,將并發(fā)壓力分到不同的小表里面。
缺點(diǎn):無法實(shí)現(xiàn)表連接查詢。
答:Apache:全球應(yīng)用最廣泛的http服務(wù)器,免費(fèi),出自apache基金組織?
Tomcat:應(yīng)用也算非常廣泛的web 服務(wù)器,支持部分j2ee,免費(fèi),出自 apache基金組織?
JBoss:開源的應(yīng)用服務(wù)器,比較受人喜愛,免費(fèi)(文檔要收費(fèi))?
weblogic:應(yīng)該說算是業(yè)界第一的app server,全部支持j2ee1.4(收費(fèi))
JBoss也支持j2ee
JBoss和WebLogic都含有Jsp和Servlet容器,也就可以做web容器,?
JBoss和WebLogic也包含EJB容器,是完整的J2EE應(yīng)用服務(wù)器
tomcat 只能做jsp和servlet的container
A. | nagios |
B. | Jenkins |
C. | nginx |
D. | docker |
分析:答案: C Nginx是一款輕量級(jí)的Web?服務(wù)器/反向代理服務(wù)器及電子郵件(IMAP/POP3)代理服務(wù)器,并在一個(gè)BSD-like 協(xié)議下發(fā)行。其特點(diǎn)是占有內(nèi)存少,并發(fā)能力強(qiáng),事實(shí)上nginx的并發(fā)能力確實(shí)在同類型的網(wǎng)頁服務(wù)器中表現(xiàn)較好,中國(guó)大陸使用nginx網(wǎng)站用戶有:百度、京東、新浪、網(wǎng)易、騰訊、淘寶等
|
作用:
Tomcat:目前應(yīng)用非常廣泛的免費(fèi)web服務(wù)器,支持部分j2ee。
WebSphere:是IBM集成軟件平臺(tái)??勺鰓eb服務(wù)器,WebSphere提供了可靠、靈活和健壯的集成軟件。
Weblogic:是美國(guó)bea公司出品的一個(gè)基于j2ee架構(gòu)的中間件。BEA WebLogic是用于開發(fā)、集成、部署和管理大型分布式Web應(yīng)用、網(wǎng)絡(luò)應(yīng)用和數(shù)據(jù)庫(kù)應(yīng)用的Java應(yīng)用服務(wù)器。
特點(diǎn)(區(qū)別):
1)價(jià)位不同:Tomcat的是免費(fèi)的;WebLogic與WebSphere是收費(fèi)的,而且價(jià)格不菲。
2) 開源性不同:Tomcat的是完全開源的,而其他兩個(gè)不是。WebLogic與WebSphere都是對(duì)業(yè)內(nèi)多種標(biāo)準(zhǔn)的全面支持,包括JSB、JMS、JDBC、XML和WML,使Web應(yīng)用系統(tǒng)實(shí)施更簡(jiǎn)單,且保護(hù)投資,同時(shí)也使基于標(biāo)準(zhǔn)的解決方案的開發(fā)更加簡(jiǎn)便。
3) 擴(kuò)展性的不同:WebLogic和WebSphere都是以其高擴(kuò)展的架構(gòu)體系聞名于業(yè)內(nèi),包括客戶機(jī)連接的共享、資源 pooling以及動(dòng)態(tài)網(wǎng)頁。
4)應(yīng)用范圍的區(qū)別:Tomcat 是一個(gè)小型的輕量級(jí)應(yīng)用服務(wù)器,在中小型系統(tǒng)和并發(fā)訪問用戶不是很多的場(chǎng)合下被普遍使用,是開發(fā)和調(diào)試JSP 程序的首選。WebLogic和WebSphere是商業(yè)軟件,功能齊全強(qiáng)大,主要應(yīng)用于大型企業(yè)的大型項(xiàng)目。
5)安全性問題區(qū)別:因?yàn)門omcat是開源的,所以它們的安全性相對(duì)來說比較低,萬一應(yīng)用服務(wù)器本身有什么漏洞,你是沒辦法向Apache索賠的。而WebLogic和WebSphere其容錯(cuò)、系統(tǒng)管理和安全性能已經(jīng)在全球數(shù)以千記的關(guān)鍵任務(wù)環(huán)境中得以驗(yàn)證。
C/S結(jié)構(gòu),即Client/Server(客戶機(jī)/服務(wù)器)結(jié)構(gòu),通過將任務(wù)合理分配到Client端和Server端,降低了系統(tǒng)的通訊開銷,可充分利用兩端硬件環(huán)境優(yōu)勢(shì)。早期軟件系統(tǒng)多以此作為首選設(shè)計(jì)標(biāo)準(zhǔn)。
B/S結(jié)構(gòu),即Browser/Server(瀏覽器/服務(wù)器)結(jié)構(gòu),是隨著Internet技術(shù)的興起,對(duì)C/S結(jié)構(gòu)的一種變化或者改進(jìn)的結(jié)構(gòu)。在這種結(jié)構(gòu)下,用戶界面完全通過WWW瀏覽器實(shí)現(xiàn),一部分事務(wù)邏輯在前端實(shí)現(xiàn),但是主要事務(wù)邏輯在服務(wù)器端實(shí)現(xiàn),節(jié)約了開發(fā)成本,便于軟件維護(hù)。
區(qū)別
1、C/S是建立在局域網(wǎng)的基礎(chǔ)上的。B/S是建立在廣域網(wǎng)的基礎(chǔ)上的,但并不是說B/S結(jié)構(gòu)不能在局域網(wǎng)上使用。
2、B/S業(yè)務(wù)擴(kuò)展簡(jiǎn)單方便,通過增加頁面即可增加服務(wù)器功能。C/S的客戶端還需要安裝專用的客戶端軟件,不利于擴(kuò)展。
3、B/S維護(hù)簡(jiǎn)單方便。開發(fā)、維護(hù)等幾乎所有工作也都集中在服務(wù)器端,當(dāng)企業(yè)對(duì)網(wǎng)絡(luò)應(yīng)用進(jìn)行升級(jí)時(shí),只需更新服務(wù)器端的軟件就可以,這減輕了異地用戶系統(tǒng)維護(hù)與升級(jí)的成本
4、B/S響應(yīng)速度不及C/S;
5、B/S用戶體驗(yàn)效果不是很理想
容器也是 java 程序,它的主要作用是為應(yīng)用程序提供運(yùn)行環(huán)境。容器用來接管安全性、并發(fā)性、事務(wù)處理、交換到輔助存儲(chǔ)器和其它服務(wù)的責(zé)任
以tomcat為例:Tomcat是一個(gè)后臺(tái)服務(wù)進(jìn)程,其它的servlet(相當(dāng)于DLL)是在Tomcat容器內(nèi)運(yùn)行,Broswer只與Tomcat通迅; Tomcat接受browser的請(qǐng)求,經(jīng)過一系列動(dòng)作(如果是靜態(tài)網(wǎng)頁,那么裝載,按http協(xié)議形成響應(yīng)流;如果是動(dòng)態(tài)的如JSP,那就要調(diào)用JDK 中的servlet.jsp接口,解釋形成靜態(tài)網(wǎng)頁,按http協(xié)議生成響應(yīng)流發(fā)送回browser)后,形成靜態(tài)網(wǎng)頁,返回響應(yīng)。
?傳統(tǒng)的數(shù)據(jù)庫(kù)連接方式
一個(gè)連接對(duì)象對(duì)應(yīng)一個(gè)物理連接
每次操作都打開一個(gè)物理連接,
使用完都關(guān)閉連接,造成系統(tǒng)性能低下。
?連接池技術(shù)
客戶程序得到的連接對(duì)象是連接池中物理連接的一個(gè)句柄,調(diào)用連接對(duì)象的close()方法,物理連接并沒有關(guān)閉,數(shù)據(jù)源的實(shí)現(xiàn)只是刪除了客戶程序中的連接對(duì)象和池中的連接對(duì)象之間的聯(lián)系.
?數(shù)據(jù)庫(kù)連接的建立及關(guān)閉是耗費(fèi)系統(tǒng)資源的操作,在大型應(yīng)用中對(duì)系統(tǒng)的性能影響尤為明顯。為了能重復(fù)利用數(shù)據(jù)庫(kù)連接對(duì)象,縮短請(qǐng)求的響應(yīng)時(shí)間和提高服務(wù)器的性能,支持更多的客戶,應(yīng)采用連接池技術(shù).
數(shù)據(jù)庫(kù)連接池的原理
傳統(tǒng)連接方式:
首先調(diào)用Class.forName()方法加載數(shù)據(jù)庫(kù)驅(qū)動(dòng),
然后調(diào)用DriverManager.getConnection()方法建立連接.
連接池技術(shù):
連接池解決方案是在應(yīng)用程序啟動(dòng)時(shí)就預(yù)先建立多個(gè)數(shù)據(jù)庫(kù)連接對(duì)象,然后將連接對(duì)象保存到連接池中。
當(dāng)客戶請(qǐng)求到來時(shí),從池中取出一個(gè)連接對(duì)象為客戶服務(wù)。
當(dāng)請(qǐng)求完成時(shí),客戶程序調(diào)用close()方法,將連接對(duì)象放回池中.
對(duì)于多于連接池中連接數(shù)的請(qǐng)求,排隊(duì)等待。
應(yīng)用程序還可根據(jù)連接池中連接的使用率,動(dòng)態(tài)增加或減少池中的連接數(shù)。
一、MVC原理
MVC是一種程序開發(fā)設(shè)計(jì)模式,它實(shí)現(xiàn)了顯示模塊與功能模塊的分離。提高了程序的可維護(hù)性、可移植性、可擴(kuò)展性與可重用性,降低了程序的開發(fā)難度。它主要分模型、視圖、控制器三層。
1、模型(model)它是應(yīng)用程序的主體部分,主要包括業(yè)務(wù)邏輯模塊和數(shù)據(jù)模塊。模型與數(shù)據(jù)格式無關(guān),這樣一個(gè)模型能為多個(gè)視圖提供數(shù)據(jù)。由于應(yīng)用于模型的代碼只需寫一次就可以被多個(gè)視圖重用,所以減少了代碼的重復(fù)性
2、視圖(view) 用戶與之交互的界面、在web中視圖一般由jsp,html組成
3、控制器(controller)接收來自界面的請(qǐng)求 并交給模型進(jìn)行處理 在這個(gè)過程中控制器不做任何處理只是起到了一個(gè)連接的作用
二、MVC的優(yōu)點(diǎn)
1、降低代碼耦合性。在MVC模式中,三個(gè)層各施其職,所以如果一旦哪一層的需求發(fā)生了變化,就只需要更改相應(yīng)的層中的代碼而不會(huì)影響到其他層中的代碼。
2、有利于分工合作。在MVC模式中,由于按層把系統(tǒng)分開,那么就能更好的實(shí)現(xiàn)開發(fā)中的分工。網(wǎng)頁設(shè)計(jì)人員可進(jìn)行開發(fā)視圖層中的JSP,而對(duì)業(yè)務(wù)熟悉的人員可開發(fā)業(yè)務(wù)層,而其他開發(fā)人員可開發(fā)控制層。
3、有利于組件的重用。如控制層可獨(dú)立成一個(gè)能用的組件,表示層也可做成通用的操作界面。可以為一個(gè)模型在運(yùn)行時(shí)同時(shí)建立和使用多個(gè)視圖。
三、MVC的不足之處
1、增加了系統(tǒng)結(jié)構(gòu)和實(shí)現(xiàn)的復(fù)雜性。對(duì)于簡(jiǎn)單的界面,嚴(yán)格遵循MVC,使模型、視圖與控制器分離,會(huì)增加結(jié)構(gòu)的復(fù)雜性,并可能產(chǎn)生過多的更新操作,降低運(yùn)行效率。
2、視圖與控制器間的過于緊密的連接。視圖與控制器是相互分離,但確實(shí)聯(lián)系緊密的部件,視圖沒有控制器的存在,其應(yīng)用是很有限的,反之亦然,這樣就妨礙了他們的獨(dú)立重用。
3、視圖對(duì)模型數(shù)據(jù)的低效率訪問。依據(jù)模型操作接口的不同,視圖可能需要多次調(diào)用才能獲得足夠的顯示數(shù)據(jù)。對(duì)未變化數(shù)據(jù)的不必要的頻繁訪問,也將損害操作性能。
4、目前,一般高級(jí)的界面工具或構(gòu)造器不支持模式。改造這些工具以適應(yīng)MVC需要和建立分離的部件的代價(jià)是很高的,從而造成MVC使用的困難。
1)頁面提交頁碼(第幾頁)到Servlet中
2)Servlet接收到頁碼后,將頁碼傳遞給分頁工具類(PageBean)
3)Servlet中調(diào)用Service層傳入PageBean對(duì)象
4)Service層調(diào)用DAO層傳入PageBean對(duì)象
5)Servlet中得到查詢出來的數(shù)據(jù),并setAttrivute保存
6)在頁面中得到(getAttribute)數(shù)據(jù),遍歷輸出
答: Unix和Linux平臺(tái)下使用最廣泛的免費(fèi)HTTP服務(wù)器是Apache服務(wù)器,而Windows平臺(tái)的服務(wù)器通常使用IIS作為Web服務(wù)器。選擇Web服務(wù)器應(yīng)考慮的因素有:性能、安全性、日志和統(tǒng)計(jì)、虛擬主機(jī)、代理服務(wù)器、緩沖服務(wù)和集成應(yīng)用程序等。下面是對(duì)常用服務(wù)器的簡(jiǎn)介:
IIS:Microsoft的Web服務(wù)器產(chǎn)品為Internet Information Services。IIS 是允許在公共Intranet或Internet上發(fā)布信息的Web服務(wù)器。IIS是目前最流行的Web服務(wù)器產(chǎn)品之一,很多著名的網(wǎng)站都是建立在IIS的平臺(tái)上。IIS提供了一個(gè)圖形界面的管理工具,稱為Internet服務(wù)管理器,可用于監(jiān)視配置和控制Internet服務(wù)。IIS是一種Web服務(wù)組件,其中包括Web服務(wù)器、FTP服務(wù)器、NNTP服務(wù)器和SMTP服務(wù)器,分別用于網(wǎng)頁瀏覽、文件傳輸、新聞服務(wù)和郵件發(fā)送等方面,它使得在網(wǎng)絡(luò)(包括互聯(lián)網(wǎng)和局域網(wǎng))上發(fā)布信息成了一件很容易的事。它提供ISAPI(Intranet Server API)作為擴(kuò)展Web服務(wù)器功能的編程接口;同時(shí),它還提供一個(gè)Internet數(shù)據(jù)庫(kù)連接器,可以實(shí)現(xiàn)對(duì)數(shù)據(jù)庫(kù)的查詢和更新。
Kangle:Kangle Web服務(wù)器是一款跨平臺(tái)、功能強(qiáng)大、安全穩(wěn)定、易操作的高性能Web服務(wù)器和反向代理服務(wù)器軟件。此外,Kangle也是一款專為做虛擬主機(jī)研發(fā)的Web服務(wù)器。實(shí)現(xiàn)虛擬主機(jī)獨(dú)立進(jìn)程、獨(dú)立身份運(yùn)行。用戶之間安全隔離,一個(gè)用戶出問題不影響其他用戶。支持PHP、ASP、ASP.NET、Java、Ruby等多種動(dòng)態(tài)開發(fā)語言。
WebSphere:WebSphere Application Server是功能完善、開放的Web應(yīng)用程序服務(wù)器,是IBM電子商務(wù)計(jì)劃的核心部分,它是基于Java的應(yīng)用環(huán)境,用于建立、部署和管理Internet和Intranet Web應(yīng)用程序,適應(yīng)各種Web應(yīng)用程序服務(wù)器的需要,范圍從簡(jiǎn)單到高級(jí)直到企業(yè)級(jí)。
WebLogic:BEA WebLogic Server是一種多功能、基于標(biāo)準(zhǔn)的Web應(yīng)用服務(wù)器,為企業(yè)構(gòu)建自己的應(yīng)用提供了堅(jiān)實(shí)的基礎(chǔ)。各種應(yīng)用開發(fā)、部署所有關(guān)鍵性的任務(wù),無論是集成各種系統(tǒng)和數(shù)據(jù)庫(kù),還是提交服務(wù)、跨Internet協(xié)作,Weblogic都提供了相應(yīng)的支持。由于它具有全面的功能、對(duì)開放標(biāo)準(zhǔn)的遵從性、多層架構(gòu)、支持基于組件的開發(fā),基于Internet的企業(yè)都選擇它來開發(fā)、部署最佳的應(yīng)用。BEA WebLogic Server在使應(yīng)用服務(wù)器成為企業(yè)應(yīng)用架構(gòu)的基礎(chǔ)方面一直處于領(lǐng)先地位,為構(gòu)建集成化的企業(yè)級(jí)應(yīng)用提供了穩(wěn)固的基礎(chǔ),它們以 Internet的容量和速度,在連網(wǎng)的企業(yè)之間共享信息、提交服務(wù),實(shí)現(xiàn)協(xié)作自動(dòng)化。
Apache:目前Apache仍然是世界上用得最多的Web服務(wù)器,市場(chǎng)占有率約為60%左右。世界上很多著名的網(wǎng)站都是Apache的產(chǎn)物,它的成功之處主要在于它的源代碼開放、有一支強(qiáng)大的開發(fā)團(tuán)隊(duì)、支持跨平臺(tái)的應(yīng)用(可以運(yùn)行在幾乎所有的Unix、Windows、Linux系統(tǒng)平臺(tái)上)以及它的可移植性等方面。
Tomcat:Tomcat是一個(gè)開放源代碼、運(yùn)行Servlet和JSP的容器。TomcatServer實(shí)現(xiàn)了Servlet和JSP規(guī)范。此外,Tomcat還實(shí)現(xiàn)了Apache-Jakarta規(guī)范而且比絕大多數(shù)商業(yè)應(yīng)用軟件服務(wù)器要好,因此目前也有不少的Web服務(wù)器都選擇了Tomcat。
Nginx:讀作"engine x",是一個(gè)高性能的HTTP和反向代理服務(wù)器,也是一個(gè)IMAP/POP3/SMTP代理服務(wù)器。 Nginx是由Igor Sysoev為俄羅斯訪問量第二的 Rambler.ru站點(diǎn)開發(fā)的,第一個(gè)公開版本0.1.0發(fā)布于2004年10月4日。其將源代碼以類BSD許可證的形式發(fā)布,因它的穩(wěn)定性、豐富的功能集、示例配置文件和低系統(tǒng)資源的消耗而聞名。
答:Model 1是以頁面為中心的Java Web開發(fā),只適合非常小型的應(yīng)用程序,Model 2是基于MVC架構(gòu)模式的應(yīng)用,這一點(diǎn)在前文的面試題中已經(jīng)詳細(xì)講解過了。
框架(framework)是一個(gè)框子--》指約束性,也是一個(gè)架子--》指支撐性IT語境中的框架,特指為解決一個(gè)開放性問題而設(shè)計(jì)的具有一定約束性的支撐結(jié)構(gòu),在此結(jié)構(gòu)上可以根據(jù)具體問題擴(kuò)展、按插更多的組成部分,從而更迅速和方便地架構(gòu)完整的解決問題的方案。
1)框架本身一般不完整到可以解決特定問題,但是可以幫助您快速解決特定問題:
沒有框架所有的工作都從零開始做,有了框架,為我們提供了一定的功能。我們就可以在框架的基礎(chǔ)上開發(fā),極大的解決了生產(chǎn)力。
不同的框架,是為了解決不同領(lǐng)域的問題,一定要為了解決問題才去學(xué)習(xí)框架。
2)框架天生就是為了擴(kuò)展而設(shè)計(jì)的
3)框架里面可以為后續(xù)的組件提供很多輔助性、支撐性的方便易用的實(shí)用工具(utilities),也就是框架時(shí)常配套一些幫組解決某類問題的庫(kù)(libraries)或工具(tools).
在java中就是一系列的jar包,其本質(zhì)就是對(duì)jdk功能的擴(kuò)展。
是為了解決傳統(tǒng)MVC模式(jsp+servlet+javabean)一些問題而出現(xiàn)的框架
傳統(tǒng)MVC模式模式問題:
1) 所有的Servlet和Servlet映射都要配置在web.xml中,如果項(xiàng)目太大,web.xml就太龐大并且不能實(shí)現(xiàn)模塊化管理。
2)Servlet的主要功能就是接受參數(shù)、調(diào)用邏輯、跳轉(zhuǎn)頁面,比如像其他字符編碼、文件上傳等功能也要寫在Servlet中,不能讓Servlet主要功能而需要做處理一些特例。
3)接受參數(shù)比較麻煩
(String name = request.getParameter(“name”)),不能通過model接受,只能單個(gè)接收,接收完成后轉(zhuǎn)換封裝model。
4)跳轉(zhuǎn)頁面方式比較單一(forward,redirect),并且當(dāng)我們的頁面名稱發(fā)生改變時(shí)需要改變Servlet源代碼。
現(xiàn)在比較常用的MVC框架:
webwork
Struts
Struts2
SpringMVC
?一個(gè)請(qǐng)求在struts2框架中處理大概分為一下幾個(gè)步驟:
1)客戶瀏覽器發(fā)送一個(gè)指向Servlet容器(例如Tomcat)的請(qǐng)求
2)這個(gè)請(qǐng)求經(jīng)過一系列的過濾器(Filter)(這些過濾器中有一個(gè)叫做ActionContextCleanUp的可選過濾器,這個(gè)過濾器對(duì)于Struts2和其他框架的集成很有幫助,例如:SiteMesh Plugin)
3)接著FilterDispatcher(StrutsPrepareAndExecuteFilter)被調(diào)用,F(xiàn)ilterDispatcher詢問ActionMapper來決定這個(gè)請(qǐng)是否需要調(diào)用某個(gè)Action
4)如果ActionMapper決定需要調(diào)用某個(gè)Action,F(xiàn)ilterDispatcher把請(qǐng)求的處理交給ActionProxy
5)ActionProxy通過Configuration Manager詢問框架的配置文件,找到需要調(diào)用的Action類
6)ActionProxy創(chuàng)建一個(gè)ActionInvocation的實(shí)例。
7)ActionInvocation實(shí)例使用命名模式來調(diào)用,在調(diào)用Action的過程前后,涉及到相關(guān)攔截器(Intercepter)的調(diào)用。
8)一旦Action執(zhí)行完畢,ActionInvocation負(fù)責(zé)根據(jù)struts.xml中的配置找到對(duì)應(yīng)的返回結(jié)果。返回結(jié)果通常是(但不總是,也 可 能是另外的一個(gè)Action鏈)一個(gè)需要被表示的JSP或者FreeMarker的模版。在表示的過程中可以使用Struts2 框架中繼承的標(biāo)簽。在這個(gè)過程中需要涉及到ActionMapper
java里的攔截器是動(dòng)態(tài)攔截Action調(diào)用的對(duì)象,它提供了一種機(jī)制可以使開發(fā)者定義一個(gè)action執(zhí)行的前后執(zhí)行的代碼,也可以在一個(gè)action執(zhí)行前阻止其執(zhí)行,同時(shí)也提供了一種可以提取action中可重用部分的方式。
在AOP(Aspect Oriented Programming)中攔截器用于在某個(gè)方法或字段被訪問之前,進(jìn)行攔截后在之前或之后加入某些操作
1)struts2中的功能(參數(shù)處理、文件上傳、字符編碼等)都是通過系統(tǒng)攔截器實(shí)現(xiàn)的
2)當(dāng)然我們也可以自定義攔截器,進(jìn)行可插拔配置,可以執(zhí)行Action的方法前后,加入相關(guān)邏輯完成業(yè)務(wù)。
使用場(chǎng)景:
1)用戶登錄判斷,在執(zhí)行action的前面判斷是否已經(jīng)登錄,如果沒有登錄的就跳轉(zhuǎn)登錄頁面。
2)用戶權(quán)限判斷,在執(zhí)行action的前面判斷是否具有,如果沒有權(quán)限就給出提示信息。
3)操作日志...
1)用戶向服務(wù)器發(fā)送請(qǐng)求,請(qǐng)求被Spring 前端控制Servelt DispatcherServlet捕獲;
2)DispatcherServlet 對(duì)請(qǐng)求URL進(jìn)行解析,得到請(qǐng)求資源標(biāo)識(shí)符(URI)。然后根據(jù)該URI,調(diào)用HandlerMapping獲得該Handler配置的所有相關(guān)的對(duì)象 (包括Handler對(duì)象以及Handler對(duì)象對(duì)應(yīng)的攔截器),最后以HandlerExecutionChain對(duì)象的形式返回;
3)DispatcherServlet 根據(jù)獲得的Handler,選擇一個(gè)合適的HandlerAdapter。(附注:如果成功獲得HandlerAdapter后,此時(shí)將開始執(zhí)行攔截器的preHandler(...)方法)
4) 提取Request中的模型數(shù)據(jù),填充Handler入?yún)?,開始執(zhí)行Handler(Controller)。 在填充Handler的入?yún)⑦^程中,根據(jù)你的配置,Spring將幫你做一些額外的工作:
HttpMessageConveter: 將請(qǐng)求消息(如Json、xml等數(shù)據(jù))轉(zhuǎn)換成一個(gè)對(duì)象,將對(duì)象轉(zhuǎn)換為指定的響應(yīng)信息
數(shù)據(jù)轉(zhuǎn)換:對(duì)請(qǐng)求消息進(jìn)行數(shù)據(jù)轉(zhuǎn)換。如String轉(zhuǎn)換成Integer、Double等
數(shù)據(jù)根式化:對(duì)請(qǐng)求消息進(jìn)行數(shù)據(jù)格式化。 如將字符串轉(zhuǎn)換成格式化數(shù)字或格式化日期等
數(shù)據(jù)驗(yàn)證: 驗(yàn)證數(shù)據(jù)的有效性(長(zhǎng)度、格式等),驗(yàn)證結(jié)果存儲(chǔ)到BindingResult或Error中
5)Handler執(zhí)行完成后,向DispatcherServlet?返回一個(gè)ModelAndView對(duì)象;
6)根據(jù)返回的ModelAndView,選擇一個(gè)適合的ViewResolver(必須是已經(jīng)注冊(cè)到Spring容器中的ViewResolver)返回給DispatcherServlet?;
7)ViewResolver 結(jié)合Model和View,來渲染視圖
8)將渲染結(jié)果返回給客戶端。
快速記憶:
核心控制器捕獲請(qǐng)求,查找Hander,執(zhí)行Handler,選擇ViewResolver,通過ViewResoler渲染視圖并返回
目前企業(yè)中使用SpringMvc的比例已經(jīng)遠(yuǎn)遠(yuǎn)超過Struts2,那么兩者到底有什么區(qū)別,是很多初學(xué)者比較關(guān)注的問題,下面我們就來對(duì)SpringMvc和Struts2進(jìn)行各方面的比較:
1)核心控制器(前端控制器、預(yù)處理控制器):對(duì)于使用過mvc框架的人來說這個(gè)詞應(yīng)該不會(huì)陌生,核心控制器的主要用途是處理所有的請(qǐng)求,然后對(duì)那些特殊的請(qǐng)求 (控制器)統(tǒng)一的進(jìn)行處理(字符編碼、文件上傳、參數(shù)接受、異常處理等等),spring mvc核心控制器是Servlet,而Struts2是Filter。
2)控制器實(shí)例:Spring Mvc會(huì)比Struts快一些(理論上)。Spring Mvc是基于方法設(shè)計(jì),而Sturts是基于對(duì)象,每次發(fā)一次請(qǐng)求都會(huì)實(shí)例一個(gè)action,每個(gè)action都會(huì)被注入??屬性,而Spring更像Servlet一樣,只有一個(gè)實(shí)例,每次請(qǐng)求執(zhí)行對(duì)應(yīng)的方法即可(注意:由于是單例實(shí)例,所以應(yīng)當(dāng)避免全局變量的修改,這樣會(huì)產(chǎn)生線程安全問題 )
3)管理方式:大部分的公司的核心架構(gòu)中,就會(huì)使用到spring,而spring mvc又是spring中的一個(gè)模塊,所以spring對(duì)于spring mvc的控制器管理更加簡(jiǎn)單方便,而且提供了全 注解方式進(jìn)行管理,各種功能的注解都比較全面,使用簡(jiǎn)單,而struts2需要采用XML很多的配置參數(shù)來管理(雖然也可以采用注解,但是幾乎沒有公司那 樣使用)
4)參數(shù)傳遞:Struts2中自身提供多種參數(shù)接受,其實(shí)都是通過(ValueStack)進(jìn)行傳遞和賦值,而SpringMvc是通過方法的參數(shù)進(jìn)行接收。
5)學(xué)習(xí)難度:Struts更加很多新的技術(shù)點(diǎn),比如攔截器、值棧及OGNL表達(dá)式,學(xué)習(xí)成本較高,springmvc 比較簡(jiǎn)單,很較少的時(shí)間都能上手。
6)intercepter 的實(shí)現(xiàn)機(jī)制:struts有以自己的interceptor機(jī)制,spring mvc用的是獨(dú)立的AOP方式。這樣導(dǎo)致struts的配置文件量還是比spring mvc大,雖然struts的配置能繼承,所以我覺得論使用上來講,spring mvc使用更加簡(jiǎn)潔,開發(fā)效率Spring MVC確實(shí)比struts2高。spring mvc是方法級(jí)別的攔截,一個(gè)方法對(duì)應(yīng)一個(gè)request上下文,而方法同時(shí)又跟一個(gè)url對(duì)應(yīng),所以說從架構(gòu)本身上spring3 mvc就容易實(shí)現(xiàn)restful url。struts2是類級(jí)別的攔截,一個(gè)類對(duì)應(yīng)一個(gè)request上下文;實(shí)現(xiàn)restful url要費(fèi)勁,因?yàn)閟truts2 action的一個(gè)方法可以對(duì)應(yīng)一個(gè)url;而其類屬性卻被所有方法共享,這也就無法用注解或其他方式標(biāo)識(shí)其所屬方法了。spring3 mvc的方法之間基本上獨(dú)立的,獨(dú)享request response數(shù)據(jù),請(qǐng)求數(shù)據(jù)通過參數(shù)獲取,處理結(jié)果通過ModelMap交回給框架方法之間不共享變量,而struts2搞的就比較亂,雖然方法之間 也是獨(dú)立的,但其所有Action變量是共享的,這不會(huì)影響程序運(yùn)行,卻給我們編碼,讀程序時(shí)帶來麻煩。
7)spring mvc處理ajax請(qǐng)求,直接通過返回?cái)?shù)據(jù),方法中使用注解@ResponseBody,spring mvc自動(dòng)幫我們對(duì)象轉(zhuǎn)換為JSON數(shù)據(jù)。而struts2是通過插件的方式來處理。
在springMVC流行起來之前,struts2在MVC框架中占核心地位,隨著SpringMVC的出現(xiàn),SpringMVC慢慢的取代了struts2,但是很多的企業(yè)原來搭建的框架都是使用struts2。
Spring是什么?
Spring是J2EE應(yīng)用程序框架,是輕量級(jí)的IOC和AOP的容器框架,主要針對(duì)JavaBean的生命周期進(jìn)行管理的輕量級(jí)容器,可以單獨(dú)使用,也可以和struts框架,ibatis框架等組合使用。
1)IOC(Inversion of Control)
ioc控制反轉(zhuǎn),又稱為“依賴注入”;
IOC的基本概念是:不創(chuàng)建對(duì)象,但是描述創(chuàng)建它們的方式。在代碼中不直接與對(duì)象和服務(wù)連接,但在配置文件中描述哪一個(gè)組件需要哪一項(xiàng)服務(wù)。容器負(fù)責(zé)將這些聯(lián)系在一起。
其原理是基于OO設(shè)計(jì)原則的The Hollywood Principle:Don't call us, we'll call you(別找我,我會(huì)來找你的)。也就是說,所有的組件都是被動(dòng)的(Passive),所有的組件初始化和調(diào)用都由容器負(fù)責(zé)。組件處在一個(gè)容器當(dāng)中,由容 器負(fù)責(zé)管理。
簡(jiǎn)單的來講,就是由容器控制程序之間的關(guān)系,而非傳統(tǒng)實(shí)現(xiàn)中,由程序代碼直接操控。這也就是所謂“控制反轉(zhuǎn)”的概念所在:控制權(quán)由應(yīng)用代碼中轉(zhuǎn)到了外部容器,控制權(quán)的轉(zhuǎn)移,是所謂反轉(zhuǎn)。
2)AOP 面向切面編程
核心原理:使用動(dòng)態(tài)代理的設(shè)計(jì)模式在執(zhí)行方法前后或出現(xiàn)異常常做加入相關(guān)邏輯
我們使用AOP來做:
1)事務(wù)處理:執(zhí)行方法前開啟事務(wù),執(zhí)行完成后關(guān)閉事務(wù),出現(xiàn)異常后回滾事務(wù)
2)權(quán)限判斷:在執(zhí)行方法前,判斷是否具有權(quán)限
3)日志:在執(zhí)行前進(jìn)行日志處理
多個(gè)事物存在是怎么處理的策略
1)PROPAGATION_REQUIRED:如果存在一個(gè)事務(wù),則支持當(dāng)前事務(wù),如果當(dāng)前沒有事務(wù),就新建一個(gè)事務(wù)。這是最常見的選擇。
2)PROPAGATION_SUPPORTS:如果存在一個(gè)事務(wù),支持當(dāng)前事務(wù),如果當(dāng)前沒有事務(wù),就以非事務(wù)方式執(zhí)行。
3)PROPAGATION_MANDATORY:如果存在一個(gè)事務(wù),支持當(dāng)前事務(wù),如果當(dāng)前沒有事務(wù),就拋出異常。
4)PROPAGATION_REQUIRES_NEW:新建事務(wù),如果當(dāng)前存在事務(wù),把當(dāng)前事務(wù)掛起。
5)PROPAGATION_NOT_SUPPORTED:以非事務(wù)方式執(zhí)行操作,如果當(dāng)前存在事務(wù),就把當(dāng)前事務(wù)掛起。
6)PROPAGATION_NEVER:以非事務(wù)方式執(zhí)行,如果當(dāng)前存在事務(wù),則拋出異常。
7)PROPAGATION_NESTED:支持當(dāng)前事務(wù),新增Savepoint點(diǎn),與當(dāng)前事務(wù)同步提交或回滾。
對(duì)象關(guān)系映射(Object Relation Mapping,簡(jiǎn)稱ORM)模式是一種為了解決面向?qū)ο笈c關(guān)系數(shù)據(jù)庫(kù)存在的互不匹配的現(xiàn)象的技術(shù),簡(jiǎn)單的說,ORM是通過使用描述對(duì)象和數(shù)據(jù)庫(kù)之間映射的元數(shù)據(jù),將程序中的對(duì)象自動(dòng)持久化到關(guān)系數(shù)據(jù)庫(kù)中,那么到底如何實(shí)現(xiàn)持久化呢?一種簡(jiǎn)單的方案時(shí)采用硬編碼方式(jdbc操作sql方式),為每一種可能的數(shù)據(jù)庫(kù)訪問操作提供單獨(dú)的方法。
這種方案存在以下不足:
1. 持久化層缺乏彈性,一旦出現(xiàn)業(yè)務(wù)需求變更,就必須修改持久化層的接口
2. 持久化層同時(shí)與域模型與關(guān)系數(shù)據(jù)庫(kù)模型綁定,不管域模型還是關(guān)系數(shù)據(jù)庫(kù)模型發(fā)生變化,都要修改持久化層的相關(guān)程序代碼,增加軟件的維護(hù)難度。
ORM提供了實(shí)現(xiàn)持久化層的另一種模式,它采用映射元數(shù)據(jù)來描述對(duì)象關(guān)系的映射,使得ORM中間件能在任何一個(gè)應(yīng)用的業(yè)務(wù)邏輯層和數(shù)據(jù)庫(kù)層之間充當(dāng)橋梁,Java典型的ORM框架有:Hibernate,ibatis(mybtis),speedframework。
ORM框架的方法論基于三個(gè)核心原則:
簡(jiǎn)單:以最基本的形式建模數(shù)據(jù)
傳達(dá)性:數(shù)據(jù)庫(kù)結(jié)構(gòu)被任何人都能理解的語言文檔化
精確性:基于數(shù)據(jù)模型創(chuàng)建正確標(biāo)準(zhǔn)化了結(jié)構(gòu)
對(duì)象關(guān)系映射(Object Relation Mapping,簡(jiǎn)稱ORM)模式是一種為了解決面向?qū)ο笈c關(guān)系數(shù)據(jù)庫(kù)存在的互不匹配的現(xiàn)象的技術(shù),可以簡(jiǎn)單的方案采用硬編碼方式(jdbc操作sql方式),為每一種可能的數(shù)據(jù)庫(kù)訪問操作提供單獨(dú)的方法,這種方法存在很多缺陷,使用ORM框架(為了解決面向?qū)ο笈c關(guān)系數(shù)據(jù)庫(kù)存在互不匹配的現(xiàn)象的框架)來解決。
臨時(shí)狀態(tài)/瞬時(shí)狀態(tài)(transient):剛剛用new語句創(chuàng)建,沒有被持久化,無id
不處于session中(沒有使用session的方法去操作臨時(shí)對(duì)象),該對(duì)象成為臨時(shí)對(duì)象
持久化狀態(tài),托管狀態(tài)(persistent):已經(jīng)被持久化,加入session的緩存中,session是沒有關(guān)閉
該狀態(tài)的對(duì)象為持久化對(duì)象。
游離狀態(tài),脫管狀態(tài)(detached):已經(jīng)被持久化,但不處于session中,該狀態(tài)的對(duì)象為游離對(duì)象。
刪除狀態(tài)(removed):對(duì)象有關(guān)聯(lián)的id,并且在session管理下,但是已經(jīng)被計(jì)劃(事務(wù)提交的時(shí)候,commit)刪除,如果沒有事務(wù)就不能刪除
相互轉(zhuǎn)換
答:一、why(為什么要用Hibernate緩存?)
Hibernate是一種持久化層框架,經(jīng)常訪問物理數(shù)據(jù)庫(kù)。
為了降低應(yīng)用程序?qū)ξ锢頂?shù)據(jù)源訪問的頻次,從而提高應(yīng)用程序的運(yùn)行性能
緩存內(nèi)的數(shù)據(jù)是對(duì)物理數(shù)據(jù)源中的數(shù)據(jù)的復(fù)制,應(yīng)用程序在運(yùn)行時(shí)從緩存讀寫數(shù)據(jù),在特定的時(shí)刻或事件會(huì)同步緩存和物理數(shù)據(jù)源的數(shù)據(jù)。
為了提高訪問速度,把磁盤或者數(shù)據(jù)庫(kù)訪問變成內(nèi)存訪問
二、what(Hibernate緩存原理是怎樣的?)Hibernate緩存包括兩大類:Hibernate 一級(jí)緩存和Hibernate二級(jí)緩存
1. Hibernate一級(jí)緩存又稱為”session的緩存”。
session緩存內(nèi)置不能被卸載,session的緩存是事務(wù)范圍的緩存(session對(duì)象的生命周期通常對(duì)應(yīng)一個(gè)數(shù)據(jù)庫(kù)事務(wù)或者一個(gè)應(yīng)用事務(wù))。
一級(jí)緩存中,持久化類的每個(gè)實(shí)例都具有唯一的OID
2. Hibernate的二級(jí)緩存又稱為”sessionFactory的緩存”。
由于sessionFactory對(duì)象的生命周期和應(yīng)用程序的整個(gè)過程對(duì)應(yīng),因此Hibernate二級(jí)緩存是進(jìn)程范圍或者集群范圍的緩存,有可能出現(xiàn)并發(fā)問題,因此需要采用適當(dāng)?shù)牟l(fā)訪問策略,該策略為被緩存的數(shù)據(jù)提供了事務(wù)隔離級(jí)別。
第二級(jí)緩存是可選的,是一個(gè)可配置的插件,默認(rèn)下sessionFactory不會(huì)啟用這個(gè)插件。
什么樣的數(shù)據(jù)適合存放到二級(jí)緩存中?
1) 很少被修改的數(shù)據(jù) (帖子的最后回復(fù)時(shí)間)
2) 經(jīng)常被查詢的數(shù)據(jù) (電商的地點(diǎn))
3) 不是很重要的數(shù)據(jù),允許出現(xiàn)偶爾并發(fā)的數(shù)據(jù)
4) 不會(huì)被并發(fā)訪問的數(shù)據(jù)
5) 常量數(shù)據(jù)
擴(kuò)展:Hibernate的二級(jí)緩存默認(rèn)是不支持分布式緩存的,使用memcache,redis等中央緩存來代替二級(jí)緩存。
webservice是一個(gè)SOA(面向服務(wù)的編程)的架構(gòu),它是不依賴于語言,不依賴于平臺(tái),可以實(shí)現(xiàn)不同的語言間的相互調(diào)用,通過Internet進(jìn)行基于http協(xié)議的網(wǎng)絡(luò)應(yīng)用間的交互。
1、異構(gòu)系統(tǒng)(不同的開發(fā)語言)的整合
2、不同客戶端的整合 (瀏覽器、手機(jī)端(android\ios)、微信)
3、實(shí)實(shí)在在的例子:
天氣預(yù)報(bào):可以通過實(shí)現(xiàn)webservice客戶端調(diào)用遠(yuǎn)程天氣服務(wù)實(shí)現(xiàn)的
4、單點(diǎn)登錄:一個(gè)服務(wù)實(shí)現(xiàn)所有系統(tǒng)的登錄
Activity是一個(gè)業(yè)務(wù)流程管理(BPM)和工作流系統(tǒng),適用于開發(fā)人員和系統(tǒng)管理員,其核心是超快速,穩(wěn)定的BPMN2的流程引擎,它易于與Spring集成使用。
主要用在OA中,把線下流程放在線上,把現(xiàn)實(shí)生活中一些流程固話定義到系統(tǒng)中,然后通過輸入表單數(shù)據(jù)完成業(yè)務(wù)。
他可以用在OA系統(tǒng)的流程管理中
請(qǐng)假流程(小于三天,一級(jí)主管審批,大于三天二級(jí)主管審批)
報(bào)銷流程(價(jià)格區(qū)間)
答:MyBatis是一個(gè)可以自定義SQL、存儲(chǔ)過程和高級(jí)映射的持久層框架。
答:1)Mybatis使用RowBounds對(duì)象進(jìn)行分頁,也可以直接編寫sql實(shí)現(xiàn)分頁,也可以使用Mybatis的分頁插件。
2)分頁插件的原理:實(shí)現(xiàn)Mybatis提供的接口,實(shí)現(xiàn)自定義插件,在插件的攔截方法內(nèi)攔截待執(zhí)行的sql,然后重寫sql。
舉例:select * from student,攔截sql后重寫為:select t.* from (select * from student)t limit 0,10
答:1)Mybatis和hibernate不同,它不完全是一個(gè)ORM框架,因?yàn)镸yBatis需要程序員自己編寫Sql語句,不過mybatis可以通過XML或注解方式靈活配置要運(yùn)行的sql語句,并將java對(duì)象和sql語句映射生成最終執(zhí)行的sql,最后將sql執(zhí)行的結(jié)果再映射生成java對(duì)象。
2)Mybatis學(xué)習(xí)門檻低,簡(jiǎn)單易學(xué),程序員直接編寫原生態(tài)sql,可嚴(yán)格控制sql執(zhí)行性能,靈活度高,非常適合對(duì)關(guān)系數(shù)據(jù)模型要求不高的軟件開發(fā),例如互聯(lián)網(wǎng)軟件、企業(yè)運(yùn)營(yíng)類軟件等,因?yàn)檫@類軟件需求變化頻繁,一但需求變化要求成果輸出迅速。但是靈活的前提是mybatis無法做到數(shù)據(jù)庫(kù)無關(guān)性,如果需要實(shí)現(xiàn)支持多種數(shù)據(jù)庫(kù)的軟件則需要自定義多套sql映射文件,工作量大。
3)Hibernate對(duì)象/關(guān)系映射能力強(qiáng),數(shù)據(jù)庫(kù)無關(guān)性好,對(duì)于關(guān)系模型要求高的軟件(例如需求固定的定制化軟件)如果用hibernate開發(fā)可以節(jié)省很多代碼,提高效率。但是Hibernate的缺點(diǎn)是學(xué)習(xí)門檻高,要精通門檻更高,而且怎么設(shè)計(jì)O/R映射,在性能和對(duì)象模型之間如何權(quán)衡,以及怎樣用好Hibernate需要具有很強(qiáng)的經(jīng)驗(yàn)和能力才行。
總之,按照用戶的需求在有限的資源環(huán)境下只要能做出維護(hù)性、擴(kuò)展性良好的軟件架構(gòu)都是好架構(gòu),所以框架只有適合才是最好。
答: Mybatis將所有Xml配置信息都封裝到All-In-One重量級(jí)對(duì)象Configuration內(nèi)部。在Xml映射文件中,< parameterMap>標(biāo)簽會(huì)被解析為ParameterMap對(duì)象,其每個(gè)子元素會(huì)被解析為ParameterMapping對(duì)象。< resultMap>標(biāo)簽會(huì)被解析為ResultMap對(duì)象,其每個(gè)子元素會(huì)被解析為ResultMapping對(duì)象。每一個(gè)< select>、< insert>、< update>、< delete>標(biāo)簽均會(huì)被解析為MappedStatement對(duì)象,標(biāo)簽內(nèi)的sql會(huì)被解析為BoundSql對(duì)象。
答:接口映射就是在MyBatis中任意定義接口,然后把接口里面的方法和SQL語句綁定,我們直接調(diào)用接口方法就可以,這樣比起原來了SqlSession提供的方法我們可以有更加靈活的選擇和設(shè)置.
答:能,Mybatis不僅可以執(zhí)行一對(duì)一、一對(duì)多的關(guān)聯(lián)查詢,還可以執(zhí)行多對(duì)一,多對(duì)多的關(guān)聯(lián)查詢,多對(duì)一查詢,其實(shí)就是一對(duì)一查詢,只需要把selectOne()修改為selectList()即可;多對(duì)多查詢,其實(shí)就是一對(duì)多查詢,只需要把selectOne()修改為selectList()即可。
關(guān)聯(lián)對(duì)象查詢,有兩種實(shí)現(xiàn)方式,一種是單獨(dú)發(fā)送一個(gè)sql去查詢關(guān)聯(lián)對(duì)象,賦給主對(duì)象,然后返回主對(duì)象。另一種是使用嵌套查詢,嵌套查詢的含義為使用join查詢,一部分列是A對(duì)象的屬性值,另外一部分列是關(guān)聯(lián)對(duì)象B的屬性值,好處是只發(fā)一個(gè)sql查詢,就可以把主對(duì)象和其關(guān)聯(lián)對(duì)象查出來。
答:MyBatis里面的動(dòng)態(tài)Sql一般是通過if節(jié)點(diǎn)來實(shí)現(xiàn),通過OGNL語法來實(shí)現(xiàn),但是如果要寫的完整,必須配合where,trim節(jié)點(diǎn),where節(jié)點(diǎn)是判斷包含節(jié)點(diǎn)有內(nèi)容就插入where,否則不插入,trim節(jié)點(diǎn)是用來判斷如果動(dòng)態(tài)語句是以and 或or開始,那么會(huì)自動(dòng)把這個(gè)and或者or取掉。
答:1)Mapper接口方法名和mapper.xml中定義的每個(gè)sql的id相同
2)Mapper接口方法的輸入?yún)?shù)類型和mapper.xml中定義的每個(gè)sql 的parameterType的類型相同
3)Mapper接口方法的輸出參數(shù)類型和mapper.xml中定義的每個(gè)sql的resultType的類型相同
4)Mapper.xml文件中的namespace即是mapper接口的類路徑。
答:第一種是使用< resultMap>標(biāo)簽,逐一定義列名和對(duì)象屬性名之間的映射關(guān)系。
第二種是使用sql列的別名功能,將列別名書寫為對(duì)象屬性名,比如T_NAME AS NAME,對(duì)象屬性名一般是name,小寫,但是列名不區(qū)分大小寫,Mybatis會(huì)忽略列名大小寫,智能找到與之對(duì)應(yīng)對(duì)象屬性名,你甚至可以寫成T_NAME AS NaMe,Mybatis一樣可以正常工作。
有了列名與屬性名的映射關(guān)系后,Mybatis通過反射創(chuàng)建對(duì)象,同時(shí)使用反射給對(duì)象的屬性逐一賦值并返回,那些找不到映射關(guān)系的屬性,是無法完成賦值的。
答:接口綁定有兩種實(shí)現(xiàn)方式,一種是通過注解綁定,就是在接口的方法上面加上@Select@Update等注解里面包含Sql語句來綁定,另外一種就是通過xml里面寫SQL來綁定,在這種情況下,要指定xml映射文件里面的namespace必須為接口的全路徑名.
答:有聯(lián)合查詢和嵌套查詢,聯(lián)合查詢是幾個(gè)表聯(lián)合查詢,只查詢一次,通過在resultMap里面配置association節(jié)點(diǎn)配置一對(duì)一的類就可以完成;嵌套查詢是先查一個(gè)表,根據(jù)這個(gè)表里面的結(jié)果的外鍵id,去再另外一個(gè)表里面查詢數(shù)據(jù),也是通過association配置,但另外一個(gè)表的查詢通過select屬性配置。
答:當(dāng)Sql語句比較簡(jiǎn)單時(shí)候,用注解綁定;當(dāng)SQL語句比較復(fù)雜時(shí)候,用xml綁定,一般用xml綁定的比較多
答:1) MyBatis把sql語句從Java源程序中獨(dú)立出來, 放在單獨(dú)的XML文件中編寫,給程序的維護(hù)帶來了很大便利。
2) MyBatis封裝了底層JDBC API的調(diào)用細(xì)節(jié),并能自動(dòng)將結(jié)果集轉(zhuǎn)換成Java Bean對(duì)象,大大簡(jiǎn)化了Java數(shù)據(jù)庫(kù)編程的重復(fù)工作。
3) 因?yàn)镸yBatis需要程序員自己去編寫sql語句,程序員可以結(jié)合數(shù)據(jù)庫(kù)自身的特點(diǎn)靈活控制sql語句, 因此能夠?qū)崿F(xiàn)比Hibernate等全自動(dòng)orm框架更高的查詢效率,能夠完成復(fù)雜查詢。
微服務(wù)框架
答:Spring Boot的優(yōu)點(diǎn)有:
減少開發(fā),測(cè)試時(shí)間和努力。
使用JavaConfig有助于避免使用XML。
避免大量的Maven導(dǎo)入和各種版本沖突。
提供意見發(fā)展方法。
通過提供默認(rèn)值快速開始開發(fā)。
沒有單獨(dú)的Web服務(wù)器需要。這意味著你不再需要啟動(dòng)Tomcat,Glassfish或其他任何東西。
需要更少的配置 因?yàn)闆]有web.xml文件。只需添加用@ Configuration注釋的類,然后添加用@Bean注釋的方法,Spring將自動(dòng)加載對(duì)象并像以前一樣對(duì)其進(jìn)行管理。您甚至可以將@Autowired添加到bean方法中,以使Spring自動(dòng)裝入需要的依賴關(guān)系中。
基于環(huán)境的配置 使用這些屬性,您可以將您正在使用的環(huán)境傳遞到應(yīng)用程序:-Dspring.profiles.active = {enviornment}。在加載主應(yīng)用程序?qū)傩晕募?,Spring將在(application{environment} .properties)中加載后續(xù)的應(yīng)用程序?qū)傩晕募?/p>
答:這可以使用DEV工具來實(shí)現(xiàn)。通過這種依賴關(guān)系,您可以節(jié)省任何更改,嵌入式tomcat將重新啟動(dòng)。Spring Boot有一個(gè)開發(fā)工具(DevTools)模塊,它有助于提高開發(fā)人員的生產(chǎn)力。Java開發(fā)人員面臨的一個(gè)主要挑戰(zhàn)是將文件更改自動(dòng)部署到服務(wù)器并自動(dòng)重啟服務(wù)器。開發(fā)人員可以重新加載Spring Boot上的更改,而無需重新啟動(dòng)服務(wù)器。這將消除每次手動(dòng)部署更改的需要。Spring Boot在發(fā)布它的第一個(gè)版本時(shí)沒有這個(gè)功能。這是開發(fā)人員最需要的功能。DevTools模塊完全滿足開發(fā)人員的需求。該模塊將在生產(chǎn)環(huán)境中被禁用。它還提供H2數(shù)據(jù)庫(kù)控制臺(tái)以更好地測(cè)試應(yīng)用程序。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> </dependency>
1、單體架構(gòu)
單體架構(gòu)也稱之為單體系統(tǒng)或者是單體應(yīng)用。就是一種把系統(tǒng)中所有的功能、模塊耦合在一個(gè)應(yīng)用中的架構(gòu)方式。
單體架構(gòu)特點(diǎn):打包成一個(gè)獨(dú)立的單元(導(dǎo)成一個(gè)唯一的jar包或者是war包),會(huì)一個(gè)進(jìn)程的方式來運(yùn)行。
單體架構(gòu)的優(yōu)點(diǎn)、缺點(diǎn)
優(yōu)點(diǎn):
項(xiàng)目易于管理
部署簡(jiǎn)單
缺點(diǎn):
測(cè)試成本高
可伸縮性差
可靠性差
迭代困難
跨語言程度差
團(tuán)隊(duì)協(xié)作難
2、MVC架構(gòu)
MVC架構(gòu)特點(diǎn):
MVC是模型(Model)、視圖(View)、控制器(Controller)3個(gè)單詞的縮寫。 下面我們從這3個(gè)方面來講解MVC中的三個(gè)要素。
Model是指數(shù)據(jù)模型,是對(duì)客觀事物的抽象。 如一篇博客文章,我們可能會(huì)以一個(gè)Post類來表示,那么,這個(gè)Post類就是數(shù)據(jù)對(duì)象。 同時(shí),博客文章還有一些業(yè)務(wù)邏輯,如發(fā)布、回收、評(píng)論等,這一般表現(xiàn)為類的方法,這也是model的內(nèi)容和范疇。 對(duì)于Model,主要是數(shù)據(jù)、業(yè)務(wù)邏輯和業(yè)務(wù)規(guī)則。相對(duì)而言,這是MVC中比較穩(wěn)定的部分,一般成品后不會(huì)改變。 開發(fā)初期的最重要任務(wù),主要也是實(shí)現(xiàn)Model的部分。這一部分寫得好,后面就可以改得少,開發(fā)起來就快。
View是指視圖,也就是呈現(xiàn)給用戶的一個(gè)界面,是model的具體表現(xiàn)形式,也是收集用戶輸入的地方。 如你在某個(gè)博客上看到的某一篇文章,就是某個(gè)Post類的表現(xiàn)形式。 View的目的在于提供與用戶交互的界面。換句話說,對(duì)于用戶而言,只有View是可見的、可操作的。 事實(shí)上也是如此,你不會(huì)讓用戶看到Model,更不會(huì)讓他直接操作Model。 你只會(huì)讓用戶看到你想讓他看的內(nèi)容。 這就是View要做的事,他往往是MVC中變化頻繁的部分,也是客戶經(jīng)常要求改來改去的地方。 今天你可能會(huì)以一種形式來展示你的博文,明天可能就變成別的表現(xiàn)形式了。
Contorller指的是控制器,主要負(fù)責(zé)與model和view打交道。 換句話說,model和view之間一般不直接打交道,他們老死不相往來。view中不會(huì)對(duì)model作任何操作, model不會(huì)輸出任何用于表現(xiàn)的東西,如HTML代碼等。這倆甩手不干了,那總得有人來干吧,只能Controller上了。 Contorller用于決定使用哪些Model,對(duì)Model執(zhí)行什么操作,為視圖準(zhǔn)備哪些數(shù)據(jù),是MVC中溝通的橋梁。
MVC架構(gòu)優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
各施其職,互不干涉。
在MVC模式中,三個(gè)層各施其職,所以如果一旦哪一層的需求發(fā)生了變化,就只需要更改相應(yīng)的層中的代碼而不會(huì)影響到其它層中的代碼。
有利于開發(fā)中的分工。
在MVC模式中,由于按層把系統(tǒng)分開,那么就能更好的實(shí)現(xiàn)開發(fā)中的分工。網(wǎng)頁設(shè)計(jì)人員可以進(jìn)行開發(fā)視圖層中的JSP,對(duì)業(yè)務(wù)熟悉的開發(fā)人員可開發(fā)業(yè)務(wù)層,而其它開發(fā)人員可開發(fā)控制層。
有利于組件的重用。
分層后更有利于組件的重用。如控制層可獨(dú)立成一個(gè)能用的組件,視圖層也可做成通用的操作界面。
缺點(diǎn):
增加了系統(tǒng)結(jié)構(gòu)和實(shí)現(xiàn)的復(fù)雜性。
視圖與控制器間的過于緊密的連接。
視圖對(duì)模型數(shù)據(jù)的低效率訪問。
3、面向服務(wù)架構(gòu)(SOA)
面向服務(wù)的架構(gòu)(SOA)是一個(gè)組件模型,它將應(yīng)用程序拆分成不同功能單元(稱為服務(wù))通過這些服務(wù)之間定義良好的接口和契約聯(lián)系起來。接口是采用中立的方式進(jìn)行定義的,它應(yīng)該獨(dú)立于實(shí)現(xiàn)服務(wù)的硬件平臺(tái)、操作系統(tǒng)和編程語言。這使得構(gòu)建在各種各樣的系統(tǒng)中的服務(wù)可以以一種統(tǒng)一和通用的方式進(jìn)行交互。
面向服務(wù)架構(gòu)特點(diǎn):
系統(tǒng)是由多個(gè)服務(wù)構(gòu)成
每個(gè)服務(wù)可以單獨(dú)獨(dú)立部署
每個(gè)服務(wù)之間是松耦合的。服務(wù)內(nèi)部是高內(nèi)聚的,外部是低耦合的。高內(nèi)聚就是每個(gè)服務(wù)只關(guān)注完成一個(gè)功能。
服務(wù)的優(yōu)點(diǎn)、缺點(diǎn)
優(yōu)點(diǎn):
測(cè)試容易
可伸縮性強(qiáng)
可靠性強(qiáng)
跨語言程度會(huì)更加靈活
團(tuán)隊(duì)協(xié)作容易
系統(tǒng)迭代容易
缺點(diǎn):
運(yùn)維成本過高,部署數(shù)量較多
接口兼容多版本
分布式系統(tǒng)的復(fù)雜性
分布式事務(wù)
業(yè)界對(duì)于可擴(kuò)展的系統(tǒng)架構(gòu)設(shè)計(jì)有一個(gè)樸素的理念,就是:通過加機(jī)器就可以解決容量和可用性問題。(如果一臺(tái)不行那就兩臺(tái))。
我是個(gè)段子:(世界上沒有什么事是一頓燒烤不能解決的。如果有,那就兩頓。)
這一理念在“云計(jì)算”概念瘋狂流行的今天,得到了廣泛的認(rèn)可!對(duì)于一個(gè)規(guī)模迅速增長(zhǎng)的系統(tǒng)而言,容量和性能問題當(dāng)然是首當(dāng)其沖的。但是隨著時(shí)間的向前,系統(tǒng)規(guī)模的增長(zhǎng),除了面對(duì)性能與容量的問題外,還需要面對(duì)功能與模塊數(shù)量上的增長(zhǎng)帶來的系統(tǒng)復(fù)雜性問題以及業(yè)務(wù)的變化帶來的提供差異化服務(wù)問題。而許多系統(tǒng),在架構(gòu)設(shè)計(jì)時(shí)并未充分考慮到這些問題,導(dǎo)致系統(tǒng)的重構(gòu)成為常態(tài),從而影響業(yè)務(wù)交付能力,還浪費(fèi)人力財(cái)力!對(duì)此,《可擴(kuò)展的藝術(shù)》一書提出了一個(gè)更加系統(tǒng)的可擴(kuò)展模型——?AKF可擴(kuò)展立方?(Scalability Cube) 。這個(gè)立方體中沿著三個(gè)坐標(biāo)軸設(shè)置分別為:X、Y、Z。
Y軸擴(kuò)展會(huì)將龐大的整體應(yīng)用拆分為多個(gè)服務(wù)。每個(gè)服務(wù)實(shí)現(xiàn)一組相關(guān)的功能,如訂單管理、客戶管理等。在工程上常見的方案是?服務(wù)化架構(gòu)(SOA)?。比如對(duì)于一個(gè)電子商務(wù)平臺(tái),我們可以拆分成不同的服務(wù)
X軸擴(kuò)展與我們前面樸素理念是一致的,通過絕對(duì)平等地復(fù)制服務(wù)與數(shù)據(jù),以解決容量和可用性的問題。其實(shí)就是將微服務(wù)運(yùn)行多個(gè)實(shí)例,做集群加負(fù)載均衡的模式。
Z軸擴(kuò)展通常是指基于請(qǐng)求者或用戶獨(dú)特的需求,進(jìn)行系統(tǒng)劃分,并使得劃分出來的子系統(tǒng)是相互隔離但又是完整的。以生產(chǎn)汽車的工廠來舉例:福特公司為了發(fā)展在中國(guó)的業(yè)務(wù),或者利用中國(guó)的廉價(jià)勞動(dòng)力,在中國(guó)建立一個(gè)完整的子工廠,與美國(guó)工廠一樣,負(fù)責(zé)完整的汽車生產(chǎn)。這就是一種Z軸擴(kuò)展。
Spring Cloud是一個(gè)微服務(wù)框架,相比Dubbo等RPC框架,?Spring Cloud提供的全套的分布式系統(tǒng)解決方案。
Spring Cloud對(duì)微服務(wù)基礎(chǔ)框架Netflix的多個(gè)開源組件進(jìn)行了封裝,同時(shí)又實(shí)現(xiàn)了和云端平臺(tái)以及和Spring Boot開發(fā)框架的集成。
Spring Cloud為微服務(wù)架構(gòu)開發(fā)涉及的配置管理,服務(wù)治理,熔斷機(jī)制,智能路由,微代理,控制總線,一次性token,全局一致性鎖,leader選舉,分布式session,集群狀態(tài)管理等操作提供了一種簡(jiǎn)單的開發(fā)方式。
Spring Cloud 為開發(fā)者提供了快速構(gòu)建分布式系統(tǒng)的工具,開發(fā)者可以快速的啟動(dòng)服務(wù)或構(gòu)建應(yīng)用、同時(shí)能夠快速和云平臺(tái)資源進(jìn)行對(duì)接
Eureka是Netflix開發(fā)的服務(wù)發(fā)現(xiàn)組件,本身是一個(gè)基于REST的服務(wù)。Spring Cloud將它集成在其子項(xiàng)目spring-cloud-netflix中,以實(shí)現(xiàn)Spring Cloud的服務(wù)注冊(cè)于發(fā)現(xiàn),同時(shí)還提供了負(fù)載均衡、故障轉(zhuǎn)移等能力。
1、Eureka Server
通過Register、Get、Renew等接口提供服務(wù)的注冊(cè)和發(fā)現(xiàn)。
2、Application Service (Service Provider)
服務(wù)提供方
把自身的服務(wù)實(shí)例注冊(cè)到Eureka Server中
3、Application Client (Service Consumer)
服務(wù)調(diào)用方
通過Eureka Server 獲取服務(wù)列表,消費(fèi)服務(wù)。
1.Ribbon 是一個(gè)基于Http和TCP的客服端負(fù)載均衡工具,它是基于Netflix Ribbon實(shí)現(xiàn)的。
2.它不像spring cloud服務(wù)注冊(cè)中心、配置中心、API網(wǎng)關(guān)那樣獨(dú)立部署,但是它幾乎存在于每個(gè)spring cloud 微服務(wù)中。包括feign提供的聲明式服務(wù)調(diào)用也是基于該Ribbon實(shí)現(xiàn)的。
3.ribbon默認(rèn)提供很多種負(fù)載均衡算法,例如 輪詢、隨機(jī) 等等。甚至包含自定義的負(fù)載均衡算法。
目前業(yè)界主流的負(fù)載均衡方案可分成兩類:
第一類:集中式負(fù)載均衡, 即在consumer和provider之間使用獨(dú)立的負(fù)載均衡設(shè)施(可以是硬件,如F5, 也可以是軟件,如nginx), 由該設(shè)施負(fù)責(zé)把 訪問請(qǐng)求 通過某種策略轉(zhuǎn)發(fā)至provider;
第二類:進(jìn)程內(nèi)負(fù)載均衡,將負(fù)載均衡邏輯集成到consumer,consumer從服務(wù)注冊(cè)中心獲知有哪些地址可用,然后自己再?gòu)倪@些地址中選擇出一個(gè)合適的provider。
Ribbon就屬于后者,它只是一個(gè)類庫(kù),集成于consumer進(jìn)程,consumer通過它來獲取到provider的地址。
id | 策略名稱 | 策略對(duì)應(yīng)的類名 | 實(shí)現(xiàn)原理 |
1 | 輪詢策略(默認(rèn)) | RoundRobinRule | 輪詢策略表示每次都順序取下一個(gè)provider,比如一共有5個(gè)provider,第1次取第1個(gè),第2次取第2個(gè),第3次取第3個(gè),以此類推 |
2 | 權(quán)重輪詢策略 | WeightedResponseTimeRule | 1.根據(jù)每個(gè)provider的響應(yīng)時(shí)間分配一個(gè)權(quán)重,響應(yīng)時(shí)間越長(zhǎng),權(quán)重越小,被選中的可能性越低。 2.原理:一開始為輪詢策略,并開啟一個(gè)計(jì)時(shí)器,每30秒收集一次每個(gè)provider的平均響應(yīng)時(shí)間,當(dāng)信息足夠時(shí),給每個(gè)provider附上一個(gè)權(quán)重,并按權(quán)重隨機(jī)選擇provider,高權(quán)越重的provider會(huì)被高概率選中。 |
3 | 隨機(jī)策略 | RandomRule | 從provider列表中隨機(jī)選擇一個(gè)provider |
4 | 最少并發(fā)數(shù)策略 | BestAvailableRule | 選擇正在請(qǐng)求中的并發(fā)數(shù)最小的provider,除非這個(gè)provider在熔斷中。 |
5 | 在“選定的負(fù)載均衡策略”基礎(chǔ)上進(jìn)行重試機(jī)制 | RetryRule | 1.“選定的負(fù)載均衡策略”這個(gè)策略是輪詢策略RoundRobinRule 2.該重試策略先設(shè)定一個(gè)閾值時(shí)間段,如果在這個(gè)閾值時(shí)間段內(nèi)當(dāng)選擇provider不成功,則一直嘗試采用“選定的負(fù)載均衡策略:輪詢策略”最后選擇一個(gè)可用的provider |
6 | 可用性敏感策略 | AvailabilityFilteringRule | 過濾性能差的provider,有2種: 第一種:過濾掉在eureka中處于一直連接失敗provider 第二種:過濾掉高并發(fā)的provider |
7 | 區(qū)域敏感性策略 | ZoneAvoidanceRule | 1.以一個(gè)區(qū)域?yàn)閱挝豢疾炜捎眯?,?duì)于不可用的區(qū)域整個(gè)丟棄,從剩下區(qū)域中選可用的provider 2.如果這個(gè)ip區(qū)域內(nèi)有一個(gè)或多個(gè)實(shí)例不可達(dá)或響應(yīng)變慢,都會(huì)降低該ip區(qū)域內(nèi)其他ip被選中的權(quán)重。 |
Feign是一種聲明式、模板化的HTTP客戶端技術(shù)(僅在consumer中使用)。
聲明式調(diào)用就像調(diào)用本地方法一樣調(diào)用遠(yuǎn)程方法;無感知遠(yuǎn)程http請(qǐng)求。
1、Spring Cloud的聲明式調(diào)用, 可以做到使用 HTTP請(qǐng)求遠(yuǎn)程服務(wù)時(shí)能就像調(diào)用本地方法一樣的體驗(yàn),開發(fā)者完全感知不到這是遠(yuǎn)程方法,更感知不到這是個(gè)HTTP請(qǐng)求。
2、它像Dubbo一樣,consumer直接調(diào)用接口方法調(diào)用provider,而不需要通過常規(guī)的Http Client構(gòu)造請(qǐng)求再解析返回?cái)?shù)據(jù)。
3、它解決了讓開發(fā)者調(diào)用遠(yuǎn)程接口就跟調(diào)用本地方法一樣,無需關(guān)注與遠(yuǎn)程的交互細(xì)節(jié),更無需關(guān)注分布式環(huán)境開發(fā)。
在微服務(wù)架構(gòu)中,一個(gè)請(qǐng)求需要調(diào)用多個(gè)服務(wù)是非常常見的。如客戶端訪問A服務(wù),而A服務(wù)需要調(diào)用B服務(wù),B服務(wù)需要調(diào)用C服務(wù),由于網(wǎng)絡(luò)原因或者自身的原因,如果B服務(wù)或者C服務(wù)不能及時(shí)響應(yīng),A服務(wù)將處于阻塞狀態(tài),直到B服務(wù)C服務(wù)響應(yīng)。此時(shí)若有大量的請(qǐng)求涌入,容器的線程資源會(huì)被消耗完畢,導(dǎo)致服務(wù)癱瘓。服務(wù)與服務(wù)之間的依賴性,故障會(huì)傳播,造成連鎖反應(yīng),會(huì)對(duì)整個(gè)微服務(wù)系統(tǒng)造成災(zāi)難性的嚴(yán)重后果,這就是服務(wù)故障的“雪崩”效應(yīng)
降級(jí)
超時(shí)降級(jí)、資源不足時(shí)(線程或信號(hào)量)降級(jí),降級(jí)后可以配合降級(jí)接口返回托底數(shù)據(jù)。實(shí)現(xiàn)一個(gè)fallback方法, 當(dāng)請(qǐng)求后端服務(wù)出現(xiàn)異常的時(shí)候, 可以使用fallback方法返回的值.
隔離(線程池隔離和信號(hào)量隔離)
限制調(diào)用分布式服務(wù)的資源使用,某一個(gè)調(diào)用的服務(wù)出現(xiàn)問題不會(huì)影響其他服務(wù)調(diào)用。
熔斷
當(dāng)失敗率(如因網(wǎng)絡(luò)故障/超時(shí)造成的失敗率高)達(dá)到閥值自動(dòng)觸發(fā)降級(jí),熔斷器觸發(fā)的快速失敗會(huì)進(jìn)行快速恢復(fù)。
緩存
提供了請(qǐng)求緩存。
請(qǐng)求合并
提供請(qǐng)求合并。
答:如下這六種
代理設(shè)計(jì)模式
聚合設(shè)計(jì)模式
鏈條設(shè)計(jì)模式
聚合鏈條設(shè)計(jì)模式
數(shù)據(jù)共享設(shè)計(jì)模式
異步消息設(shè)計(jì)模式
答:網(wǎng)關(guān)服務(wù),通常是外部訪問服務(wù)的唯一接口,訪問內(nèi)部的所有服務(wù)都必須先經(jīng)過網(wǎng)關(guān)服務(wù)。網(wǎng)關(guān)服務(wù)的主要功能是消息解析過濾,路由,轉(zhuǎn)發(fā)等。
答:采用URL指定路由方式
采用服務(wù)名稱指定路由方式
路由的排除方法
路由的添加前綴方法
ELK是三個(gè)工具的集合,Elasticsearch + Logstash + Kibana,這三個(gè)工具組合形成了一套實(shí)用、易用的監(jiān)控架構(gòu),很多公司利用它來搭建可視化的海量日志分析平臺(tái)。
1. ElasticSearch
ElasticSearch是一個(gè)基于Lucene的搜索服務(wù)器。它提供了一個(gè)分布式多用戶能力的全文搜索引擎,基于RESTful web接口。Elasticsearch是用Java開發(fā)的,并作為Apache許可條款下的開放源碼發(fā)布,是當(dāng)前流行的企業(yè)級(jí)搜索引擎。設(shè)計(jì)用于云計(jì)算中,能夠達(dá)到實(shí)時(shí)搜索,穩(wěn)定,可靠,快速,安裝使用方便。
2. Logstash
Logstash是一個(gè)用于管理日志和事件的工具,你可以用它去收集日志、轉(zhuǎn)換日志、解析日志并將他們作為數(shù)據(jù)提供給其它模塊調(diào)用,例如搜索、存儲(chǔ)等。
3. Kibana
Kibana是一個(gè)優(yōu)秀的前端日志展示框架,它可以非常詳細(xì)的將日志轉(zhuǎn)化為各種圖表,為用戶提供強(qiáng)大的數(shù)據(jù)可視化支持。
數(shù)據(jù)庫(kù)
A. | Oracle |
B. | MySql |
C. | IMS |
D. | MongoDB |
答案:AB分析: IMS 是IP Mulitimedia Subsystem的縮寫,是IP多媒體系統(tǒng)
MongoDB分布式文檔存儲(chǔ)數(shù)據(jù)庫(kù)
|
答:在Java中開源的常用的數(shù)據(jù)庫(kù)連接池有以下幾種 :
(1)DBCP
DBCP是一個(gè)依賴Jakarta commons-pool對(duì)象池機(jī)制的數(shù)據(jù)庫(kù)連接池.DBCP可以直接的在應(yīng)用程序中使用,Tomcat的數(shù)據(jù)源使用的就是DBCP。
(2)c3p0
c3p0是一個(gè)開放源代碼的JDBC連接池,它在lib目錄中與Hibernate一起發(fā)布,包括了實(shí)現(xiàn)jdbc3和jdbc2擴(kuò)展規(guī)范說明的Connection 和Statement 池的DataSources 對(duì)象。
(3)Druid
阿里出品,淘寶和支付寶專用數(shù)據(jù)庫(kù)連接池,但它不僅僅是一個(gè)數(shù)據(jù)庫(kù)連接池,它還包含一個(gè)ProxyDriver,一系列內(nèi)置的JDBC組件庫(kù),一個(gè)SQL Parser。支持所有JDBC兼容的數(shù)據(jù)庫(kù),包括Oracle、MySql、Derby、Postgresql、SQL Server、H2等等。
A. | 一對(duì)一的聯(lián)系 |
B. | 多對(duì)一的聯(lián)系 |
C. | 一對(duì)多的聯(lián)系 |
D. | 多對(duì)多的聯(lián)系 |
答案:D
|
A. | 基本表或視圖 |
B. | 視圖 |
C. | 數(shù)據(jù)字典 |
D. | 基本表 |
答案:A
|
A. | 第一范式的 |
B. | 第二范式的 |
C. | 第三范式的 |
D. | BCNF范式的 |
答案:A
分析:
根據(jù)數(shù)據(jù)庫(kù)三大范式的依賴性要求,從B,BC函數(shù)確定A和D這一點(diǎn)上,明顯看出B,BC都有可能是主碼.
若B是主碼的話,仔細(xì)看會(huì)發(fā)現(xiàn),F中竟然沒有誰去函數(shù)確定C,這顯然是說不通的,(因?yàn)镃至少會(huì)被B這個(gè)主碼函數(shù)確定);
若BC是主碼,那么F中存在非主屬性對(duì)候選碼的部分依賴,不滿足第二范式的要求,故為第一范式.
|
答:DAO(DataAccess Object)顧名思義是一個(gè)為數(shù)據(jù)庫(kù)或其他持久化機(jī)制提供了抽象接口的對(duì)象,在不暴露數(shù)據(jù)庫(kù)實(shí)現(xiàn)細(xì)節(jié)的前提下提供了各種數(shù)據(jù)操作。為了建立一個(gè)健壯的Java EE應(yīng)用,應(yīng)該將所有對(duì)數(shù)據(jù)源的訪問操作進(jìn)行抽象化后封裝在一個(gè)公共API中。用程序設(shè)計(jì)語言來說,就是建立一個(gè)接口,接口中定義了此應(yīng)用程序中將會(huì)用到的所有事務(wù)方法。在這個(gè)應(yīng)用程序中,當(dāng)需要和數(shù)據(jù)源進(jìn)行交互的時(shí)候則使用這個(gè)接口,并且編寫一個(gè)單獨(dú)的類來實(shí)現(xiàn)這個(gè)接口,在邏輯上該類對(duì)應(yīng)一個(gè)特定的數(shù)據(jù)存儲(chǔ)。DAO模式實(shí)際上包含了兩個(gè)模式,一是Data Accessor(數(shù)據(jù)訪問器),二是Data Object(數(shù)據(jù)對(duì)象),前者要解決如何訪問數(shù)據(jù)的問題,而后者要解決的是如何用對(duì)象封裝數(shù)據(jù)。
Mysql:使用limit關(guān)鍵字
Select * from 表名 where 條件 limit 開始位置,結(jié)束位置。通過動(dòng)態(tài)的改變開始和結(jié)束位置的值來實(shí)現(xiàn)分頁。
Oracle:通過rownum來實(shí)現(xiàn)
select * from ( select rownum rn,t.* from addressbook where rownum<= 20 ) where rownum > 10
Sqlserver:
select top 20 * from addressbook where id not in (select top 10 id from addressbook)
如:select * from (select t.*,rownum r from (select * from A) t where rownum < 10) where r >5
select * from A:要查詢的數(shù)據(jù)
select t.*,rownum r from (select * from A) t where rownum < 10:取前10行
select * from (select t.*,rownum r from (select * from A) t where rownum < 10) where r >5:取5-10行
答: 1. SQL優(yōu)化的原則是:將一次操作需要讀取的BLOCK數(shù)減到最低,即在最短的時(shí)間達(dá)到最大的數(shù)據(jù)吞吐量。
調(diào)整不良SQL通??梢詮囊韵聨c(diǎn)切入:
1) 檢查不良的SQL,考慮其寫法是否還有可優(yōu)化內(nèi)容
2) 檢查子查詢 考慮SQL子查詢是否可以用簡(jiǎn)單連接的方式進(jìn)行重新書寫
3) 檢查優(yōu)化索引的使用
4) 考慮數(shù)據(jù)庫(kù)的優(yōu)化器
2. 避免出現(xiàn)SELECT * FROM table 語句,要明確查出的字段。
3. 在一個(gè)SQL語句中,如果一個(gè)where條件過濾的數(shù)據(jù)庫(kù)記錄越多,定位越準(zhǔn)確,則該where條件越應(yīng)該前移。
4. 查詢時(shí)盡可能使用索引覆蓋。即對(duì)SELECT的字段建立復(fù)合索引,這樣查詢時(shí)只進(jìn)行索引掃描,不讀取數(shù)據(jù)塊。
5. 在判斷有無符合條件的記錄時(shí)建議不要用SELECT COUNT (*)和select top 1 語句。
6. 使用內(nèi)層限定原則,在拼寫SQL語句時(shí),將查詢條件分解、分類,并盡量在SQL語句的最里層進(jìn)行限定,以減少數(shù)據(jù)的處理量。
7. 應(yīng)絕對(duì)避免在order by子句中使用表達(dá)式。
9. 小心使用 IN 和 OR,需要注意In集合中的數(shù)據(jù)量。建議集合中的數(shù)據(jù)不超過200個(gè)。
10. <> 用 < 、 > 代替,>用>=代替, < 用< =代替,這樣可以有效的利用索引。
11. 在查詢時(shí)盡量減少對(duì)多余數(shù)據(jù)的讀取包括多余的列與多余的行。
12. 對(duì)于復(fù)合索引要注意,例如在建立復(fù)合索引時(shí)列的順序是F1,F(xiàn)2,F(xiàn)3,則在where或order by子句中這些字段出現(xiàn)的順序要與建立索引時(shí)的字段順序一致,且必須包含第一列。只能是F1或F1,F(xiàn)2或F1,F(xiàn)2,F(xiàn)3。否則不會(huì)用到該索引。
一、表中字符串帶空格的原因
1、空格就是空格。
2、控制符 顯示為 空格。
二、解決方法
第一種情況,去空格的處理的比較簡(jiǎn)單,Replace(column,' ','') 就可以解決。
第二種情況,解決方法就比較麻煩點(diǎn):需要先查出相應(yīng)的ASCII碼,再用Replace(column,char(ascii碼),'')解決,以下舉個(gè)栗子:
CREATE TABLE #temp
(NAME NVARCHAR(50))
INSERT INTO #temp SELECT '明天就是國(guó)慶了'+CHAR(10) --換行符
SELECT * FROM #temp --末尾顯示為空格
SELECT REPLACE(NAME,' ','') FROM #temp --去不掉這個(gè)空格
SELECT REPLACE(NAME,CHAR(10),'') FROM #temp --去掉空格
SELECT REPLACE(NAME,CHAR(ASCII(RIGHT(NAME,1))),'') FROM #temp --在不知道是最后一位是什么字符導(dǎo)致空格的情況下,先轉(zhuǎn)ASCII碼,在替換
DROP TABLE #temp
----下面是查詢結(jié)果:
--'明天就是國(guó)慶了 '
--'明天就是國(guó)慶了 '
--'明天就是國(guó)慶了'
--'明天就是國(guó)慶了'
答:
1.數(shù)據(jù)庫(kù)的設(shè)計(jì)
盡量把數(shù)據(jù)庫(kù)設(shè)計(jì)的更小的占磁盤空間.
1).盡可能使用更小的整數(shù)類型.(mediumint就比int更合適).
2).盡可能的定義字段為not null,除非這個(gè)字段需要null.
3).如果沒有用到變長(zhǎng)字段的話比如varchar,那就采用固定大小的紀(jì)錄格式比如char.
4).表的主索引應(yīng)該盡可能的短.這樣的話每條紀(jì)錄都有名字標(biāo)志且更高效.
5).只創(chuàng)建確實(shí)需要的索引。索引有利于檢索記錄,但是不利于快速保存記錄。如果總是要在表的組合字段上做搜索,那么就在這些字段上創(chuàng)建索引。索引的第一部分必須是最常使用的字段.如果總是需要用到很多字段,首先就應(yīng)該多復(fù)制這些字段,使索引更好的壓縮。
6).所有數(shù)據(jù)都得在保存到數(shù)據(jù)庫(kù)前進(jìn)行處理。
7).所有字段都得有默認(rèn)值。
8).在某些情況下,把一個(gè)頻繁掃描的表分成兩個(gè)速度會(huì)快好多。在對(duì)動(dòng)態(tài)格式表掃描以取得相關(guān)記錄時(shí),它可能使用更小的靜態(tài)格式表的情況下更是如此。
2.系統(tǒng)的用途
1).盡量使用長(zhǎng)連接.
2).explain 復(fù)雜的SQL語句。
3).如果兩個(gè)關(guān)聯(lián)表要做比較話,做比較的字段必須類型和長(zhǎng)度都一致.
4).LIMIT語句盡量要跟order by或者 distinct.這樣可以避免做一次full table scan.
5).如果想要清空表的所有記錄,建議用truncate table tablename而不是delete from tablename.
6).能使用STORE PROCEDURE 或者 USER FUNCTION的時(shí)候.
7).在一條insert語句中采用多重紀(jì)錄插入格式.而且使用load data infile來導(dǎo)入大量數(shù)據(jù),這比單純的indert快好多.
8).經(jīng)常OPTIMIZE TABLE 來整理碎片.
9).還有就是date 類型的數(shù)據(jù)如果頻繁要做比較的話盡量保存在unsigned int 類型比較快。
3.系統(tǒng)的瓶頸
1).磁盤搜索.
并行搜索,把數(shù)據(jù)分開存放到多個(gè)磁盤中,這樣能加快搜索時(shí)間.
2).磁盤讀寫(IO)
可以從多個(gè)媒介中并行的讀取數(shù)據(jù)。
3).CPU周期
數(shù)據(jù)存放在主內(nèi)存中.這樣就得增加CPU的個(gè)數(shù)來處理這些數(shù)據(jù)。
4).內(nèi)存帶寬
當(dāng)CPU要將更多的數(shù)據(jù)存放到CPU的緩存中來的話,內(nèi)存的帶寬就成了瓶頸.
命令行工具
–crsctl管理集群相關(guān)的操作:
-啟動(dòng)和關(guān)閉Oracle集群
-啟用和禁用Oracle集群后臺(tái)進(jìn)程
-注冊(cè)集群資源
-srvctl 管理Oracle 資源相關(guān)操作
-啟動(dòng)和關(guān)閉數(shù)據(jù)庫(kù)實(shí)例和服務(wù)
在Oracle Grid安裝的home路徑下的命令行工具crsctl和srvctl用來管理Oracle集群。使用crsctl可以監(jiān)控和管理任何集群節(jié)點(diǎn)的集群組件和資源。srvctl工具提供了類似的功能,來監(jiān)控和管理Oracle相關(guān)的資源,例如數(shù)據(jù)庫(kù)實(shí)例和數(shù)據(jù)庫(kù)服務(wù)。crsctl命令只能是集群管理者來運(yùn)行,srvctl命令可以是其他用戶,例如數(shù)據(jù)庫(kù)管理員來使用。
一、存儲(chǔ)過程與函數(shù)的區(qū)別:
1.一般來說,存儲(chǔ)過程實(shí)現(xiàn)的功能要復(fù)雜一點(diǎn),而函數(shù)的實(shí)現(xiàn)的功能針對(duì)性比較強(qiáng)。
2.對(duì)于存儲(chǔ)過程來說可以返回參數(shù)(output),而函數(shù)只能返回值或者表對(duì)象。
3.存儲(chǔ)過程一般是作為一個(gè)獨(dú)立的部分來執(zhí)行,而函數(shù)可以作為查詢語句的一個(gè)部分來調(diào)用,由于函數(shù)可以返回一個(gè)表對(duì)象,因此它可以在查詢語句中位于FROM關(guān)鍵字的后面。
二、存儲(chǔ)過程的優(yōu)點(diǎn):
1.執(zhí)行速度更快 – 在數(shù)據(jù)庫(kù)中保存的存儲(chǔ)過程語句都是編譯過的
2.允許模塊化程序設(shè)計(jì) – 類似方法的復(fù)用
3.提高系統(tǒng)安全性 – 防止SQL注入
4.減少網(wǎng)絡(luò)流通量 – 只要傳輸存儲(chǔ)過程的名稱
系統(tǒng)存儲(chǔ)過程一般以sp開頭,用戶自定義的存儲(chǔ)過程一般以u(píng)sp開頭
缺點(diǎn):
第一,創(chuàng)建索引和維護(hù)索引要耗費(fèi)時(shí)間,這種時(shí)間隨著數(shù)據(jù)量的增加而增加。
第二,索引需要占物理空間,除了數(shù)據(jù)表占數(shù)據(jù)空間之外,每一個(gè)索引還要占一定的物理空間,如果要建立聚簇索引,那么需要的空間就會(huì)更大。
第三,當(dāng)對(duì)表中的數(shù)據(jù)進(jìn)行增加、刪除和修改的時(shí)候,索引也要?jiǎng)討B(tài)的維護(hù),這樣就降低了數(shù)據(jù)的維護(hù)速度。
客戶信息表(c CUSTOM)有以下字段:
id、name、mobile
客戶訂單表(C_ORDER)有以下字段:
id、custom_id、commodity、count、order _date
Mysql:
Select * from c_order order by order_date desc limit 0,5;
Oracle:
Select o.*,rownum n
from c_order order by order_date desc where n<6;
A. | HQL與SQL沒什么差別 |
B. | HQL面向?qū)ο螅鳶QL操縱關(guān)系數(shù)據(jù)庫(kù) |
C. | 在 HQL 與 SQL 中,都包含 select,insert,update,delete 語句 |
D. | HQL僅用于査詢數(shù)據(jù),不支持insert,update和delete語句 |
答案:BC
|
字段名稱 | 字段解釋 | 字段類型 | 字段長(zhǎng)度 | 約束 |
s_id | 學(xué)號(hào) | 字符 | 10 | PK |
s_name | 學(xué)生姓名 | 字符 | 50 | Not null |
s_age | 學(xué)生年齡 | 數(shù)值 | 3 | Not null |
s-sex | 學(xué)生性別 | 字符(男:1女:0) | 1 | Not null |
下面是教師表(Teacher )的結(jié)構(gòu)說明
字段名稱 | 字段解釋 | 字段類型 | 字段長(zhǎng)度 | 約束 |
t_id | 教師編號(hào) | 字符 | 10 | PK |
t_name | 教師名字 | 字符 | 50 | Not null |
下面是課程表(Course)的結(jié)構(gòu)說明
字段名稱 | 字段解釋 | 字段類型 | 字段長(zhǎng)度 | 約束 |
c_id | 課程編號(hào) | 字符 | 10 | PK |
c_name | 課程名字 | 字符 | 50 | Not null |
t_id | 教師編號(hào) | 字符 | 10 | Not null |
下面是成績(jī)表(SC)的結(jié)構(gòu)說明
字段名稱 | 字段解釋 | 字段類型 | 字段長(zhǎng)度 | 約束 |
s_id | 學(xué)號(hào) | 字符 | 10 | PK |
c_id | 課程編號(hào) | 字符 | 10 | Not null |
score | 成績(jī) | 數(shù)值 | 3 | Not null |
1、查詢“001”課程比“002”課程成績(jī)高的所有學(xué)生的學(xué)號(hào);
select a.s_id from (select s_id,score from SC where C_ID='001') a,(select s_id,score
from SC where C_ID='002') b
where a.score>b.score and a.s_id=b.s_id;
2、查詢平均成績(jī)大于60分的同學(xué)的學(xué)號(hào)和平均成績(jī);
select S_ID,avg(score)
from sc
group by S_ID having avg(score) >60;
3、查詢所有同學(xué)的學(xué)號(hào)、姓名、選課數(shù)、總成績(jī);
select Student.S_ID,Student.Sname,count(SC.C_ID),sum(score)
from Student left Outer join SC on Student.S_ID=SC.S_ID
group by Student.S_ID,Sname
4、查詢姓“李”的老師的個(gè)數(shù);
select count(distinct(Tname))
from Teacher
where Tname like '李%';
5、查詢沒學(xué)過“葉平”老師課的同學(xué)的學(xué)號(hào)、姓名;
select Student.S_ID,Student.Sname
from Student
where S_ID not in (select distinct( SC.S_ID) from SC,Course,Teacher where SC.C_ID=Course.C_ID and Teacher.T#=Course.T# and Teacher.Tname='葉平');
6、查詢學(xué)過“001”并且也學(xué)過編號(hào)“002”課程的同學(xué)的學(xué)號(hào)、姓名;
elect Student.S_ID,Student.Sname from Student,SC where Student.S_ID=SC.S_ID and SC.C_ID='001'and exists( Select * from SC as SC_2 where SC_2.S_ID=SC.S_ID and SC_2.C_ID='002');
7、查詢學(xué)過“葉平”老師所教的所有課的同學(xué)的學(xué)號(hào)、姓名;
select S_ID,Sname
from Student
where S_ID in (select S_ID from SC ,Course ,Teacher where SC.C_ID=Course.C_ID and Teacher.T#=Course.T# and Teacher.Tname='葉平' group by S_ID having count(SC.C_ID)=(select count(C_ID) from Course,Teacher where Teacher.T#=Course.T# and Tname='葉平'));
8、查詢課程編號(hào)“002”的成績(jī)比課程編號(hào)“001”課程低的所有同學(xué)的學(xué)號(hào)、姓名;
Select S_ID,Sname from (select Student.S_ID,Student.Sname,score ,(select score from SC SC_2 where SC_2.S_ID=Student.S_ID and SC_2.C_ID='002') score2
from Student,SC where Student.S_ID=SC.S_ID and C_ID='001') S_2 where score2 < score;
9、查詢所有課程成績(jī)小于60分的同學(xué)的學(xué)號(hào)、姓名;
select S_ID,Sname
from Student
where S_ID not in (select S.S_ID from Student AS S,SC where S.S_ID=SC.S_ID and score>60);
10、查詢沒有學(xué)全所有課的同學(xué)的學(xué)號(hào)、姓名;
select Student.S_ID,Student.Sname
from Student,SC
where Student.S_ID=SC.S_ID group by Student.S_ID,Student.Sname having count(C_ID) <(select count(C_ID) from Course);
11、查詢至少有一門課與學(xué)號(hào)為“1001”的同學(xué)所學(xué)相同的同學(xué)的學(xué)號(hào)和姓名;
select distinct S_ID,Sname from Student,SC where?Student.S_ID=SC.S_ID and SC.C_ID in (select C_ID from SC where S_ID='1001');
12、查詢至少學(xué)過學(xué)號(hào)為“001”同學(xué)所有一門課的其他同學(xué)學(xué)號(hào)和姓名;
select distinct SC.S_ID,Sname
from Student,SC
where Student.S_ID=SC.S_ID and C_ID in (select C_ID from SC where S_ID='001');
S(S#,SN,SD,SA),其中S#,SN,SD,SA分別代表學(xué)號(hào)、學(xué)員姓名、所屬單位、學(xué)員年齡。
C (C#,CN ),其中C#,CN分別代表課程編號(hào)、課程名稱
SC(S#,C#,G),其中S#,C#,G分別代表學(xué)號(hào)、所選修的課程編號(hào)、學(xué)習(xí)成績(jī)
請(qǐng)使用2種標(biāo)準(zhǔn)SQL語句査洵選修課程名稱為“稅收基礎(chǔ)”的學(xué)員學(xué)號(hào)和姓名,并說明其優(yōu)缺點(diǎn) 。
SQL92標(biāo)準(zhǔn):
SELECT SN,SD FROM S
WHERE [S#] IN(
SELECT [S#] FROM C,SC
WHERE C.[C#]=SC.[C#]
AND CN=N'稅收基礎(chǔ)')
SQL99標(biāo)準(zhǔn):
elect s.s#,s.sn from s
join sc on s.s#=sc.s#
join c on sc.c#=c.c#
where c.cn='稅收基礎(chǔ)'
優(yōu)點(diǎn):
SQL99將連接條件和過濾條件分開,顯得代碼清晰。
SQL92書寫簡(jiǎn)單易于理解。
缺點(diǎn):
SQL92連接條件和過濾條件都寫在一起,不利于查看。
SQL99書寫相對(duì)麻煩不易于理解。
1.這么大數(shù)據(jù)量首先建議 使用大數(shù)據(jù)的DB,可以用spring batch 來做類似這樣的處理。定量向DB存儲(chǔ)數(shù)據(jù)。如果需要定時(shí),可以考慮 quartz。
Mysql數(shù)據(jù)庫(kù)設(shè)計(jì):
1.讀寫分離;
2.縱向橫向拆分庫(kù)、表。
MySQL的基本功能中包括replication(復(fù)制)功能。所謂replication,就是確定master以及與之同步的slave服務(wù)器,再加上slave將master中寫入的內(nèi)容polling過來更新自身內(nèi)容的功能。這樣slave就是master的replica(復(fù)制品)。這樣就可以準(zhǔn)備多臺(tái)內(nèi)容相同的服務(wù)器。
通過master和salve的replication,準(zhǔn)備好多臺(tái)服務(wù)器之后,讓應(yīng)用程序服務(wù)器通過負(fù)載均衡器去處理查詢slave。這樣就能將查詢分散到多臺(tái)服務(wù)器上。
應(yīng)用程序?qū)崿F(xiàn)上應(yīng)該只把select等讀取之類的查詢發(fā)送給負(fù)載均衡器,而更新應(yīng)當(dāng)直接發(fā)送給master。要是在slave上執(zhí)行更新操作,slave和master的內(nèi)容就無法同步。MySQL會(huì)檢測(cè)到master和slave之間內(nèi)容差異,并停止replication,這回導(dǎo)致系統(tǒng)故障。Slave可以采用LVS(linux系統(tǒng)自帶的負(fù)載均衡器)實(shí)現(xiàn)查詢的負(fù)載均衡。
使用MySQL的replication是利用的冗余化,實(shí)現(xiàn)冗余化需要實(shí)現(xiàn)的最小服務(wù)器數(shù)量是4臺(tái),三臺(tái)slave和一臺(tái)master,slave為什么是需要三臺(tái)呢,比如一臺(tái)slave死機(jī)了,現(xiàn)在需要修復(fù)再次上線,那么意味著你必須停止一臺(tái)slave來復(fù)制MySQL的數(shù)據(jù),如果只有兩臺(tái)slave,一臺(tái)壞了,你就必須停止服務(wù),如果有三臺(tái),壞了一臺(tái),你復(fù)制數(shù)據(jù)時(shí)停止一臺(tái),還有一臺(tái)可以運(yùn)維。
對(duì)于數(shù)據(jù)的處理是能放入到內(nèi)存中就盡量放入到內(nèi)存中如果不能放入到內(nèi)存中,可以利用MySQL的Partitioning。
Partitioning就是表分割也就是講A表和B表放在不同的服務(wù)器上。簡(jiǎn)單來說,Partitioning就是充分利用局部性進(jìn)行分割,提高緩存利用效率,從而實(shí)現(xiàn)Partitioning的效果。其中最重要的一點(diǎn)就是以Partitioning為前提設(shè)計(jì)的系統(tǒng)將表分割開,用RDBMS的方式的話,對(duì)于一對(duì)多的關(guān)系經(jīng)常使用JOIN查詢將兩張表連接起來。但是如果將表分割開了之后,也就是兩張表不在同一個(gè)數(shù)據(jù)庫(kù),不在同一個(gè)服務(wù)器上怎樣使用JOIN操作,這里需要注意的是如果是用where in操作不是省了一些麻煩了嘛。
MySQL有多種存儲(chǔ)引擎,每種存儲(chǔ)引擎有各自的優(yōu)缺點(diǎn),可以擇優(yōu)選擇使用:
MyISAM、InnoDB、MERGE、MEMORY(HEAP)、BDB(BerkeleyDB)、EXAMPLE、FEDERATED、ARCHIVE、CSV、BLACKHOLE。
MySQL支持?jǐn)?shù)個(gè)存儲(chǔ)引擎作為對(duì)不同表的類型的處理器。MySQL存儲(chǔ)引擎包括處理事務(wù)安全表的引擎和處理非事務(wù)安全表的引擎。
· MyISAM管理非事務(wù)表。它提供高速存儲(chǔ)和檢索,以及全文搜索能力。MyISAM在所有MySQL配置里被支持,它是默認(rèn)的存儲(chǔ)引擎,除非你配置MySQL默認(rèn)使用另外一個(gè)引擎。
· MEMORY存儲(chǔ)引擎提供“內(nèi)存中”表。MERGE存儲(chǔ)引擎允許集合將被處理同樣的MyISAM表作為一個(gè)單獨(dú)的表。就像MyISAM一樣,MEMORY和MERGE存儲(chǔ)引擎處理非事務(wù)表,這兩個(gè)引擎也都被默認(rèn)包含在MySQL中。
注釋:MEMORY存儲(chǔ)引擎正式地被確定為HEAP引擎。
· InnoDB和BDB存儲(chǔ)引擎提供事務(wù)安全表。BDB被包含在為支持它的操作系統(tǒng)發(fā)布的MySQL-Max二進(jìn)制分發(fā)版里。InnoDB也默認(rèn)被包括在所 有MySQL 5.1二進(jìn)制分發(fā)版里,你可以按照喜好通過配置MySQL來允許或禁止任一引擎。
· EXAMPLE存儲(chǔ)引擎是一個(gè)“存根”引擎,它不做什么。你可以用這個(gè)引擎創(chuàng)建表,但沒有數(shù)據(jù)被存儲(chǔ)于其中或從其中檢索。這個(gè)引擎的目的是服務(wù),在 MySQL源代碼中的一個(gè)例子,它演示說明如何開始編寫新存儲(chǔ)引擎。同樣,它的主要興趣是對(duì)開發(fā)者。
· NDB Cluster是被MySQL Cluster用來實(shí)現(xiàn)分割到多臺(tái)計(jì)算機(jī)上的表的存儲(chǔ)引擎。它在MySQL-Max 5.1二進(jìn)制分發(fā)版里提供。這個(gè)存儲(chǔ)引擎當(dāng)前只被Linux, Solaris, 和Mac OS X 支持。在未來的MySQL分發(fā)版中,我們想要添加其它平臺(tái)對(duì)這個(gè)引擎的支持,包括Windows。
· ARCHIVE存儲(chǔ)引擎被用來無索引地,非常小地覆蓋存儲(chǔ)的大量數(shù)據(jù)。
· CSV存儲(chǔ)引擎把數(shù)據(jù)以逗號(hào)分隔的格式存儲(chǔ)在文本文件中。
· BLACKHOLE存儲(chǔ)引擎接受但不存儲(chǔ)數(shù)據(jù),并且檢索總是返回一個(gè)空集。
· FEDERATED存儲(chǔ)引擎把數(shù)據(jù)存在遠(yuǎn)程數(shù)據(jù)庫(kù)中。在MySQL 5.1中,它只和MySQL一起工作,使用MySQL C Client API。在未來的分發(fā)版中,我們想要讓它使用其它驅(qū)動(dòng)器或客戶端連接方法連接到另外的數(shù)據(jù)源。
fname | kecheng | fenshu |
張三 | 語文 | 81 |
張三 | 數(shù)學(xué) | 65 |
李四 | 語文 | 76 |
李四 | 數(shù)學(xué) | 90 |
王五 | 語文 | 61 |
王五 | 數(shù)學(xué) | 100 |
王五 | 英語 | 90 |
1.請(qǐng)用一條sql語句從t_result表中查詢出每門課都大于75分的學(xué)生姓名;
select b.fname from
(select fname,count(kecheng) c from t_result group by fname)a,
(Select fname,kecheng,count(fname) c from t_result where fenshu >75 group by fname)b
where a.fname = b.fname and a.c = b.c
2.請(qǐng)用一條sql寫出總分排名前三的學(xué)生姓名,總分,平均分
select fname,sum(fenshu),avg(fenshu) from t_result GROUP By fname order by SUM(fenshu) desc;
org_employee;表中字段:雇員編號(hào)(emp_id),雇員姓名(em_name),雇員年齡(emp_age),雇員部門(depart_name);請(qǐng)寫出執(zhí)行以下操作的sql語句:
1)向表中增加一條數(shù)據(jù):雇員編號(hào)(1001),雇員姓名(張三),雇員年齡(24),雇員部門(研發(fā)部);
INSERT INTO org_employee
VALUES(‘1001’,’張三’,’24’,’研發(fā)部’);
2)查詢雇員年齡在55(包含)至60(不包含)歲之間的雇員數(shù)據(jù)
SELECT * FROM org_employee
WHERE emp_age>=55 and emp_age <60;
3)分部門查詢各個(gè)部門的雇員數(shù)量
SELECT COUNT(*),depart_name group by depart_name;
4)刪除姓名為張三的雇員數(shù)據(jù)
Delete from org_employee where em_name =’張三’;
5)在表中增加一個(gè)日期類型的字段雇員出生日期,字段為emp_brithday
Alter table org_employee add(emp_brithday date);
6)將表org_employee刪除
drop org_employee;
請(qǐng)用sql語句實(shí)現(xiàn)表2的查詢結(jié)果
表1
ID | matchdate | result |
1 | 2015-02-04 | 勝 |
2 | 2015-02-04 | 負(fù) |
3 | 2015-02-04 | 勝 |
4 | 2015-04-07 | 勝 |
5 | 2015-04-07 | 勝 |
6 | 2015-04-07 | 勝 |
表2
比賽日期 | 勝 | 負(fù) |
2015-02-04 | 2 | 1 |
2015-04-07 | 1 | 2 |
SQL語句:
create table t_second( matchdate date, win varchar(3), lose varchar(3) ); insert into t_second (matchdate,win) select matchdate,count(result) from t_test where result ='勝' GROUP BY matchdate; update t_second,(select matchdate,count(result) as lose from t_test where result ='負(fù)' GROUP BY matchdate)s set t_second.lose = s.lose where t_second.matchdate = s.matchdate;
SELECT… FROM EMP WHERE DEPT_NO NOT IN (SELECT DEPT_NO FROM DEPT WHERE DEPT_CAT=’A’);
SELECT… FROM EMP WHERE DEPT_NO NOT EXISTS(SELECT DEPT_NO FROM DEPT WHERE DEPT_CAT=’A’);
優(yōu)化的理由:not in 和not exists
如果查詢語句使用了not in 那么內(nèi)外表都進(jìn)行全表掃描,沒有用到索引;
而not extsts 的子查詢依然能用到表上的索引。所以無論那個(gè)表大,用not exists 都比not in 要快。
使用ETL工具,如infomatic,datastage,kettle等,可以完成異構(gòu)數(shù)據(jù)庫(kù)的遷移
以kettle為例
表輸入選擇 oracle庫(kù)
表輸出選擇DB庫(kù)
循環(huán)執(zhí)行可以進(jìn)行全庫(kù)遷移
姓名:name | 課程:subject | 分?jǐn)?shù):score | 學(xué)號(hào):stuid |
張三 | 數(shù)學(xué) | 89 | 1 |
張三 | 語文 | 80 | 1 |
張三 | 英語 | 70 | 1 |
李四 | 數(shù)學(xué) | 90 | 2 |
李四 | 語文 | 70 | 2 |
李四 | 英語 | 80 | 2 |
1.計(jì)算每個(gè)人的總成績(jī)并排名(要求顯示字段:姓名,總成績(jī))
select name,sum(score) s from t_stu GROUP BY name;
2.列出各門課程成績(jī)最好的學(xué)生(要求顯示字段:學(xué)號(hào),姓名,科目,成績(jī))
select t1.stuid,t1.name,t1.subject,t1.score from t_stu t1,
(select subject,MAX(score) as maxscore from t_stu group by subject)t2
where t1.subject = t2.subject and t1.score = t2.maxscore;
3.列出各個(gè)課程的平均成績(jī)(要求顯示字段;課程,平均成績(jī))
select subject,AVG(score)平均成績(jī) from t_stu
group by subject;
Stu表
sid(學(xué)生ID) | sname(姓名) | sage(年齡) |
1 | 張三 | 23 |
2 | 李四 | 25 |
3 | 王五 | 24 |
Grade表
gid(分?jǐn)?shù)主鍵) | cid(課程ID) | sid(學(xué)生主鍵) | grade(分?jǐn)?shù)) |
1 | 2 | 3 | 86 |
2 | 2 | 2 | 79 |
3 | 1 | 2 | 80 |
4 | 1 | 1 | 81 |
5 | 1 | 3 | 70 |
6 | 2 | 1 | 78 |
請(qǐng)寫sql統(tǒng)計(jì)出有兩門以上的課的分?jǐn)?shù)在80分以上的學(xué)生的姓名和年齡?
Select sname,sage from Stu where Stu.sid in (
Select sid from Grade where grade >80
)
字段名稱 | 字段解釋 | 字段類型 | 字段長(zhǎng)度 | 約束 |
s_id | 學(xué)號(hào) | 字符 | 10 | PK |
s_name | 學(xué)生姓名 | 字符 | 50 | Not null |
s_age | 學(xué)生年齡 | 數(shù)值 | 3 | Not null |
s-sex | 學(xué)生性別 | 字符(男:1女:0) | 1 | Not null |
下面是教師表(Teacher )的結(jié)構(gòu)說明
字段名稱 | 字段解釋 | 字段類型 | 字段長(zhǎng)度 | 約束 |
t_id | 教師編號(hào) | 字符 | 10 | PK |
t_name | 教師名字 | 字符 | 50 | Not null |
下面是課程表(Course)的結(jié)構(gòu)說明
字段名稱 | 字段解釋 | 字段類型 | 字段長(zhǎng)度 | 約束 |
c_id | 課程編號(hào) | 字符 | 10 | PK |
c_name | 課程名字 | 字符 | 50 | Not null |
t_id | 教師編號(hào) | 字符 | 10 | Not null |
下面是成績(jī)表(SC)的結(jié)構(gòu)說明
字段名稱 | 字段解釋 | 字段類型 | 字段長(zhǎng)度 | 約束 |
s_id | 學(xué)號(hào) | 字符 | 10 | PK |
c_id | 課程編號(hào) | 字符 | 10 | Not null |
score | 成績(jī) | 數(shù)值 | 3 | Not null |
查詢同名同姓學(xué)生名單,并統(tǒng)計(jì)同名人數(shù)
select 姓名,count(學(xué)號(hào)) as num
from 學(xué)生表
group by 姓名
having count(學(xué)號(hào))>1 --保證查找到的都是存在2個(gè)以上(包括2)的同名同姓的姓名及人數(shù)。
查詢平均成績(jī)大于60分的學(xué)生的學(xué)號(hào)和平均成績(jī);
Select s_id,avg(score) from sc groupby s_id having avg(score)>60
查詢姓“李”的老師的個(gè)數(shù);
Select count(*),teacher.t_name from teacher where teacher.t_name like '李%'
Sql server方案:
select top 10 * from t where id not in
(select top 30 id from t order by id ) orde by id
Mysql方案:select * from t order by id limit 30,10
Oracle方案:
select rownum num,tid from (select rownum num,tid from t_test) where num>=30 and num<=41;
A表
ID | NAME |
B表
ID | NAME | OTHER |
1 | Aaa | Ddd |
2 | Bbb | Eee |
insert into a select id,name from b;
它是從一個(gè)或幾個(gè)基本表中導(dǎo)出的 表,是從現(xiàn)有基本表中抽取若干子集組成用戶的“專用表”。
基本表:基本表的定義指建立基本關(guān)系模式,
而變更則是指對(duì)數(shù)據(jù)庫(kù)中已存在的基本表進(jìn)行刪除與修改。
區(qū)別:
1、視圖是已經(jīng)編譯好的sql語句。而表不是
2、視圖沒有實(shí)際的物理記錄。而表有。
3、表是內(nèi)容,視圖是窗口
4、表只用物理空間而視圖不占用物理空間,
視圖只是邏輯概念的存在,表可以及時(shí)對(duì)它進(jìn)行修改,
但視圖只能有創(chuàng)建的語句來修改
5、表是內(nèi)模式,試圖是外模式
6、視圖是查看數(shù)據(jù)表的一種方法,
可以查詢數(shù)據(jù)表中某些字段構(gòu)成的數(shù)據(jù),
只是一些SQL語句的集合。從安全的角度說,
視圖可以不給用戶接觸數(shù)據(jù)表,從而不知道表結(jié)構(gòu)。
7、表屬于全局模式中的表,是實(shí)表;視圖屬于局部模式的表,
是虛表。
8、視圖的建立和刪除只影響視圖本身,不影響對(duì)應(yīng)的基本表。
聯(lián)系:視圖(view)是在基本表之上建立的表,它的結(jié)構(gòu)(
即所定義的列)和內(nèi)容(即所有數(shù)據(jù)行)都來自基本表,
它依據(jù)基本表存在而存在。一個(gè)視圖可以對(duì)應(yīng)一個(gè)基本表,
也可以對(duì)應(yīng)多個(gè)基本表。
視圖是基本表的抽象和在邏輯意義上建立的新關(guān)系
事務(wù)與鎖是不同的。事務(wù)具有ACID(原子性、一致性、隔離性和持久性),鎖是用于解決隔離性的一種機(jī)制。事務(wù)的隔離級(jí)別通過鎖的機(jī)制來實(shí)現(xiàn)。另外鎖有不同的粒度,同時(shí)事務(wù)也是有不同的隔離級(jí)別的(一般有四種:讀未提交Read uncommitted,
讀已提交Read committed,
可重復(fù)讀Repeatable read,
可串行化Serializable)。
在具體的程序設(shè)計(jì)中,開啟事務(wù)其實(shí)是要數(shù)據(jù)庫(kù)支持才行的,如果數(shù)據(jù)庫(kù)本身不支持事務(wù),那么仍然無法確保你在程序中使用的事務(wù)是有效的。
鎖可以分為樂觀鎖和悲觀鎖:
悲觀鎖:認(rèn)為在修改數(shù)據(jù)庫(kù)數(shù)據(jù)的這段時(shí)間里存在著也想修改此數(shù)據(jù)的事務(wù);
樂觀鎖:認(rèn)為在短暫的時(shí)間里不會(huì)有事務(wù)來修改此數(shù)據(jù)庫(kù)的數(shù)據(jù);
我們一般意義上講的鎖其實(shí)是指悲觀鎖,在數(shù)據(jù)處理過程中,將數(shù)據(jù)置于鎖定狀態(tài)(由數(shù)據(jù)庫(kù)實(shí)現(xiàn))
如果開啟了事務(wù),在事務(wù)沒提交之前,別人是無法修改該數(shù)據(jù)的;如果rollback,你在本次事務(wù)中的修改將撤消(不是別人修改的會(huì)沒有,因?yàn)閯e人此時(shí)無法修改)。當(dāng)然,前提是你使用的數(shù)據(jù)庫(kù)支持事務(wù)。還有一個(gè)要注意的是,部分?jǐn)?shù)據(jù)庫(kù)支持自定義SQL鎖覆蓋事務(wù)隔離級(jí)別默認(rèn)的鎖機(jī)制,如果使用了自定義的鎖,那就另當(dāng)別論。
重點(diǎn):一般事務(wù)使用的是悲觀鎖(具有排他性)
寫一個(gè)SQL語句,查詢選修了計(jì)算機(jī)原理的學(xué)生學(xué)號(hào)和姓名
select 學(xué)號(hào),姓名 from Student where 學(xué)號(hào) in
(select 學(xué)號(hào) from Sc where 課程編號(hào) in
(Select 課程編號(hào) from Course where 課程名稱 = ‘計(jì)算機(jī)原理’))
寫一個(gè)SQL語句,查詢“周星馳”同學(xué)選修了的課程名字
select 課程名稱 from Course where 編號(hào) in (
select Sc.課程編號(hào) from Student,Sc where Student.姓名=’周星馳’ and Student.學(xué)號(hào) = Sc.學(xué)號(hào))
寫一個(gè)SQL語句,查詢選修了5門課程的學(xué)生學(xué)號(hào)和姓名
Select 學(xué)號(hào),姓名 from Student where 學(xué)號(hào) in (
Select 學(xué)號(hào),count(課程編號(hào)) from Sc group by 學(xué)號(hào) having count(課程編號(hào))>=5)
Student(S#,Sname,Sage,Ssex)學(xué)生表
S#:學(xué)號(hào)
Sname:學(xué)生姓名
Sage:學(xué)生年齡
Ssex: 學(xué)生性別
Course(C#,Cname,T#)課程表
C#,課程編號(hào);
Cname:課程名字;
T#:教師編號(hào);
SC(S#,C#,score)成績(jī)表
S#:學(xué)號(hào);
C#,課程編號(hào);
Score:成績(jī);
Teacher(T#,Tname)教師表
T#:教師編號(hào);
Tname:教師名字
查詢“001”課程比“002”課程成績(jī)高的所有學(xué)生學(xué)號(hào)
select SC1.S#
from SC SC1 JOIN SC SC2 ON SC1.S#=SC2.S#
WHERE SC1.C#='001' AND SC2.C#='002' AND SC1.score>SC2.score
查詢平均成績(jī)大于60分的同學(xué)的學(xué)號(hào)和平均成績(jī)
select S#,AVG(score) 平均成績(jī)
from SC
group by S#
having AVG(score)>60
查詢所有同學(xué)的學(xué)號(hào)、姓名、選課數(shù)、總成績(jī)
select Student.S#,Sname,COUNT(*) 選課數(shù),SUM(score) 總成績(jī)
from Student JOIN SC on Student.S#=SC.S#
group by Student.S#,Sname
查詢姓“李”的老師的個(gè)數(shù)
Select count(*) from Teacher where Tname like ‘李%’;
查詢沒學(xué)過“葉平”老師課的同學(xué)的學(xué)號(hào)、姓名
SELECT stu2.s#,stu2.stuname FROM Student stu2 WHERE stu2.s# NOT IN
(SELECT DISTINCT stu.s# FROM student stu, course c,teacher tea,score score
WHERE stu.s#= score.s# AND course.c#= score.c#
AND tea.t#= course.t#AND tea.tname= '葉平' )
JVM
內(nèi)存管理的職責(zé)為分配內(nèi)存,回收內(nèi)存。 沒有自動(dòng)內(nèi)存管理的語言/平臺(tái)容易發(fā)生錯(cuò)誤。
典型的問題包括懸掛指針問題,一個(gè)指針引用了一個(gè)已經(jīng)被回收的內(nèi)存地址,導(dǎo)致程序的運(yùn)行完全不可知。
另一個(gè)典型問題為內(nèi)存泄露,內(nèi)存已經(jīng)分配,但是已經(jīng)沒有了指向該內(nèi)存的指針,導(dǎo)致內(nèi)存泄露。 程序員要花費(fèi)大量時(shí)間在調(diào)試該類問題上。
JVM中類的裝載是由類加載器(ClassLoader)和它的子類來實(shí)現(xiàn)的,Java中的類加載器是一個(gè)重要的Java運(yùn)行時(shí)系統(tǒng)組件,它負(fù)責(zé)在運(yùn)行時(shí)查找和裝入類文件中的類。
由于Java的跨平臺(tái)性,經(jīng)過編譯的Java源程序并不是一個(gè)可執(zhí)行程序,而是一個(gè)或多個(gè)類文件。當(dāng)Java程序需要使用某個(gè)類時(shí),JVM會(huì)確保這個(gè)類已經(jīng)被加載、連接(驗(yàn)證、準(zhǔn)備和解析)和初始化。類的加載是指把類的.class文件中的數(shù)據(jù)讀入到內(nèi)存中,通常是創(chuàng)建一個(gè)字節(jié)數(shù)組讀入.class文件,然后產(chǎn)生與所加載類對(duì)應(yīng)的Class對(duì)象。加載完成后,Class對(duì)象還不完整,所以此時(shí)的類還不可用。當(dāng)類被加載后就進(jìn)入連接階段,這一階段包括驗(yàn)證、準(zhǔn)備(為靜態(tài)變量分配內(nèi)存并設(shè)置默認(rèn)的初始值)和解析(將符號(hào)引用替換為直接引用)三個(gè)步驟。最后JVM對(duì)類進(jìn)行初始化,包括:1)如果類存在直接的父類并且這個(gè)類還沒有被初始化,那么就先初始化父類;2)如果類中存在初始化語句,就依次執(zhí)行這些初始化語句。
類的加載是由類加載器完成的,類加載器包括:根加載器(BootStrap)、擴(kuò)展加載器(Extension)、系統(tǒng)加載器(System)和用戶自定義類加載器(java.lang.ClassLoader的子類)。從Java 2(JDK 1.2)開始,類加載過程采取了父親委托機(jī)制(PDM)。PDM更好的保證了Java平臺(tái)的安全性,在該機(jī)制中,JVM自帶的Bootstrap是根加載器,其他的加載器都有且僅有一個(gè)父類加載器。類的加載首先請(qǐng)求父類加載器加載,父類加載器無能為力時(shí)才由其子類加載器自行加載。JVM不會(huì)向Java程序提供對(duì)Bootstrap的引用。下面是關(guān)于幾個(gè)類加載器的說明:
Bootstrap:一般用本地代碼實(shí)現(xiàn),負(fù)責(zé)加載JVM基礎(chǔ)核心類庫(kù)(rt.jar);
Extension:從java.ext.dirs系統(tǒng)屬性所指定的目錄中加載類庫(kù),它的父加載器是Bootstrap;
System:又叫應(yīng)用類加載器,其父類是Extension。它是應(yīng)用最廣泛的類加載器。它從環(huán)境變量classpath或者系統(tǒng)屬性java.class.path所指定的目錄中記載類,是用戶自定義加載器的默認(rèn)父加載器。
答:JVM原理:
JVM是Java Virtual Machine(Java虛擬機(jī))的縮寫,它是整個(gè)java實(shí)現(xiàn)跨平臺(tái)的最核心的部分,所有的Java程序會(huì)首先被編譯為.class的類文件,這種類文件可以在虛擬機(jī)上執(zhí)行,也就是說class并不直接與機(jī)器的操作系統(tǒng)相對(duì)應(yīng),而是經(jīng)過虛擬機(jī)間接與操作系統(tǒng)交互,由虛擬機(jī)將程序解釋給本地系統(tǒng)執(zhí)行。JVM是Java平臺(tái)的基礎(chǔ),和實(shí)際的機(jī)器一樣,它也有自己的指令集,并且在運(yùn)行時(shí)操作不同的內(nèi)存區(qū)域。JVM通過抽象操作系統(tǒng)和CPU結(jié)構(gòu),提供了一種與平臺(tái)無關(guān)的代碼執(zhí)行方法,即與特殊的實(shí)現(xiàn)方法、主機(jī)硬件、主機(jī)操作系統(tǒng)無關(guān)。JVM的主要工作是解釋自己的指令集(即字節(jié)碼)到CPU的指令集或?qū)?yīng)的系統(tǒng)調(diào)用,保護(hù)用戶免被惡意程序騷擾。JVM對(duì)上層的Java源文件是不關(guān)心的,它關(guān)注的只是由源文件生成的類文件(.class文件)。
內(nèi)存泄漏與溢出的區(qū)別:
1) 內(nèi)存泄漏是指分配出去的內(nèi)存無法回收了。
2) 內(nèi)存溢出是指程序要求的內(nèi)存,超出了系統(tǒng)所能分配的范圍,從而發(fā)生溢出。比如用byte類型的變量存儲(chǔ)10000這個(gè)數(shù)據(jù),就屬于內(nèi)存溢出。
3) 內(nèi)存溢出是提供的內(nèi)存不夠;內(nèi)存泄漏是無法再提供內(nèi)存資源。
何時(shí)產(chǎn)生內(nèi)存泄漏:
1) 靜態(tài)集合類:在使用Set、Vector、HashMap等集合類的時(shí)候需要特別注意,有可能會(huì)發(fā)生內(nèi)存泄漏。當(dāng)這些集合被定義成靜態(tài)的時(shí)候,由于它們的生命周期跟應(yīng)用程序一樣長(zhǎng),這時(shí)候,就有可能會(huì)發(fā)生內(nèi)存泄漏。
2) 監(jiān)聽器:在Java中,我們經(jīng)常會(huì)使用到監(jiān)聽器,如對(duì)某個(gè)控件添加單擊監(jiān)聽器addOnClickListener(),但往往釋放對(duì)象的時(shí)候會(huì)忘記刪除監(jiān)聽器,這就有可能造成內(nèi)存泄漏。好的方法就是,在釋放對(duì)象的時(shí)候,應(yīng)該記住釋放所有監(jiān)聽器,這就能避免了因?yàn)楸O(jiān)聽器而導(dǎo)致的內(nèi)存泄漏。
3) 各種連接:Java中的連接包括數(shù)據(jù)庫(kù)連接、網(wǎng)絡(luò)連接和io連接,如果沒有顯式調(diào)用其close()方法,是不會(huì)自動(dòng)關(guān)閉的,這些連接就不能被GC回收而導(dǎo)致內(nèi)存泄漏。一般情況下,在try代碼塊里創(chuàng)建連接,在finally里釋放連接,就能夠避免此類內(nèi)存泄漏。
4) 外部模塊的引用:調(diào)用外部模塊的時(shí)候,也應(yīng)該注意防止內(nèi)存泄漏。如模塊A調(diào)用了外部模塊B的一個(gè)方法,如:public void register(Object o)。這個(gè)方法有可能就使得A模塊持有傳入對(duì)象的引用,這時(shí)候需要查看B模塊是否提供了去除引用的方法,如unregister()。這種情況容易忽略,而且發(fā)生了內(nèi)存泄漏的話,比較難察覺,應(yīng)該在編寫代碼過程中就應(yīng)該注意此類問題。
5) 單例模式:使用單例模式的時(shí)候也有可能導(dǎo)致內(nèi)存泄漏。因?yàn)閱卫龑?duì)象初始化后將在JVM的整個(gè)生命周期內(nèi)存在,如果它持有一個(gè)外部對(duì)象(生命周期比較短)的引用,那么這個(gè)外部對(duì)象就不能被回收,而導(dǎo)致內(nèi)存泄漏。如果這個(gè)外部對(duì)象還持有其它對(duì)象的引用,那么內(nèi)存泄漏會(huì)更嚴(yán)重,因此需要特別注意此類情況。這種情況就需要考慮下單例模式的設(shè)計(jì)會(huì)不會(huì)有問題,應(yīng)該怎樣保證不會(huì)產(chǎn)生內(nèi)存泄漏問題。
GC線程是守護(hù)線程。線程分為守護(hù)線程和非守護(hù)線程(即用戶線程)。只要當(dāng)前JVM實(shí)例中尚存在任何一個(gè)非守護(hù)線程沒有結(jié)束,守護(hù)線程就全部工作;只有當(dāng)最后一個(gè)非守護(hù)線程結(jié)束時(shí),守護(hù)線程隨著JVM一同結(jié)束工作。
類加載器按照層次,從頂層到底層,分為以下三種:
(1)啟動(dòng)類加載器(Bootstrap ClassLoader)
這個(gè)類加載器負(fù)責(zé)將存放在JAVA_HOME/lib下的,或者被-Xbootclasspath參數(shù)所指定的路徑中的,并且是虛擬機(jī)識(shí)別的類庫(kù)加載到虛擬機(jī)內(nèi)存中。啟動(dòng)類加載器無法被Java程序直接引用。
(2)擴(kuò)展類加載器(Extension ClassLoader)
這個(gè)加載器負(fù)責(zé)加載JAVA_HOME/lib/ext目錄中的,或者被java.ext.dirs系統(tǒng)變量所指定的路徑中的所有類庫(kù),開發(fā)者可以直接使用擴(kuò)展類加載器
(3)應(yīng)用程序類加載器(Application ClassLoader)
這個(gè)加載器是ClassLoader中g(shù)etSystemClassLoader()方法的返回值,所以一般也稱它為系統(tǒng)類加載器。它負(fù)責(zé)加載用戶類路徑(Classpath)上所指定的類庫(kù),可直接使用這個(gè)加載器,如果應(yīng)用程序沒有自定義自己的類加載器,一般情況下這個(gè)就是程序中默認(rèn)的類加載器
雙親委派模型:
雙親委派模型要求除了頂層的啟動(dòng)類加載器外,其他的類加載器都應(yīng)當(dāng)有自己的父類加載器。這里類加載器之間的父子關(guān)系一般不會(huì)以繼承關(guān)系來實(shí)現(xiàn),而是都使用組合關(guān)系來復(fù)用父加載器的代碼
工作過程:
如果一個(gè)類加載器收到了類加載的請(qǐng)求,它首先不會(huì)自己去嘗試加載這個(gè)類,而是把這個(gè)請(qǐng)求委派給父類加載器去完成,每一個(gè)層次的類加載器都是如此,因此所有的加載請(qǐng)求最終都應(yīng)該傳遞到頂層的啟動(dòng)類加載器中,只有當(dāng)父類加載器反饋?zhàn)约簾o法完成這個(gè)請(qǐng)求(它的搜索范圍中沒有找到所需的類)時(shí),子加載器才會(huì)嘗試自己去加載。
好處:
Java類隨著它的類加載器一起具備了一種帶有優(yōu)先級(jí)的層次關(guān)系。例如類Object,它放在rt.jar中,無論哪一個(gè)類加載器要加載這個(gè)類,最終都是委派給啟動(dòng)類加載器進(jìn)行加載,因此Object類在程序的各種類加載器環(huán)境中都是同一個(gè)類,判斷兩個(gè)類是否相同是通過classloader.class這種方式進(jìn)行的,所以哪怕是同一個(gè)class文件如果被兩個(gè)classloader加載,那么他們也是不同的類。
1、對(duì)于GC來說,當(dāng)程序員創(chuàng)建對(duì)象時(shí),GC就開始監(jiān)控這個(gè)對(duì)象的地址、大小以及使用情況。通常,GC采用有向圖的方式記錄和管理堆(heap)中的所有對(duì)象。通過這種方式確定哪些對(duì)象是"可達(dá)的",哪些對(duì)象是"不可達(dá)的"。當(dāng)GC確定一些對(duì)象為"不可達(dá)”時(shí),GC就有責(zé)任回收這些內(nèi)存空間。
2、可以。程序員可以手動(dòng)執(zhí)行System.gc(),通知GC運(yùn)行,但是Java語言規(guī)范并不保證GC一定會(huì)執(zhí)行。
3. System.gc();或者Runtime.getRuntime().gc();
答:理論上Java因?yàn)橛欣厥諜C(jī)制(GC)不會(huì)存在內(nèi)存泄露問題(這也是Java被廣泛使用于服務(wù)器端編程的一個(gè)重要原因);然而在實(shí)際開發(fā)中,可能會(huì)存在無用但可達(dá)的對(duì)象,這些對(duì)象不能被GC回收也會(huì)發(fā)生內(nèi)存泄露。一個(gè)例子就是hibernate的Session(一級(jí)緩存)中的對(duì)象屬于持久態(tài),垃圾回收器是不會(huì)回收這些對(duì)象的,然而這些對(duì)象中可能存在無用的垃圾對(duì)象。下面的例子也展示了Java中發(fā)生內(nèi)存泄露的情況:
package com.bjsxt; import java.util.Arrays; import java.util.EmptyStackException; public class MyStack<T> { private T[] elements; private int size = 0; private static final int INIT_CAPACITY = 16; public MyStack() { elements = (T[]) new Object[INIT_CAPACITY]; } public void push(T elem) { ensureCapacity(); elements[size++] = elem; } public T pop() { if(size == 0) throw new EmptyStackException(); return elements[--size]; } private void ensureCapacity() { if(elements.length == size) { elements = Arrays.copyOf(elements, 2 * size + 1); } } }
上面的代碼實(shí)現(xiàn)了一個(gè)棧(先進(jìn)后出(FILO))結(jié)構(gòu),乍看之下似乎沒有什么明顯的問題,它甚至可以通過你編寫的各種單元測(cè)試。然而其中的pop方法卻存在內(nèi)存泄露的問題,當(dāng)我們用pop方法彈出棧中的對(duì)象時(shí),該對(duì)象不會(huì)被當(dāng)作垃圾回收,即使使用棧的程序不再引用這些對(duì)象,因?yàn)闂?nèi)部維護(hù)著對(duì)這些對(duì)象的過期引用(obsolete reference)。在支持垃圾回收的語言中,內(nèi)存泄露是很隱蔽的,這種內(nèi)存泄露其實(shí)就是無意識(shí)的對(duì)象保持。如果一個(gè)對(duì)象引用被無意識(shí)的保留起來了,那么垃圾回收器不會(huì)處理這個(gè)對(duì)象,也不會(huì)處理該對(duì)象引用的其他對(duì)象,即使這樣的對(duì)象只有少數(shù)幾個(gè),也可能會(huì)導(dǎo)致很多的對(duì)象被排除在垃圾回收之外,從而對(duì)性能造成重大影響,極端情況下會(huì)引發(fā)Disk Paging(物理內(nèi)存與硬盤的虛擬內(nèi)存交換數(shù)據(jù)),甚至造成OutOfMemoryError。?
答:GC是垃圾收集的意思,內(nèi)存處理是編程人員容易出現(xiàn)問題的地方,忘記或者錯(cuò)誤的內(nèi)存回收會(huì)導(dǎo)致程序或系統(tǒng)的不穩(wěn)定甚至崩潰,Java提供的GC功能可以自動(dòng)監(jiān)測(cè)對(duì)象是否超過作用域從而達(dá)到自動(dòng)回收內(nèi)存的目的,Java語言沒有提供釋放已分配內(nèi)存的顯示操作方法。Java程序員不用擔(dān)心內(nèi)存管理,因?yàn)槔占鲿?huì)自動(dòng)進(jìn)行管理。要請(qǐng)求垃圾收集,可以調(diào)用下面的方法之一:System.gc() 或Runtime.getRuntime().gc() ,但JVM可以屏蔽掉顯示的垃圾回收調(diào)用。
垃圾回收可以有效的防止內(nèi)存泄露,有效的使用可以使用的內(nèi)存。垃圾回收器通常是作為一個(gè)單獨(dú)的低優(yōu)先級(jí)的線程運(yùn)行,不可預(yù)知的情況下對(duì)內(nèi)存堆中已經(jīng)死亡的或者長(zhǎng)時(shí)間沒有使用的對(duì)象進(jìn)行清除和回收,程序員不能實(shí)時(shí)的調(diào)用垃圾回收器對(duì)某個(gè)對(duì)象或所有對(duì)象進(jìn)行垃圾回收。在Java誕生初期,垃圾回收是Java最大的亮點(diǎn)之一,因?yàn)榉?wù)器端的編程需要有效的防止內(nèi)存泄露問題,然而時(shí)過境遷,如今Java的垃圾回收機(jī)制已經(jīng)成為被詬病的東西。移動(dòng)智能終端用戶通常覺得iOS的系統(tǒng)比Android系統(tǒng)有更好的用戶體驗(yàn),其中一個(gè)深層次的原因就在于Android系統(tǒng)中垃圾回收的不可預(yù)知性。
補(bǔ)充:垃圾回收機(jī)制有很多種,包括:分代復(fù)制垃圾回收、標(biāo)記垃圾回收、增量垃圾回收等方式。標(biāo)準(zhǔn)的Java進(jìn)程既有棧又有堆。棧保存了原始型局部變量,堆保存了要?jiǎng)?chuàng)建的對(duì)象。Java平臺(tái)對(duì)堆內(nèi)存回收和再利用的基本算法被稱為標(biāo)記和清除,但是Java對(duì)其進(jìn)行了改進(jìn),采用“分代式垃圾收集”。這種方法會(huì)跟Java對(duì)象的生命周期將堆內(nèi)存劃分為不同的區(qū)域,在垃圾收集過程中,可能會(huì)將對(duì)象移動(dòng)到不同區(qū)域:
伊甸園(Eden):這是對(duì)象最初誕生的區(qū)域,并且對(duì)大多數(shù)對(duì)象來說,這里是它們唯一存在過的區(qū)域。
幸存者樂園(Survivor):從伊甸園幸存下來的對(duì)象會(huì)被挪到這里。
終身頤養(yǎng)園(Tenured):這是足夠老的幸存對(duì)象的歸宿。年輕代收集(Minor-GC)過程是不會(huì)觸及這個(gè)地方的。當(dāng)年輕代收集不能把對(duì)象放進(jìn)終身頤養(yǎng)園時(shí),就會(huì)觸發(fā)一次完全收集(Major-GC),這里可能還會(huì)牽扯到壓縮,以便為大對(duì)象騰出足夠的空間。
與垃圾回收相關(guān)的JVM參數(shù):
-Xms / -Xmx --- 堆的初始大小 / 堆的最大大小
-Xmn --- 堆中年輕代的大小
-XX:-DisableExplicitGC --- 讓System.gc()不產(chǎn)生任何作用
-XX:+PrintGCDetail --- 打印GC的細(xì)節(jié)
-XX:+PrintGCDateStamps --- 打印GC操作的時(shí)間戳?
Linux操作
答:linux指令
arch 顯示機(jī)器的處理器架構(gòu)(1)
uname -m 顯示機(jī)器的處理器架構(gòu)(2)
shutdown -h now 關(guān)閉系統(tǒng)(1)
shutdown -r now 重啟(1)
cd /home 進(jìn)入 '/ home' 目錄'
cd .. 返回上一級(jí)目錄
cd ../.. 返回上兩級(jí)目錄
mkdir dir1 創(chuàng)建一個(gè)叫做 'dir1' 的目錄'
mkdir dir1 dir2 同時(shí)創(chuàng)建兩個(gè)目錄
find / -name file1 從 '/' 開始進(jìn)入根文件系統(tǒng)搜索文件和目錄
find / -user user1 搜索屬于用戶 'user1' 的文件和目錄
linuxtomcat啟動(dòng)
進(jìn)入tomcat下的bin目錄執(zhí)行 ./catalina.sh start直接啟動(dòng)即可,然后使用tail -f /usr/local/tomcat6/logs/catalina.out查看tomcat啟動(dòng)日志。
A. | Mic |
B. | mid |
C. | mitegistry |
D. | policytool |
答案:A
|
A. | kill |
B. | tar |
C. | rsyne |
D. | policytool |
答案:c
分析:
A:kill命令,常用于殺死進(jìn)程;
B:tar命令,tar命令是Unix/Linux系統(tǒng)中備份文件的可靠方法,幾乎可以工作于任何環(huán)境中,它的使用權(quán)限是所有用戶
C:類unix系統(tǒng)下的數(shù)據(jù)鏡像備份工具
D:在終端下輸入lsof即可顯示系統(tǒng)打開的文件,因?yàn)?lsof 需要訪問核心內(nèi)存和各種文件,所以必須以 root 用戶的身份運(yùn)行它才能夠充分地發(fā)揮其功能
|
A. | 傳輸控制協(xié)議 |
B. | 用戶數(shù)據(jù)報(bào)協(xié)議 |
C. | 網(wǎng)際協(xié)議 |
D. | 網(wǎng)際控制報(bào)文協(xié)議 |
答案:A
|
A. | defaults |
B. | sw |
C. | rw 和 ro |
D. | noauto |
答案:D
|
A. | 文件類型 |
B. | 文件所有者的權(quán)限 |
C. | 文件所有者所在組的權(quán)限 |
D. | 其他用戶的權(quán)限 |
答案:C
|
A. | kill |
B. | < CTRL >;+C |
C. | shut down |
D. | halt |
答案:B
|
A. | -m |
B. | -d |
C. | -d |
D. | -p |
答案:D
|
A. | i 節(jié)點(diǎn)和文件是一一對(duì)應(yīng)的(每個(gè)文件都有唯一一個(gè)索引結(jié)點(diǎn)號(hào)與之對(duì)應(yīng),而對(duì)于一個(gè)索引結(jié)點(diǎn)號(hào),卻可以有多個(gè)文件名與之對(duì)應(yīng)) |
B. | i 節(jié)點(diǎn)能描述文件占用的塊數(shù) |
C. | i 節(jié)點(diǎn)描述了文件大小和指向數(shù)據(jù)塊的指針 |
D. | 通過i 節(jié)點(diǎn)實(shí)現(xiàn)文件的邏輯結(jié)構(gòu)和物理結(jié)構(gòu)的轉(zhuǎn)換 |
答案:A
|
A. | tar |
B. | gzip |
C. | compress |
D. | uncompress |
答案:D
|
A. | csh |
B. | tcsh |
C. | awk |
D. | sed |
答案:C
|
A. | 配置域名服務(wù)器 |
B. | 定義一條本機(jī)指向所在網(wǎng)絡(luò)的路由 |
C. | 定義一條本機(jī)指向所在網(wǎng)絡(luò)網(wǎng)關(guān)的路由 |
D. | 定義一條本機(jī)指向目標(biāo)網(wǎng)絡(luò)網(wǎng)關(guān)的路由 |
答案:C
|
A. | /etc/hosts |
B. | /etc/HOSTNAME |
C. | /etc/resolv.conf |
D. | /etc/gateways |
答案:D
|
A. | route add –net 192.168.1.0 gw 192.168.1.1 netmask 255.255.255.0 metric 1 |
B. | route add –net 172.16.1.0 gw 192.168.1.1 netmask 255.255.255.0 metric 1 |
C. | route add –net 172.16.1.0 gw 172.16.1.1 netmask 255.255.255.0 metric 1 |
D. | route add default 192.168.1.0 netmask 172.168.1.1 metric 1 |
答案:B
|
A. | 配置本地回環(huán)地址 |
B. | 配置網(wǎng)卡的IP地址 |
C. | 激活網(wǎng)絡(luò)適配器 |
D. | 加載網(wǎng)卡到內(nèi)核中 |
答案:D
|
A. | 硬鏈接就是讓鏈接文件的i 節(jié)點(diǎn)號(hào)指向被鏈接文件的i 節(jié)點(diǎn) |
B. | 硬鏈接和符號(hào)連接都是產(chǎn)生一個(gè)新的i 節(jié)點(diǎn) |
C | 鏈接分為硬鏈接和符號(hào)鏈接 |
D. | 硬連接不能鏈接目錄文件 |
答案:B
|
A. | 主機(jī)IP設(shè)置有誤 |
B. | 沒有設(shè)置連接局域網(wǎng)的網(wǎng)關(guān) |
C. | 局域網(wǎng)的網(wǎng)關(guān)或主機(jī)的網(wǎng)關(guān)設(shè)置有誤 |
D. | 局域網(wǎng)DNS服務(wù)器設(shè)置有誤 |
答案:C
|
A. | /etc/HOSTNAME |
B. | /etc/hosts |
C. | /etc/resolv.conf |
D. | /etc/networks |
答案:B
|
A. | 刪除系統(tǒng)不用的設(shè)備驅(qū)動(dòng)程序時(shí) |
B. | 升級(jí)內(nèi)核時(shí) |
C. | 添加新硬件時(shí) |
D. | 將網(wǎng)卡激活 |
答案:D
|
A. | 直接賦值 |
B. | 使用read命令 |
C. | 使用命令行參數(shù) |
D. | 使用命令的輸出 |
答案:A
|
A. | cp |
B. | dd |
C. | fmt |
D. | cut |
答案:D
|
A. | 交互進(jìn)程 |
B. | 批處理進(jìn)程 |
C. | 守護(hù)進(jìn)程 |
D. | 就緒進(jìn)程 |
答案:D
|
A. | CPU 已滿負(fù)荷地運(yùn)轉(zhuǎn) |
B. | CPU 的運(yùn)行效率為30% |
C. | CPU 的運(yùn)行效率為50% |
D. | CPU 的運(yùn)行效率為80% |
答案:A
|
A. | 64MB |
B. | 128MB |
C. | 256MB |
D. | 512MB |
答案:C
|
A. | full |
B. | expert |
C. | newbie |
D. | menu |
答案:D
|
A. | cat |
B. | more |
C. | less |
D. | menu |
答案:C
|
A. | root 1 4.0 0.0 344 204? S 17:09 0:00 init |
B. | root 2 0.0 0.1 2916 1520? S 17:09 0:00 /sbin/getty |
C. | root 3 0.0 0.2 1364 632? S 17:09 0:00 /usr/sbin/syslogd |
D. | root 4 0.0 1344 1204? S 17:09 0:10 /usr/sbin/inetd |
答案:D
|
A. | telnet |
B. | FTP |
C. | SNMP |
D. | NFS |
答案:B
|
A. | ping |
B. | ifconfig |
C. | traceroute |
D. | netstat |
答案:C
|
A. | -rwxr-xr-x |
B. | -rwxr--r-- |
C. | -r--r--r-- |
D. | -r-xr-x—x |
答案:C
|
A. | -rw-rw-rw- 2 hel-s users 56 Sep 09 11:05 hello |
B. | -rwxrwxrwx 2 hel-s users 56 Sep 09 11:05 goodbey |
C. | drwxr--r-- 1 hel users 1024 Sep 10 08:10 zhang |
D. | lrwxr--r-- 1 hel users 2024 Sep 12 08:12 cheng |
答案:D
|
A. | IP地址 |
B. | MAC地址 |
C. | 網(wǎng)絡(luò)地址 |
D. | 主機(jī)別名 |
答案:A
|
A. | 服務(wù)器/工作站 |
B. | B/S |
C. | 集中式 |
D. | 分布式 |
答案:B
|
A. | less |
B. | mesg |
C. | write |
D. | echo to |
答案:C
|
A. | 文件 |
B. | 磁盤 |
C. | 網(wǎng)絡(luò)文件 |
D. | 操作 |
答案:C
|
A. | cp |
B. | tr |
C. | dir |
D. | cpio |
答案:D
|
A. | /bin |
B. | /etc |
C. | /dev |
D. | /lib |
答案:C
|
A. | # reboot |
B. | # halt |
C. | # reboot |
D. | # shutdown –r now |
答案:D
|
A. | 故障管理 |
B. | 日常備份管理 |
C. | 升級(jí)管理 |
D. | 發(fā)送 |
答案:A
|
A. | Ctrl+Alt+Del |
B. | halt |
C. | shutdown -r now |
D. | reboot |
答案:B
|
A. | ping |
B. | ifconfig |
C. | arp |
D. | traceroute |
答案:C
|
A. | < a>; |
B. | < o>; |
C. | < I>; |
D. | A |
答案:B
|
A. | < x>; |
B. | < d>;< w>; |
C. | < D>; |
D. | < d>;< d>; |
答案:A
|
A. | 上箭頭 |
B. | 下箭頭 |
C. | < .>; |
D. | < *>; |
答案:C
|
A. | mkdir |
B. | rmdir |
C. | mv |
D. | traceroute |
答案:D
|
A. | < Esc>; |
B. | ^q |
C. | exit |
D. | quit__ |
答案:C
|
算法分析及手寫代碼
寫出合格的身份證的正則表達(dá)式,
^(\d{15}|\d{17}[\dx])$
寫程序提取身份證中的年月日
public class IdCard { private String idCard;//私有變量 public IdCard(){}//構(gòu)造方法 //構(gòu)造方法 public IdCard(String idCard){ this.idCard=idCard; } public void setIdCard(String idCard) { this.idCard=idCard; } public String getIdCard() { return idCard; } //從身份證號(hào)碼中截取生日 public String getBirthday() { return this.getIdCard().substring(6, 14); } public static void main(String args[]) { ShenFenZheng sfz = new ShenFenZheng("420154199908157841"); //調(diào)用getBirthday()方法獲取生日 System.out.println("生日:" + sfz.getBirthday()); } }
package com.bjsxt; import java.util.ArrayList; import java.util.List; public class FirstRepeat { public static void main(String[] args) { System.out.println(findFirstRepeat("pmedmitjtckhxwhvpwemznhmhzhpueainchqrftkmbjlradhmjekcqzansyzkvqhwnrdgzdbzewdmxkzrscikdaugbvygntrifnolehdtrqjlasofuvzeijbmzehkxknmjekcxswqldknysfsxrqaqzp",152)); } //返回:y public static char findFirstRepeat(String A, int n) { String[] str=A.split(""); for(int x=0;x<n;x++){ int index=0; int num=0; //對(duì)于每一個(gè)值,都需要從前開始遍歷 while(index<=x){ if(str[index].equals(str[x])){ num++; } index++; } //該值出現(xiàn)了兩次,說明重復(fù)了 if(num>1){ char flag='x'; flag=str[x].toCharArray()[0]; return flag; } } //返回該值說明已經(jīng)沒有重復(fù)的 return 'p'; } }
public class test { public static void main(String[] args) { int [] arr1 = {10,20,30,40,50}; int [] arr2 = CopyArray(arr1); System.out.println(Arrays.toString(arr2)); } private static int[] CopyArray(int[] arr) { int [] arr2 = new int[arr.length]; for (int i = 0; i < arr.length; i++) { arr2[i] = arr[i]; } return null; } }
package cn.bjsxt.demo; import java.util.Scanner; public class SortDemo { /** * 給定的字符串使用,號(hào)分隔 * @param strNumber * @return */ public static String [] split(String strNumber){ String [] strSplit=strNumber.split(","); return strSplit; } /** * 將String類型的數(shù)組轉(zhuǎn)換成int類型的數(shù)組 * @param strSplit * @return */ public static int [] getInt(String [] strSplit){ int arr[]=new int[strSplit.length]; for (int i = 0; i < strSplit.length; i++) { arr[i]=Integer.parseInt(strSplit[i]); } return arr; } /** * 冒泡排序 * @param arr */ public static void sort(int [] arr){ for (int i = 0; i < arr.length-1; i++) { for (int j = 0; j < arr.length-1-i; j++) { if (arr[j]>arr[j+1]) { change(arr,j,j+1); } } } } /** * 兩數(shù)交換的方法 * @param arr 數(shù)組 * @param x 數(shù)組中元素的下標(biāo) * @param y 數(shù)組中元素的下標(biāo) */ public static void change(int [] arr,int x,int y){ int temp=arr[x]; arr[x]=arr[y]; arr[y]=temp; } /** * 測(cè)試類 * @param args */ public static void main(String[] args) { Scanner input=new Scanner(System.in); System.out.println("請(qǐng)輸入一個(gè)數(shù)字串,每個(gè)數(shù)字以逗號(hào)分隔"); String str=input.next(); //調(diào)用方法 String [] s=split(str);//使用逗號(hào)分隔 int [] arr=getInt(s);//調(diào)有獲得整型數(shù)組的方法 sort(arr);//調(diào)用排序的方法 for (int i : arr) { System.out.print(i+"\t"); } } }
package cn.bjsxt.demo; import java.util.Scanner; public class StringDemo { public static void main(String[] args) { Scanner input=new Scanner(System.in); System.out.println("請(qǐng)輸入一個(gè)字符串,第一個(gè)字符必須是字母:"); String str=input.next(); if (str.length()<5||str.length()>20) { System.out.println("對(duì)不起,字符串的長(zhǎng)度必須在5-20之間!"); }else{ char []ch=str.toCharArray(); if (Character.isLetter(ch[0])) {//判斷第一個(gè)字符是否是字母 for (int i = 1; i < ch.length; i++) { if (!Character.isLetterOrDigit(ch[i])&&ch[i]!='_') { System.out.println("字符串不符合要求"); break; } } } } } }
思路說明:循環(huán)遞增數(shù)組有這么一個(gè)性質(zhì):以數(shù)組中間元素將循環(huán)遞增數(shù)組劃分為兩部分,則一部分為一個(gè)嚴(yán)格遞增數(shù)組,而另一部分為一個(gè)更小的循環(huán)遞增數(shù)組。當(dāng)中間元素大于首元素時(shí),前半部分為嚴(yán)格遞增數(shù)組,后半部分為循環(huán)遞增數(shù)組;當(dāng)中間元素小于首元素時(shí),前半部分為循環(huán)遞增數(shù)組;后半部分為嚴(yán)格遞增數(shù)組。
記要檢索的元素為e,數(shù)組的首元素為a[low],中間元素為a[mid],末尾元素為a[high]。則當(dāng)e等于a[mid] 時(shí),直接返回mid的值即可;當(dāng)e不等于a[mid] 時(shí):
1) a[mid] > a[low],即數(shù)組前半部分為嚴(yán)格遞增數(shù)組,后半部分為循環(huán)遞增數(shù)組時(shí),若key小于a[mid]并且不小于a[low]時(shí),則key落在數(shù)組前半部分;否則,key落在數(shù)組后半部分。
2) a[mid] < a[high],即數(shù)組前半部分為循環(huán)遞增數(shù)組,后半部分為嚴(yán)格遞增數(shù)組時(shí),若key大于a[mid]并且不大于a[high]時(shí),則key落在數(shù)組后半部分;否則,key落在數(shù)組前半部分。
這種方式的時(shí)間復(fù)雜度為:O(log(n)),空間復(fù)雜度為O(1)。
public class TestBinarySearch { public static void main(String[] args) { // 定義數(shù)組 int[] a = { 17, 19, 20, 21, 25, 1, 4, 7 }; // 調(diào)用改進(jìn)后的二分查找法求索引 int pos = search(a, 7); System.out.println("要查找的元素的索引為:" + pos); } /** 改進(jìn)后的二分查找法:e為要查找的元素 */ public static int search(int[] a, int e) { int low = 0; int high = a.length - 1; int mid = 0; int pos = -1; // 返回-1,表示查找失敗 // 如果low < high,說明循環(huán)查找結(jié)束,直接返回-1;否則循環(huán)查找 while (low <= high) { // mid為中間值索引 mid = (low + high) / 2; // 如果中間值剛好是e,則查找成功,終止查找,e的索引為mid if (a[mid] == e) { pos = mid; break; } // 如果a[low] <= a[mid],說明原數(shù)組的前半部分是嚴(yán)格遞增的,后半部分是一個(gè)更小的循環(huán)遞增數(shù)組 if (a[low] <= a[mid]) { // 如果要查找的元素e小于a[mid]并且不小于a[low]時(shí),則說明e落在數(shù)組前半部分 if (a[low] <= e && e < a[mid]) { high = mid - 1; } else {// 否則的話,需要在數(shù)組的后半部分繼續(xù)查找 low = mid + 1; } } else {// 否則,后半部分是嚴(yán)格遞增的,前半部分是一個(gè)更小的循環(huán)遞增數(shù)組 // 如果要查找的元素e大于a[mid]并且不大于a[high]時(shí),則說明e落在數(shù)組后半部分 if (a[mid] < e && e <= a[high]) { low = mid + 1; } else {// 否則的話,需要在數(shù)組的前半部分繼續(xù)查找 high = mid - 1; } } } return pos; } }
思路說明:因?yàn)閚! = (n-1)! * n,所以要求n!首先要求出(n-1)!,而(n-1)! = (n-1-1)! * (n-1),以此類推,直到n = 1為止。
import java.util.Scanner; public class TestFactorial { public static void main(String[] args) { System.out.print("請(qǐng)輸入一個(gè)整數(shù):"); Scanner sc = new Scanner(System.in); int n = sc.nextInt(); System.out.println(n + "的階乘是:" + factorial(n)); } /**求階乘的方法*/ public static int factorial(int n) { if(n == 1){ return 1; } return factorial(n - 1) * n; } }
思路說明:斐波那契數(shù)列的排列是:0,1,1,2,3,5,8,13,21,34,55,89,144……,特別指出的是0不是第一項(xiàng)而是第0項(xiàng);因?yàn)镕(n)=F(n-1)+F(n-2),所以要求F(n)首先要求出F(n-1)和F(n-2),而F(n-1)=F(n-1-1)+F(n-1-2),以此類推,直到,F(2)=F(1)+F(0)為止,已知F(1) = 1,F(xiàn)(0) = 0。
import java.util.Scanner; public class TestFibo { public static void main(String[] args) { System.out.print("請(qǐng)輸要求斐波那契數(shù)列的第幾項(xiàng):"); Scanner sc = new Scanner(System.in); int n = sc.nextInt(); System.out.println("斐波那契數(shù)列的第"+ n + "是:" + fibo(n)); } public static int fibo(int n) { if(n == 0){ return 0; } else if(n == 1){ return 1; } return fibo(n -1) + fibo(n - 2); } }
冒泡思路說明:
(1) 最開始將數(shù)組看做一個(gè)無序數(shù)列(個(gè)數(shù)是數(shù)組的長(zhǎng)度)與一個(gè)有序數(shù)列(0個(gè))的組合;
(2) 每一趟比較完后, 找到了無序數(shù)列的最大值, 將其放到有序數(shù)列中(有序數(shù)列個(gè)數(shù)+1);
(3) N個(gè)數(shù), 比較N-1趟;
(4) 每一趟挨個(gè)進(jìn)行比較:從數(shù)組的第一個(gè)元素開始, 到無序數(shù)列的最后一個(gè)為止;
(5) 如果前邊一個(gè)大于后邊一個(gè), 那么交換位置;
(6) 每趟比較的次數(shù)與趟數(shù)有關(guān);
(7) 根據(jù)每趟比較是否發(fā)生了交換判斷數(shù)據(jù)是否已經(jīng)有序,從而進(jìn)行優(yōu)化。
public class TestSort { public static void main(String[] args) { int[] arr = {11, 66, 22, 0, 55, 32}; // 調(diào)用排序方法 sort(arr); // 輸出排除后的數(shù)組 for (int num : arr) { System.out.print(num + "\t"); } } public static void sort(int[] arr) { // 定義標(biāo)記 boolean flag = false; int temp; // 排序 // 外層循環(huán)控制的是比較的趟數(shù) for (int i = 0; i < arr.length - 1; i++) { // 每一趟比較之前初始化, 否則會(huì)保留上一堂比較的結(jié)果 flag = false; // 內(nèi)層循環(huán)控制的是每趟比較的次數(shù) for (int j = 0; j < arr.length - 1 - i; j++) { // 挨個(gè)進(jìn)行比較: 從數(shù)組的第一個(gè)元素開始, 到無序數(shù)列的最后一個(gè) if (arr[j] > arr[j + 1]) { // 交換 temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; //如果發(fā)生交換,改變flag的值 flag = true; } } if (!flag) { break; } } } }
// 這個(gè)類用于存取一組權(quán)限,每個(gè)權(quán)限用非負(fù)整數(shù)表示的.這組枳限存儲(chǔ)在 // righiString屬性中。如果權(quán)限N權(quán)限存在,rightString第N個(gè)字符為“1”,否則, 為空格。 class RightStore { public String righString = ""; // 如果傳入的權(quán)限r(nóng)ight存在,該方法返回true.否期,為false., // right為傳入的權(quán)限的整數(shù)值. public boolean getRight(int right) { return true; } // 該方法存儲(chǔ)或消除傳入的權(quán)限.如果value為true,存儲(chǔ)傳入的權(quán)限, // 否則淸除該權(quán)限. // right為傳入的權(quán)限的整數(shù)值. public void setRight(int right, boolean value) { } }
思路說明:我們首先要讀懂這道題的意思:righString這個(gè)字符串是用來存儲(chǔ)一系列權(quán)限的,并且權(quán)限的取值只有兩種:有和沒有;在righString中使用字符‘1’表示有權(quán)限,字符空格‘ ’表示沒有權(quán)限。舉個(gè)例子:如果righString的長(zhǎng)度為3,第一位表示對(duì)訂單系統(tǒng)是否有權(quán)限,第二位表示對(duì)人員管理系統(tǒng)是否有權(quán)限,第三位表示對(duì)庫(kù)存系統(tǒng)是否有權(quán)限。而方法中的int right參數(shù)則表示的是字符串的第幾位。
上邊這些搞明白之后,方法的編寫就簡(jiǎn)單多了。
public class RightStore { public String righString = ""; public boolean getRight(int right) { //先求得第right個(gè)字符 char ch = righString.charAt(right - 1); //如果ch為'1',返回true,否則返回false return ch == '1'; } public void setRight(int right, boolean value) { //如果value為true,存儲(chǔ)傳入的權(quán)限,否則消除權(quán)限(改為空格) righString.replace(righString.charAt(right - 1), value ? '1' : ' '); } }
思路說明:假設(shè)在一個(gè)已經(jīng)排好序的有序序列(N個(gè)元素,升序排列),首先讓序列中的中間的元素與需要查找的關(guān)鍵字進(jìn)行比較,如果相等,則查找成功,否則利用中間位置將序列分成兩個(gè)子序列,如果待查找的關(guān)鍵字小于中間的元素,則在前一個(gè)子序列中同樣的方法進(jìn)一步查找,如果待查找的關(guān)鍵字大于中間的元素,則在后一個(gè)子序列中同樣的方法進(jìn)一步查找,重復(fù)以上過程一直到查找結(jié)束!
import java.util.Scanner; public class TestBinarySearchRecursion { public static void main(String[] args) { int[] a = { 1, 3, 5, 7, 9, 11, 13 }; System.out.print("請(qǐng)輸入要查找的元素:"); int e = new Scanner(System.in).nextInt(); int index = binarySearch(a, 0, a.length - 1, e); System.out.println(index != -1 ? "元素索引為" + index : "沒有該元素"); } private static int binarySearch(int[] a, int low, int high, int e) { int mid = 0; if (low <= high) { mid = (low + high) / 2; if (a[mid] == e) { return mid; } else if (a[mid] > e) { return binarySearch(a, low, mid - 1, e); } else { return binarySearch(a, mid + 1, high, e); } } return -1; } }
函數(shù)形如:
public static String reverseWords(String input) { String str = ""; return str; }
思路說明:將字符串轉(zhuǎn)化成字符數(shù)組,然后根據(jù)數(shù)組中空格的位置判斷每個(gè)單詞所占的索引范圍,根據(jù)得到的索引將數(shù)組中的每個(gè)單詞逆序后拼接到新的字符串中。
public class TestStringReverse{ public static void main(String[] args) { String input = "There is a dog"; System.out.println("逆轉(zhuǎn)后的字符串為:" + reverseWords(input)); } public static String reverseWords(String input) { String str = ""; //將字符串轉(zhuǎn)化成字符數(shù)組 char[] arr = input.toCharArray(); //index用來記錄每個(gè)單詞的起始索引 int index = 0; //遍歷字符數(shù)組,將空格前邊的單詞挨個(gè)拼接到str中 for (int i = 0; i < arr.length; i++) { if(arr[i] == ' '){ //根據(jù)空格的位置將空格前邊一個(gè)單詞密續(xù)追加到str中 for(int j = i - 1; j >= index; j--){ str += arr[j]; } //單詞拼接完成后,拼接一個(gè)空格 str += ' '; //讓index指向下一個(gè)單詞的起始位置 index = i + 1; } } //將最后一個(gè)單詞拼接上 for(int i = arr.length - 1; i >= index; i--){ str += arr[i]; } return str; } }
9x9乘法表:
class Demo { public static void main(String[] args) { for(int x = 0;x <= 9; x++) { for(int y = 1;y <= x; y++) { System.out.print(y+"*"+x+"="+x*y+"\t"); } System.out.println(); } } }
冒泡排序:
public class BubbleSort{ public static void main(String[] args){ int score[] = {67, 69, 75, 87, 89, 90, 99, 100}; for (int i = 0; i < score.length -1; i++){//最多做n-1趟排序 for(int j = 0 ;j < score.length - i - 1; j++){//對(duì)當(dāng)前無序區(qū)間score[0......length-i-1]進(jìn)行排序(j的范圍很關(guān)鍵,這個(gè)范圍是在逐步縮小的) if(score[j] < score[j + 1]){ //把小的值交換到后面 int temp = score[j]; score[j] = score[j + 1]; score[j + 1] = temp; } } System.out.print("第" + (i + 1) + "次排序結(jié)果:"); for(int a = 0; a < score.length; a++){ System.out.print(score[a] + "\t"); } System.out.println(""); } System.out.print("最終排序結(jié)果:"); for(int a = 0; a < score.length; a++){ System.out.print(score[a] + "\t"); } } }
public class Solution { public boolean containsDuplicate(int[] nums) { Set<Integer> numSet = new HashSet<Integer>(); for(int i=0;i<nums.length;i++){· if(numSet.contains(nums[i])) return true; else numSet.add(nums[i]); } return false; } }
public void moveZeroes(int[] nums) { int size = nums.length; int startIndex = 0; // 0元素開始的位置 int endIndex = 0; // 0元素結(jié)束的位置 int currentNum; int i= 0; // 第一步:找到第一個(gè)0元素開始的位置 // 并將第一個(gè)0元素的游標(biāo)賦值給startIndex&endIndex while(i < size){ currentNum = nums[i]; if (currentNum == 0) { startIndex = i; endIndex = i; break; } ++i; } // 如果當(dāng)前數(shù)組中沒有找到0元素,則推出 if (nums[endIndex] != 0) return; // 將當(dāng)前i的值加1;直接從剛才0元素位置的后一位置開始循環(huán) ++i; while (i < size) { currentNum = nums[i]; if (currentNum == 0){//如果當(dāng)前元素等于0,則將i值賦值給endIndex endIndex = i; } else { // 如果不為0 //則將當(dāng)前元素賦值給nums[startIndex] // 并將當(dāng)前位置的元素賦值為0 // startIndex和endIndex都加1; nums[startIndex] = currentNum; nums[i] = 0; ++startIndex; ++endIndex; } ++i; } }
public class Solution { public List<Integer> preorderTraversal(TreeNode root) { List<Integer> result = new ArrayList<Integer>(); if(root == null) return result; Stack<TreeNode> stack = new Stack<TreeNode>(); stack.push(root); while(!stack.isEmpty()) { TreeNode node = stack.pop(); result.add(node.val); if(node.right != null) stack.push(node.right); if(node.left != null) stack.push(node.left); } return result; } }
public class Solution { private static int lastVisit = Integer.MIN_VALUE; public boolean isValidBST(TreeNode root) { if(root == null) return true; boolean judgeLeft = isValidBST(root.left); // 先判斷左子樹 if(root.data >= lastVisit && judgeLeft) { // 當(dāng)前節(jié)點(diǎn)比上次訪問的數(shù)值要大 lastVisit = root.data; } else { return false; } boolean judgeRight = isValidBST(root.right); // 后判斷右子樹 return judgeRight; } }
題目: 寫一個(gè)函數(shù)用于在一個(gè)單向鏈表中刪除一個(gè)節(jié)點(diǎn)(?非尾節(jié)點(diǎn)),前提是僅僅能夠訪問要?jiǎng)h除的那個(gè)節(jié)點(diǎn)。
比如給定鏈表1 -> 3 -> 5 -> 7 -> 9 -> 16,給定你值為3的那個(gè)節(jié)點(diǎn), 調(diào)?用你的函數(shù)后,鏈表變?yōu)?/p>
1 -> 5 -> 7 -> 9 -> 16。
/** Definition for singly-linked list. public class ListNode { int val; ListNode next; ListNode(int x) { val = x; } * } */ public class Solution { public void deleteNode(ListNode node) { if(node==null||node.next==null) { System.out.println("節(jié)點(diǎn)不存在或者是尾節(jié)點(diǎn)"); }else{ node.val=node.next.val; node.next=node.next.next; } } }
/** Definition for a binary tree node. public class TreeNode { int val; TreeNode left; TreeNode right; TreeNode(int x) { val = x; } * } */ public class Solution2 { public int kthSmallest(TreeNode root, int k) { Stack<TreeNode> store = new Stack<TreeNode>(); if (root == null) { return -1; } store.push(root); while (root.left != null) { store.push(root.left); root = root.left; } while (!store.empty()) { TreeNode cur = store.pop(); k--; if (k == 0) { return cur.val; } if (cur.right != null) { root = cur.right;// let cur.right be the current node store.push(root); while (root.left != null) { store.push(root.left); root = root.left; } } } return -1; } }
比如,
S = [-1, 0, 1, 2, -1, -4],,
結(jié)果集為: [
[-1, 0, 1],
[-1, -1, 2]
]
/** * 給定一個(gè)n個(gè)元素的數(shù)組,是否存在a,b,c三個(gè)元素,使用得a+b+c=0,找出所有符合這個(gè)條件的三元組 * 注意: - 三元組中的元素必須是非遞減的 - 結(jié)果不能包含重復(fù)元素 */ public class Solution { public static void main(String[] args) { int[] S = {-1, 0, 1, 2, -1, -4,-3,-4,4,3}; new Solution().get3Sum(S); } public Set<String> get3Sum(int[] S){ if(S.length<3 || S==null){ return null; } //接收拼接的字符串 StringBuffer sb = new StringBuffer(); for(int i=0; i<S.length; i++){ for(int j=0; j<S.length; j++){ for(int z=0; z<S.length; z++){ //篩選出不是遞減的一組元素 if(S[i]<=S[j] && S[j]<=S[z]){ int sum = S[i] + S[j] + S[z]; if(sum==0){ String str = "("+S[i]+","+S[j]+","+S[z]+")"; sb.append(str+";"); } } } } } String s = sb.toString(); s = s.substring(0, sb.length()-1); String[] arr = s.split(";"); Set<String> set = new HashSet<String>(); //將所篩選出來的元素放入Set集合中,去重 for (int k = 0; k < arr.length; k++) { set.add(arr[k]); } System.out.println(set); return set; } public List<List<Integer>> threeSum(int[] nums) { List<List<Integer>> result = new LinkedList<>(); if (nums != null && nums.length > 2) { // 先對(duì)數(shù)組進(jìn)行排序 Arrays.sort(nums); // i表示假設(shè)取第i個(gè)數(shù)作為結(jié)果 for (int i = 0; i < nums.length - 2; ) { // 第二個(gè)數(shù)可能的起始位置 int j = i + 1; // 第三個(gè)數(shù)可能是結(jié)束位置 int k = nums.length - 1; while (j < k) { // 如果找到滿足條件的解 if (nums[j] + nums[k] == -nums[i]) { // 將結(jié)果添加到結(jié)果含集中 List<Integer> list = new ArrayList<>(3); list.add(nums[i]); list.add(nums[j]); list.add(nums[k]); result.add(list); // 移動(dòng)到下一個(gè)位置,找下一組解 k--; j++; // 從左向右找第一個(gè)與之前處理的數(shù)不同的數(shù)的下標(biāo) while (j < k && nums[j] == nums[j - 1]) { j++; } // 從右向左找第一個(gè)與之前處理的數(shù)不同的數(shù)的下標(biāo) while (j < k && nums[k] == nums[k + 1]) { k--; } } // 和大于0 else if (nums[j] + nums[k] > -nums[i]) { k--; // 從右向左找第一個(gè)與之前處理的數(shù)不同的數(shù)的下標(biāo) while (j < k && nums[k] == nums[k + 1]) { k--; } } // 和小于0 else { j++; // 從左向右找第一個(gè)與之前處理的數(shù)不同的數(shù)的下標(biāo) while (j < k && nums[j] == nums[j - 1]) { j++; } } } // 指向下一個(gè)要處理的數(shù) i++; // 從左向右找第一個(gè)與之前處理的數(shù)不同的數(shù)的下標(biāo) while (i < nums.length - 2 && nums[i] == nums[i - 1]) { i++; } } } return result; } }
題目: 給定一個(gè)不包含相同元素的整數(shù)集合,nums,返回所有可能的子集集合。解答中集合不能包含重 復(fù)的子集。
比如,
nums = [1, 2, 3], ?一種解答為:
[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2], []
]
/** * 不重復(fù)集合求子集 解答采用的是深度優(yōu)先遍歷,先取原數(shù)組一個(gè)元素,再構(gòu)造包括這個(gè)元素的兩個(gè),三個(gè)……n個(gè)元素的集合。dfs中的start就指向這個(gè)元素的,它在不斷地后移(i+1)。 * @param S: A set of numbers. * @return: A list of lists. All valid subsets. */ public class Solution1 { public static void main(String[] args) { int[] first = new int[]{1, 2, 3}; ArrayList<ArrayList<Integer>> res = subsets(first); for(int i = 0; i < res.size(); i ++){ System.out.println(res.get(i)); } } public static ArrayList<ArrayList<Integer>> subsets(int[] nums) { ArrayList<ArrayList<Integer>> res = new ArrayList<ArrayList<Integer>>(); ArrayList<Integer> item = new ArrayList<Integer>(); if(nums.length == 0 || nums == null) return res; Arrays.sort(nums); //排序 dfs(nums, 0, item, res); //遞歸調(diào)用 res.add(new ArrayList<Integer>()); //最后加上一個(gè)空集 return res; } public static void dfs(int[] nums, int start, ArrayList<Integer>item, ArrayList<ArrayList<Integer>>res){ for(int i = start; i < nums.length; i ++){ item.add(nums[i]); //item是以整數(shù)為元素的動(dòng)態(tài)數(shù)組,而res是以數(shù)組為元素的數(shù)組,在這一步,當(dāng)item增加完元素后,item所有元素構(gòu)成一個(gè)完整的子串,再由res納入 res.add(new ArrayList<Integer>(item)); dfs(nums, i + 1, item, res); item.remove(item.size() - 1); } } }
比如, 給定二叉樹{1,#,2,3}, 返回 [1,2,3]
/** Definition for a binary tree node. public class TreeNode { int val; TreeNode left; TreeNode right; TreeNode(int x) { val = x; } * } */ public class Solution { List<Integer> result = new ArrayList<Integer>(); /** * 迭代實(shí)現(xiàn),維護(hù)一個(gè)棧,因?yàn)槿霔m樞虬凑崭易筮M(jìn)行入棧,因此首先將根出棧,然后出棧左子節(jié)點(diǎn), * 最后出棧右子節(jié)點(diǎn)。 * @param root * @return */ public List<Integer> preorderTraversal(TreeNode root) { if(root == null) return result; Stack<TreeNode> stack = new Stack<TreeNode>(); stack.push(root); while(!stack.isEmpty()) { TreeNode node = stack.pop(); result.add(node.val); if(node.right != null) stack.push(node.right); if(node.left != null) stack.push(node.left); } return result; } }
class TreeNode { int val; TreeNode left; TreeNode right; TreeNode(int x) { val = x; } } public class BSTChecker { private static int lastVisit = Integer.MIN_VALUE; public static boolean isBST(TreeNode root) { if(root == null) return true; boolean judgeLeft = isBST(root.left); // 先判斷左子樹 if(root.val >= lastVisit && judgeLeft) { // 當(dāng)前節(jié)點(diǎn)比上次訪問的數(shù)值要大 lastVisit = root.val; } else { return false; } boolean judgeRight = isBST(root.right); // 后判斷右子樹 return judgeRight; } }
參考地址:http://www.cnblogs.com/masterlibin/p/5785092.html
參考地址:沒有完全理解的
http://www.mamicode.com/info-detail-1087177.html
http://www.mamicode.com/info-detail-1087177.html
/** * 解題思路: * 比如給定一組數(shù)組,[1,2,3,6,9,3,10] * 最多可以2次去獲取最大的利益,可以用2分的思想,分成2部分, * 從0元素開始遍歷分別求出左右2邊的最大利益,求出的左右2邊最大的利益即為解 */ class Solution { public static int maxProfit(int[] prices) { // write your code here if(null==prices||0==prices.length) return 0; int sumProfit = 0; for(int i=1;i<prices.length;i++){ int tmpsum = maxProfit(prices, 0, i) + maxProfit(prices, i+1, prices.length-1); sumProfit = Math.max(sumProfit, tmpsum); } return sumProfit; } public static int maxProfit(int[] prices,int s,int e){ if(e<=s) return 0; int min = prices[s]; int maxProfit = 0; for(int i=s+1;i<=e;i++){ maxProfit = Math.max(maxProfit, prices[i]-min); min = Math.min(min, prices[i]); } return maxProfit; } public static void main(String[] args) { int arr [] = {4,4,6,1,1,4,2,5}; System.out.println(maxProfit(arr)); } }
public class Test8 { public static void main(String[] args) { //輸入n個(gè)整數(shù)和一個(gè)整數(shù) Scanner input = new Scanner(System.in); System.out.println("請(qǐng)輸入n個(gè)整數(shù),數(shù)量任意,以逗號(hào)分隔"); String str = input.next(); System.out.println("請(qǐng)輸入一個(gè)整數(shù):"); int x = input.nextInt(); //將n個(gè)整數(shù)的字符串轉(zhuǎn)換為數(shù)組 String arr1[] = str.split(","); int [] arr2 = new int[arr1.length]; for(int i=0;i<arr1.length;i++){ arr2[i] = Integer.parseInt(arr1[i]); } System.out.println(Arrays.toString(arr2)); //判斷并輸出n個(gè)整數(shù)中有幾對(duì)的和等于x int count = 0; for(int i=0;i<arr2.length-1;i++){ for(int j = i+1;j<arr2.length;j++){ if(arr2[i]+arr2[j]==x){ count++; } } } System.out.println(count); } }
快速排序由C. A. R. Hoare在1962年提出。它的基本思想是:通過一趟排序?qū)⒁判虻臄?shù)據(jù)分割成獨(dú)立的兩部分,其中一部分的所有數(shù)據(jù)都比另外一部分的所有數(shù)據(jù)都要小,然后再按此方法對(duì)這兩部分?jǐn)?shù)據(jù)分別進(jìn)行快速排序,整個(gè)排序過程可以遞歸進(jìn)行,以此達(dá)到整個(gè)數(shù)據(jù)變成有序序列。
設(shè)要排序的數(shù)組是A[0]……A[N-1],首先任意選取一個(gè)數(shù)據(jù)(通常選用數(shù)組的第一個(gè)數(shù))作為關(guān)鍵數(shù)據(jù),然后將所有比它小的數(shù)都放到它前面,所有比它大的數(shù)都放到它后面,這個(gè)過程稱為一趟快速排序。值得注意的是,快速排序不是一種穩(wěn)定的排序算法,也就是說,多個(gè)相同的值的相對(duì)位置也許會(huì)在算法結(jié)束時(shí)產(chǎn)生變動(dòng)。
一趟快速排序的算法是:
1、設(shè)置兩個(gè)變量i、j,排序開始的時(shí)候:i=0,j=N-1;
2、以第一個(gè)數(shù)組元素作為關(guān)鍵數(shù)據(jù),賦值給key,即key=A[0];
3、從j開始向前搜索,即由后開始向前搜索(j--),找到第一個(gè)小于key的值A(chǔ)[j],將A[j]和A[i]互換;
4、從i開始向后搜索,即由前開始向后搜索(i++),找到第一個(gè)大于key的A[i],將A[i]和A[j]互換;
5、重復(fù)第3、4步,直到i=j; (3,4步中,沒找到符合條件的值,即3中A[j]不小于key,4中A[i]不大于key的時(shí)候改變j、i的值,使得j=j-1,i=i+1,直至找到為止。找到符合條件的值,進(jìn)行交換的時(shí)候i, j指針位置不變。另外,i==j這一過程一定正好是i+或j-完成的時(shí)候,此時(shí)令循環(huán)結(jié)束)。
public class Quick { public static void main(String[] args) { int arr [] = {90,60,70,50,40,80,20,100,10}; sort(arr,0,arr.length-1); System.out.println(Arrays.toString(arr)); } public static void sort(int arr[], int low, int high) { //設(shè)置兩個(gè)變量l、h,排序開始的時(shí)候:l=0,h=N-1 int l = low; int h = high; //以第一個(gè)數(shù)組元素作為關(guān)鍵數(shù)據(jù),賦值給key,即key=A[0] int key = arr[low]; //重復(fù)操作,直到i=j while (l < h) { //從h開始向前搜索,即由后開始向前搜索(h--),找到第一個(gè)小于key的值arr[h],將arr[h]和arr[l]互換 while (l < h && arr[h] >= key) h--; if (l < h) { int temp = arr[h]; arr[h] = arr[l]; arr[l] = temp; l++; } //從l開始向后搜索,即由前開始向后搜索(l++),找到第一個(gè)大于key的arr[l],將arr[l]和arr[h]互換; while (l < h && arr[l] <= key) l++; if (l < h) { int temp = arr[h]; arr[h] = arr[l]; arr[l] = temp; h--; } } //對(duì)前一部分進(jìn)行快速排序 if (l > low) sort(arr, low, l - 1); //對(duì)前一部分進(jìn)行快速排序 if (h < high) sort(arr, l + 1, high); } }
輸入會(huì)依照以下規(guī)則:
1、所有輸入為整數(shù)、
2、“,”為分隔符
3、“~”表示一個(gè)區(qū)間,比如“-1~3”表示-1到3總共5個(gè)整數(shù),同時(shí)“~”前的數(shù)小于“~”后的數(shù):
4、“x”表示步長(zhǎng),“x3”指每3個(gè)整數(shù)一個(gè),比如“1~15×3”表示1,4,7,10,13;
根據(jù)以上得到的結(jié)果進(jìn)行打印,打印的規(guī)則為:
1、所有得到的整數(shù)按從小到大排列,以“,”分隔,不計(jì)重復(fù);
2、每行最多顯示3個(gè)整數(shù);
3、如果兩個(gè)整數(shù)是連續(xù)的,可以放在同一行,否則自動(dòng)換行。
例如對(duì)于輸入“1,-1~3,1~15×3”的輸出結(jié)果為:
-1,0,1,
2,3,4,
7,
10,
13
public class Test { public static void main(String[] args) { Map<Integer, Integer> map = new TreeMap<Integer, Integer>(); String str = "5~20x3,1,-1~3,1~15x3"; String[] s = str.split(","); for (int i = 0; i < s.length; i++) { if (s[i].contains("~")) { String ss[] = s[i].split("~"); int first = Integer.parseInt(ss[0]); if (s[i].contains("x")) { String sss[] = ss[1].split("x"); int end = Integer.parseInt(sss[0]); int l = Integer.parseInt(sss[1]); for (int j = first; j < end;) { map.put(j, j); j += l; } } else { int end = Integer.parseInt(ss[ss.length - 1]); for (int j = first; j <= end; j++) { map.put(j, j); } } } else { int j = Integer.parseInt(s[i]); map.put(j, j); } } List<Integer> list = new ArrayList<Integer>(); Set<Integer> set = map.keySet(); Iterator<Integer> ite = set.iterator(); while (ite.hasNext()) { int key = ite.next(); int value = map.get(key); list.add(value); System.out.println("v :" + value); } System.out.println("================="); for (int i = 0; i < list.size();) { int value = list.get(i); List<Integer> co = new ArrayList<Integer>(); co.add(value + 1); co.add(value + 2); if (list.containsAll(co)) { System.out.println(value + "," + (value + 1) + "," + (value + 2)); i += 3; } else { System.out.println(value); i++; } } } }
答:
字符串匹配操作定義:
目標(biāo)串S="S0S1S2...Sn-1" , 模式串T=“T0T1T2...Tm-1”
對(duì)合法位置 0<= i <= n-m (i稱為位移)依次將目標(biāo)串的字串 S[i ... i+m-1] 和模式串T[0 ... m-1] 進(jìn)行比較,若:
1、S[i ... i+m-1] = T[0 ... m-1] , 則從位置i開始匹配成功,稱模式串 T 在目標(biāo)串 S 中出現(xiàn)。
2、S[i ... i+m-1] != T[0 ... m-1] ,則從位置i開始匹配失敗。
字符串匹配算法 —— Brute-Force 算法
字符串匹配過程中,對(duì)于位移i (i在目標(biāo)串中的某個(gè)位置),當(dāng)?shù)谝淮?Sk != Tj 時(shí),i 向后移動(dòng)1位 , 及 i = i+1,此時(shí)k退回到i+1位置 ;模式串要退回到第一個(gè)字符。該算法時(shí)間復(fù)雜度O(M*N),但是實(shí)際情況中時(shí)間復(fù)雜度接近于O(M + N),以下為Brute-Force算法的Java實(shí)現(xiàn)版本:
public static int bruteForce(String target, String pattern, int pos) { if (target == null || pattern == null) { return -1; } int k = pos - 1, j = 0, tLen = target.length(), pLen = pattern.length(); while (k < tLen && j < pLen) { if (target.charAt(k) == pattern.charAt(j)) { j++; k++; } else { k = k - j + 1; j = 0; } } if (j == pLen) { return k - j + 1; } return -1; }
public class Test { public static void main(String[] args) { int num=(int)(Math.random()*101); System.out.println(num); } }
import java.util.Arrays; publicclass Demo1 { publicstaticvoid main(String[] args) { int[] a = { 1, 2, 3, 4, 5, 7, 8, 9, 10 }; int[] b = { 3, 5, 7, 9, 10 }; int[] target = newint[a.length + b.length]; for (inti = 0; i<a.length; i++) target[i] = a[i]; for (intj = 0; j<b.length; j++) target[a.length + j] = b[j]; Arrays.sort(target); for (inti = 0; i<target.length; i++) System.out.println(target[i]); } }
A. | 直接插入排序 |
B. | 直接選擇排序 |
C. | 冒泡排序 |
D. | 歸并排序 |
分析:答案: D
排序方法 最壞時(shí)間復(fù)雜度 最好時(shí)間復(fù)雜度 平均時(shí)間復(fù)雜度
直接插入 O(n2) O(n) O(n2)
簡(jiǎn)單選擇 O(n2) O(n2) O(n2)
冒泡排序 O(n2) O(n) O(n2)
快速排序 O(n2) O(nlog2n) O(nlog2n)
堆排序 O(nlog2n) O(nlog2n) O(nlog2n)
歸并排序 O(nlog2n) O(nlog2n) O(nlog2n)
|
publicstaticboolean demo(int[] arr){ for (inti = 0; i<arr.length; i++) { for (intj = i + 1; j<arr.length; j++) { if (arr[i] == arr[j]) { returntrue; } } } returnfalse; }
A. | 45231 |
B. | 42351 |
C. | 12345 |
D. | 54321 |
A. | 12 |
B. | 13 |
C. | 14 |
D. | 15 |
分析:選b 子葉節(jié)點(diǎn)是度為零的節(jié)點(diǎn),而二叉樹的性質(zhì)可知,度是0的節(jié)點(diǎn)比度是2的節(jié)點(diǎn)數(shù)多1個(gè),所以度是2的節(jié)點(diǎn)為2個(gè),所以共有3+8+2=13
|
答:先序序列:ABDEGHCF;中序序列:DBGEHACF;后序序列:DGHEBFCA。
補(bǔ)充:二叉樹也稱為二分樹,它是樹形結(jié)構(gòu)的一種,其特點(diǎn)是每個(gè)結(jié)點(diǎn)至多有二棵子樹,并且二叉樹的子樹有左右之分,其次序不能任意顛倒。二叉樹的遍歷序列按照訪問根節(jié)點(diǎn)的順序分為先序(先訪問根節(jié)點(diǎn),接下來先序訪問左子樹,再先序訪問右子樹)、中序(先中序訪問左子樹,然后訪問根節(jié)點(diǎn),最后中序訪問右子樹)和后序(先后序訪問左子樹,再后序訪問右子樹,最后訪問根節(jié)點(diǎn))。如果知道一棵二叉樹的先序和中序序列或者中序和后序序列,那么也可以還原出該二叉樹。
例如,已知二叉樹的先序序列為:xefdzmhqsk,中序序列為:fezdmxqhks,那么還原出該二叉樹應(yīng)該如下圖所示:
答:穩(wěn)定的排序算法有:插入排序、選擇排序、冒泡排序、雞尾酒排序、歸并排序、二叉樹排序、基數(shù)排序等;不穩(wěn)定排序算法包括:希爾排序、堆排序、快速排序等。
下面是關(guān)于排序算法的一個(gè)列表:
下面按照策略模式給出一個(gè)排序系統(tǒng),實(shí)現(xiàn)了冒泡、歸并和快速排序。
package com.bjsxt; import java.util.Comparator; /** * 排序器接口(策略模式: 將算法封裝到具有共同接口的獨(dú)立的類中使得它們可以相互替換) * @author SXT李端陽 * */ public interface Sorter { /** * 排序 * @param list 待排序的數(shù)組 */ public <T extends Comparable<T>> void sort(T[] list); /** * 排序 * @param list 待排序的數(shù)組 * @param comp 比較兩個(gè)對(duì)象的比較器 */ public <T> void sort(T[] list, Comparator<T> comp); }
BubbleSorter.java
package com.bjsxt; import java.util.Comparator; /** * 冒泡排序 * @author SXT李端陽 * */ public class BubbleSorter implements Sorter { @Override public <T extends Comparable<T>> void sort(T[] list) { boolean swapped = true; for(int i = 1; i < list.length && swapped;i++) { swapped= false; for(int j = 0; j < list.length - i; j++) { if(list[j].compareTo(list[j+ 1]) > 0 ) { T temp = list[j]; list[j]= list[j + 1]; list[j+ 1] = temp; swapped= true; } } } } public <T> void sort(T[] list,Comparator<T> comp) { boolean swapped = true; for(int i = 1; i < list.length && swapped; i++) { swapped = false; for(int j = 0; j < list.length - i; j++) { if(comp.compare(list[j], list[j + 1]) > 0 ) { T temp = list[j]; list[j]= list[j + 1]; list[j+ 1] = temp; swapped= true; } } } } }
package com.bjsxt; import java.util.Comparator; /** * 歸并排序 * 歸并排序是建立在歸并操作上的一種有效的排序算法。 * 該算法是采用分治法(divide-and-conquer)的一個(gè)非常典型的應(yīng)用, * 先將待排序的序列劃分成一個(gè)一個(gè)的元素,再進(jìn)行兩兩歸并, * 在歸并的過程中保持歸并之后的序列仍然有序。 * @author SXT李端陽 * */ public class MergeSorter implements Sorter { @Override public <T extends Comparable<T>> void sort(T[] list) { T[] temp = (T[]) new Comparable[list.length]; mSort(list,temp, 0, list.length- 1); } private <T extends Comparable<T>> void mSort(T[] list, T[] temp, int low, int high) { if(low == high) { return ; } else { int mid = low + ((high -low) >> 1); mSort(list,temp, low, mid); mSort(list,temp, mid + 1, high); merge(list,temp, low, mid + 1, high); } } private <T extends Comparable<T>> void merge(T[] list, T[] temp, int left, int right, int last) { int j = 0; int lowIndex = left; int mid = right - 1; int n = last - lowIndex + 1; while (left <= mid && right <= last){ if (list[left].compareTo(list[right]) < 0){ temp[j++] = list[left++]; } else { temp[j++] = list[right++]; } } while (left <= mid) { temp[j++] = list[left++]; } while (right <= last) { temp[j++] = list[right++]; } for (j = 0; j < n; j++) { list[lowIndex + j] = temp[j]; } } @Override public <T> void sort(T[] list, Comparator<T> comp) { T[]temp = (T[])new Comparable[list.length]; mSort(list,temp, 0, list.length- 1, comp); } private <T> void mSort(T[] list, T[] temp, int low, int high, Comparator<T> comp) { if(low == high) { return ; } else { int mid = low + ((high -low) >> 1); mSort(list,temp, low, mid, comp); mSort(list,temp, mid + 1, high, comp); merge(list,temp, low, mid + 1, high, comp); } } private <T> void merge(T[] list, T[]temp, int left, int right, int last, Comparator<T> comp) { int j = 0; int lowIndex = left; int mid = right - 1; int n = last - lowIndex + 1; while (left <= mid && right <= last){ if (comp.compare(list[left], list[right]) <0) { temp[j++] = list[left++]; } else { temp[j++] = list[right++]; } } while (left <= mid) { temp[j++] = list[left++]; } while (right <= last) { temp[j++] = list[right++]; } for (j = 0; j < n; j++) { list[lowIndex + j] = temp[j]; } } }
QuickSorter.java
package com.bjsxt; import java.util.Comparator; /** * 快速排序 * 快速排序是使用分治法(divide-and-conquer)依選定的樞軸 * 將待排序序列劃分成兩個(gè)子序列,其中一個(gè)子序列的元素都小于樞軸, * 另一個(gè)子序列的元素都大于或等于樞軸,然后對(duì)子序列重復(fù)上面的方法, * 直到子序列中只有一個(gè)元素為止 * @author Hao * */ public class QuickSorter implements Sorter { @Override public <T extends Comparable<T>> void sort(T[] list) { quickSort(list, 0, list.length- 1); } @Override public <T> void sort(T[] list, Comparator<T> comp) { quickSort(list, 0, list.length- 1, comp); } private <T extends Comparable<T>> void quickSort(T[] list, int first, int last) { if (last > first) { int pivotIndex = partition(list, first, last); quickSort(list, first, pivotIndex - 1); quickSort(list, pivotIndex, last); } } private <T> void quickSort(T[] list, int first, int last,Comparator<T> comp) { if (last > first) { int pivotIndex = partition(list, first, last, comp); quickSort(list, first, pivotIndex - 1, comp); quickSort(list, pivotIndex, last, comp); } } private <T extends Comparable<T>> int partition(T[] list, int first, int last) { T pivot = list[first]; int low = first + 1; int high = last; while (high > low) { while (low <= high && list[low].compareTo(pivot) <= 0) { low++; } while (low <= high && list[high].compareTo(pivot) >= 0) { high--; } if (high > low) { T temp = list[high]; list[high]= list[low]; list[low]= temp; } } while (high > first&& list[high].compareTo(pivot) >= 0) { high--; } if (pivot.compareTo(list[high])> 0) { list[first]= list[high]; list[high]= pivot; return high; } else { return low; } } private <T> int partition(T[] list, int first, int last, Comparator<T> comp) { T pivot = list[first]; int low = first + 1; int high = last; while (high > low) { while (low <= high&& comp.compare(list[low], pivot) <= 0) { low++; } while (low <= high&& comp.compare(list[high], pivot) >= 0) { high--; } if (high > low) { T temp = list[high]; list[high] = list[low]; list[low]= temp; } } while (high > first&& comp.compare(list[high], pivot) >= 0) { high--; } if (comp.compare(pivot,list[high]) > 0) { list[first]= list[high]; list[high]= pivot; return high; } else { return low; } } }
答:折半搜索,也稱二分查找算法、二分搜索,是一種在有序數(shù)組中查找某一特定元素的搜索算法。搜素過程從數(shù)組的中間元素開始,如果中間元素正好是要查找的元素,則搜素過程結(jié)束;如果某一特定元素大于或者小于中間元素,則在數(shù)組大于或小于中間元素的那一半中查找,而且跟開始一樣從中間元素開始比較。如果在某一步驟數(shù)組為空,則代表找不到。這種搜索算法每一次比較都使搜索范圍縮小一半。
package com.bjsxt; import java.util.Comparator; public class MyUtil1 { public static <T extends Comparable<T>> int binarySearch(T[] x, T key) { return binarySearch(x, 0, x.length- 1, key); } public static <T> int binarySearch(T[] x, T key, Comparator<T> comp) { int low = 0; int high = x.length - 1; while (low <= high) { int mid = (low + high) >>> 1; int cmp = comp.compare(x[mid], key); if (cmp < 0) { low = mid + 1; } else if (cmp > 0) { high = mid - 1; } else { return mid; } } return -1; } private static <T extends Comparable<T>> int binarySearch(T[] x, int low, int high, T key) { if(low <= high) { int mid = low + ((high -low) >> 1); if(key.compareTo(x[mid]) == 0) { return mid; } else if(key.compareTo(x[mid])< 0) { return binarySearch(x,low, mid - 1, key); } else { return binarySearch(x, mid + 1, high, key); } } return -1; } }
說明:兩個(gè)版本一個(gè)用遞歸實(shí)現(xiàn),一個(gè)用循環(huán)實(shí)現(xiàn)。需要注意的是計(jì)算中間位置時(shí)不應(yīng)該使用(high+ low) / 2的方式,因?yàn)榧臃ㄟ\(yùn)算可能導(dǎo)致整數(shù)越界,這里應(yīng)該使用一下三種方式之一:low+ (high – low) / 2或low + (high – low) >> 1或(low + high) >>> 1(注:>>>是邏輯右移,不帶符號(hào)位的右移)
package com.bjsxt; import java.io.FileReader; public class WordCounting { public static void main(String[] args) { try(FileReader fr = new FileReader("a.txt")) { int counter = 0; boolean state = false; int currentChar; while((currentChar= fr.read()) != -1) { if(currentChar== ' ' || currentChar == '\n' || currentChar == '\t' || currentChar == '\r') { state = false; } else if(!state) { state = true; counter++; } } System.out.println(counter); } catch(Exception e) { e.printStackTrace(); } } }
補(bǔ)充:這個(gè)程序可能有很多種寫法,這里選擇的是Dennis M. Ritchie和Brian W. Kernighan老師在他們不朽的著作《The C Programming Language》中給出的代碼,向兩位老師致敬。下面的代碼也是如此。
package com.bjsxt; import java.util.Scanner; public class DayCounting { public static void main(String[] args) { int[][] data = { {31,28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, {31,29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} }; Scanner sc = new Scanner(System.in); System.out.print("請(qǐng)輸入年月日(1980 11 28): "); int year = sc.nextInt(); int month = sc.nextInt(); int date = sc.nextInt(); int[] daysOfMonth = data[(year % 4 == 0 && year % 100 != 0 || year % 400 == 0)?1 : 0]; int sum = 0; for(int i = 0; i < month -1; i++) { sum += daysOfMonth[i]; } sum += date; System.out.println(sum); sc.close(); } }
package com.bjsxt; public class PalindromicPrimeNumber { public static void main(String[] args) { for(int i = 11; i <= 9999; i++) { if(isPrime(i) && isPalindromic(i)) { System.out.println(i); } } } public static boolean isPrime(int n) { for(int i = 2; i <= Math.sqrt(n); i++) { if(n % i == 0) { return false; } } return true; } public static boolean isPalindromic(int n) { int temp = n; int sum = 0; while(temp > 0) { sum= sum * 10 + temp % 10; temp/= 10; } return sum == n; } }
package com.bjsxt; public class FullPermutation { public static void perm(int[] list) { perm(list,0); } private static void perm(int[] list, int k) { if (k == list.length) { for (int i = 0; i < list.length; i++) { System.out.print(list[i]); } System.out.println(); }else{ for (int i = k; i < list.length; i++) { swap(list, k, i); perm(list, k + 1); swap(list, k, i); } } } private static void swap(int[] list, int pos1, int pos2) { int temp = list[pos1]; list[pos1] = list[pos2]; list[pos2] = temp; } public static void main(String[] args) { int[] x = {1, 2, 3, 4, 5}; perm(x); } }
答:下面給出幾個(gè)例子(最大子數(shù)組用粗體表示):
數(shù)組:{ 1, -2,?3,5, -3, 2 },結(jié)果是:8
2)?數(shù)組:{ 0, -2,?3,?5,?-1,?2?},結(jié)果是:9
3)?數(shù)組:{ -9,?-2,-3, -5, -3 },結(jié)果是:-2
可以使用動(dòng)態(tài)規(guī)劃的思想求解:
package com.bjsxt; public class MaxSum { private static int max(int x, int y) { return x > y? x: y; } public static int maxSum(int[] array) { int n = array.length; int[] start = new int[n]; int[] all = new int[n]; all[n - 1] = start[n - 1] = array[n - 1]; for(int i = n - 2; i >= 0;i--) { start[i] = max(array[i], array[i] + start[i + 1]); all[i] = max(start[i], all[i + 1]); } return all[0]; } public static void main(String[] args) { int[] x1 = { 1, -2, 3, 5,-3, 2 }; int[] x2 = { 0, -2, 3, 5,-1, 2 }; int[] x3 = { -9, -2, -3,-5, -3 }; System.out.println(maxSum(x1)); // 8 System.out.println(maxSum(x2)); // 9 System.out.println(maxSum(x3)); //-2 } }
package com.bjsxt; public class StringReverse { public static String reverse(String originStr) { if(originStr == null || originStr.length()== 1) { return originStr; } return reverse(originStr.substring(1))+ originStr.charAt(0); } public static void main(String[] args) { System.out.println(reverse("hello")); } }
package com.bjsxt; import java.util.ArrayList; import java.util.List; import java.util.Scanner; public class DecomposeInteger { private static List<Integer> list = new ArrayList<Integer>(); public static void main(String[] args) { System.out.print("請(qǐng)輸入一個(gè)數(shù): "); Scanner sc = new Scanner(System.in); int n = sc.nextInt(); decomposeNumber(n); System.out.print(n + " = "); for(int i = 0; i < list.size() - 1; i++) { System.out.print(list.get(i) + " * "); } System.out.println(list.get(list.size() - 1)); } public static void decomposeNumber(int n) { if(isPrime(n)) { list.add(n); list.add(1); } else { doIt(n, (int)Math.sqrt(n)); } } public static void doIt(int n, int div) { if(isPrime(div) && n % div == 0) { list.add(div); decomposeNumber(n / div); } else { doIt(n, div - 1); } } public static boolean isPrime(int n) { for(int i = 2; i <= Math.sqrt(n);i++) { if(n % i == 0) { return false; } } return true; } }
package com.bjsxt; public class GoSteps { public static int countWays(int n) { if(n < 0) { return 0; } else if(n == 0) { return 1; } else { return countWays(n - 1) + countWays(n - 2) + countWays(n -3); } } public static void main(String[] args) { System.out.println(countWays(5)); // 13 } }
package com.bjsxt; public class AllNotTheSame { public static boolean judge(String str) { String temp = str.toLowerCase(); int[] letterCounter = new int[26]; for(int i = 0; i <temp.length(); i++) { int index = temp.charAt(i)- 'a'; letterCounter[index]++; if(letterCounter[index] > 1) { return false; } } return true; } public static void main(String[] args) { System.out.println(judge("hello")); System.out.print(judge("smile")); } }
package com.bjsxt; import java.util.Arrays; public class RemoveDuplication { public static int[] removeDuplicates(int a[]) { if(a.length <= 1) { return a; } int index = 0; for(int i = 1; i < a.length; i++) { if(a[index] != a[i]) { a[++index] = a[i]; } } int[] b = new int[index + 1]; System.arraycopy(a, 0, b, 0, b.length); return b; } public static void main(String[] args) { int[] a = {1, 1, 2, 2, 3}; a = removeDuplicates(a); System.out.println(Arrays.toString(a)); } }
package com.bjsxt; public class FindMost { public static <T> T find(T[] x){ T temp = null; for(int i = 0, nTimes = 0; i< x.length;i++) { if(nTimes == 0) { temp= x[i]; nTimes= 1; } else { if(x[i].equals(temp)) { nTimes++; } else { nTimes--; } } } return temp; } public static void main(String[] args) { String[]strs = {"hello","kiss","hello","hello","maybe"}; System.out.println(find(strs)); } }
public int getWordCount(String s) { int length = 0; for(int i = 0; i < s.length(); i++) { int ascii = Character.codePointAt(s, i); if(ascii >= 0 && ascii <=255) length++; else length += 2; } return length; }
一:招聘程序員的內(nèi)幕
1.面試和相親
面試其實(shí)本質(zhì)上是一個(gè)交流的過程,它跟你去相親本質(zhì)完全一樣。那么,把握面試官的心理狀態(tài),從面試官的角度出發(fā)思考問題,將是你可以順利收到offer的關(guān)鍵。
如果你知道面試官的動(dòng)機(jī),就可以建立共通點(diǎn),很容易就能恰當(dāng)?shù)鼗貞?yīng)問題。從而為你的面試加分、添彩。
相親時(shí),你期望碰到美女的渴望和美女期望碰到白馬王子的渴望,二者的“渴望程度”完全是一樣的。 那么,你如果是男方,你需要做的事情就是“包裝”自己,讓自己顯得比實(shí)際上“更高,更富,更帥”,接近女方的心中白馬王子的高度,越接近越容易成功。這個(gè)過程也存在“心理博弈”的過程,雙方聊過去、聊現(xiàn)在、聊未來。 有輝煌過去的喜歡聊過去來證明自己的未來;現(xiàn)在就輝煌的就喜歡聊當(dāng)下;過去不行,現(xiàn)在不行的就喜歡聊未來,展現(xiàn)自己的雄心。
同上面相親的案例,面試中,面試官需要人才的熱烈程度等于你求職的熱烈程度。 我們首先要明白面試官需要什么樣的人才,然后展示自己,告訴他,我就是這樣的人才!
明白上面的道理,我們就需要針對(duì)整個(gè)招聘的過程進(jìn)行詳細(xì)的分析,讓大家心里更有底,更容易把握面試官的心理狀態(tài)。
2.為什么要招聘程序員?為什么絕大部分總能找到工作?
一般公司招聘員工有三大類原因:
1.公司計(jì)劃性擴(kuò)張
2.特定項(xiàng)目
3.有員工離職
因此,招聘者也是“求賢若渴”,他也面臨公司給他的績(jī)效壓力。 如何能盡快、低成本的招聘到合適的人到崗,而不耽誤業(yè)務(wù)的進(jìn)展,這是招聘者最大的工作。
通常如果受到高層壓力,感覺招聘進(jìn)度已經(jīng)限制了公司業(yè)務(wù)的發(fā)展、已經(jīng)阻礙了業(yè)務(wù)推廣的時(shí)間,招聘者就會(huì)變“急”。 就跟開發(fā)人員迫于項(xiàng)目時(shí)間的壓力,湊合完成一段不合格的代碼一樣。招聘者也會(huì)由于這些壓力,有可能降低招聘的崗位標(biāo)準(zhǔn)(這種降低不是明面上通知降低標(biāo)準(zhǔn),而是各個(gè)環(huán)節(jié)把控較松)。 這也就是為什么很多人技術(shù)并不太好,也能找到工作的原因。 公司最大的成本有時(shí)候不是金錢、而是時(shí)間。 這也就像很多優(yōu)秀的男生女生30歲之后,迫于時(shí)間壓力,降低標(biāo)準(zhǔn)找對(duì)象的道理一樣。
雖然學(xué)習(xí)編程的人員很多,但是各行各業(yè)都需要信息化,人員需求也非常巨大,缺口仍然很大。 如果某個(gè)公司招聘并不順利,連續(xù)面試很多人都不合格,那么可能就在面試你的時(shí)候降低“標(biāo)準(zhǔn)”。 這也是為什么很多技術(shù)很水的人也能找到工作的原因。 對(duì)于招聘者來說,如果你心態(tài)好,很踏實(shí),即使現(xiàn)在技術(shù)不行,花一點(diǎn)時(shí)間培養(yǎng)你,也沒什么大不了。
當(dāng)然,這不能成為你不好好學(xué)習(xí)技術(shù)的理由?!奔夹g(shù)強(qiáng)、心態(tài)好、踏實(shí)”將會(huì)讓你面臨更多的人生機(jī)會(huì)。
3.為什么有人會(huì)找不到工作?
任何一個(gè)行業(yè)都有失敗者,這就是規(guī)律。 就像婚姻、戀愛市場(chǎng),總會(huì)有打光棍的問題(100%是男同胞,男女比例嚴(yán)重失調(diào)啊)。 為什么會(huì)有人找不到工作?為什么會(huì)有人找不到老婆?這是個(gè)大課題。想明白了,你將會(huì)走向人生巔峰。
我們先以婚姻、戀愛市場(chǎng)為例。研究研究為什么會(huì)有人找不到老婆? 有人說,打光棍是因?yàn)檫@個(gè)人沒錢。 但你總會(huì)發(fā)現(xiàn)比他還沒錢的人娶了老婆,有的還很漂亮。老婆還很賢惠,出去打工養(yǎng)老公。 有人說,打光棍是因?yàn)檫@個(gè)人沒能力。 但你總會(huì)發(fā)現(xiàn)很多沒能力的人也娶了老婆,有的也很漂亮。 這時(shí)候,你只能仰天長(zhǎng)嘆,“好白菜都讓豬拱了”。有人說,打光棍是因?yàn)檫@個(gè)人長(zhǎng)得丑,個(gè)子矮、家里窮等等。但你總會(huì)找到層出不窮的反例。這時(shí)候,你可能就會(huì)迷茫了。 到底什么才是關(guān)鍵、才是問題的核心?
好吧,我告訴你, 是心態(tài)!心態(tài)!心態(tài)!重要的問題說三遍! 心態(tài)積極,勤奮努力什么事情都能干成。 心態(tài)消極,懶惰不努力,什么條件都沒戲! 很多“懶屌絲”寧愿天天宅在家里睡懶覺、玩游戲,也不愿意走出去。寧愿窩在家里練習(xí)右手臂力,也不愿意出去多跟異性接觸。 這些人,不管什么條件都將被淘汰。
大家如果看過電影《夏洛特?zé)馈?,里面的“大傻”,智商低,但是人?shí)在。就是靠死纏爛打硬泡的方式,竟然也追上了自己的女神。 追女神也是概率問題,努力去追,提高成功率,女神總有空虛、心理沒底的時(shí)候,這時(shí)候可能就會(huì)有機(jī)會(huì)了。 某天,女神忽然微信呼你:“忙嗎?”,這時(shí)候機(jī)會(huì)就來了。 但是,如果你不努力,你連女神的候選名單都上不去,怎么可能有機(jī)會(huì)?
在招聘市場(chǎng),應(yīng)聘者面臨的是同樣的問題。 即使你技術(shù)水平差,只要多面試、多總結(jié)、多努力,沒有不成功的。 你想想,面試是個(gè)概率事件,技術(shù)差你的成功率即使只有1%,面試100家也上去了。 技術(shù)好你的成功率是10%,不去面試,面試的少,你可能也沒戲。 因此,我們要千方百計(jì)提高自己“面試的機(jī)會(huì)”,至少可以讓自己進(jìn)入企業(yè)“眼里”,一旦有機(jī)會(huì),即可成功。
我們?cè)?jīng)碰到一個(gè)學(xué)員,大學(xué)學(xué)的是文科,學(xué)歷是專科, 畢業(yè)后做了一名“光榮的水手”,環(huán)球航行了兩年,決定回歸陸地。 開始學(xué)習(xí)編程,學(xué)了1個(gè)多月后,仍然在糾結(jié)什么是變量的問題。 但是,這個(gè)同學(xué)心態(tài)好,積極向上,畢業(yè)后,積極主動(dòng)的去面試,結(jié)果很快搞定了工作,剛開始工資并不高。 工作兩年后,成了項(xiàng)目經(jīng)理,年薪30萬。風(fēng)風(fēng)光光的回尚學(xué)堂招聘學(xué)弟學(xué)妹了。 積極努力,一天當(dāng)兩天用,起點(diǎn)再低也會(huì)成功。
我們也碰到過一個(gè)奇葩的學(xué)員,在尚學(xué)堂學(xué)完后,就糾結(jié)于你們不是“推薦就業(yè)”嗎?窩在宿舍等著。 企業(yè)來了,老師通知也不來參加面試,偶爾來了,結(jié)果窩在宿舍根本沒有鍛煉出能力,也無法面試成功,這是極其個(gè)別的案例。即使你是千里馬,不出去跑,天天窩在家里,消極等待,最終你也會(huì)成為一匹“廢馬”。
所以,無論你是什么條件,高富帥還是矮矬窮,心態(tài)不對(duì),戀愛和工作都不可能成功。 希望大家積極起來,大著膽子沖向社會(huì),千方百計(jì)進(jìn)入企業(yè)招聘環(huán)節(jié),即使不成功,就當(dāng)做一次鍛煉機(jī)會(huì),鍛煉多了,一旦機(jī)會(huì)來了,是不是成功率就大大提高了? 做“屌絲”可以,自嘲一下也不錯(cuò),但千萬不要做“懶屌絲”,那樣你就完蛋了。
4. 公司最喜歡什么樣的程序員?
公司喜歡什么樣的程序員?特別簡(jiǎn)單,三個(gè)特點(diǎn):
第一、態(tài)度好
態(tài)度永遠(yuǎn)是第一要素,面試者通常都是你以后的直接上級(jí)。如果跟你交流順暢,看你態(tài)度也不錯(cuò),這樣對(duì)他來說,領(lǐng)導(dǎo)起來就容易一些。 因此,態(tài)度通常是面試官看人的第一要素。 態(tài)度不端正,一切免談。能力強(qiáng)我也駕馭不了,要你何用? 能力差態(tài)度好也勉強(qiáng)能接受,能力差態(tài)度還差那就分分鐘被滅掉。
如果你知道面試官的動(dòng)機(jī),就可以建立共通點(diǎn),很容易就能恰當(dāng)?shù)鼗貞?yīng)問題。從而為你的面試加分、添彩。
第二、技術(shù)能力較強(qiáng)
企業(yè)招聘人員畢竟是來做事的,技術(shù)能力是考察的重點(diǎn)。技術(shù)能力能勝任目前的工作,是面試官主要看重的。
第三、熱愛技術(shù)工作,學(xué)習(xí)能力強(qiáng)
通過跟面試官的交流,能讓別人覺得你熱愛技術(shù)工作,會(huì)讓你具備極大的優(yōu)勢(shì)。即使感覺你現(xiàn)在水平較差,也沒有關(guān)系。興趣是最好的老師,喜歡技術(shù),把加班當(dāng)成玩游戲一樣的態(tài)度,面試官顯然會(huì)大大的給你點(diǎn)個(gè)贊。
PS:這里順便給個(gè)技巧,可以讓你身價(jià)立刻增加30%以上(本來你值8000,可以拿到1萬,一下子讓你一年多掙3萬),那就是學(xué)習(xí)本專業(yè)的一些新的技術(shù)、高級(jí)一點(diǎn)的技術(shù)。不需要多么精通,了解即可??梢栽诿嬖嚨臅r(shí)候說出來。這樣就會(huì)令面試官對(duì)你刮目相看,薪水標(biāo)準(zhǔn)也會(huì)立刻增加。因?yàn)槟阏f的這些技術(shù),可能是面試官也不會(huì)的,這種對(duì)你的好感度和驚詫的眼神立刻就會(huì)讓你身價(jià)暴增。 很多java學(xué)員學(xué)完后再學(xué)大數(shù)據(jù)或者架構(gòu)師班,都有這樣的誤解,覺得一定要學(xué)到多么多么好。其實(shí),沒必要,了解大數(shù)據(jù)或者架構(gòu)師班某些技術(shù)能交流即可,面試時(shí)優(yōu)勢(shì)已經(jīng)極大了; 而且,即使上了班,用到這些技術(shù),查查資料加加班能弄出來就OK了。
如上三點(diǎn)決定了你是否能被錄用。大家掌握這三點(diǎn),也可以互相補(bǔ)充。比如,你技術(shù)差,可以通過展現(xiàn)態(tài)度好,愛技術(shù),愛學(xué)習(xí)來獲得加分。 當(dāng)然,如果技術(shù)好,也要通過展現(xiàn)態(tài)度好,愛技術(shù),愛學(xué)習(xí)獲得更多的分。
面試官經(jīng)常會(huì)碰到技術(shù)非常合適,但是態(tài)度較差,計(jì)較是否加班的面試者,基本都被pass。畢竟,技術(shù)再?gòu)?qiáng)也不是地球上只有你會(huì),對(duì)不對(duì)? 如果態(tài)度差,加入團(tuán)隊(duì)變成團(tuán)隊(duì)的負(fù)能量,那就損失大了。
5.我到底值多少錢?
第一、態(tài)度好
“我是誰?”這是人生最大的命題,找工作最大的命題是什么呢?顯然,就是“我到底值多少錢?”。給自己確定了合適的定位,才能找到合適的工作。 如果你能力只值5000,一定要找3萬的工作,那怎么可能找得到?
一般情況,面試官評(píng)價(jià)你的薪資標(biāo)準(zhǔn)通常從下面幾項(xiàng):
1.個(gè)人素質(zhì)和口才(占比:20%)
這其實(shí)是個(gè)印象分,所以要被別人認(rèn)可的其實(shí)就是上一個(gè)話題《公司最喜歡什么樣的程序員》中表示的第一特點(diǎn):“態(tài)度好”。
如果你向面試官充分表達(dá)了良好的個(gè)人素質(zhì)、對(duì)工作積極的態(tài)度,整個(gè)面試過程中讓面試官都覺得非常的順暢、很投緣,即使你技術(shù)較差,也可以讓你順利拿到offer。
“個(gè)人素質(zhì)和口才”是你拿到offer的最關(guān)鍵因素。
2.基礎(chǔ)技術(shù)(占比:40%)
基礎(chǔ)編程能力、理論知識(shí)是否扎實(shí)、知識(shí)體系是否系統(tǒng)是面試官比較看重的。老師講課過程中的基本知識(shí)點(diǎn)要盡力吃透,良好的知識(shí)體系對(duì)于后期面試極其有利。
如果面試官感覺你項(xiàng)目經(jīng)驗(yàn)不豐富,但是基礎(chǔ)扎實(shí),也可以完全的彌補(bǔ)項(xiàng)目經(jīng)驗(yàn)欠缺的問題。這也是很多應(yīng)屆畢業(yè)生能順利就業(yè)的法寶。 當(dāng)然,如果項(xiàng)目經(jīng)驗(yàn)欠缺的話,高薪的概率就降低了, 需要降低薪資要求,保持較普通的薪水來實(shí)現(xiàn)就業(yè)。
“基礎(chǔ)技術(shù)”是你能否就業(yè)的基礎(chǔ)因素。
3.項(xiàng)目經(jīng)驗(yàn)(占比:40%)
項(xiàng)目經(jīng)驗(yàn)顯然是面試官極其看重的一項(xiàng)。從項(xiàng)目經(jīng)驗(yàn)的描述中可以體現(xiàn)你的個(gè)人素質(zhì)、基礎(chǔ)技術(shù)等等。盡量多的積累項(xiàng)目案例,盡量多的敲代碼,可以完成基本的項(xiàng)目模塊,會(huì)成為你以后面試的殺手锏。
在培訓(xùn)期間,老師講的項(xiàng)目案例大家要學(xué)會(huì)舉一反三,畢竟這些案例對(duì)著幾十人、幾百人講過,你在面試時(shí)直接寫到簡(jiǎn)歷上并不是特別好的做法。最好的做法是,做一個(gè)有心人,多留意和查找適合自己的項(xiàng)目案例。
項(xiàng)目案例是你的,里面的項(xiàng)目流程和開發(fā)中遇到的問題是老師課上講過的。說白了,就是將你的項(xiàng)目案例換了個(gè)衣服,“換湯不換藥”,這樣就可以在面試中起到更好的效果。
“項(xiàng)目經(jīng)驗(yàn)”是你能否實(shí)現(xiàn)高薪的關(guān)鍵因素。
4.最新和高級(jí)技術(shù)了解程度(額外,增值30%--50%)前面3項(xiàng)如果做好了就可以完全保證就業(yè)了?!白钚潞透呒?jí)技術(shù)了解度”是能否爭(zhēng)取到合理范圍內(nèi)更高薪水的關(guān)鍵,也就是讓你實(shí)現(xiàn)更高“溢價(jià)”,“超額把你自己賣出去“。
面試官通常由于平時(shí)工作忙,無暇學(xué)習(xí)新的技術(shù)和知識(shí),除非是項(xiàng)目用到的技術(shù)。但是,作為一個(gè)“技術(shù)控“,通常會(huì)關(guān)注最新技術(shù)的信息,擁有學(xué)習(xí)這些技術(shù)的渴望,但是沒有時(shí)間和精力。 這個(gè)時(shí)候,應(yīng)聘者簡(jiǎn)歷上寫的新技術(shù)、面試時(shí)聊的新技術(shù),都會(huì)成為讓”面試官欣賞你的理由“。
但是,注意千萬不要有心理負(fù)擔(dān),這種”欣賞的眼神“是上級(jí)發(fā)現(xiàn)一個(gè)得力下屬的”喜歡的眼神“,而不是好基友。 面試官也知道你基礎(chǔ)一般、項(xiàng)目經(jīng)驗(yàn)一般,但是這些新技術(shù)你都在學(xué),證明你是個(gè)”技術(shù)好胚子“,很像曾經(jīng)的”他自己“而已。
如果前三項(xiàng)決定了你的薪水是8000,那么有了第四項(xiàng),你的薪水標(biāo)準(zhǔn)通常會(huì)提高至少30%,最高50%。也就是實(shí)現(xiàn)了”你的溢價(jià)”, 每個(gè)月可以多賺:4000元左右。 而且,你會(huì)發(fā)現(xiàn)拿8000和溢價(jià)拿1萬,1萬2, 最后干的活其實(shí)差別不大。
這里有個(gè)經(jīng)過我們統(tǒng)計(jì)的”1.5倍定律”: 就是經(jīng)過”最新和高級(jí)技術(shù)”的助力,你的薪水會(huì)在原定值上增加50%,薪水是原來的1.5倍。
6.找工作最重要的是什么?薪水?機(jī)會(huì)?
什么最重要,因人而異。一般分為如下幾類:
這種情況,我也不多說。缺錢就看薪水,不缺就看機(jī)會(huì)。個(gè)人建議,看機(jī)會(huì)。
第二種情況:offer少,沒得挑
這種情況,當(dāng)然,就是”別挑了。先進(jìn)入行業(yè),再尋找機(jī)會(huì)”。時(shí)間浪費(fèi)不起,如果因?yàn)樾剿m結(jié),兩個(gè)月不上班,損失兩個(gè)月薪水不說,還浪費(fèi)了兩個(gè)月時(shí)間。
第三種情況:沒offer
這種情況,就是降低標(biāo)準(zhǔn),千方百計(jì)就業(yè),不管什么企業(yè),先進(jìn)去再說。進(jìn)去行業(yè)后,再學(xué)習(xí),再進(jìn)步,再找更大的機(jī)會(huì)。
我們始終強(qiáng)調(diào)”機(jī)會(huì)成本”,差不多的前提下,盡快就業(yè),不要糾結(jié)于薪水多500少1000的問題,進(jìn)入行業(yè)后,還需要再學(xué)習(xí)再提高。 現(xiàn)在就業(yè)不是你的終點(diǎn),而是你的起點(diǎn)。
7.學(xué)習(xí)很多技術(shù),現(xiàn)在的公司不用,不是虧了嗎?
很多朋友還是跟小孩一樣, 感覺學(xué)習(xí)了東西后如果考試不考,公司暫時(shí)不用就沒有價(jià)值,不想學(xué)習(xí)。 感覺學(xué)習(xí)好累啊,是給老師學(xué)的,給尚學(xué)堂交了學(xué)費(fèi),是給尚學(xué)堂學(xué)的。別不承認(rèn),很多人潛意識(shí)里面就是這種”應(yīng)試教育”思維。
多學(xué)東西到底是為什么?其實(shí),很簡(jiǎn)單。掌握更多的技術(shù),意味著更多的機(jī)會(huì),有更多選擇的機(jī)會(huì)。 人和人之間本質(zhì)的差距就是“選擇權(quán)“的差距。 農(nóng)民自家種蔬菜、養(yǎng)豬吃,很干凈很有機(jī);千萬富翁可能還要吃著普通的豬肉和蔬菜;他們之間的差距在于:千萬富翁可以隨便選擇,可以隨時(shí)過農(nóng)民的生活;而農(nóng)民卻沒有選擇過千萬富翁生活的權(quán)利。 多學(xué)技術(shù),就意味著有更多選擇的機(jī)會(huì),發(fā)展的機(jī)會(huì),就會(huì)造成工作和生活的差距。
同時(shí),在IT行業(yè)多學(xué)東西,除了這些“機(jī)會(huì)和選擇權(quán)“之外,更直接的就是能帶來金錢的收益。 舉例來說,同樣招聘一個(gè)java程序員。小A只會(huì)java已經(jīng)合格了。 小B除了會(huì)java,還會(huì)一點(diǎn)大數(shù)據(jù)和架構(gòu)知識(shí),要價(jià)比小A高20%。 關(guān)鍵是,我們公司現(xiàn)在也不需要大數(shù)據(jù)和架構(gòu)技術(shù),小A和小B來了以后還是寫java代碼。 你猜,面試官會(huì)選擇小A還是小B? 絕大多數(shù)面試官會(huì)選擇小B。 有了小B,一旦后期有大數(shù)據(jù)和架構(gòu)的需求,技術(shù)經(jīng)理就多了一個(gè)選擇。 而且,小B顯然更好學(xué),成長(zhǎng)性更好,雖然薪水高20%,但是幾個(gè)月時(shí)間就能把這20%的薪水賺回來。
掌握或了解更多的技術(shù)知識(shí),拋開企業(yè)用和不用的角度,單純看應(yīng)聘者就是一個(gè)態(tài)度的問題、成長(zhǎng)潛力的問題。 面試官顯然會(huì)要態(tài)度更好、成長(zhǎng)力更大的員工。
另外,你的企業(yè)現(xiàn)在不用,以后可能會(huì)用呀,這個(gè)時(shí)候你可能就具備強(qiáng)大的話語權(quán)和機(jī)會(huì)了。 我們一個(gè)大數(shù)據(jù)的學(xué)員畢業(yè)后,他還是應(yīng)屆生,去了一家公司做java開發(fā),沒多久老板成立大數(shù)據(jù)業(yè)務(wù)的公司,結(jié)果公司就他會(huì),直接就被任命為大數(shù)據(jù)業(yè)務(wù)的技術(shù)負(fù)責(zé)人。 你可以說,這個(gè)學(xué)員還年輕,技術(shù)不行什么的,但是他有這個(gè)技術(shù)負(fù)責(zé)人的平臺(tái),還要學(xué)習(xí)和提高,現(xiàn)在不行,一年后呢?
多學(xué)習(xí),意味著更多的機(jī)會(huì)和選擇;更多的機(jī)會(huì),意味著完全不同的人生。
二:找工作前需要準(zhǔn)備的殺手锏
高考前,我們要練兵考試和集訓(xùn)?!迸R陣磨槍不快也光 ”,找工作前,我們也必須要花很多精力去完成一些必要的準(zhǔn)備。 “不打無準(zhǔn)備之仗”, 精心準(zhǔn)備和訓(xùn)練會(huì)對(duì)你有相當(dāng)正面的作用。
有人認(rèn)為“找工作要靠能力”。這話沒錯(cuò),我要說的是,“臨陣磨槍準(zhǔn)備的內(nèi)容也是能力的一部分”。 找工作其實(shí)是結(jié)果導(dǎo)向的一個(gè)事情,而不是過程導(dǎo)向。
小A和小B技術(shù)實(shí)力差不多, 小A經(jīng)過精心的準(zhǔn)備和策劃,獲得的機(jī)會(huì)顯然要遠(yuǎn)遠(yuǎn)多于小B。也許一個(gè)機(jī)會(huì),就能完全將小A的命運(yùn)改變了。
1.職場(chǎng)的十大基本素質(zhì)
大家進(jìn)入職場(chǎng)前,非常有必要明白職場(chǎng)的一些基本要領(lǐng)。其實(shí),道理都非常簡(jiǎn)單,甚至可以說是常識(shí), 關(guān)鍵是我們能否執(zhí)行下去。很多人不明白這些基本的道理,幾年下來,壞的行為固化成習(xí)慣,習(xí)慣進(jìn)一步融入到命運(yùn),最后很悲慘的成為人人鄙視的loser。所以,我希望大家從看到這篇文章起,就遵守這樣的行為準(zhǔn)則,你將會(huì)在職場(chǎng)中很快迎來自己的好運(yùn)。
①著裝整潔、個(gè)人衛(wèi)生合格
這個(gè)都不能算作職場(chǎng)素質(zhì),應(yīng)該是做人的素質(zhì)。每天逢頭垢面出門、指甲里面都是污垢、身體有異味,如何讓別人覺得你是個(gè)靠譜的人?千萬不要跟我說,你不拘小節(jié)。不拘小節(jié)是謙詞,別人可以給你面子這么說你,但你不能這么說自己。每天出門前,男士花十分鐘打理一下自己,穿一身干凈的衣服。你可以沒有阿瑪尼,穿地?cái)傌浂伎梢?,關(guān)鍵是干凈整潔。干凈整潔、形象良好,馬上可以讓人對(duì)你的印象提高N個(gè)檔次。
記得幾年前,一個(gè)學(xué)員過來找我,說:“老師,我面試了好多家了。為什么都是幾分鐘就被人打發(fā)了”。我極其驚訝地看著他,N天沒有洗澡,亂糟糟的頭發(fā),滿臉油膩,“逢頭垢面”就是形容他的。那時(shí)候是夏天,估計(jì)N天沒洗澡,一股異味?;旧衔铱梢詳喽?,這個(gè)哥們的處境。第一、沒朋友,無論男女。沒有人會(huì)愿意跟他呆的距離在1米以內(nèi),那真是一種折磨。第二、沒前途。不知道哪個(gè)瞎眼的面試官會(huì)要他?于是,我很殘忍的告訴他現(xiàn)在的處境。
我問他:“你個(gè)人衛(wèi)生是不是太差了。這個(gè)儀表,人家跟你說十分鐘都是給你天大的面子了”。他說:“我知道衛(wèi)生有點(diǎn)差。但我覺得別人不會(huì)那么庸俗的,應(yīng)該更多的關(guān)注我的技術(shù)和我的人品”。
我說:”大家時(shí)間都很有限,都很忙。第一、跟你技術(shù)水平相當(dāng)?shù)娜硕嗟檬?,沒必要花時(shí)間透過你這個(gè)外表去琢磨你的內(nèi)在。第二、你太自我為中心了。別人應(yīng)該關(guān)注你的內(nèi)在,你怎么不說,你應(yīng)該改改你的外在?連基本外在衛(wèi)生都沒有,你還能做什么?“。
他仍然固執(zhí):”講衛(wèi)生很簡(jiǎn)單,我每天花點(diǎn)時(shí)間整理一下就行了。但是…“。
我打斷他的話:”先回去洗個(gè)澡,換身干凈的衣服。你這樣的儀表,第一、不尊重你自己。第二。不尊重別人。不說工作了,你這樣怎么找女朋友?想改變你的處境,先改變你的儀表,改變你的行為。以后,每天早上花十分鐘整理一下自己,不然,你完蛋了“
后來,就沒再來找我。一年后,我收到一個(gè)短信:“高老師,感謝你的醍醐灌頂。以前,太自以為是,以為世界都是圍繞我的。那天回去后,我就真的“洗心革面”了,每天早上整理一下外表,都不用十分鐘,五分鐘就夠了。后來,我再面試只花了一周時(shí)間就上班了。這一年里,收獲很大,也有了女朋友,也有了很多男性朋友,整個(gè)人生都感覺改變了。再次謝謝您的直言不諱”。
②有正常的交流習(xí)慣
一個(gè)正常的交流習(xí)慣也是及其重要的。正常的交流習(xí)慣有如下五點(diǎn):
1.不打斷對(duì)方說話
這是對(duì)別人最基本的尊重,把話讓別人講完,也是最基本的禮貌。
2. 說話時(shí),盯著對(duì)方的眼睛。眼神堅(jiān)定,不飄忽
眼睛是心靈的窗戶。跟人交流時(shí),千萬不要邊說話,眼睛邊四處看。要緊盯著對(duì)方的眼睛,如果你實(shí)在不好意思,可以盯著鼻梁看。盯著鼻梁,在對(duì)方看來也是盯著眼睛的,效果差不多。
3. 說話時(shí),語氣不拖拉。
說話語氣肯定,有自信,千萬不要嗯嗯啊啊。
4. 沒有小動(dòng)作,但可以適當(dāng)增加手勢(shì)
抖腿、搓手、動(dòng)手碰別人這都是不禮貌的習(xí)慣。交流時(shí),不要有這些不良動(dòng)作,但是可以適當(dāng)增加手勢(shì),讓你的交流更順暢。
5. 表情放松,多一些微笑
不要將跟別人的交流搞得太過正式,放松一些,多一些微笑。
③準(zhǔn)時(shí),不遲到
一個(gè)沒有時(shí)間觀念的人,怎么可能做好事情?因此,面試不遲到、約會(huì)不遲到,這都是最基本的禮儀。而且,所有的面試、約會(huì)最好保證提前十分鐘到達(dá)。
但是,萬一發(fā)生了遲到的狀況,怎么辦?萬一由于堵車等原因遲到,要立刻打電話聯(lián)系對(duì)方,告知對(duì)方原因,并表示抱歉。
領(lǐng)導(dǎo)不下班,你也不走
對(duì)于初入職場(chǎng)的你來說,非常有必要讓領(lǐng)導(dǎo)看到你的工作態(tài)度。你可以工作做的慢,但是態(tài)度必須端正,至少要讓領(lǐng)導(dǎo)覺得你是可造之材而不是爛泥。
如果你的直接上級(jí)仍然在加班工作,你非常有必要保持同步。如果能幫上忙,可以上前問問有沒有需要你做的事情。如果暫時(shí)幫不上忙,可以坐在電腦前學(xué)習(xí)一些專業(yè)性的知識(shí)。能做到這一點(diǎn)的人,其實(shí)真的不多。做到了,也基本就可以奠定你工作認(rèn)真、愿意付出的形象,為以后創(chuàng)造更多的機(jī)會(huì)打下基礎(chǔ)。
⑤和周圍的同事打成一片
多跟同事交流、打成一片,是職場(chǎng)最基本的規(guī)矩。這在平時(shí)工作和休息時(shí),一定要多注意不能落單。最典型的:中午午餐時(shí)間,一定跟同事們一起吃飯,不要落單。
⑥有困難,就馬上尋求幫助
工作中遇到問題,自己通過查資料無法解決。立刻尋求同事幫忙,千萬不要因?yàn)椴缓靡馑奸_口而耽誤工作時(shí)間,影響公司整體的工作進(jìn)度。
⑦有責(zé)任心、事情到我這里結(jié)束
基本的責(zé)任心及其重要!千萬不要以分工清楚、不是我的事情作為推脫的借口。在大公司,分工過細(xì)是事實(shí),但是你也經(jīng)常需要參與工作之外的事情。在中小企業(yè)就更不用說了。事情到你這里,你能把他解決掉,本身就是能力的鍛煉和提升,是讓自己升值的機(jī)會(huì)。如果,你把它推脫開,不僅喪失了鍛煉的機(jī)會(huì),也讓別人看到了你的態(tài)度,看清了你的前途。
以前遇到過一個(gè)“搬椅子”的小事情。一次開會(huì),會(huì)議室少五把椅子,老板已經(jīng)坐下,說:“多了5個(gè)人,少5把椅子”。負(fù)責(zé)安排會(huì)議的人竟然問:“讓我去搬嗎?”他也許是想說,我是個(gè)女孩哎,搬不動(dòng)。也許是想說,我是個(gè)經(jīng)理哎,讓我去搬椅子,多沒面子??傊?,他說了這5個(gè)字。老板一臉錯(cuò)愕,沒說什么。一周后,這個(gè)女孩辭職走人。
工作中,你碰到了就是你的事情。解決的事情越多,你得到的鍛煉機(jī)會(huì)越多,你的能力就越強(qiáng),還怕沒有升職和發(fā)展的機(jī)會(huì)嗎?
很遺憾的是,工作中很大一部分都是責(zé)任心缺失的人。這也很幸運(yùn),這些無責(zé)任心的人會(huì)讓出很多的機(jī)會(huì)給你。一定要相信,你有沒有責(zé)任心,你的上級(jí)、你的女朋友一定能第一時(shí)間知道。
⑧學(xué)習(xí)的心態(tài)對(duì)待同事和上級(jí)、包容的心態(tài)對(duì)待同事和下級(jí)
“懂得配合才能有領(lǐng)導(dǎo)力、才能有協(xié)作力”,對(duì)待你的上級(jí)一定要抱著學(xué)習(xí)的態(tài)度。他能做到這個(gè)位置,肯定有過人之處、肯定有比你強(qiáng)的地方。把他這些優(yōu)點(diǎn)學(xué)習(xí)到位,再進(jìn)行改進(jìn),青出于藍(lán),你不就有機(jī)會(huì)了嗎?
工作中,很多同事都會(huì)私下議論上級(jí),覺得這個(gè)決定好傻、那個(gè)決定好呆。往往是由于下級(jí)和上級(jí)看問題的角度不一樣導(dǎo)致的,“屁股決定腦袋”。那么,為什么不嘗試配合一下領(lǐng)導(dǎo)的決定看看到底行不行呢?或者,你覺得確實(shí)有問題,完全可以私下跟領(lǐng)導(dǎo)說說你的感想。在企業(yè)中的人事關(guān)系要比政府關(guān)系簡(jiǎn)單的多,你私下有禮貌的提出來你的意見,往往還能博得上級(jí)的好感。
⑨忠誠(chéng)
如果你不忠于你的公司,私下貪污公款、私下為其他公司牟利。一旦有這些行為,基本上你就為人所不齒了。在公司你肯定不會(huì)有好的前途,其他公司看你這樣,無非就是利用一下你,但絕對(duì)不可能重用你。
永遠(yuǎn)不要以自己的小聰明耍弄你的上級(jí)和你的同事,這個(gè)世界,智商都差不多,誰比誰笨呀?你可以蒙他一次,兩次,不可能蒙他三次、四次。就像你考試作弊一樣,自以為很聰明,但如果你坐在講臺(tái)上監(jiān)考,你就明白,下面的動(dòng)作一覽無余,更多的時(shí)候,只是老師不愿意去把你拎出來而已。
所以,職場(chǎng)上,忠誠(chéng)是人的最基本的素養(yǎng)。
⑩辦法總比問題多,積極的心態(tài)面對(duì)問題
工作中遇到問題,不要害怕。工作就是解決一個(gè)個(gè)問題呀!既然是問題,就有應(yīng)對(duì)的辦法。想盡辦法,總能解決。不要遇到問題就牢騷滿腹:“完蛋了。這絕對(duì)不能解決”。發(fā)牢騷的人,在公司里面不僅毫無價(jià)值,而且是負(fù)價(jià)值。
2.公司調(diào)研
對(duì)于你即將要面試的公司,一定要做到“知己知彼”,在面試前做充分的調(diào)研。這樣既能讓你在面試的時(shí)候與HR有充分的互動(dòng)機(jī)會(huì),也可以避免很多無良公司的“坑”。
做公司調(diào)研需要做到如下幾個(gè)關(guān)鍵點(diǎn):
1. 公司發(fā)展的歷程
2. 公司的產(chǎn)品或者項(xiàng)目以及周期
3. 公司下一步的發(fā)展規(guī)劃
4. 公司開發(fā)使用的技術(shù)架構(gòu)
5. 公司跟開發(fā)有關(guān)的組織結(jié)構(gòu)(開發(fā)部、測(cè)試部、運(yùn)維部、產(chǎn)品部等)
3.項(xiàng)目調(diào)研
對(duì)于企業(yè)來說,會(huì)關(guān)注你大學(xué)期間成績(jī)單呢,還是關(guān)注你的項(xiàng)目經(jīng)驗(yàn)?答案顯然是:項(xiàng)目經(jīng)驗(yàn)。甚至在很多研究生復(fù)試時(shí)候,導(dǎo)師看到你的簡(jiǎn)歷上寫了很多項(xiàng)目經(jīng)驗(yàn),也會(huì)極大的增加你的分?jǐn)?shù)。五年前,我的一個(gè)學(xué)生在尚學(xué)堂培訓(xùn)時(shí)的項(xiàng)目寫在研究生復(fù)試簡(jiǎn)歷上,被導(dǎo)師問了又問,最終被中科院計(jì)算所錄取。這就是項(xiàng)目的力量。
因此,前期的項(xiàng)目準(zhǔn)備會(huì)讓你的簡(jiǎn)歷更加豐富,贏得更多的機(jī)會(huì)。一個(gè)小小的機(jī)會(huì)也許就能完全改變你的命運(yùn)。
對(duì)于項(xiàng)目調(diào)研,大家要避免誤區(qū)。不是說,一定要將項(xiàng)目的商業(yè)源碼搞到手,通讀一遍才算是完成調(diào)研;也不是說,一定要把這個(gè)項(xiàng)目代碼寫一遍;其實(shí),項(xiàng)目調(diào)研的本質(zhì)是讓你開闊眼界,增加和“面試官”的談資。
項(xiàng)目調(diào)研最重要目的是要讓你明白某個(gè)項(xiàng)目開發(fā)的流程、某個(gè)項(xiàng)目的內(nèi)在邏輯,此類項(xiàng)目常見的問題,開闊眼界,最終真正理解項(xiàng)目開發(fā)的整體流程。
項(xiàng)目調(diào)研關(guān)鍵是要做到有心!現(xiàn)代互聯(lián)網(wǎng)這么發(fā)達(dá),任何資料都可以在網(wǎng)絡(luò)上找到。我可以給大家提供各種項(xiàng)目調(diào)研的思路:
A. 打開各種網(wǎng)站,其實(shí)就是一個(gè)個(gè)項(xiàng)目。
B. 打開相關(guān)軟件公司,下載他們軟件的試用版,就可以去研究他的內(nèi)在邏輯。
C. 下載各種app,也是一個(gè)個(gè)完整的項(xiàng)目。
D. 各種開源網(wǎng)站下載的項(xiàng)目,也可以作為研究的對(duì)象。
E. 大膽出去,參加一些創(chuàng)業(yè)、創(chuàng)意相關(guān)的活動(dòng)。比如:中關(guān)村創(chuàng)業(yè)一條街的各種會(huì)議。
4.基礎(chǔ)技術(shù)準(zhǔn)備
就業(yè)前,大家需要將自己平時(shí)培訓(xùn)期間學(xué)習(xí)的技術(shù)捋一遍,全面復(fù)習(xí)一遍。臨陣磨槍仍然是最重要的應(yīng)急手段,面試前的準(zhǔn)備就像高考前一樣,越充分越好。
但是,需要記住如下兩點(diǎn):
1. 對(duì)于一些常見的面試和筆試問題,一定要反復(fù)練習(xí),最好能背下來。
2. 對(duì)于一些工作和面試不常見的問題,記住結(jié)論即可,不要糾結(jié)。不要因?yàn)橐恍┬「怕实膯栴}而浪費(fèi)太多的時(shí)間。畢竟,任何人都沒有必要有能力可以應(yīng)對(duì)所有的問題,只要能應(yīng)對(duì)常見的問題足以實(shí)現(xiàn)就業(yè)。
5.熱門技術(shù)準(zhǔn)備
軟件行業(yè)技術(shù)更新較快,經(jīng)常會(huì)出現(xiàn)新的技術(shù)。但是,這些技術(shù)通常不會(huì)馬上應(yīng)用于企業(yè)中,企業(yè)一般都會(huì)使用穩(wěn)定和大眾化的技術(shù)。所以,企業(yè)應(yīng)用技術(shù)通常都有2-3年的滯后期。
身處軟件開發(fā)第一線的人往往對(duì)新技術(shù)學(xué)習(xí)也會(huì)滯后,畢竟企業(yè)不用,大家還是不愿意多花時(shí)間和精力去學(xué)習(xí)。但是,作為程序猿往往對(duì)這些技術(shù)保留了極大的好奇心。絕大部分程序猿會(huì)心想:“等我有時(shí)間,我一定要學(xué)習(xí)一下”。
這種滯后性,就是剛進(jìn)入軟件行業(yè)的新人的機(jī)會(huì)。如果你是做IOS開發(fā)的,簡(jiǎn)歷上寫明會(huì)使用swift語言開發(fā),就會(huì)引起一直使用Object-C開發(fā)項(xiàng)目的面試官極大的興趣。如果你是做JAVA開發(fā)的,會(huì)使用微服務(wù)架構(gòu),了解大數(shù)據(jù)相關(guān)的技術(shù),也會(huì)引起面試官較大的興趣。而且,更有意思的是,你不需要精通這些新技術(shù),只要了解即可。就能很快的引起面試官的興趣,畢竟“好奇心”是程序猿最大的特點(diǎn)。
對(duì)于熱門新技術(shù)的了解,可以明明白白的告訴對(duì)方,你就是一個(gè)喜歡技術(shù)、喜歡鉆研的典型的程序猿。這會(huì)給你起到加薪加分的效果?!?1.5倍薪水定律”就會(huì)起到作用。
6.更高端技術(shù)準(zhǔn)備
技術(shù)行業(yè)是一個(gè)非常干凈的行業(yè),付出和得到基本是正比關(guān)系,你不需要靠關(guān)系靠背景。作為程序猿,學(xué)習(xí)就是本能,學(xué)習(xí)跟你的薪水是成正比的!學(xué)習(xí)越多,薪水越高。作為一個(gè)專業(yè)的程序猿,必須做好進(jìn)一步提升的準(zhǔn)備。千萬不能有已經(jīng)到頭的想法!一個(gè)二三十歲,剛?cè)胄械哪贻p人,如果產(chǎn)生了已經(jīng)學(xué)夠的想法,那說明你的前途也到盡頭了!”觀念決定行動(dòng),最終決定命運(yùn)”。
對(duì)于本專業(yè)更加高端的技術(shù),一定要保持學(xué)習(xí)的心態(tài)。即使,這些技術(shù)暫時(shí)用不到。對(duì)于開闊眼界,提高思維境界,應(yīng)對(duì)面試都是極好的。掌握或了解本專業(yè)更高端的技術(shù),加薪加分效果也很明顯。“1.5倍薪水定律”效用也非常明顯。
7.本專業(yè)之外的技術(shù)準(zhǔn)備
很多人會(huì)以:“專業(yè)貴精不貴多”,“一招鮮吃遍天”,作為不學(xué)習(xí)其他技術(shù)的借口。這些話沒有錯(cuò),我也贊成這些話。但是,這些話不能作為不學(xué)習(xí)的理由。
一個(gè)學(xué)習(xí)安卓、IOS開發(fā)的程序猿當(dāng)然最重要的就是掌握本專業(yè)的開發(fā)技能,但是如果你還了解后臺(tái)服務(wù)器程序的開發(fā),這就是你不同于普通程序猿的優(yōu)勢(shì)。
一個(gè)學(xué)習(xí)JAVAEE開發(fā)的程序猿,學(xué)好JAVAEE是最重要的,再了解大數(shù)據(jù)開發(fā)的知識(shí)、人工智能開發(fā)的知識(shí), 也可以觸類旁通, 讓自己獲得更多技巧。同時(shí),在面試JAVAEE的時(shí)候,你竟然也懂大數(shù)據(jù)、懂人工智能(也許只是皮毛)?但也一定可以給你的面試加分。
知識(shí)面寬往往意味著好學(xué),潛力巨大。經(jīng)過兩三年的磨練后,熟悉各種技術(shù)的你,必將迎來一次發(fā)展的機(jī)遇。為什么機(jī)遇一定會(huì)給你?顯然,一般人是做不到這一點(diǎn)的。
我們有一個(gè)學(xué)員學(xué)完JAVAEE后,又學(xué)習(xí)了大數(shù)據(jù)開發(fā),很多人說他:“好傻,你去公司只是做一份工作。學(xué)那么多干什么?“。但是,這些嘲笑他的人錯(cuò)了。這位學(xué)員三個(gè)月后,就成了公司項(xiàng)目的負(fù)責(zé)人,很簡(jiǎn)單,就是因?yàn)樗鸍AVAEE會(huì),大數(shù)據(jù)也會(huì),公司正好需要兩方面都懂的人。
“如果因?yàn)閷W(xué)習(xí),別人說你傻”,我們只能回應(yīng):“別人笑我太瘋癲,我笑他人看不穿”。這個(gè)社會(huì),如果不能跟別人拼爹,那就只能跟別人拼頭腦拼血汗了。
8.共同話題準(zhǔn)備
面試你的人基本都是程序員,或者程序員出身,因此你們?cè)趯?duì)話中都可以找到很多共同話題。那么,為了讓我們的面試充滿各種“亮點(diǎn)”,對(duì)于共同話題的準(zhǔn)備就相當(dāng)有必要了。“用心去準(zhǔn)備的面試,連面試官都會(huì)被你認(rèn)真的態(tài)度打動(dòng);反過來說,如果連面試都不重視的人,我怎么相信你會(huì)對(duì)工作更有責(zé)任?”。
我們可以準(zhǔn)備以下這些問題:
1. 是否曾經(jīng)耗費(fèi)幾個(gè)小時(shí)甚至幾天的時(shí)間來追蹤一個(gè)頑固的bug?
2. 你有沒有因?yàn)槟硞€(gè)問題加班到半夜的經(jīng)歷?
3. 你喜歡某種編程語言的哪一點(diǎn)?
4. 經(jīng)常訪問哪個(gè)程序員的網(wǎng)站?
5. 你最喜歡看的編程類的書籍是什么?
6. 關(guān)于IDE,什么事最讓你抓狂?
7. 精心準(zhǔn)備幾個(gè)能說明你技術(shù)能力的專業(yè)問題,在面試時(shí)盡量發(fā)揮出來。
9.自我模擬面試和對(duì)練
開始投遞簡(jiǎn)歷前,可以五人一組互相對(duì)練,進(jìn)行角色扮演。分組練習(xí)的好處非常明顯,可以讓我們?cè)诜浅6痰臅r(shí)間里得到提升。分組練習(xí)的角色有:面試官、應(yīng)聘者、旁觀者。
分組練習(xí)的好處有:
1. 面試官面試別人可以體會(huì)如何設(shè)問,對(duì)方回答是否得體
2. 應(yīng)聘者可以身臨其境體驗(yàn)被面的過程。
3. 旁觀者可以清晰的看到面試官的優(yōu)缺點(diǎn)、應(yīng)聘者的優(yōu)缺點(diǎn)。加強(qiáng)學(xué)習(xí),避免自己發(fā)生這些問題。
但是,也不能過多的訓(xùn)練。以每人各扮演兩次角色(兩次面試官、兩次應(yīng)聘者)為宜。然后,馬上投遞簡(jiǎn)歷,開始實(shí)戰(zhàn)?。?/p>
三:面試準(zhǔn)備
1. 簡(jiǎn)歷的作用
一份格式規(guī)范、要點(diǎn)突出的簡(jiǎn)歷是你找工作的“敲門磚”,值得你花上一周、甚至兩周時(shí)間精心打磨。這樣你會(huì)獲得更多的機(jī)會(huì)。當(dāng)然,簡(jiǎn)歷僅僅是敲門磚,任何一個(gè)面試官都不可能僅憑簡(jiǎn)歷就雇傭一個(gè)人。
2.簡(jiǎn)歷兩個(gè)靈魂
第一要點(diǎn):必須自己親自寫簡(jiǎn)歷。
簡(jiǎn)歷必須每個(gè)字都自己寫,絕對(duì)不能抄!自己親自寫一次簡(jiǎn)歷,相當(dāng)于把技術(shù)復(fù)習(xí)一遍,把項(xiàng)目捋一遍,對(duì)于其中的關(guān)鍵點(diǎn)可以做到心中有數(shù)。 面試中的很多問題都是根據(jù)簡(jiǎn)歷問出來的,只有自己親自寫一遍才能靈活應(yīng)對(duì)。
第二要點(diǎn):簡(jiǎn)歷要突出自己的核心競(jìng)爭(zhēng)力。
一個(gè)職位會(huì)有幾十、幾百份簡(jiǎn)歷的投遞!投遞簡(jiǎn)歷顯然是存在競(jìng)爭(zhēng)關(guān)系的,一定要對(duì)簡(jiǎn)歷作出適當(dāng)?shù)陌b,就像去相親要化妝一樣。 不包裝的簡(jiǎn)歷如同沒有穿衣服逛街一樣,雖然顯得本真,但是也很神經(jīng)病,很傻。在面試官看來,沒有包裝的簡(jiǎn)歷會(huì)顯得你這個(gè)人不識(shí)時(shí)務(wù),不靈活,而不會(huì)覺得你這個(gè)人本真(其實(shí)就是天真)。 處在世俗社會(huì)里面,我們要隨“社會(huì)大流”,別人化妝我們也要跟進(jìn),不求占別人便宜,但是也不能吃虧。但是,包裝不能欺騙企業(yè),掌握好“度”。
3.一份完美的簡(jiǎn)歷(6大要素)
1.囊括相關(guān)技術(shù)關(guān)鍵詞,注意上下文
公司每天會(huì)收到幾十份簡(jiǎn)歷,篩選這些簡(jiǎn)歷往往是不懂技術(shù)的招聘人員,因此盡量寫上你會(huì)的技術(shù)的關(guān)鍵詞。
2.文筆要好,要點(diǎn)突出,簡(jiǎn)明扼要
如果你不知道如何組織文字,可以先嘗試將想表達(dá)的內(nèi)容講給朋友聽,這非常有效。第一、可以起到互動(dòng)、交流的作用,讓你的朋友給你指正。第二、可以捋思路。第三、為面試時(shí)的回答打下堅(jiān)實(shí)基礎(chǔ)。
3.對(duì)工作經(jīng)驗(yàn)、項(xiàng)目經(jīng)驗(yàn)、實(shí)習(xí)經(jīng)驗(yàn)作出解釋
如果你聲稱具備某種工作經(jīng)驗(yàn)、項(xiàng)目經(jīng)驗(yàn),那么就必須說明是如何獲得的。如果簡(jiǎn)歷上寫了“3年java開發(fā)經(jīng)驗(yàn)”、“3年ios開發(fā)經(jīng)驗(yàn)”,不進(jìn)行進(jìn)一步的說明,就顯得太虛假了。 不說明倒也沒關(guān)系,但是面試官收到的簡(jiǎn)歷可不止你這一份,畢竟還是有很多人進(jìn)行了詳細(xì)的說明。你不說明就意味著白白丟失了很多機(jī)會(huì)。 就像去相親見面,但是你不化妝、不打扮,穿著拖鞋去了,那我想你太吃虧了。 我們不想占別人便宜,但絕不能吃虧。
4.工作經(jīng)歷不要留有情況不明的空白期
簡(jiǎn)歷中,不要留下特別長(zhǎng)的空白期,這會(huì)讓人覺得你心中有鬼。
5.個(gè)人愛好和特殊證書
很多人會(huì)寫上自己的個(gè)人愛好:“卡拉ok,聽音樂,看電影”。這些不能體現(xiàn)個(gè)人素質(zhì)的內(nèi)容不如不寫。但是,如果你是籃球校隊(duì)、乒乒球?qū)W校冠軍、廚藝大賽冠軍這些倒是可以寫在自己的簡(jiǎn)歷上。
6.簡(jiǎn)歷結(jié)構(gòu)明了,條理清晰
簡(jiǎn)歷結(jié)構(gòu)一定要清晰明了,便于招聘者快速閱讀。不過,現(xiàn)在的招聘網(wǎng)站都有標(biāo)準(zhǔn)的模板,應(yīng)聘者往里填數(shù)據(jù)即可。
如下是一份比較規(guī)范的簡(jiǎn)歷,該學(xué)員當(dāng)時(shí)年薪為30萬(稅前,北京)。 大家可以作為奮斗的參考。當(dāng)然,寫簡(jiǎn)歷簡(jiǎn)單,掌握簡(jiǎn)歷上的內(nèi)容難??梢哉f,簡(jiǎn)歷上的每個(gè)字都代表“一段血淚史”。
4.簡(jiǎn)歷的常見錯(cuò)誤
“千里之堤,潰于蟻穴”, 簡(jiǎn)歷可以讓招聘者對(duì)你形成第一印象。如果簡(jiǎn)歷中存在細(xì)小的錯(cuò)誤,也會(huì)被視為不認(rèn)真的體現(xiàn),可能會(huì)讓你失去很多機(jī)會(huì)。
通常有如下錯(cuò)誤:
1.手機(jī)號(hào)、qq號(hào)錯(cuò)誤、電子郵箱格式不正確
真的有傻瓜竟然會(huì)把自己手機(jī)號(hào)碼寫錯(cuò),或者寫了已經(jīng)停機(jī)的舊手機(jī)號(hào)碼。然后,坐等招聘電話。 這些基本聯(lián)系方式,一定要核準(zhǔn)無誤。
2.技術(shù)詞匯拼寫錯(cuò)誤
這也是常見的錯(cuò)誤,技術(shù)詞匯單詞錯(cuò)誤、大小寫不對(duì)等等,這會(huì)直接降低你的第一印象。連自己的簡(jiǎn)歷都不認(rèn)真,還能做什么? 就像出門不洗臉的人,還能期望他做什么?
3.排版混亂
排版必須清晰,大方,結(jié)構(gòu)整齊。
4.抄襲別人的簡(jiǎn)歷
這是對(duì)自己和他人最大的不負(fù)責(zé)任。想找工作連個(gè)簡(jiǎn)歷都懶得寫,這種態(tài)度如何處人處事?面試中,針對(duì)簡(jiǎn)歷提出的問題,你如何能回答?
所以,抄簡(jiǎn)歷,一定是死路一條。
5.注冊(cè)招聘網(wǎng)站和簡(jiǎn)歷投遞
簡(jiǎn)歷準(zhǔn)備好以后,必須盡快的進(jìn)入投遞環(huán)節(jié)。不要等待,不要老琢磨“我要把各個(gè)環(huán)節(jié)搞明白再投簡(jiǎn)歷和面試”,這是錯(cuò)誤的想法。我們必須在戰(zhàn)場(chǎng)中提高自己,實(shí)戰(zhàn)中提高自己是最快的。
首先,注冊(cè)著名招聘網(wǎng)站或者地方類招聘網(wǎng)站,并在這些網(wǎng)站上完善簡(jiǎn)歷。智聯(lián)招聘、51job、中華英才、拉勾網(wǎng)等這些網(wǎng)站是必須要注冊(cè)的,一個(gè)都不能少。如果在地方城市找工作,地方類招聘網(wǎng)站也可以注冊(cè),比如:長(zhǎng)沙的芙蓉人才網(wǎng)、太原人才網(wǎng)等。
簡(jiǎn)歷投遞一般采用海投的方式,并且要隔兩三天海投一次。 海投會(huì)給企業(yè)招聘者帶來一定的麻煩,但是對(duì)于應(yīng)聘者是最高效的方式。對(duì)于應(yīng)聘者來說,時(shí)間很寶貴。千萬不要把時(shí)間花在一個(gè)個(gè)篩選企業(yè)上面,對(duì)于剛?cè)胄械男氯?,還沒有資格篩選企業(yè)。至于有善良的應(yīng)聘者害怕企業(yè)的HR麻煩,我只能說: “你想多了”。
一份合格的簡(jiǎn)歷海投完后,你就會(huì)接到一些面試電話。下面就應(yīng)該學(xué)習(xí)怎么應(yīng)對(duì)面試電話了。
6.接面試電話如何應(yīng)對(duì)
接到面試電話的時(shí)候,一些基本的電話禮儀你需要知道。通過如下的場(chǎng)景模擬,讓你對(duì)接電話后的流程有一個(gè)基本的了解。
流程如下:
1. 接聽電話第一句通常是: “喂(二聲),你好”。
2. 對(duì)方通常會(huì)說:“我是xxx公司,我們這里收到你的簡(jiǎn)歷。你明天上午10點(diǎn)有時(shí)間來我公司面試嗎?”
3. 你通常會(huì)說:“可以,沒有問題。貴公司的地址在哪里?”。注意,如果時(shí)間上不允許,比如跟你已經(jīng)約好的一家公司沖突了。你也可以大方的告訴別人,明天上午有面試了,能不能換一個(gè)時(shí)間。
4. 對(duì)方會(huì)說: “我們公司在海淀區(qū)xx大廈12層1201”。
5. 你可以說: “那我到了以后,跟您聯(lián)系嗎?您怎么稱呼?”
6. 對(duì)方會(huì)說: “我姓高。到了,你跟前臺(tái)說找高七七就行”。
7. 如果你對(duì)自己查詢交通路線不太放心,可以問一下對(duì)方,如何到他們公司。如果有信心,就不用問了。
8. 最后,你一定要這樣說,“好的。謝謝你。我跟您確認(rèn)一下。您的公司名字是:xxx公司。明天上午10點(diǎn),在海淀區(qū)xx大廈12層1201。對(duì)嗎?”
9. 對(duì)方回答: “是的。沒有問題。還有其他問題嗎?”
10.你回答: “沒有了。謝謝。我明天準(zhǔn)時(shí)到貴公司”。
11.對(duì)方回答: “好的。再見”。
12.你回答:“OK。再見”。等對(duì)方掛掉電話后,你再掛掉電話。即可結(jié)束本次電話邀約。通過一次交流,將公司名稱、地址、面試時(shí)間、聯(lián)系人問清楚即可。
然后,立刻馬上,使用手機(jī)或者電腦查詢這個(gè)公司相關(guān)的信息,越詳細(xì)越好。直到能夠回答如下問題為止:
1. 公司發(fā)展的歷程
2. 公司的產(chǎn)品或者項(xiàng)目(該公司同類型公司的產(chǎn)品和項(xiàng)目,各自的優(yōu)劣勢(shì)分析)
3. 公司下一步的發(fā)展規(guī)劃
這些問題,將會(huì)讓你在后續(xù)的面試中獲得意向不到的收獲。
7.去公司之前的準(zhǔn)備
去公司面試前,做到如下五點(diǎn):
1. 查詢和調(diào)研該公司的基本情況
2. 個(gè)人衛(wèi)生整潔,著裝干凈
3. 提前10-15分鐘到達(dá),不遲到(萬一遲到,一定電話通知對(duì)方,告知實(shí)情)
4. 將以前面試遇到的問題再預(yù)演一遍
5. 將筆試題再?gòu)?fù)習(xí)一遍
8.筆試
去企業(yè)筆試,通常都會(huì)做一份該企業(yè)的筆試題目,作為基本的考核。通常,企業(yè)筆試題目都大同小異,都是一些常見工作問題,不會(huì)出現(xiàn)偏題難題怪題。如果你之前,已經(jīng)做過常見筆試題目,絕大部分題目都可以囊括。所以,只要好好準(zhǔn)備,筆試不會(huì)構(gòu)成特別大的問題。筆試過后,通常都會(huì)帶你進(jìn)入面試環(huán)節(jié)。面試官通常都是你以后的直接上級(jí),這時(shí)候就需要你好好表現(xiàn)了。
四: 面試
1.面試時(shí),為什么沒必要緊張?
第一、從心態(tài)上你要把這次面試看做一次練習(xí),成敗都可。畢竟,說實(shí)話,面試成功是小概率事件,按照一個(gè)人面試十家公司成功一家來看,每家成功的概率只有10%。所以,完全沒有必要緊張。
第二、面試官在跟你交流的時(shí)候,并不會(huì)將你說的每個(gè)字都記在心里。畢竟,他也有工作壓力,他可能在想:“下午開會(huì),怎么跟老板交代的問題”。面試官多數(shù)時(shí)候,是處于一個(gè)完全放松的狀態(tài),聽你回答只是聽個(gè)流程和大概,并不會(huì)全身心投入。所以,你盡可以放輕松的交流。你的若干小問題,對(duì)方通常都不會(huì)注意到。
第三、面試完你以后,面試官還要再面試N個(gè)人。最后留到腦子里的就是你當(dāng)時(shí)表現(xiàn)的打分結(jié)果,不會(huì)對(duì)你們這些應(yīng)聘者每個(gè)都留下特別多的回憶。如果你覺得你說的做的每個(gè)細(xì)節(jié),面試官都看到了。通常,是你想多了。
第四、失敗又有何懼?此地不留爺,自有留爺處!天下公司那么多,只要我多面試,多總結(jié)問題。即使只有1%的機(jī)會(huì),面試100家不是也能面上嗎?
當(dāng)然,上面是給大家做“失敗并不可怕的心態(tài)調(diào)整”,并不意味著你就可以浪費(fèi)大把面試機(jī)會(huì)而不珍惜。
2.面試中的禮儀
面試中,遵循正常的職場(chǎng)禮儀即可。這是“最基本要求”,如果你有任何一點(diǎn)問題,都可以讓你的成功率立馬降低50%以上。
所以,一定要遵守基本原則:
1. 微笑、禮貌、大方
2. 有正常的交流習(xí)慣,沒有小動(dòng)作(抖腿、搓手等)
3. 絕對(duì)不能爭(zhēng)論
4. 衛(wèi)生干凈,衣冠整潔即可(沒必要西裝領(lǐng)帶)
面試開始時(shí):
1.面試官進(jìn)入、求職者從座位起立,微笑說:“你好”。
2.如果對(duì)方是男士,可以主動(dòng)伸手握手。如果是女士,不要主動(dòng),看對(duì)方示意即可。
面試結(jié)束時(shí):
1.結(jié)束時(shí),一定要對(duì)面試官表示感謝。
2.將座位放回原位,幫助收拾一下桌面衛(wèi)生,所有物品物歸原位。
3.常見技術(shù)面試場(chǎng)景分析
無論面試官是否是技術(shù)人員出身,我們一定要給出充分準(zhǔn)備的回答,發(fā)音準(zhǔn)確的技術(shù)名稱,不要有所保留,盡可能仔細(xì)地回答問題。一定要在面試前,準(zhǔn)備本專業(yè)至少20個(gè)常見的專業(yè)技術(shù)問題,能對(duì)答如流,可以變成自己的話說出來。當(dāng)然,再完美的準(zhǔn)備也會(huì)碰到不會(huì)的問題,那么如何應(yīng)對(duì)呢?
1. 面試官提出的某個(gè)技術(shù),你不會(huì)。
第一,絕對(duì)不能就說“不會(huì)”兩個(gè)字。太傻,太二,無法繼續(xù)交流,典型直男癌。
第二,態(tài)度上正視差距,如實(shí)回答?!斑@個(gè)技術(shù)我確實(shí)不會(huì)。之前的項(xiàng)目沒用到,只是用了xxx技術(shù)。面試完后,我也想學(xué)習(xí)一下”。
這樣,既說明了實(shí)際情況和自己的學(xué)習(xí)態(tài)度,也引向了你會(huì)的xxx技術(shù),從而可能會(huì)小小的帶一波節(jié)奏。
2. 你對(duì)這個(gè)技術(shù)有一定的認(rèn)知,但沒有把握。
對(duì)策:可以告訴面試官去年項(xiàng)目不太忙的時(shí)候,我學(xué)習(xí)過幾天,后來項(xiàng)目忙了就沒繼續(xù)看。然后,簡(jiǎn)單說說對(duì)這個(gè)技術(shù)的理解。最后,問一下,我們公司是否在使用這個(gè)技術(shù)?我也正想撿起來再學(xué)習(xí)一下。
3. 面試官提出尖銳的問題,質(zhì)疑你的簡(jiǎn)歷或者技術(shù)能力。
面試官:“我在你的簡(jiǎn)歷中沒有看到對(duì)我們有用的項(xiàng)目經(jīng)驗(yàn),你的技術(shù)能力也不符合我們的要求。”
面試者:“可能是我的經(jīng)歷還是太淺。對(duì)咱們公司這塊業(yè)務(wù)確實(shí)沒涉及過。您這塊還有什么技術(shù)要求,我可以推薦我的朋友過來試試”。
當(dāng)碰到直接質(zhì)疑的情況,面試成功的概率就非常低了。但也不能緊張,天下公司這么多,此處不留人,自有留我處。但要盡量多的跟面試官交流,獲得更多的行業(yè)知識(shí),為下一次面試做準(zhǔn)備。
4. 問到自己特別了解的技術(shù)
好吧,發(fā)揮吧,少年!還不眉飛色舞好好表現(xiàn)表現(xiàn)。
4.十大非技術(shù)面試問題及策略
社會(huì)競(jìng)爭(zhēng)很殘酷、面試其實(shí)就是一場(chǎng)表演,企業(yè)永遠(yuǎn)喜歡可以隨機(jī)應(yīng)變、聰明的求職者。而不喜歡看似老實(shí)、實(shí)則笨拙不懂變通的求職者。所以,大家也要按套路出牌,出面試官喜歡的牌才能有更多的勝算。
面試官也知道求職者肯定是經(jīng)過精心準(zhǔn)備的表演,但是仍然會(huì)認(rèn)可。如果你連面試都懶得用心準(zhǔn)備、你肯定也不會(huì)為了工作而用心。這是面試官內(nèi)在的邏輯。
1.自我介紹
這個(gè)問題是面試的時(shí)候最常被問到的問題。很多人回答這些問題會(huì)陷入一個(gè)誤區(qū),以為簡(jiǎn)單介紹一下自己的名字、多少歲、哪里工作過、什么大學(xué)什么專業(yè)、有什么愛好就好了。如果這樣回答,你的自我介紹只能算是30分。
“面試官最想聽他想知道的內(nèi)容”,換位思考一下,假如你是面試官最想知道什么?顯然,就是”應(yīng)聘者能不能勝任現(xiàn)在的崗位”。所以,應(yīng)聘者應(yīng)該更多的從這個(gè)角度出發(fā)思考問題。
所以,我們一般建議應(yīng)聘者在自我介紹中側(cè)重于自己“實(shí)戰(zhàn)經(jīng)驗(yàn)”的介紹。比如:在xxx公司從事過什么工作、做過什么項(xiàng)目、我為什么可以勝任貴公司的崗位。這些才是面試官最想聽到的內(nèi)容。
好的自我介紹應(yīng)該分如下幾個(gè)部分:
a.實(shí)戰(zhàn)經(jīng)驗(yàn)描述
實(shí)戰(zhàn)經(jīng)驗(yàn)可以是在公司的工作經(jīng)驗(yàn)、實(shí)習(xí)經(jīng)驗(yàn)、甚至是參與大學(xué)老師的項(xiàng)目都可以。你需要告訴面試官實(shí)戰(zhàn)經(jīng)驗(yàn)的公司名稱、時(shí)間多長(zhǎng)、做了什么項(xiàng)目、有什么收獲。說到此處,你這個(gè)問題就可以拿到60分了。
b.為什么來應(yīng)聘貴公司
根據(jù)自己網(wǎng)上查到的該公司的基本信息,可以說一下對(duì)公司的了解情況:看好公司未來發(fā)展前景、想進(jìn)來以后多多學(xué)習(xí)。說到此處,你這個(gè)問題可以拿到80分。
c.我可以勝任貴公司這個(gè)崗位的原因
前面兩點(diǎn)說完后。結(jié)合自己的實(shí)戰(zhàn)經(jīng)歷和應(yīng)聘公司的情況,告訴面試官我可以勝任目前的崗位、并且有決心干好。說到此處,你這個(gè)問題可以拿到100分。靜等面試官欣賞的、色瞇瞇的眼神吧。
2.你的優(yōu)點(diǎn)是什么?
優(yōu)缺點(diǎn)的描述是想看看應(yīng)聘者對(duì)自己的了解程度。求職者關(guān)于優(yōu)點(diǎn)的描述一定要跟工作相關(guān),并且有具體的案例描述你的優(yōu)點(diǎn)。
面試官通常喜歡具備如下優(yōu)點(diǎn)的程序猿:
1. 態(tài)度好
2. 技術(shù)實(shí)力強(qiáng)
3. 熱愛技術(shù)、學(xué)習(xí)能力強(qiáng)
大家描述的自己的優(yōu)點(diǎn)可以圍繞這三點(diǎn)展開??梢詤⒖迹骸豆鞠矚g什么樣的程序猿》。
3.你的缺點(diǎn)是什么?
求職者面對(duì)這個(gè)問題一定要把握一個(gè)原則:“缺點(diǎn)不能跟工作相關(guān)”。你不能說“我的缺點(diǎn)就是不喜歡技術(shù)、不喜歡加班”,那你完蛋了。缺點(diǎn)盡量不跟工作相關(guān)。比如:我覺得我的缺點(diǎn)是比較內(nèi)向、比較宅。周末我可以一個(gè)人在家悶頭鉆研技術(shù)、但是就是不想走出去跟別人去玩。這方面我覺得應(yīng)該改一改。
缺點(diǎn)也不能說的太假。比如:我覺得我的缺點(diǎn)就是工作太拼命了,不注意身體。這么一說,面試官立馬就噴了。
4.對(duì)我們公司了解嗎?
我一直強(qiáng)調(diào),面試前一定要查詢?cè)摴鞠嚓P(guān)的信息。所以,這個(gè)問題是必須要回答的。如果面試官?zèng)]問你這個(gè)問題。你也要在其他問題中說出你對(duì)他們公司的了解。
5.為什么從上一家公司離職?
公司都希望穩(wěn)定、有培養(yǎng)價(jià)值的員工。因此,都會(huì)特別關(guān)注你的離職理由。離職理由盡量正能量、客觀,絕對(duì)不能表示對(duì)上一家公司和上級(jí)的不滿。比如:我覺得上一個(gè)公司太摳了,加班還沒有加班費(fèi)。好了,你這么負(fù)能量的回答,等于判了自己死刑。哪個(gè)公司都是摳門的、IT行業(yè)加班普遍是沒有加班費(fèi)的。
6.如何看待加班?
面試官問這個(gè)問題顯然是他們公司經(jīng)常加班的。如果你確實(shí)接受不了也可以說出來。但是,對(duì)于剛?cè)胄械哪贻p人一定要了解,加班是非常正常的一件事。
回答這個(gè)問題,一定要客觀的說。你說你喜歡加班,這有點(diǎn)太扯了。你可以說:“項(xiàng)目緊的時(shí)候,加班也很正常?,F(xiàn)在行業(yè)情況就是這樣的,沒有問題。而且,我還年輕,能扛的住”。
7.如何看待出差?
出差在有的人眼里看是辛苦,在有的人眼里看是經(jīng)歷。有的年輕人就特喜歡出差,感覺可以去不同的城市、有不同的體驗(yàn)。對(duì)于求職者來說,可以根據(jù)自己實(shí)際情況說出自己的真實(shí)感受。如果你確實(shí)無法接受、也可以明確拒絕。
8.你的職業(yè)規(guī)劃是什么?
這個(gè)問題是想了解求職者的規(guī)劃能力、對(duì)于自己是否有規(guī)劃?求職者可以根據(jù)自己的情況正常的說出自己的職業(yè)規(guī)劃,不能太低人一等、也不能好高騖遠(yuǎn)。
一般較好的回答如下:
“這三年,我還是想腳踏實(shí)地的鉆研技術(shù)。希望通過三年的努力成為我們這個(gè)行業(yè)比較牛的人。三年后,我想學(xué)著做管理。再用兩年時(shí)間,一共五年,最終可以獨(dú)當(dāng)一面”。
三年鉆研技術(shù)、顯得你很踏實(shí)。五年進(jìn)入管理,這是一個(gè)有心人的正常的晉升流程。
9.你對(duì)跳槽怎么看?
公司非常不喜歡頻繁跳槽的人,所以你對(duì)這個(gè)問題的回答一定要謹(jǐn)慎對(duì)待。
經(jīng)典回答如下:
“現(xiàn)在這個(gè)行業(yè)大家都很浮躁,跳槽頻繁。但是,我并不喜歡頻繁的換環(huán)境。我想,我只要在一個(gè)公司扎扎實(shí)實(shí)做下去,不可能沒有機(jī)會(huì)。做好了,薪水不可能比跳槽的低”。
10.你還有什么問題要問我嗎?
這是通常面試要結(jié)束的時(shí)候的問題。求職者一定不能說:“我沒有問題”。一下子就把你搞得很low,最后一定要問一個(gè)問題問回去,即使面試官?zèng)]有這個(gè)問題。結(jié)束時(shí),也一定要問個(gè)問題。
求職者也不能太過于急功近利的問:“今天我能面試上嗎?你能給我多少錢?”。雖然你很想知道,但這么一問,你的檔次立馬降低。通常的問題應(yīng)該是跟工作相關(guān)。
技術(shù)人員可以這樣問:
1. 今天我們聊到的某個(gè)技術(shù),我想回去好好研究一下,您這里有什么資料嗎?
2. XX新技術(shù),您怎么看他的發(fā)展?我想趁這幾天時(shí)間寬裕,學(xué)習(xí)一下。
3. XXX技術(shù),我感覺您好像有比較深的研究。我也想學(xué)學(xué),您能推薦些資料嗎?
類似這樣的問題,可以讓你喜愛技術(shù)的特點(diǎn),立馬暴露的一覽無余。本來面試70分的你,立刻加到80分。而你,只是問了個(gè)問題而已,回答的竟然是面試官。這么好的無本生意,不做是不是有點(diǎn)可惜?
5.面試后一定要總結(jié)
很多人面試后,就開始等公司的消息,焦躁不安,這絕對(duì)是錯(cuò)誤的做法。面試后,大局已定,戰(zhàn)爭(zhēng)已經(jīng)打完了,還需要再糾結(jié)嗎?我們應(yīng)該做的事是為下一場(chǎng)面試做準(zhǔn)備,立刻做面試的總結(jié),沒有總結(jié)就沒有進(jìn)步。
必須總結(jié)如下內(nèi)容:
1. 列出問了哪些問題?
2. 列出自己回答較好的問題
3. 列出自己回答交差的問題,并進(jìn)行改進(jìn)
心態(tài)上不要等待,”謀事在人,成事在天”,成了好,不成也無所謂,就當(dāng)面試失敗了。立刻,投入緊張的復(fù)習(xí)和下一次面試中。
一:JAVA學(xué)習(xí)知識(shí)點(diǎn)明細(xì)以及配套視頻
這是JAVA工程師的完整學(xué)習(xí)路徑,我們也會(huì)公布大部分的學(xué)習(xí)視頻,這些視頻來自于我們的線下培訓(xùn)課程,大多數(shù)直接錄制于課堂,歡迎大家下載或者在線觀看。
我們每個(gè)月都會(huì)更新相應(yīng)的視頻,大家可以持續(xù)關(guān)注下載地址:
http://bj0393.com.cn/javashipin.html (java視頻的拼音,方便記憶)
1.JAVASE
首先要學(xué)JavaSE,這是毋庸置疑的。與此同時(shí),和JavaSE的學(xué)習(xí)同步,建議大家研究一下數(shù)據(jù)結(jié)構(gòu)與算法。
在JavaSE完成之后,可以試著完成一些小項(xiàng)目,同時(shí)關(guān)注一下設(shè)計(jì)模式的內(nèi)容,不必強(qiáng)求自己能夠完全掌握各種細(xì)節(jié),往前走吧。
掌握一種編程工具,比如說Eclipse。當(dāng)然,工具掌握很簡(jiǎn)單,大約只需要30分鐘。
建議大家讀北京尚學(xué)堂的《實(shí)戰(zhàn)JAVA程序設(shè)計(jì)》,同時(shí)可以配合《java300集視頻教程》(好吧,書是我寫的,視頻也是我錄的。個(gè)人認(rèn)為還是很不錯(cuò)的)。這里有JAVASE講解、有項(xiàng)目實(shí)戰(zhàn)、有數(shù)據(jù)結(jié)構(gòu)、有算法、有JDK源碼解讀、有底層內(nèi)存分析、有設(shè)計(jì)模式,從一開始就植入了“高手思維和高手習(xí)慣”, 可以說是非常適合大學(xué)生和入門學(xué)習(xí)的人使用。
學(xué)習(xí)列表和學(xué)習(xí)說明如下:
- 知識(shí)塊
- 1.JAVA入門
- 2.面向?qū)ο蠡A(chǔ)
- 3.飛機(jī)小項(xiàng)目(前兩個(gè)階段練習(xí))
- 4.面向?qū)ο笊钊?/li>
- 5.常用類
- 6.異常機(jī)制
- 7.容器和數(shù)據(jù)結(jié)構(gòu)
- 8.IO流技術(shù)
- 9.多線程
- 10.網(wǎng)絡(luò)編程
- 11.手寫服務(wù)器(java基礎(chǔ)集大成者)
- 12.注解、反射機(jī)制、字節(jié)碼
- 13.GOF23種設(shè)計(jì)模式
- 14.正則表達(dá)式和文本操作
- 15.JDBC數(shù)據(jù)庫(kù)操作(可在學(xué)完數(shù)據(jù)庫(kù)后學(xué)習(xí))
- 16.手寫SORM框架(學(xué)有余力的同學(xué)學(xué)習(xí))
對(duì)于基礎(chǔ)的同學(xué),建議大家學(xué)習(xí)一下預(yù)科階段(大約2小時(shí))。對(duì)于整個(gè)行業(yè)、JAVA技術(shù)體系、就業(yè)流程、職業(yè)發(fā)展都會(huì)有個(gè)基本的認(rèn)識(shí)和了解。
2.數(shù)據(jù)庫(kù)
數(shù)據(jù)庫(kù)是程序員必學(xué)的技術(shù),大家可以選擇Oracle或者M(jìn)ySQL開始。學(xué)數(shù)據(jù)庫(kù)時(shí),重點(diǎn)掌握SQL語言、熟悉各種查詢、數(shù)據(jù)庫(kù)設(shè)計(jì)范式。這也是以后工作中常用、面試和筆試中??嫉膬?nèi)容
再學(xué)習(xí)JDBC技術(shù),這樣就可以用Java操作數(shù)據(jù)庫(kù)了。
大家可以按照如下順序?qū)W習(xí):
- 知識(shí)塊
- 1.Oracle數(shù)據(jù)庫(kù)安裝和配置、客戶端使用
- 2.Mysql數(shù)據(jù)庫(kù)的安裝和配置、客戶端使用
- 3.SQL語言
- 4.SQL語言強(qiáng)化(查詢深入)
- 5.數(shù)據(jù)庫(kù)設(shè)計(jì)范式
- 6.項(xiàng)目數(shù)據(jù)庫(kù)表設(shè)計(jì)核心
- 7.PL/SQL
3.網(wǎng)頁設(shè)計(jì)和開發(fā)
互聯(lián)網(wǎng)時(shí)代,不學(xué)習(xí)網(wǎng)頁知識(shí)的程序員不是好司機(jī)。HTML、CSS、JavaScript、ajax,這些東西是做web項(xiàng)目必需內(nèi)容。當(dāng)然,作為java程序員不需要學(xué)的很深入,熟悉即可。畢竟,前端工程師也是一個(gè)需要學(xué)習(xí)4-5個(gè)月的專門崗位。
4.Servlet/ JSP和企業(yè)級(jí)項(xiàng)目開發(fā)
Servlet/JSP是JAVAEE的核心內(nèi)容,必須作為重點(diǎn)掌握。學(xué)完基本知識(shí)后,做一些項(xiàng)目吧。比如:BBS、留言系統(tǒng)、學(xué)籍管理、商城、客戶關(guān)系管理等。剛開始找一些業(yè)務(wù)邏輯比較簡(jiǎn)單的做一做。只有通過開發(fā)項(xiàng)目、調(diào)試項(xiàng)目才能真正的掌握學(xué)到的知識(shí),真正的開啟自己的“JAVA騰飛之路”。
5.SSM框架(Spring、Spring MVC、Mybatis)
Spring 是java程序員必須掌握的一個(gè)框架,已經(jīng)形成了事實(shí)上的行業(yè)標(biāo)準(zhǔn)。 剛開始學(xué)習(xí)一下“IOC + AOP”。 依賴注入 + 面向切面,嗯,完善的旅程
Spring MVC是典型的MVC框架,企業(yè)非常流行。已經(jīng)超過struts2成為行業(yè)第一。
Mybatis是經(jīng)典的ORM框架,讓我們可以用面向?qū)ο蟮姆绞綇娜莶僮鲾?shù)據(jù)庫(kù)。已經(jīng)超過Hibernate成為第一的ORM框架。
學(xué)完三個(gè)經(jīng)典框架后,整合他們吧。然后,開始做一些商業(yè)項(xiàng)目加深自己的功力。這里可以找一些相對(duì)復(fù)雜的商業(yè)項(xiàng)目,加上復(fù)雜的業(yè)務(wù)邏輯。這樣,才能在你的簡(jiǎn)歷中加入濃重的一筆。
6.各種JAVA新技術(shù)和大型項(xiàng)目的整合
其他一些工作中可能會(huì)用到的技術(shù),也需要大家學(xué)習(xí): Maven、Shiro、Nginx、Lucene、Solr、Redis、Dubbo、Zookeeper 等。
這些技術(shù)的學(xué)習(xí),不需要特別深入,畢竟一個(gè)企業(yè)并不是使用所有的技術(shù)。但是,為了搭建“java技術(shù)體系”,必須學(xué)習(xí)這些內(nèi)容。這樣,你就形成了完完整整的“系統(tǒng)”。工作中,就可以從容應(yīng)對(duì)各種各樣的問題。
記?。捍罱w系,要比鉆研某個(gè)知識(shí)點(diǎn)的細(xì)節(jié)重要的多。不要因?yàn)槟硞€(gè)細(xì)節(jié)而耽誤搭建體系!不要因?yàn)榭床欢硞€(gè)單詞就停止閱讀整篇文章!
7.微服務(wù)架構(gòu)
企業(yè)和服務(wù)提供商正在尋找更好的方法將應(yīng)用程序部署在云環(huán)境中,微服務(wù)被認(rèn)為是未來的方向。通過將應(yīng)用和服務(wù)分解成更小的、松散耦合的組件,它們可以更加容易升級(jí)和擴(kuò)展。
目前,越來越流行的微服務(wù)技術(shù)是需要大家重視的。SpringBoot、SpringData、Springcloud相關(guān)的技能已經(jīng)成為JAVA程序員必備的技能了。在后面的面試中也越來越重要,企業(yè)用的也越來越多。
8.一定要做一個(gè)大項(xiàng)目!
學(xué)了這么多,也做了一些小項(xiàng)目。最后,一定要做一個(gè)大的項(xiàng)目整合一下自己的所學(xué)。就像高考時(shí)候的綜合題一樣,這才是拉開差距的關(guān)鍵。
經(jīng)歷一個(gè)大項(xiàng)目的錘煉,就能“百煉成鋼”??梢詫讉€(gè)月所有的知識(shí)成體系的應(yīng)用起來,這是成為“高手”的起步!也是你騰飛的起點(diǎn)。
二:JAVA基礎(chǔ)如何學(xué)習(xí),才能又快又穩(wěn)?
學(xué)java編程,一般有兩種情況。一種是已經(jīng)掌握了其他語言,那學(xué)習(xí)java比較簡(jiǎn)單,語言只是工具,編程能力才是根本。另一種是基礎(chǔ),對(duì)于編程未入門或者懵懵懂懂。本文針對(duì)第二種情況。
作為初學(xué)者,在一開始學(xué)習(xí)就要培養(yǎng)良好的習(xí)慣和思維方式。因此,在入門的時(shí)候除了學(xué)著寫代碼,更重要的是這種習(xí)慣的培養(yǎng)。
企業(yè)要求:程序員既有實(shí)戰(zhàn)技能可以快速上手,也內(nèi)功扎實(shí)熟悉底層原理后勁十足。因此,在筆試和面試考察時(shí)候也是結(jié)合 “底層原理、數(shù)據(jù)結(jié)構(gòu)、實(shí)戰(zhàn)應(yīng)用、設(shè)計(jì)思維” 四方面進(jìn)行考察。
因此,作為初學(xué)者,需要掌握下面五個(gè)核心:
1.JAVA本身內(nèi)容的應(yīng)用。比如:一些類的字面用法。
2.需要掌握面向?qū)ο蟮乃季S模式。
3.掌握程序基于內(nèi)存底層的運(yùn)行方式。這可以讓你對(duì)于編程理解的更加深刻。
4.掌握基本的數(shù)據(jù)結(jié)構(gòu)和算法。
5.開始會(huì)寫項(xiàng)目,將學(xué)到的知識(shí)融會(huì)貫通。
所以我們可以根據(jù)上面的理論,開始JAVA基礎(chǔ)課程的學(xué)習(xí)了。
第一步:學(xué)習(xí)JAVA的開發(fā)環(huán)境配置、開發(fā)第一個(gè)Java程序。也建議大家開始使用eclipse等IDE,不必糾結(jié)是不是一定要從記事本開始。
第二步:學(xué)習(xí)數(shù)據(jù)類型、運(yùn)算符、變量。這是編程的基礎(chǔ),是程序的“磚塊”。這些內(nèi)容大多數(shù)編程語言都有,而且非常類似。
第三步:學(xué)習(xí)控制語句。這是編程的基礎(chǔ),是程序的“混凝土”。有了控制語句+變量,理論上你就可以寫任意的程序了。因此,這是進(jìn)入程序的門檻,需要大量的練習(xí)。
第四步:學(xué)習(xí)面向?qū)ο蠡A(chǔ)。通過類、對(duì)象、包等基本概念講解。學(xué)習(xí)的時(shí)候,一定要在此處介入內(nèi)存分析,這樣可以對(duì)于對(duì)象等知識(shí)有非常深刻的理解。
第五步:繼續(xù)面向?qū)ο?,主要包含三大特征:繼承、封裝,以及接口、抽象類、內(nèi)部類等概念。這些概念需要掌握。但是對(duì)于初學(xué)者來說,先熟悉語法。通過后面的學(xué)習(xí)再深入。不要期待初學(xué)時(shí)候就能深刻領(lǐng)會(huì)這些概念。
第六步:異常機(jī)制。Java程序的安全需要異常機(jī)制,這是必學(xué)內(nèi)容。當(dāng)然,也非常簡(jiǎn)單。學(xué)習(xí)過程中,先不要揪著什么自定義異常不放,學(xué)會(huì)基本用法即可。
第七步:數(shù)組和算法。學(xué)習(xí)數(shù)組時(shí),注重結(jié)合循環(huán)管理數(shù)組。也要從底層內(nèi)存理解數(shù)組,這既是學(xué)數(shù)組也是復(fù)習(xí)面向?qū)ο?;再結(jié)合一些算法,比如排序和搜索算法,既練習(xí)數(shù)組的用法,也學(xué)習(xí)了算法知識(shí),為應(yīng)對(duì)企業(yè)筆試和面試做好準(zhǔn)備。
第八步:常用類和JDK源碼閱讀。學(xué)習(xí)常用類的用法:包裝類、字符串相關(guān)類、實(shí)踐類、Math類、File類等。學(xué)習(xí)過程中,只學(xué)怎么用這些API就及格了。要優(yōu)秀,要培養(yǎng)高手思維,一定要結(jié)合JDK源碼,一開始就培養(yǎng)閱讀源碼的習(xí)慣(雖然,可能大多數(shù)看不懂)。
第九步:容器和數(shù)據(jù)結(jié)構(gòu)。容器有:List、Set、Map。學(xué)習(xí)這三種容器用法只需要一兩個(gè)小時(shí)。但,此時(shí)你要結(jié)合數(shù)據(jù)結(jié)構(gòu),再結(jié)合JDK源碼講解。這就是“高手習(xí)慣”,讓大家既學(xué)習(xí)容器,也學(xué)習(xí)了數(shù)據(jù)結(jié)構(gòu),打深了內(nèi)功,應(yīng)對(duì)企業(yè)面試綽綽有余。
第十步:IO流技術(shù)。學(xué)會(huì)各種常用流即可,掌握一些工具類的用法,比如:Apache IOUtil這樣會(huì)讓你在以后使用時(shí)效率大增。
第十一步:多線程技術(shù)。這也是筆試和面試中常見的內(nèi)容。我們要學(xué)習(xí)多線程基本使用、生命周期、狀態(tài)轉(zhuǎn)化。如果學(xué)有余力,學(xué)習(xí)一下生產(chǎn)者消費(fèi)者模式,讓你一開始就具備架構(gòu)的思維;既然學(xué),就按照“高標(biāo)準(zhǔn)”要求自己。
第十二步:網(wǎng)絡(luò)編程。工作中直接用到的不多,而且socket編程范式差不多,了解即可。畢竟直接讓你編寫基于socket底層代碼的情況比較少見。
第十三步:做個(gè)項(xiàng)目吧。 學(xué)了這么多,不做個(gè)東西怎么對(duì)得起自己?不管是小游戲項(xiàng)目也好,還是基于swing的項(xiàng)目,還是其他控制臺(tái)項(xiàng)目。
大家也可以下載我錄制的《尚學(xué)堂JAVA300集視頻教程》,已經(jīng)上百萬人在學(xué)習(xí)了?;旧县灤┝宋疑厦娴乃枷?,有知識(shí)、有底層、有數(shù)據(jù)結(jié)構(gòu)、有算法、還有項(xiàng)目,從一開始就培養(yǎng)你的“高手思維”。
三:Python學(xué)習(xí)知識(shí)點(diǎn)以及配套視頻
這是Python工程師的完整學(xué)習(xí)路徑,我們會(huì)公布大部分的學(xué)習(xí)視頻,這些視頻來自于我們線下培訓(xùn)課程,大多數(shù)直接錄制于課堂,歡迎大家免費(fèi)下載或者在線觀看。
我們每個(gè)月都會(huì)更新相應(yīng)的視頻,大家可以持續(xù)關(guān)注下載地址:
http://bj0393.com.cn/pythonshipin.html (python視頻的拼音)
1.Python基礎(chǔ)
“人生苦短,我用Python”, 隨著人工智能的發(fā)展,Python無疑是現(xiàn)在熱度最高的語言。從“小白”到成為一個(gè)合格的Python程序員首先要先邁過Python基礎(chǔ)這個(gè)門檻。
第一步:需要學(xué)習(xí)編程最基本的知識(shí):變量、數(shù)據(jù)類型、控制語句、容器、函數(shù)和文件操作。同時(shí),我們也深入數(shù)組結(jié)構(gòu)的組織,打扎實(shí)大家的基本功。
第二步:學(xué)習(xí)python的面向?qū)ο髾C(jī)制,并學(xué)習(xí)一些常用的設(shè)計(jì)模式,這些都是成為Python編程高手必經(jīng)的磨練。并通過一個(gè)項(xiàng)目實(shí)際體會(huì)面向?qū)ο箝_發(fā)的優(yōu)勢(shì)。
第三步:還需要了解python是如何管理內(nèi)存的以及很多高級(jí)特性;學(xué)習(xí)內(nèi)存管理會(huì)讓我們更深入掌握python的運(yùn)行機(jī)制; 很多函數(shù)式編程的特性,比如閉包、裝飾器和生成器,這些都是一些比較難掌握的概念,但面試和工作中會(huì)經(jīng)常遇到,所以大家也必須掌握。
第四步: 網(wǎng)絡(luò)編程中的高并發(fā)問題是大型互聯(lián)網(wǎng)企業(yè)必須面對(duì)的核心問題,解決高并發(fā)可以用多進(jìn)程、多線程,python中還有協(xié)程。高并發(fā)和網(wǎng)絡(luò)是相關(guān)的,最后我們會(huì)利用學(xué)到的并發(fā)編程的知識(shí)來編寫不同的服務(wù)器模型。
上面四大塊學(xué)習(xí)完后,你已經(jīng)具備了比較強(qiáng)的python基礎(chǔ),但是離工作要求還有差距。還需要繼續(xù)學(xué)習(xí)其他內(nèi)容。
2.Linux環(huán)境編程基礎(chǔ)
現(xiàn)在企業(yè)中不管是Web項(xiàng)目,還是數(shù)據(jù)庫(kù),以及部署的爬蟲,更不要說大數(shù)據(jù)處理,甚至是人工智能,絕大多數(shù)都運(yùn)行在Linux系統(tǒng)內(nèi),所以打好一個(gè)Linux基礎(chǔ)可謂是必備技能。
我們將學(xué)習(xí)如何在虛擬機(jī)中安裝Linux系統(tǒng),在Linux系統(tǒng)中安裝各種常用的軟件。學(xué)習(xí)如何配置Linux系統(tǒng)的網(wǎng)絡(luò)。學(xué)習(xí)使用Linux系統(tǒng)的常用基本命令。最后成為一個(gè)Linux系統(tǒng)的熟練管理員。
當(dāng)然,我們的目標(biāo)是會(huì)用Linux,熟悉相關(guān)常用命令即可。不需要掌握很多運(yùn)維方面的知識(shí),畢竟運(yùn)維也是一個(gè)專業(yè)的崗位。
3.數(shù)據(jù)庫(kù)編程基礎(chǔ)
任何企業(yè)級(jí)項(xiàng)目都離不開數(shù)據(jù)庫(kù),數(shù)據(jù)庫(kù)知識(shí)是程序員的必備技能。大家主要學(xué)習(xí)現(xiàn)在各大互聯(lián)網(wǎng)公司最常用的數(shù)據(jù)庫(kù):Mysql
當(dāng)然,不管學(xué)習(xí)哪一個(gè)數(shù)據(jù)庫(kù)。SQL語言是必須要深入掌握的,包含:數(shù)據(jù)庫(kù)設(shè)計(jì)思想、三大范式以及SQL語言實(shí)現(xiàn)增、刪、改、查最基本的操作。然后,也需要掌握Mysql一些基本的操作。
4.網(wǎng)頁編程基礎(chǔ)
目前軟件行業(yè)大多數(shù)的項(xiàng)目都是基于B/S架構(gòu),即在瀏覽器端實(shí)現(xiàn)效果展示。網(wǎng)頁編程也是每個(gè)程序員必懂的技能
本階段課程主要講解Web開發(fā)的三大基礎(chǔ):HTML5、CSS3和JavaScript語言,并學(xué)習(xí)前端項(xiàng)目中經(jīng)常使用的Jquery和Ajax。
對(duì)于python程序員來說,不需要像前端程序員那樣精通這部分內(nèi)容,但是也需要做到熟悉。
5.Django Web開發(fā)框架
python也越來越多的被用在開發(fā)WEB應(yīng)用上,這得益于Django這個(gè)強(qiáng)大的WEB框架。
學(xué)習(xí)Django的使用,要深入了解Django中MVT的開發(fā)模式,掌握模型的設(shè)計(jì)、視圖路由的設(shè)置和模板。并在最后帶領(lǐng)大家用Django開發(fā)一個(gè)博客項(xiàng)目,貫穿所有Django的常用特性。
python在WEB應(yīng)用開發(fā)方向的需求在近段時(shí)間逐步增長(zhǎng), 薪水范圍在10k-25k之間,是大家學(xué)完python后的一個(gè)重要就業(yè)方向。
6.做一個(gè)項(xiàng)目
學(xué)完Django,必須做一個(gè)項(xiàng)目。將前面學(xué)習(xí)的Python基礎(chǔ)、數(shù)據(jù)庫(kù)、網(wǎng)頁開發(fā)等等技能整合起來,這樣才能學(xué)以致用。讓自己快速成長(zhǎng)起來。
7.Tornado 異步編程框架
Tornado也是一個(gè)常用的python WEB開發(fā)框架,但Tornado更強(qiáng)大的地方是它的異步IO處理能力。在真正的項(xiàng)目中,經(jīng)常會(huì)混合使用Django和Torndao這兩大框架,充分利用Django的方便快捷和Tornado的高負(fù)載來解決項(xiàng)目中的實(shí)際問題。
8.Python爬蟲開發(fā)
由于近年大數(shù)據(jù)分析、人工智能都需要大量的數(shù)據(jù)做支持,所以爬蟲工程師的需求量也越來越多,有經(jīng)驗(yàn)的爬蟲工程師經(jīng)常能拿到15k-25k的工資,有興趣的同學(xué)可以向這個(gè)方向發(fā)展。
首先,大家要理解網(wǎng)絡(luò)爬蟲編寫的基本套路,了解網(wǎng)絡(luò)爬蟲編寫的各種坑,能夠應(yīng)對(duì)一些常用的反爬蟲技術(shù),能夠應(yīng)對(duì)動(dòng)態(tài)網(wǎng)站爬取,能夠應(yīng)對(duì)帶有驗(yàn)證碼的網(wǎng)站。我們還要學(xué)習(xí)一些做爬蟲的常用框架:request,bs4,scrapy等。并利用scrapy結(jié)合redis實(shí)現(xiàn)分布式爬蟲的開發(fā)。
學(xué)習(xí)了這些技術(shù),我們就可以在互聯(lián)網(wǎng)的汪洋大海中獲取到任何想要的數(shù)據(jù)。
四:人工智能學(xué)習(xí)知識(shí)點(diǎn)和配套視頻
人工智能成為了IT行業(yè)未來幾十年極其重要的學(xué)科。尚學(xué)堂·百戰(zhàn)程序員開設(shè)了完整的人工智能課程,由從歐美留學(xué)歸國(guó)的陳博老師領(lǐng)銜主講。
為了讓更多人受益, 我們會(huì)陸續(xù)公布大部分的學(xué)習(xí)視頻,這些視頻來自于我們線下培訓(xùn)精品課程,大多數(shù)直接錄制于課堂,歡迎大家免費(fèi)下載或者在線觀看。
我們每個(gè)月都會(huì)更新相應(yīng)的視頻,大家可以關(guān)注下載地址(人工智能視頻的拼音):
http://bj0393.com.cn/rengongzhinengshipin.html
1. 機(jī)器學(xué)習(xí)
首先要學(xué)習(xí)機(jī)器學(xué)習(xí)算法,這是人工智能的核心,也是重中之重。
在學(xué)習(xí)機(jī)器學(xué)習(xí)算法理論同時(shí),建議大家使用scikit-learn這個(gè)python機(jī)器學(xué)習(xí)的庫(kù),試著完成一些小項(xiàng)目。同時(shí)關(guān)注一下能否各種算法結(jié)合使用來提高預(yù)測(cè)結(jié)果準(zhǔn)確率。在學(xué)習(xí)的過程中不必強(qiáng)求自己能夠完全掌握各種算法推導(dǎo),抓住重點(diǎn)理解算法,然后把算法用起來才是王道。
掌握一種編程工具,比如說PyCharm或者Jupyter Notebook,當(dāng)然工具掌握不難,大約只需要30分鐘。
建議大家不要盲目的去看各種市面上的書籍和博客,有的對(duì)于大家來說過于理論,推導(dǎo)太多還有些跳步顯得過于深?yuàn)W,有的又太浮于表面了不涉及算法原理細(xì)節(jié),還是以北京尚學(xué)堂的視頻作為學(xué)習(xí)材料,這里有算法的理解,算法的推導(dǎo),算法的應(yīng)用,非常適合大學(xué)生和入門學(xué)習(xí)的人使用,從一開始就即有算法的逐步深入,又有算法的實(shí)戰(zhàn)。給自己成為一個(gè)數(shù)據(jù)挖掘工程師,算法工程師打好基礎(chǔ)。
上面提到的機(jī)器學(xué)習(xí)算法譬如有監(jiān)督學(xué)習(xí)回歸算法中多元線性回歸,Lasso回歸,嶺回歸。分類算法中邏輯回歸,支持向量機(jī),決策樹,隨機(jī)森林,GBDT,Adaboost,XGBOOST。無監(jiān)督學(xué)習(xí)聚類算法中K均值聚類,密度聚類,譜聚類。降維算法中PCA降維,F(xiàn)M因式分解,SVD奇異值分解。推薦算法中協(xié)調(diào)過濾,ALS交替最小二乘。還有機(jī)器學(xué)習(xí)里面的大招多層感知機(jī),神經(jīng)網(wǎng)絡(luò)。關(guān)聯(lián)分析的算法Apriori,F(xiàn)P-Growth。最后研究樸素貝葉斯,貝葉斯網(wǎng)絡(luò),隱含馬爾科夫模型,條件隨機(jī)場(chǎng)。
對(duì)于人工智能專業(yè)不了解的同學(xué),建議大家學(xué)習(xí)一下預(yù)科階段,對(duì)于整個(gè)行業(yè),技術(shù)體系,就業(yè)方向,未來職業(yè)發(fā)展都會(huì)有個(gè)基本的認(rèn)識(shí)和了解。
2.深度學(xué)習(xí)
深度學(xué)習(xí)是當(dāng)今非常熱門的一個(gè)領(lǐng)域,是機(jī)器學(xué)習(xí)算法神經(jīng)網(wǎng)絡(luò)的延申,是把機(jī)器學(xué)習(xí)的擬人更加發(fā)揚(yáng)光大的領(lǐng)域。深度學(xué)習(xí)工程師也是各大公司需要的人才。
學(xué)習(xí)深度學(xué)習(xí)可以從Google開源的tensorflow框架開始學(xué)習(xí)如何完成DNN(深度神經(jīng)網(wǎng)絡(luò))的構(gòu)建以及應(yīng)用。然后還是使用tensorflow框架來學(xué)習(xí)如何完成CNN(卷積神經(jīng)網(wǎng)絡(luò))的構(gòu)建以及應(yīng)用。最后來使用tensorflow框架來學(xué)習(xí)如何完成RNN(循環(huán)神經(jīng)網(wǎng)絡(luò))的構(gòu)建以及應(yīng)用。
學(xué)習(xí)建議:大家在學(xué)習(xí)過程中可以試著利用構(gòu)建的DNN來完成機(jī)器學(xué)習(xí)算法做的分類和回歸的案例,對(duì)比看看結(jié)果是否有提升,從而體會(huì)深度學(xué)習(xí)的奧妙。也可以利用CNN來完成一些圖像識(shí)別任務(wù),和利用RNN來完成一些NLP(自然語言處理)任務(wù)。CNN和RNN不僅限于這兩個(gè)領(lǐng)域,但是目前來看它們?cè)谶@兩個(gè)領(lǐng)域各有優(yōu)勢(shì)。
Tensorflow框架是深度學(xué)習(xí)框架之一,但不是唯一,Keras框架也是一個(gè)非常優(yōu)秀的框架,大家有興趣也可繼續(xù)學(xué)習(xí)Keras框架。代碼量會(huì)比TensorFlow更少一些,更適合去做一些實(shí)驗(yàn)。
3.Python數(shù)據(jù)分析模塊
Python當(dāng)今作為數(shù)據(jù)科學(xué)的第一語言,熟練掌握numpy、scipy、pandas、matplotlib等數(shù)據(jù)分析的模塊不光是作為數(shù)據(jù)分析師必須的,也是作為人工智能工程師所必須的, 如果大家認(rèn)為自己的python語言掌握的不夠熟練,可以從學(xué)習(xí)這些基礎(chǔ)的模塊開始,來鍛煉自己。因?yàn)閟cikit-learn機(jī)器學(xué)習(xí)算法庫(kù)是基于numpy、scipy、matplotlib開發(fā)的,所以大家掌握好了這些基礎(chǔ)庫(kù),對(duì)于分析別人封裝的算法源代碼,甚至日后自己開發(fā)一些算法也有了可能性。
學(xué)習(xí)建議:在學(xué)習(xí)這些數(shù)據(jù)分析模塊的同時(shí),可以補(bǔ)補(bǔ)python語言的基礎(chǔ)語法,重復(fù)一遍基礎(chǔ)語法即可,不要跑偏到python其他比如什么web開發(fā),爬蟲等領(lǐng)域里面去。
4.Spark MLlib機(jī)器學(xué)習(xí)庫(kù)
如果說當(dāng)今有什么是算法工程師的加分項(xiàng),那么分布式計(jì)算框架Spark中算法庫(kù)MLlib就是一個(gè),如果想掌握Spark MLlib,首先需要會(huì)使用spark計(jì)算框架,建議大家還是使用python語言通過pyspark來學(xué)習(xí),在掌握了前面的機(jī)器學(xué)習(xí)部分后,這里再來學(xué)習(xí)里面的算法使用將變得異常容易。
學(xué)習(xí)建議:大家要抓住重點(diǎn),千萬不要鉆到集群搭建里面,甚至是大數(shù)據(jù)各種框架里面,因?yàn)閷?duì)于我們來說,spark計(jì)算框架只是一個(gè)工具,幫助我們來更好的做數(shù)據(jù)預(yù)處理,和幫助我們將算法使用分布式集群來完成海量數(shù)據(jù)場(chǎng)景下結(jié)果的計(jì)算。在公司里面,有運(yùn)維的人員管理集群,在一些大公司,有專門給算法工程師配備數(shù)據(jù)預(yù)處理的工程師。
5.做一個(gè)人工智能項(xiàng)目
學(xué)了這么多,也做了一些小項(xiàng)目,最后一定要做一些個(gè)大項(xiàng)目整合一下自己的知識(shí)。做一些個(gè)人工智能領(lǐng)域的譬如醫(yī)療圖像識(shí)別、人臉識(shí)別、自動(dòng)聊天機(jī)器人、推薦系統(tǒng)、用戶畫像等的大項(xiàng)目才是企業(yè)很需要的經(jīng)驗(yàn)??梢詫⒗碚摻Y(jié)合實(shí)際的運(yùn)用也是成為高手的必經(jīng)之路,也是在企業(yè)工作所需要的能力。
6.數(shù)學(xué)
數(shù)學(xué)是一個(gè)誤區(qū),很多人說自己的數(shù)學(xué)不夠好,是不是做不了算法工程師?面對(duì)這樣的問題,公司里面的算法工程師誰又敢說自己的數(shù)學(xué)真的好?數(shù)學(xué)是在學(xué)習(xí)機(jī)器學(xué)習(xí)階段算法推導(dǎo)用的到的,但是這里的推導(dǎo)你又不需要非要一步步扣數(shù)學(xué)計(jì)算過程,舉個(gè)例子,2+2=4,那么數(shù)據(jù)基礎(chǔ)是1+1=2,但是咱們需要證明1+1=2嗎?不需要,對(duì)吧,所以在機(jī)器學(xué)習(xí)階段算法推導(dǎo)這里更重要的還是理解算法證明的思想,能夠把講的算法推導(dǎo)理清楚足夠了,而這在講的過程中如何有好的引導(dǎo),又何須非自己沒頭緒的補(bǔ)數(shù)學(xué)然后走那個(gè)彎路呢?
學(xué)習(xí)建議:很多數(shù)學(xué)符號(hào)只是一種表達(dá)而已,在學(xué)習(xí)過程中稍微補(bǔ)一下即可,不需要花大量時(shí)間前期準(zhǔn)備數(shù)學(xué)知識(shí),最重要的是,企業(yè)中人工智能工程師沒人天天抱著數(shù)學(xué)公式推導(dǎo)。所以同學(xué)們?cè)诖髮W(xué)期間數(shù)學(xué)學(xué)的不錯(cuò)的同學(xué)恭喜你,你在機(jī)器學(xué)習(xí)算法學(xué)習(xí)時(shí)會(huì)稍微輕松一些,相反,在大學(xué)期間數(shù)學(xué)學(xué)的不行的同學(xué)也恭喜你,因?yàn)閿?shù)學(xué)不是決定能否成為一個(gè)企業(yè)所需算法工程師的鴻溝!
五:H5前端和移動(dòng)APP開發(fā)知識(shí)點(diǎn)和配套視頻
隨著互聯(lián)網(wǎng)、移動(dòng)互聯(lián)網(wǎng)的發(fā)展,HTML5成為了客戶端軟件開發(fā)的主流技術(shù),HTML5實(shí)際上是由:HTML5語言、CSS3、JAVASCRIPT語言組成。
尚學(xué)堂的HTML5前端課程由國(guó)內(nèi)知名技術(shù)專家劉興宇老師領(lǐng)銜,已經(jīng)培訓(xùn)就業(yè)數(shù)千人,取得了非常好的社會(huì)影響。
為了讓更多人受益, 我們會(huì)陸續(xù)公布大部分的學(xué)習(xí)視頻,這些視頻來自于我們線下培訓(xùn)精品課程,大多數(shù)直接錄制于課堂,歡迎大家免費(fèi)下載或者在線觀看。
我們每個(gè)月都會(huì)更新相應(yīng)的視頻,大家可以持續(xù)關(guān)注下載地址(前端視頻的拼音):
http://bj0393.com.cn/qianduanshipin.html
1.WEB前端快速入門
在本階段,我們需要掌握HTML與CSS基礎(chǔ),當(dāng)然,也包含H5和C3的新特性。這個(gè)部分內(nèi)容非常簡(jiǎn)單,而且非常容易掌握。相信你也更愿意學(xué)習(xí)這個(gè)部分,畢竟他可以讓你最直觀的感受到前端的魅力。為了鍛煉大家寫代碼,可以根據(jù)你喜歡的站點(diǎn)去實(shí)現(xiàn)效果。
這一階段是非常重要的基礎(chǔ)階段,所謂基礎(chǔ)就是可能這個(gè)階段我們的學(xué)習(xí)的內(nèi)容,可以讓我們開發(fā)出來絢麗網(wǎng)站站點(diǎn),但是功能豐富卻暫時(shí)做不到。 為了完成更絢麗的站點(diǎn),我們需要掌握常見特效的實(shí)現(xiàn),利用css3和h5的新特性實(shí)現(xiàn)動(dòng)畫,布局,雪碧圖,滑動(dòng)門,tab切換等特效。并且掌握基礎(chǔ)的站點(diǎn)優(yōu)化內(nèi)容。例如sprite等。雖然我們還不能完成更多交互內(nèi)容,但是我們會(huì)學(xué)習(xí)到很多的知識(shí)模型和理論,而這些知識(shí)模型和理論是我們后期工作和學(xué)習(xí)的基石。扎實(shí)的基礎(chǔ)有了,我們才能走的更穩(wěn)更快。
注:本階段不涉及到編程,主要是熟悉HTML5各種標(biāo)簽用法、CSS3各種屬性的用法。
2.JavaScript基礎(chǔ)與深入解析
JavaScript語言非常重要,可以說學(xué)習(xí)前端本質(zhì)就是學(xué)習(xí)“JavaScript”編程。后面學(xué)的很多高級(jí)技術(shù),全部都是基于JavaScript的。
JavaScript語言可以讓網(wǎng)頁元素具備動(dòng)態(tài)效果,讓體驗(yàn)度更加流暢。這在目前流行的B/S架構(gòu)體系下,是極端重要的事情。這也是為什么前端工程師大行其道,被廣泛需求的根本原因。
在本階段中,我們主要學(xué)習(xí)基礎(chǔ)JavaScript語法與深入解析JavaScript,包含DOM操作同時(shí)也涵蓋了面向?qū)ο蠛驮O(shè)計(jì)模式,課程也涵蓋了兼容性處理和數(shù)據(jù)解析。希望大家在本階段可以熟練掌握這些知識(shí)點(diǎn)。
3.jQuery應(yīng)用與項(xiàng)目開發(fā)
jQuery是一個(gè)快速、簡(jiǎn)潔的JavaScript框架,jQuery設(shè)計(jì)的宗旨是“write Less,Do More”,即倡導(dǎo)寫更少的代碼,做更多的事情。它封裝JavaScript常用的功能代碼,提供一種簡(jiǎn)便的JavaScript設(shè)計(jì)模式,優(yōu)化HTML文檔操作、事件處理、動(dòng)畫設(shè)計(jì)和Ajax交互。在本階段,我們注重講解如何更好的應(yīng)用jQuery以及他的設(shè)計(jì)方式,同時(shí)也包含jQuery擴(kuò)展內(nèi)容。
4.PHP、數(shù)據(jù)庫(kù)編程與設(shè)計(jì)
后端服務(wù)器工程師需要了解前端的基本知識(shí),同樣,前端工程師也必須了解服務(wù)器端編程的基本內(nèi)容。我們可以不精通,但必須知道整體的流程。
作為一名前端開發(fā)工程師,會(huì)一門后端語言是必然的。在我們的課程中,為您選擇的是PHP,因?yàn)镻HP環(huán)境搭建簡(jiǎn)單,語言與JavaScript相似性比較大,并且容易上手,連接數(shù)據(jù)庫(kù)也非常方便。希望本階段的內(nèi)容能幫助你快速掌握前后端交互數(shù)據(jù)。
通過學(xué)習(xí)PHP,前端工程師也能稱為“全棧工程師”。既能做前端開發(fā),也能做后端服務(wù)器開發(fā)。
5. Http服務(wù)于Ajax編程
Ajax真的是一個(gè)非常古老的技術(shù)了,但是到現(xiàn)在為止,這門技術(shù)仍然被大量使用,可以看出來,他是多么的優(yōu)秀。在本階段,我們將帶你了解Ajax,并且掌握它的應(yīng)用。也包含了解Http相關(guān)的知識(shí)。對(duì)于站點(diǎn)來說,除了頁面效果能看到的就是數(shù)據(jù)了。所以,數(shù)據(jù)的獲取合理適配尤為重要。與Ajax相關(guān)的也包含跨域處理,希望大家可以掌握這些核心知識(shí)點(diǎn)。
6. 做一個(gè)階段項(xiàng)目
本階段為純項(xiàng)目實(shí)戰(zhàn),可以將前面學(xué)到的知識(shí)融會(huì)貫通,不實(shí)戰(zhàn)就相當(dāng)于沒有學(xué)習(xí);主要練習(xí)網(wǎng)絡(luò)請(qǐng)求、站點(diǎn)布局、網(wǎng)站優(yōu)化等內(nèi)容,同時(shí)我們需要對(duì)項(xiàng)目有一定的而了解。 所以,在老師的帶領(lǐng)下,可以更快的了解項(xiàng)目如何搭建,如何更優(yōu)雅的實(shí)現(xiàn)代碼。老師會(huì)將整個(gè)項(xiàng)目的開發(fā)流程完整的羅列出來。本階段也鍛煉BootStrap的應(yīng)用,也包含一些常用的第三方插件。在實(shí)戰(zhàn)中展示具體應(yīng)用。
7. H5新特性與移動(dòng)端開發(fā)
H5新特性在現(xiàn)在來說已經(jīng)不再是新內(nèi)容了,項(xiàng)目中隨處可見,畢竟移動(dòng)端不會(huì)存在兼容性問題,而且這些新特性在移動(dòng)端的體現(xiàn)也是非常好的。例如定位,語義化等。利用Canvas實(shí)現(xiàn)更多的效果等。
在移動(dòng)端中,我們主要注重移動(dòng)端布局和資源加載,布局方向,我們主要講解百分比、flex、REM、柵格系統(tǒng)來實(shí)現(xiàn)。資源加載采用(SPA)單頁面加載,也是目前比較火的形式。在頁面跳轉(zhuǎn)時(shí)可以非常節(jié)省資源?;旌祥_發(fā)也同樣是移動(dòng)端的一大特點(diǎn),在我們的課程中都會(huì)詳細(xì)講解。
8.高級(jí)框架
隨著項(xiàng)目的需求越來越多。傳統(tǒng)的開發(fā)方式已經(jīng)不能滿足我們的需求了,所以我們需要更多的支持。在本階段中,我們講解模塊化,將程序分解為模塊化開發(fā)。我們需要Nodejs做支撐,無論是作為構(gòu)建工具中的服務(wù)器存在,還是為我們提供數(shù)據(jù)模擬測(cè)試,都是必不可少的。
隨著ES5開發(fā)者體會(huì)在開發(fā)中的難言之隱,ES6的到來解決了各種頭痛的問題。也是我們必須要掌握的一個(gè)重點(diǎn)。還有更多,例如多人協(xié)同開發(fā)(git或者svn),利用Less和Sass完成更好的CSS的編寫
接下來我們介紹一下目前前端三大框架:
Angular:Angular是一個(gè)開發(fā)平臺(tái),他能幫我們輕松的構(gòu)建Web應(yīng)用,我們將在這部分課程中講解Angular的聲明式模板,依賴注入,端到端的工具和一些最佳實(shí)踐于一身。我們通過完整項(xiàng)目配合實(shí)例講解課程,以便于大家更容易去理解Angular的應(yīng)用。
React:作為前端三大框架之一,React擁有聲明式和組件化兩大特點(diǎn),React可以輕松創(chuàng)建交互式用戶界面。為應(yīng)用程序中的每個(gè)狀態(tài)設(shè)計(jì)簡(jiǎn)單的視圖,當(dāng)數(shù)據(jù)更改時(shí),React將高效地更新和正確的渲染組件。聲明式視圖使您的代碼更具可預(yù)測(cè)性,更易于調(diào)試。創(chuàng)建好擁有各自State(狀態(tài)) 的組件,再將其組合構(gòu)成更加復(fù)雜的UI界面。由于組件邏輯是用JavaScript而不是模板編寫的,因此可以通過應(yīng)用程序輕松傳遞豐富的數(shù)據(jù),并將State(狀態(tài)) 保留在DOM之外。我們將會(huì)從零開發(fā)講解,講解過程中個(gè),我們也帶領(lǐng)大家從環(huán)境的構(gòu)建開始學(xué)習(xí),這樣可以讓你更好更快的對(duì)接企業(yè)級(jí)項(xiàng)目的環(huán)境架構(gòu)。
VUE:在借鑒了Angular和React兩個(gè)優(yōu)秀框架的基礎(chǔ)上,Vue無疑是非常受歡迎的,它使用簡(jiǎn)單,強(qiáng)大的生態(tài)系統(tǒng),高效的運(yùn)行速度也是我們?cè)陂_發(fā)中的選擇之一。Vue是一套用于構(gòu)建用戶界面的漸進(jìn)式框架。與其它大型框架不同的是,Vue被設(shè)計(jì)為可以自底向上逐層應(yīng)用。Vue的核心庫(kù)只關(guān)注視圖層,不僅易于上手,還便于與第三方庫(kù)或既有項(xiàng)目整合。
另一方面,當(dāng)與現(xiàn)代化的工具鏈以及各種支持類庫(kù)結(jié)合使用時(shí),Vue也完全能夠?yàn)閺?fù)雜的單頁應(yīng)用提供驅(qū)動(dòng)。在學(xué)習(xí)真?zhèn)€Vue的過程中,我們會(huì)通過兩個(gè)企業(yè)級(jí)項(xiàng)目來講解他的使用,以便于大家更好的掌握使用Vue熟練開發(fā)。
9.微信小程序
作為微信推出的一種新的項(xiàng)目展示形式,微信小程序必然是非常受到人們重視的,而且,目前為止,大部分推廣為主的公司都存在了微信小程序,也催生了一個(gè)崗位,微信小程序開發(fā)工程師??上攵?,微信小程序是非?;鸬?。我們課程是在小程序正式發(fā)布后就已經(jīng)加入到課程了,通過近1年的實(shí)戰(zhàn)演練,在我們的課程中,通過項(xiàng)目直接入手,在項(xiàng)目中掌握API知識(shí)點(diǎn)的應(yīng)用。這樣可以更快適應(yīng)項(xiàng)目開發(fā)。
六:大數(shù)據(jù)和云計(jì)算學(xué)習(xí)知識(shí)點(diǎn)和配套視頻
IT時(shí)代,最重要的特征就是:“數(shù)據(jù)越來越多”。每天產(chǎn)生的數(shù)據(jù)源源不斷,成為了現(xiàn)代社會(huì)的“石油”。大數(shù)據(jù)的存儲(chǔ)、分析都成了非常重要的技術(shù)。
尚學(xué)堂從2014年國(guó)內(nèi)第一批開設(shè)大數(shù)據(jù)專業(yè),由國(guó)內(nèi)知名專家夏中云、肖斌、周智雷創(chuàng)建。我們培訓(xùn)的大數(shù)據(jù)學(xué)員絕大多數(shù)成為了目前各大數(shù)據(jù)企業(yè)的骨干,深刻的影響了國(guó)內(nèi)大數(shù)據(jù)行業(yè)。
為了讓更多人受益, 我們會(huì)陸續(xù)公布大部分的大數(shù)據(jù)課程視頻,這些視頻來自于我們線下培訓(xùn)精品課程,大多數(shù)直接錄制于課堂,歡迎大家免費(fèi)下載或者在線觀看。
我們每個(gè)月都會(huì)更新相應(yīng)的視頻,大家可以持續(xù)關(guān)注下載地址(大數(shù)據(jù)視頻的拼音):
http://bj0393.com.cn/dashujushipin.html
1.大數(shù)據(jù)學(xué)習(xí)之前“必看”
大數(shù)據(jù)是現(xiàn)在這個(gè)時(shí)代非常流行的概念,并且隨著人工智能的崛起,大數(shù)據(jù)也越來越有價(jià)值。人工智能算法其實(shí)在三十年前就有了,但是沒有用。原因是:第一、計(jì)算機(jī)不夠快;第二、數(shù)據(jù)量不夠大,訓(xùn)練出來的模型太差。
IT時(shí)代,其實(shí)也是大數(shù)據(jù)時(shí)代。我們產(chǎn)生的數(shù)據(jù)越來越多,這些數(shù)據(jù)反過來就像“石油”一樣,為我們提供了進(jìn)一步的價(jià)值。人工智能等算法就像“吞食數(shù)據(jù)的怪獸”,數(shù)據(jù)越多人工智能也越強(qiáng)大。
因此,在學(xué)習(xí)大數(shù)據(jù)之前,一定要先搞明白幾個(gè)問題:
1.什么大數(shù)據(jù)?
2.什么是云計(jì)算?
3.什么是數(shù)據(jù)挖掘?
4.什么是人工智能?
5.什么條件才能學(xué)習(xí)大數(shù)據(jù)?
了解之后你才能有的放矢,以及想一想自己是否適合學(xué)習(xí)。同時(shí),也至少不會(huì)被人騙,因?yàn)榱私膺@些問題之后,一看課程大綱里面有“遙控機(jī)器人技術(shù),android技術(shù)”等。這些技術(shù)肯定和大數(shù)據(jù)是沒有關(guān)系的。
由于篇幅的問題,這個(gè)幾個(gè)問題的解答已經(jīng)錄制成一套視頻。視頻列表如下:
- 知識(shí)塊
- 1、什么大數(shù)據(jù)?
- 2、什么是人工智能?
- 3、什么是機(jī)器學(xué)習(xí)和深度學(xué)習(xí)?
- 4、數(shù)據(jù)挖掘到底挖什么?
- 5、大數(shù)據(jù)技術(shù)體系介紹
- 6、基礎(chǔ)可以學(xué)習(xí)大數(shù)據(jù)嗎?
- 7、大數(shù)據(jù)工作職務(wù)多嗎?薪水怎么樣?
- 8、大數(shù)據(jù)簡(jiǎn)歷怎么寫?
- 9、大數(shù)據(jù)的學(xué)習(xí)方法
- 10、哪些技術(shù)才是大數(shù)據(jù)的重點(diǎn)內(nèi)容?
建議:在學(xué)習(xí)大數(shù)據(jù)之前最好花2個(gè)小時(shí),認(rèn)真看一下,所有人都能看懂。就算不想學(xué)習(xí)大數(shù)據(jù),也可以增加大家的知識(shí)面。
2.Hadoop框架
Hadoop的框架最核心的設(shè)計(jì)就是:HDFS和MapReduce。HDFS為海量的數(shù)據(jù)提供了存儲(chǔ),則MapReduce為海量的數(shù)據(jù)提供了計(jì)算。
HDFS是一個(gè)高度容錯(cuò)性的系統(tǒng),適合部署在廉價(jià)的機(jī)器上。HDFS能提供高吞吐量的數(shù)據(jù)訪問,非常適合大規(guī)模數(shù)據(jù)集上的程序計(jì)算。HDFS技術(shù)是整個(gè)大數(shù)據(jù)的“入門”。只要從事大數(shù)據(jù)方面工作的程序員,不管你后面用什么樣的分析技術(shù)都必須要學(xué)會(huì)HDFS。
MapReduce是用于大規(guī)模數(shù)據(jù)集(大于1TB)的并行運(yùn)算。它極大地方便了編程人員在不會(huì)分布式并行編程的情況下,將自己的程序運(yùn)行在分布式系統(tǒng)上。因?yàn)橹挥蟹植际接?jì)算才能解決“海量數(shù)據(jù)”的分析問題。
學(xué)好HDFS,就能知道為什么它可以存儲(chǔ)海量數(shù)據(jù),知道“百度網(wǎng)盤”本身是什么?能否自己也能實(shí)現(xiàn)一個(gè)網(wǎng)盤。讓大家一開始就進(jìn)入大數(shù)據(jù)實(shí)戰(zhàn)狀態(tài)。
Hadoop是大數(shù)據(jù)中必學(xué)的一個(gè)技術(shù),也是大數(shù)據(jù)職位要求必有的一個(gè)技術(shù)。Hadoop也是后面其他技術(shù)的基礎(chǔ),學(xué)好了Hadoop才能更好的學(xué)好Hive,Hbase,Spark,Storm等。
3.數(shù)據(jù)倉(cāng)庫(kù)技術(shù)
大數(shù)據(jù)的數(shù)據(jù)倉(cāng)庫(kù)技術(shù)主要包括:Hive,Hbase,Sqoop,F(xiàn)lume等。其中Hive在企業(yè)中使用最為廣泛。對(duì)于同學(xué)們來說,Hive最容易入門,因?yàn)椴挥脤懘a;只需要有sql基礎(chǔ)就能很好的學(xué)習(xí)Hive。
Hbase是一個(gè)分布式、列式數(shù)據(jù)庫(kù)。它解決的問題是:在海量數(shù)據(jù)的情況下還能做到秒級(jí)的增、刪、改、查操作。
4.Spark內(nèi)存計(jì)算框架
Spark是當(dāng)前最為流行的基于內(nèi)存計(jì)算的分布式框架,在Spark的生態(tài)圈中的框架幾乎能夠解決所有的大數(shù)據(jù)的應(yīng)用場(chǎng)景,如果基于內(nèi)存計(jì)算,計(jì)算速度比Hadoop生態(tài)圈中的MapReduce快100倍,如果是基于磁盤的計(jì)算,那么速度快10倍以上,所以Spark是當(dāng)前大數(shù)據(jù)開發(fā)人員必備的。
Spark是有Scala語言開發(fā)的,包括:Spark-Core(離線計(jì)算)、Spark-SQL、Spark-Streaming(流式計(jì)算)、Spark-MLlib(機(jī)器學(xué)習(xí))。
Spark是整個(gè)大數(shù)據(jù)技術(shù)中的“重中之重”。因?yàn)樵诿嬖囘^程中,筆試題和面試題有60%的可能性會(huì)涉及到Spark知識(shí)點(diǎn)。所以,Spark的學(xué)習(xí)要求是:了解Spark源碼,能夠優(yōu)化Spark、能夠用Java,Scala,Python三種計(jì)算機(jī)語言開發(fā)任何的Spark程序。
5.機(jī)器學(xué)習(xí)和數(shù)據(jù)挖掘
機(jī)器學(xué)習(xí)(Machine Learning, ML)是一門多領(lǐng)域交叉學(xué)科,涉及概率論、統(tǒng)計(jì)學(xué)、逼近論、凸分析、算法復(fù)雜度理論等多門學(xué)科。專門研究計(jì)算機(jī)怎樣模擬或?qū)崿F(xiàn)人類的學(xué)習(xí)行為,以獲取新的知識(shí)或技能,重新組織已有的知識(shí)結(jié)構(gòu)使之不斷改善自身的性能。它是人工智能的核心,是使計(jì)算機(jī)具有智能的根本途徑,其應(yīng)用遍及人工智能的各個(gè)領(lǐng)域。
在公司項(xiàng)目應(yīng)用過程中,重點(diǎn)強(qiáng)調(diào)的分布式的機(jī)器學(xué)習(xí),因?yàn)榛诤A康臄?shù)據(jù)必須采用分布式的機(jī)器學(xué)習(xí)庫(kù)。否則根本就是“扯淡”。所以根據(jù)企業(yè)的需求,同學(xué)們也要分辨出哪些是分布式的機(jī)器學(xué)習(xí)庫(kù),比如:M ahout,Spark-Mllib等。
6.Storm流式計(jì)算框架
目前有兩種比較流行的計(jì)算方式:離線計(jì)算和流式計(jì)算。
流計(jì)算方式:它可以很好地對(duì)大規(guī)模流動(dòng)數(shù)據(jù)在不斷變化的運(yùn)動(dòng)過程中實(shí)時(shí)地進(jìn)行分析,捕捉到可能有用的信息,并把結(jié)果發(fā)送到下一計(jì)算節(jié)點(diǎn)。
Storm是流式計(jì)算中的技術(shù)之一,Storm集群由一個(gè)主節(jié)點(diǎn)和多個(gè)工作節(jié)點(diǎn)組成。主節(jié)點(diǎn)運(yùn)行了一個(gè)名為“Nimbus”的守護(hù)進(jìn)程,用于分配代碼、布置任務(wù)及故障檢測(cè)。每個(gè)工作節(jié) 點(diǎn)都運(yùn)行了一個(gè)名為“Supervisor”的守護(hù)進(jìn)程,用于監(jiān)聽工作,開始并終止工作進(jìn)程。Nimbus和Supervisor都能快速失敗,而且是無 狀態(tài)的,這樣一來它們就變得十分健壯。
一般來說只要用到了流式計(jì)算,還得用到Kafka。所以大數(shù)據(jù)里面需要掌握一套Kafka+Storm流式解決方案。
7.云計(jì)算之Openstack和docker
云計(jì)算從服務(wù)角度分為三層:
同學(xué)們需要重點(diǎn)掌握:Iaas層的云計(jì)算技術(shù)。目前比較流行的云平臺(tái)都是基于Iaas層的云計(jì)算,包括:阿里云(https://www.aliyun.com/)、騰訊云、百度云等。 而Openstack 和Docker就是屬于Iaas層的云計(jì)算技術(shù)。
Openstack和Docker在找工作的過程中,對(duì)應(yīng)的職位比較少,但是有很好的發(fā)展前景。建議大家先在入個(gè)門。等工作之后或者有剩余的時(shí)間再深入研究。
8.做一個(gè)大數(shù)據(jù)項(xiàng)目
“實(shí)戰(zhàn)學(xué)習(xí),最重要的就是參與項(xiàng)目”。大數(shù)據(jù)的技術(shù)學(xué)完之后,需要參與一個(gè)企業(yè)級(jí)的大項(xiàng)目,這樣才能真正的出山,拿到高薪、獲得更多的好機(jī)會(huì)。
七:區(qū)塊鏈學(xué)習(xí)知識(shí)點(diǎn)和配套視頻
區(qū)塊鏈已經(jīng)成為近年非常熱門的技術(shù),并且正在飛速的發(fā)展。各大公司都成立了區(qū)塊鏈相關(guān)部門, 大量職位空缺等待區(qū)塊鏈專業(yè)人才加入,而目前區(qū)塊鏈專業(yè)人才少之又少,所以抓住機(jī)會(huì)就是成功了一大步。
區(qū)塊鏈中涉及的面比較廣,技術(shù)又相對(duì)”底層”,學(xué)好區(qū)塊鏈后我們可以很快學(xué)習(xí)其他方向,因?yàn)閰^(qū)塊鏈可以給學(xué)習(xí)者打下很牢固的基礎(chǔ)。
在尚學(xué)堂的區(qū)塊鏈課程中,囊括了目前企業(yè)絕大多數(shù)區(qū)塊鏈相關(guān)知識(shí),又配套大量企業(yè)級(jí)項(xiàng)目,可以說是廣且深。
區(qū)塊鏈課程適用于各種人群,即使是行業(yè)小白,也可以在由淺入深的課程中逐漸學(xué)會(huì)區(qū)塊鏈。技術(shù)不是遙不可及的,都是扎扎實(shí)實(shí)學(xué)出來的。不要對(duì)某個(gè)技術(shù)有過度崇拜的沖動(dòng),一層窗戶紙而已,大膽捅破它。
我們將公布區(qū)塊鏈課程中的大部分視頻,大家可以通過下面網(wǎng)址免費(fèi)下載或者在線觀看:
http://bj0393.com.cn/qukuanlianshipin.html (區(qū)塊鏈視頻的拼音)
1.區(qū)塊鏈行業(yè)介紹
本階段主要是為了讓學(xué)習(xí)者對(duì)區(qū)塊鏈有總體的認(rèn)識(shí),從宏觀角度闡述了區(qū)塊鏈相關(guān)內(nèi)容.本階段是一個(gè)純理論階段,不需要編程, 所以學(xué)習(xí)本階段重點(diǎn)在聽而不是寫。區(qū)塊鏈也將作為像人工智能那樣的一個(gè)基礎(chǔ)技術(shù),改造現(xiàn)在的很多行業(yè)。讓很多行業(yè)去中心化,極大的提升行業(yè)效率。
2.Golang從入門到高級(jí)
本階段主要是為了讓學(xué)習(xí)者對(duì)區(qū)塊鏈有總體的認(rèn)識(shí),從宏觀角度闡述了區(qū)塊鏈相關(guān)內(nèi)容.本階段是一個(gè)純理論階段,不需要編程, 所以學(xué)習(xí)本階段重點(diǎn)在聽而不是寫。區(qū)塊鏈也將作為像人工智能那樣的一個(gè)基礎(chǔ)技術(shù),改造現(xiàn)在的很多行業(yè)。讓很多行業(yè)去中心化,極大的提升行業(yè)效率
3.數(shù)據(jù)庫(kù)操作和Golang Web
Go語言可以當(dāng)作服務(wù)端語言,使用Go語言可以完成Web項(xiàng)目開發(fā)。本階段需要Go語言的數(shù)據(jù)庫(kù)操作和網(wǎng)絡(luò)操作,其中數(shù)據(jù)庫(kù)操作是以MySQL舉例。學(xué)習(xí)完本階段后就可以使用Go開發(fā)項(xiàng)目了。如果以后是找Go語言相關(guān)工作,這階段也很重要。
4. Golang 實(shí)戰(zhàn)項(xiàng)目
在學(xué)習(xí)完前幾個(gè)階段后,本階段是要對(duì)前面幾個(gè)階段的實(shí)際應(yīng)用。單獨(dú)學(xué)習(xí)每個(gè)語法可能都不難,但是要把學(xué)習(xí)的內(nèi)容融入到實(shí)際項(xiàng)目中就需要一個(gè)轉(zhuǎn)化的過程。這個(gè)階段重點(diǎn)在敲代碼, 一定要按照視頻中順序把每個(gè)功能都認(rèn)真完成。
密碼學(xué)是區(qū)塊鏈中幾個(gè)核心部分之一,是實(shí)現(xiàn)數(shù)據(jù)按照的重要手段。在本階段中介紹了大部分區(qū)塊鏈成名項(xiàng)目中應(yīng)用頻率比較高的密碼學(xué)知識(shí)。每個(gè)密碼學(xué)都有單獨(dú)的講解,這部分要重點(diǎn)學(xué)習(xí),是后面學(xué)習(xí)比特幣、以太坊、超級(jí)賬本源碼的基礎(chǔ)。
6. 共識(shí)算法
所謂“共識(shí)機(jī)制”,是通過特殊節(jié)點(diǎn)的投票,在很短的時(shí)間內(nèi)完成對(duì)交易的驗(yàn)證和確認(rèn);對(duì)一筆交易,如果利益不相干的若干個(gè)節(jié)點(diǎn)能夠達(dá)成共識(shí),我們就可以認(rèn)為全網(wǎng)對(duì)此也能夠達(dá)成共識(shí)。再通俗一點(diǎn)來講,如果中國(guó)一名微博大V、美國(guó)一名虛擬幣玩家、一名非洲留學(xué)生和一名歐洲旅行者互不相識(shí),但他們都一致認(rèn)為你是個(gè)好人,那么基本上就可以斷定你這人還不壞。
區(qū)塊鏈作為一種按時(shí)間順序存儲(chǔ)數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu),可支持不同的共識(shí)機(jī)制。共識(shí)機(jī)制是區(qū)塊鏈技術(shù)的重要組件。
共識(shí)算法和密碼學(xué)都是區(qū)塊鏈核心部分, 學(xué)習(xí)完共識(shí)后就可以準(zhǔn)備開始學(xué)習(xí)具體的區(qū)塊鏈項(xiàng)目了。
7. Solidity
Solidity是以太坊中專門描述智能合約的語言,學(xué)習(xí)Solidity的同時(shí)也在講述什么是智能合約。 學(xué)習(xí)完Solidity就可以學(xué)習(xí)以太坊相關(guān)內(nèi)容.所以本段內(nèi)容是專門給以太坊打基礎(chǔ)。
8. 以太坊原理
以太坊和比特幣都是學(xué)習(xí)區(qū)塊鏈中經(jīng)典的例子。 這個(gè)階段,包含了以太坊原理架構(gòu)流程和一些區(qū)塊鏈中專業(yè)概念。這一階段講解比較全面,重點(diǎn)學(xué)習(xí)后就可以對(duì)區(qū)塊鏈有了較深的認(rèn)識(shí)。
9.以太坊客戶端
本階段繼續(xù)學(xué)習(xí)以太坊,主要講解以太坊客戶端配置和原理。為后面講解以太坊DApp打基礎(chǔ)。主要講解:geth客戶端配置和運(yùn)行、geth源代碼解讀。
10.去中心換拍賣系統(tǒng)DApp
本階段是對(duì)以太坊的鞏固學(xué)習(xí),屬于一個(gè)編碼階段,所有編碼階段的重點(diǎn)都是在動(dòng)手,實(shí)戰(zhàn)。所有內(nèi)容都編寫完成后就完成了對(duì)區(qū)塊第一次完整認(rèn)識(shí)。
最終我們可以利用:區(qū)塊鏈、星際文件系統(tǒng)、Node.js、MongoDB構(gòu)建一個(gè)“去中心化”革命性的電商平臺(tái)。
11.超級(jí)賬本和DApp實(shí)戰(zhàn)
超級(jí)賬本是一個(gè)大體系。 在這個(gè)階段中會(huì)使用Linux的一些命令和使用,同時(shí)這一階段中使用Go作為源碼語言。學(xué)習(xí)完這個(gè)階段后會(huì)更加加深對(duì)區(qū)塊鏈的認(rèn)識(shí)。
12.C++編程快速入門
C++語言是比特幣項(xiàng)目的編寫語言, 學(xué)習(xí)C++主要目的是為了讀懂比特幣中關(guān)鍵代碼。所以這階段不是非常詳細(xì)的把C++所有知識(shí)點(diǎn)都講解到,只是一個(gè)快速入門,能夠讀懂比特幣的核心代碼即可。
大家沒有必要對(duì)C++做過分深入的研究,畢竟應(yīng)用范圍越來越小了。
13.比特幣
比特幣作為區(qū)塊鏈的起源,也是區(qū)塊鏈行業(yè)中的標(biāo)桿。學(xué)習(xí)區(qū)塊鏈,也一定要學(xué)習(xí)比特幣相關(guān)內(nèi)容。 之前已經(jīng)學(xué)習(xí)了區(qū)塊鏈的兩大部分,這階段學(xué)習(xí)起來將會(huì)比較輕松。
14.EOS
除了幾個(gè)經(jīng)典的比特幣項(xiàng)目以外,在本套課程引入了其他的項(xiàng)目講解,目前講解的是EOS,在以后的課程中還會(huì)陸續(xù)引入小蟻、星云、量子等其他項(xiàng)目。
EOS:可以理解為Enterprise Operation System,即為商用分布式應(yīng)用設(shè)計(jì)的一款區(qū)塊鏈操作系統(tǒng)。EOS是引入的一種新的區(qū)塊鏈架構(gòu),旨在實(shí)現(xiàn)分布式應(yīng)用的性能擴(kuò)展。注意,它并不是像比特幣和以太坊那樣的貨幣,而是基于EOS軟件項(xiàng)目之上發(fā)布的代幣,被稱為區(qū)塊鏈3.0。
EOS有點(diǎn)類似于微軟的windows平臺(tái),通過創(chuàng)建一個(gè)對(duì)開發(fā)者友好的區(qū)塊鏈底層平臺(tái),支持多個(gè)應(yīng)用同時(shí)運(yùn)行,為開發(fā)dAPP提供底層的模板。
當(dāng)你擁有了EOS的話,就相當(dāng)于擁有了計(jì)算機(jī)資源,隨著DAPP的開發(fā),你可以將手里的EOS租賃給別人使用,單從這一點(diǎn)來說EOS也具有廣泛的價(jià)值。簡(jiǎn)單來說,就是你擁有了EOS,就相當(dāng)于擁有了一套房租給別人收房租,或者說擁有了一塊地租給別人建房。
八:100套畢業(yè)設(shè)計(jì)和課程設(shè)計(jì)項(xiàng)目案例和配套視頻
本套100個(gè)完整項(xiàng)目源碼是由【北京尚學(xué)堂·百戰(zhàn)程序員】學(xué)員做畢設(shè)時(shí)提供,老師提供了相應(yīng)的畢設(shè)輔導(dǎo)服務(wù)。
一共分為5季,每季約20套項(xiàng)目,希望大家持續(xù)關(guān)注。
很多大四同學(xué)苦于沒有參考的畢設(shè)資料,或者下載的資料不全、代碼有問題、數(shù)據(jù)有問題等等,造成畢設(shè)出現(xiàn)問題影響大學(xué)畢業(yè)?,F(xiàn)在,我們提供了經(jīng)過審核的100個(gè)項(xiàng)目源碼和對(duì)應(yīng)的輔導(dǎo)視頻,讓大家在短時(shí)間內(nèi)可以完成自己的畢業(yè)設(shè)計(jì)。
同時(shí),我們也錄制了更多的項(xiàng)目視頻,2018年計(jì)劃100套,后續(xù)將會(huì)有更多。大家可以到www.itbaizhan.cn在線觀看和學(xué)習(xí),也可以到北京尚學(xué)堂官網(wǎng)免費(fèi)下載。
關(guān)于版權(quán)的聲明,源碼由北京尚學(xué)堂學(xué)員做項(xiàng)目時(shí)提供,非北京尚學(xué)堂原創(chuàng)。北京尚學(xué)堂講師只提供了項(xiàng)目的部署和使用說明的視頻,如果侵犯了原作者的版權(quán),請(qǐng)聯(lián)系我們。
未來,我們將發(fā)布H5前端畢設(shè)項(xiàng)目、Python畢設(shè)項(xiàng)目、大數(shù)據(jù)畢設(shè)項(xiàng)目、人工智能畢設(shè)項(xiàng)目等。讓我們的大學(xué)生朋友再也不用為畢設(shè)發(fā)愁。請(qǐng)大家隨時(shí)關(guān)注尚學(xué)堂bjsxt.com或者百戰(zhàn)程序員(itbaizhan.cn)的官網(wǎng)。
大家可以在:
http://bj0393.com.cn/biyeshejishipin.html (畢業(yè)視頻視頻的拼音)
1.關(guān)于各種開發(fā)軟件的使用說明和配套視頻
由于很多大學(xué)生對(duì)于開發(fā)軟件不是很熟悉,我們將常見的開發(fā)軟件使用方式集中進(jìn)行了錄制。大家項(xiàng)目中用到哪些軟件,自行對(duì)比學(xué)習(xí)即可。
為了方便大家的學(xué)習(xí),我們提供了常用開發(fā)軟件的安裝包,大家可以根據(jù)需要直接從網(wǎng)盤下載:
軟件的使用方式都特別簡(jiǎn)單,大家不要有畏懼心理,這里講解了軟件在開發(fā)中最常用的使用方式。包含了常見數(shù)據(jù)庫(kù)軟件的使用(oracle、mysql、sqlserver)、數(shù)據(jù)庫(kù)客戶端操作軟件、eclipse、Myeclipse、Tomcat服務(wù)器等的使用。包含如下視頻:
1.Eclipse的使用1_開發(fā)環(huán)境使用原因
2.Eclipse的使用2_下載樓基本選擇和使用
3.Eclipse的使用3_建立JAVA項(xiàng)目_項(xiàng)目的結(jié)構(gòu)說明
4.Eclipse的使用4_開發(fā)和運(yùn)行JAVA程序
5.Eclipse(JEE)的使用_Tomcat整合_項(xiàng)目部署
6.JDK安裝1_下載和安裝_JDK目錄介紹
7.JDK安裝2_環(huán)境變量PATH設(shè)置_classpath問題
8.JDK安裝3_控制臺(tái)測(cè)試JDK安裝和配置成功
9.Myeclipse2014的安裝和使用_web項(xiàng)目創(chuàng)建和發(fā)布
10.Myeclipse和Tomcat整合_web項(xiàng)目部署
11.Mysql數(shù)據(jù)庫(kù)1_安裝和配置_命令行簡(jiǎn)單使用
12.Mysql數(shù)據(jù)庫(kù)2_navicat客戶端軟件的使用_加載SQL文件到庫(kù)
13.Oracle數(shù)據(jù)庫(kù)1_安裝
14.Oracle數(shù)據(jù)庫(kù)2_客戶端plsql安裝并連接
15.SqlServer數(shù)據(jù)庫(kù)1_安裝
16.SqlServer數(shù)據(jù)庫(kù)2_連接并回復(fù)數(shù)據(jù)庫(kù)
17.SqlServer數(shù)據(jù)庫(kù)3_客戶端操作
18.SqlServer數(shù)據(jù)庫(kù)4_卸載
19.Tomcat服務(wù)器安裝_使用介紹
2.第一季20套項(xiàng)目源代碼和配套視頻
第一季20套源代碼覆蓋范圍較廣,有比較基礎(chǔ)的JAVA初級(jí)項(xiàng)目,也有比較大的WEB項(xiàng)目。每個(gè)項(xiàng)目我們都提供了完整的內(nèi)容,涵蓋:論文、PPT、源代碼、數(shù)據(jù)庫(kù)文件、配套講解視頻。我們以“土地局檔案管理系統(tǒng)”為例:
打開“論文等資料”文件夾,就發(fā)現(xiàn)有完整的論文和答辯內(nèi)容,供大家參考:
打開“項(xiàng)目輔導(dǎo)視頻”,就發(fā)現(xiàn)有詳細(xì)的項(xiàng)目講解視頻,幫助大家解決項(xiàng)目部署、項(xiàng)目模塊講解的問題:
為了快速查看這個(gè)項(xiàng)目是否符合你的需求,可以打開“項(xiàng)目截圖”文件夾:
報(bào)表圖.png
捕獲.png
檔案修改.png
登錄.png
功能.png
注冊(cè).png
第一季視頻涵蓋如下圖所示項(xiàng)目,范圍比較廣泛。有電子政務(wù)項(xiàng)目、也有醫(yī)療項(xiàng)目、也有供應(yīng)鏈管理項(xiàng)目、互聯(lián)網(wǎng)項(xiàng)目也有若干。同時(shí),也有幾個(gè)java基礎(chǔ)項(xiàng)目,大家可以用于做JAVA的課程設(shè)計(jì)。
九:7U職場(chǎng)軟實(shí)力課程和配套視頻
1.職場(chǎng)軟實(shí)力是什么?
“每一個(gè)人都要訓(xùn)練軟實(shí)力”。成功職場(chǎng)和成功人生不僅需要硬實(shí)力,更需要軟實(shí)力。兩種實(shí)力就像人的雙腿,缺一即“殘”。中國(guó)傳媒大學(xué)老師王雪和北京尚學(xué)堂總裁高淇發(fā)明了7U軟實(shí)力理論,讓人的軟實(shí)力有可測(cè)量的七種維度和提升的標(biāo)準(zhǔn)。已經(jīng)有上百位學(xué)員受益,短時(shí)間極速提升自己的軟實(shí)力,讓自己的工作、愛情、生活都極大受益。
程序員往往關(guān)注“編碼能力”等硬實(shí)力的提升,而忽視了“口才”、“溝通”等軟實(shí)力的提升,造成發(fā)展的困境、職位升遷的困境、甚至戀愛婚姻的困境。所以,對(duì)于軟實(shí)力不太好的朋友,非常有必要學(xué)習(xí)軟實(shí)力。
更重要的是,軟實(shí)力是一個(gè)相對(duì)的概念。而且大多數(shù)人對(duì)認(rèn)為“軟實(shí)力”是天生的,無法通過訓(xùn)練改變。而實(shí)際上,軟實(shí)力可以通過訓(xùn)練快速提升。大家都不學(xué)習(xí)的情況下,你是很容易脫穎而出的。
職場(chǎng)軟實(shí)力不等于技能,但可以讓你的技能得到更好的發(fā)揮。它是你個(gè)人發(fā)展的“催化劑”,可以讓你發(fā)展更快、走的更穩(wěn)。
2.形象氣質(zhì)和社交禮儀
好的形象氣質(zhì)和職場(chǎng)禮儀是你成功的“助跑器”。除了你父母,沒有人有義務(wù)通過你邋遢的外表和不專業(yè)的禮儀深入了解你的內(nèi)在。
本階段將詳細(xì)介紹在各種場(chǎng)合的實(shí)用技巧。包括:服裝搭配、言談舉止、社交禮儀、生活禮儀、宴會(huì)禮儀。
讓你完全掌握職場(chǎng)上的基本禮儀,商務(wù)接待和談判的禮儀;掌握生活中待人接物的禮儀,成為一個(gè)落落大方的人;掌握宴會(huì)禮儀,明白如何講話,如何根據(jù)自己的身份說恰當(dāng)?shù)脑捫g(shù)。
3.聲音素質(zhì)
聲音不是天生的,可以通過專業(yè)的發(fā)聲技巧來改變。如果聲音不好聽,在人際交往中的效果就要大打折扣。本階段旨在培養(yǎng)大家如何在溝通中發(fā)出好聽的聲音,讓我們的聲音更有磁性,更有力量,更有感染力。
學(xué)會(huì)掌握自己的聲音,在卡拉OK的場(chǎng)合,再也不懼了。在公眾發(fā)言的場(chǎng)合,心里也會(huì)更加有底氣。
聲音是人的第二張名片。我們可以通過掌握胸腹式聯(lián)合呼吸法、共鳴訓(xùn)練,正確的用氣技巧,很快就能成為一個(gè)再也不懼“發(fā)言”場(chǎng)合的人。
4.情商
人際關(guān)系有多重要,情商就有多重要。情商是我們所有軟實(shí)力的基礎(chǔ),也是最后的一個(gè)升華,所以掌握情商能夠讓我們的人際關(guān)系更加的和諧,同時(shí)在處理困難挫折的時(shí)候又不至于焦頭爛額。本階段將告訴大家我們緊張的原因以及克服的技巧,從微表情中看出對(duì)方?jīng)]有用語言表達(dá)出來的想法,學(xué)會(huì)如何面對(duì)各種“失意”的情緒,以及在朋友圈中,在職場(chǎng)中如何利用情商處理人際關(guān)系。
通過學(xué)習(xí)情緒控制的基本原理:緊張的原理、條件反射原理。讓自己明白,情商的基礎(chǔ)物理知識(shí)。再進(jìn)一步學(xué)習(xí),微表情、自身情商的激勵(lì),成為一個(gè)“高情商”的人。
再進(jìn)一步學(xué)習(xí),“朋友中的情商”讓自己成為一個(gè)善解人意的人;學(xué)習(xí)“職場(chǎng)情商”,讓自己成為一個(gè)懂領(lǐng)導(dǎo)、懂同事、懂下屬的“高情商”的合作伙伴;
5.溝通力
好的溝通力是人際交往的基礎(chǔ),可以極大降低生活和工作成本。壞的溝通力能把好事也辦成壞事。本階段將詳細(xì)介紹如何更好的打開對(duì)方的心扉快速對(duì)接,以及贊美和批評(píng)的20多種技巧,還會(huì)講到如何講好故事,方便我們的溝通,以及酒宴場(chǎng)合的一些應(yīng)對(duì)技巧。
我們需要學(xué)習(xí):
1.如何介紹自己、商務(wù)場(chǎng)合介紹他人、八卦場(chǎng)合介紹他人
2.人性的特點(diǎn)
3.如何尋找合適的話題
4.掌握贊美的藝術(shù)
5.掌握批評(píng)他人的技巧
6.各種酒宴場(chǎng)合的演講技巧
7.掌握講好一件事的技術(shù)
6.說服力
生活是由一個(gè)個(gè)說服和被說服構(gòu)成的,不是被別人說服,就是在說服別人。說服力是職場(chǎng)成功的關(guān)鍵。本階段講解提升說服力的技巧方法,讓我們快速的說服領(lǐng)導(dǎo)、同事以及家人。
好的說服力,在你談戀愛、找工作中能發(fā)揮極致作用。我們需要學(xué)習(xí)如下內(nèi)容:
1.如何破冰,破冰的八大策略
2.如何增加籌碼說服別人
3.十大說服技巧
4.條理公式(說服需要條理和邏輯)
7.說服力之銷售
不管你的職業(yè)是什么,每個(gè)人都是銷售。有人銷售產(chǎn)品,有人銷售思想,有人銷售自己。本階段主要針對(duì)銷售的技巧進(jìn)行提升,對(duì)于沒有經(jīng)驗(yàn)的學(xué)員能夠快速提升銷售技巧,對(duì)于有經(jīng)驗(yàn)的銷售人員極大提高轉(zhuǎn)化效率。
做任何職業(yè),掌握銷售技巧都是非常有幫助的。畢竟,本質(zhì)上“人人都是銷售員”。我們需要學(xué)習(xí)如下內(nèi)容:
成功銷售三部曲(問、聽、看)
銷售十大步驟
絕對(duì)成交七個(gè)技巧
8.演講力
“能面對(duì)多少人講話,就能有多大的成就”。本階段從演講的三個(gè)關(guān)鍵點(diǎn)入手,進(jìn)行細(xì)節(jié)分析和技巧把握,以及如何應(yīng)對(duì)演講過程中的尷尬,如何在舞臺(tái)上進(jìn)行即興演講,讓我們站在舞臺(tái)上更加從容。
我們需要學(xué)習(xí)演講訓(xùn)練的如下關(guān)鍵點(diǎn):
1.如何寫出漂亮的演講稿
2.如何克服恐懼
3.演講自我介紹和互動(dòng)技巧
4.萬能開場(chǎng)白
5.把握演講節(jié)奏和內(nèi)容
6.眼神、形體、語氣如何運(yùn)用
7.演講的小策略
①.如何營(yíng)造互動(dòng)氛圍
②.如何贏取掌聲
③.忘詞怎么辦
④.如何面對(duì)刁鉆古怪的問題
9.領(lǐng)導(dǎo)力
“不想當(dāng)將軍的士兵不是好士兵”,領(lǐng)導(dǎo)力培養(yǎng)需要從娃娃抓起,是先有領(lǐng)導(dǎo)力才能成為領(lǐng)導(dǎo),而不是成為領(lǐng)導(dǎo)再鍛煉領(lǐng)導(dǎo)力(除非有個(gè)好爸爸給你大量練手機(jī)會(huì))。本階段圍繞領(lǐng)導(dǎo)力的的九種特質(zhì)及快速提升領(lǐng)導(dǎo)力的方法,以及怎樣創(chuàng)建一個(gè)優(yōu)秀的適合企業(yè)發(fā)展的團(tuán)隊(duì)。
學(xué)好領(lǐng)導(dǎo)力,需要學(xué)習(xí)如下課程,并開始實(shí)戰(zhàn)訓(xùn)練:
1.理解領(lǐng)導(dǎo)力的九大特質(zhì)
2.領(lǐng)導(dǎo)的創(chuàng)新心態(tài)調(diào)整
組織管理的核心秘訣
4.如何制定合理的戰(zhàn)略決策
5.正確的溝通協(xié)調(diào)下屬方式
1.JAVA專業(yè),1000課 | 3.大數(shù)據(jù)專業(yè),500課 |
2.Python專業(yè),500課 | 4.人工智能專業(yè),500課 |
四個(gè)專業(yè)都要學(xué),從零開始2000小時(shí),成為高端人才,打下一生技術(shù)基礎(chǔ),不再是低端碼農(nóng)。
2.掃一掃,咨詢?cè)斍椋?/p>
訪問官網(wǎng) www.itbaizhan.cn