Java 基礎總結。

 

1.爲何要用裝箱與拆箱css

Java是面嚮對象語言。基本數據類型不具備面向對象的特性。html

2.== 與 Equals方法有什麼區別前端

== 用來判斷像個變量之間的值是否相等,變量分爲基本數據類型對象與引用類型對象。java

若是是基本數據類型變量直接比較而引用類型比較對應的引用內存的首地址。mysql

equals 用來比較兩個對象長的是否同樣,判斷兩個對象某些特徵是否同樣。程序員

3.String 與 StringBuffer 區別  ?web

String 是內容不可變得字符串。String 底層使用一個不可變得字符數組(Final chart[])面試

FInal若是修飾一個類就不能被繼承,若是修飾一個變量那麼被賦值就不能再改變redis

StringBuffer與StringBuilder是內容能夠改變的字符串。底層使用一個可變的字符數組。算法

4.StringBuffer與StringBuilder區別?

StringBuilder 是線程不安全的效率較高。

StringBuffer 是線程安全的效率較低、添加一個同步鎖。

最經典的拼接字符串.

1.String進行拼接,String c = "a" + "b";

2.StringBuffer與StringBuilder  拼接。  經過append進行拼接。

字符串池的優缺點:

優勢:字符串池的優勢避免相同字符串的建立節省內存,省去建立相同字符串的的時間提升性能

缺點:Jvm在常量池遍歷對象花費的時間,不過期間成本較少

/**
* 情景一:字符串池 
* JAVA虛擬機(JVM)中存在着一個字符串池,其中保存着不少String對象; 
* 而且能夠被共享使用,所以它提升了效率。 
* 因爲String類是final的,它的值一經建立就不可改變。 
* 字符串池由String類維護,咱們能夠調用intern()方法來訪問字符串池。  
*/  
String s1 = "abc";
//↑ 在字符串池建立了一個對象  
String s2 = "abc";
//↑ 字符串pool已經存在對象「abc」(共享),因此建立0個對象,累計建立一個對象  
System.out.println("s1 == s2 : "+(s1==s2));
//↑ true 指向同一個對象,  
System.out.println("s1.equals(s2) : " + (s1.equals(s2)));
//↑ true  值相等  
//↑------------------------------------------------------over  
/**
* 情景二:關於new String("") 
*
*/
String s3 = new String("abc");
//↑ 建立了兩個對象,一個存放在字符串池中,一個存在與堆區中;  
//↑ 還有一個對象引用s3存放在棧中  
String s4 = new String("abc");
//↑ 字符串池中已經存在「abc」對象,因此只在堆中建立了一個對象  
System.out.println("s3 == s4 : "+(s3==s4));
//↑false   s3和s4棧區的地址不一樣,指向堆區的不一樣地址;  
System.out.println("s3.equals(s4) : "+(s3.equals(s4)));
//↑true  s3和s4的值相同  
System.out.println("s1 == s3 : "+(s1==s3));
//↑false 存放的地區多不一樣,一個棧區,一個堆區  
System.out.println("s1.equals(s3) : "+(s1.equals(s3)));
//↑true  值相同  
//↑------------------------------------------------------over  
/**
* 情景三:  
* 因爲常量的值在編譯的時候就被肯定(優化)了。 
* 在這裏,"ab"和"cd"都是常量,所以變量str3的值在編譯時就能夠肯定。 
* 這行代碼編譯後的效果等同於: String str3 = "abcd"; 
*/
String str1 = "ab" + "cd";  //1個對象  
String str11 = "abcd";
System.out.println("str1 = str11 : "+ (str1 == str11));
//↑------------------------------------------------------over  
/**
* 情景四:  
* 局部變量str2,str3存儲的是存儲兩個拘留字符串對象(intern字符串對象)的地址。 
*
* 第三行代碼原理(str2+str3): 
* 運行期JVM首先會在堆中建立一個StringBuilder類, 
* 同時用str2指向的拘留字符串對象完成初始化, 
* 而後調用append方法完成對str3所指向的拘留字符串的合併, 
* 接着調用StringBuilder的toString()方法在堆中建立一個String對象, 
* 最後將剛生成的String對象的堆地址存放在局部變量str3中。 
*
* 而str5存儲的是字符串池中"abcd"所對應的拘留字符串對象的地址。 
* str4與str5地址固然不同了。 
*
* 內存中實際上有五個字符串對象: 
*       三個拘留字符串對象、一個String對象和一個StringBuilder對象。 
*/
String str2 = "ab";  //1個對象  
String str3 = "cd";  //1個對象                                         
String str4 = str2+str3;
String str5 = "abcd";
System.out.println("str4 = str5 : " + (str4==str5)); // false  
//↑------------------------------------------------------over  
/**
* 情景五: 
*  JAVA編譯器對string + 基本類型/常量 是當成常量表達式直接求值來優化的。 
*  運行期的兩個string相加,會產生新的對象的,存儲在堆(heap)中 
*/
String str6 = "b";
String str7 = "a" + str6;
String str67 = "ab";
System.out.println("str7 = str67 : "+ (str7 == str67));
//↑str6爲變量,在運行期纔會被解析。  
final String str8 = "b";
String str9 = "a" + str8;
String str89 = "ab";
System.out.println("str9 = str89 : "+ (str9 == str89));
//↑str8爲常量變量,編譯期會被優化  
//↑------------------------------------------------------over  

 

 

 

5.Java 中的集合

Java集合分爲 value 與  key - value (Collection Map)兩種

存儲值得有 list和Set

  List是有序的能夠重複

  Set是無序的不能夠重複

存儲Key - value 有Map

6.ArrayList 和LinkList 區別

ArrayList  底層使用是數組

※  數組具備索引查詢特定元素較快。而插入刪除較慢。(數組在內存中是一塊連續的內存。若是插入刪除須要移動內存)

LinkList  底層使用鏈表

※鏈表內存是不須要連續的。在當前元素中存放下一個或上一個元素地址。查詢須要從頭開始找。效率低。

拆入是不須要移動內存。只須要改變引用指向便可。因此插入或者刪除效率高

7.HashMap和HashTable區別。HashMap和ConcurrentHashMap區別

相同點:HashMap和HashTable均可以存儲key  - value的數據

不一樣點:

1.HashMap是能夠將NULL做爲key或者Value ,HashTable是不能夠的

2.HashMap是線程不安全的,效率較高。而HashTable是線程安全的。效率較低

我想線程安全又想效率高?

ConcurrentHashMap 經過整個Map分爲N個segment(相似HashMap)。

能夠提供相同的線程安全。但效率提升N倍。默認是16倍。

 8.拷貝一個文件工具類使用字節流仍是字符流?

拷貝文件不肯定是否包含字符流。有可能有字節。(圖片、聲音、圖形) 考慮通用性使用字節流。

字節流附加:

1.IO流概述
概述:
  IO流簡單來講就是Input和Output流,IO流主要是用來處理設備之間的數據傳輸,Java對於數據的操做都是經過流實現,而java用於操做流的對象都在IO包中。 分類:   按操做數據分爲:字節流和字符流。 如:Reader和InpurStream   按流向分:輸入流和輸出流。如:InputStream和OutputStream IO流經常使用的基類:   
* InputStream , OutputStream 字符流的抽象基類:   * Reader , Writer 由上面四個類派生的子類名稱都是以其父類名做爲子類的後綴:如:FileReader和FileInputStream

 

1. 字符流簡介:
* 字符流中的對象融合了編碼表,也就是系統默認的編碼表。咱們的系統通常都是GBK編碼。
* 字符流只用來處理文本數據,字節流用來處理媒體數據。
* 數據最多見的表現方式是文件,字符流用於操做文件的子類通常是FileReader和FileWriter。
2.字符流讀寫:
注意事項:
* 寫入文件後必需要用flush()刷新。
* 用完流後記得要關閉流
* 使用流對象要拋出IO異常
 
* 定義文件路徑時,能夠用「/」或者「\\」。
* 在建立一個文件時,若是目錄下有同名文件將被覆蓋。
* 在讀取文件時,必須保證該文件已存在,不然出異常

 

import java.io.*;  
import java.util.Scanner;  
  
class CopyText {  
    public static void main(String[] args) throws IOException {  
        sop("請輸入要拷貝的文件的路徑:");  
        Scanner in = new Scanner(System.in);  
        String source = in.next();  
        sop("請輸入須要拷貝到那個位置的路徑以及生成的文件名:");  
        String destination = in.next();  
        in.close();  
        CopyTextDemo(source,destination);  
  
    }  
  
/*****************文件Copy*********************/  
    private static void CopyTextDemo(String source,String destination) {  
  
        try {  
            FileWriter fw = new FileWriter(destination);  
            FileReader fr = new FileReader(source);  
            char []  buf = new char[1024];   
            //將Denmo中的文件讀取到buf數組中。  
            int num = 0;      
            while((num = fr.read(buf))!=-1) {  
                               //String(char[] value , int offest,int count) 分配一個新的String,包含從offest開始的count個字符  
                fw.write(new String(buf,0,num));  
            }  
            fr.close();  
            fw.close();  
        }  
        catch (IOException e) {  
            sop(e.toString());  
        }  
    }  
  
  
  
/**********************Println************************/  
    private static void sop(Object obj) {  
        System.out.println(obj);  
    }  
}  
1. 字符流的緩衝區:BufferedReader和BufferedWreiter
* 緩衝區的出現時爲了提升流的操做效率而出現的.
* 須要被提升效率的流做爲參數傳遞給緩衝區的構造函數
* 在緩衝區中封裝了一個數組,存入數據後一次取出
BufferedReader示例:
讀取流緩衝區提供了一個一次讀一行的方法readline,方便對文本數據的獲取。
readline()只返回回車符前面的字符,不返回回車符。若是是複製的話,必須加入newLine(),寫入回車符
newLine()是java提供的多平臺換行符寫入方法。
import java.io.*;  
  
  
class BufferedWriterDemo {  
    public static void main(String[] args)  throws IOException {  
  
        //建立一個字符寫入流對象  
        FileWriter fw = new FileWriter("buf.txt");  
  
        //爲了提升字符寫入效率,加入了緩衝技術。  
        //只要將須要被提升效率的流做爲參數傳遞給緩衝區的構造函數便可  
        BufferedWriter bfw = new BufferedWriter(fw);  
  
        //bfw.write("abc\r\nde");  
        //bfw.newLine();               這行代碼等價於bfw.write("\r\n"),至關於一個跨平臺的換行符  
        //用到緩衝區就必需要刷新  
        for(int x = 1; x < 5; x++) {  
            bfw.write("abc");  
            bfw.newLine();                  //java提供了一個跨平臺的換行符newLine();  
            bfw.flush();  
        }  
  
  
  
        bfw.flush();                                                //刷新緩衝區  
        bfw.close();                                                //關閉緩衝區,可是必需要先刷新  
  
        //注意,關閉緩衝區就是在關閉緩衝中的流對象  
        fw.close();                                                 //關閉輸入流對象  
  
    }  
}  

字節流:

1、字節流和字符流的基本操做是相同的,可是要想操做媒體流就須要用到字節流。
2、字節流由於操做的是字節,因此能夠用來操做媒體文件。(媒體文件也是以字節存儲的)
3、讀寫字節流:InputStream   輸入流(讀)和OutputStream  輸出流(寫)
4、字節流操做能夠不用刷新流操做。
五、InputStream特有方法: int available();//返回文件中的字節個數
注:能夠利用此方法來指定讀取方式中傳入數組的長度,從而省去循環判斷。可是若是文件較大,而虛擬機啓動分配的默認內存通常爲64M。當文件過大時,此數組長度所佔內存空間就會溢出。
因此,此方法慎用,當文件不大時,能夠使用。
import java.io.*;  
  
  
class CopyPic {  
    public static void main(String[] args){  
        copyBmp();  
        System.out.println("複製完成");  
    }  
  
    public static void copyBmp() {  
  
        FileInputStream fis = null;  
        FileOutputStream fos = null;  
        try {  
            fis = new FileInputStream("F:\\java_Demo\\day9_28\\1.bmp");             //寫入流關聯文件  
            fos = new FileOutputStream("F:\\java_Demo\\day9_28\\2.bmp");            //讀取流關聯文件  
            byte[] copy = new byte[1024];  
            int len = 0;  
            while((len=fis.read(copy))!=-1) {  
            fos.write(copy,0,len);  
            }  
        }  
        catch (IOException e) {  
            e.printStackTrace();  
            throw new RuntimeException("複製文件異常");  
        }  
        finally {  
            try {  
                if(fis!=null) fis.close();  
            }  
            catch (IOException e) {  
                e.printStackTrace();  
                throw new RuntimeException("讀取流");  
            }  
        }  
          
    }  
  
}  

 

9.線程實現方式?

1.繼承Thread;類實現一個線程

2.實現Runnable接口實現一個線程

  繼承過展性不強。Java只支持單繼承。

3.怎麼啓動?

  Thread  thread = new Thread(繼承Thread的對象/實現Runnable對象)

  thread.start();

  啓動線程使用start方法。而啓動之後執行了run方法。

4.怎麼區分線程?

  thread.setName("設置一個線程名稱")。

線程:

1:什麼是線程?
    線程是操做系統可以進行運算調度的最小單位,它被包含在進程之中,是進程中的實際運做單位。程序員能夠經過它進行多處理器編程,你能夠使用多線程對運算密集型任務提速。好比,若是一個線程完成一個任務要100毫秒,那麼用十個線程完成改任務只需10毫秒。Java在語言層面對多線程提供了卓越的支持,它也是一個很好的賣點。欲瞭解更多詳細信息請點擊這裏。
2:線程和進程有什麼區別?
    線程是進程的子集,一個進程能夠有不少線程,每條線程並行執行不一樣的任務。不一樣的進程使用不一樣的內存空間,而全部的線程共享一片相同的內存空間。別把它和棧內存搞混,每一個線程都擁有單獨的棧內存用來存儲本地數據。更多詳細信息請點擊這裏。
3:如何在Java中實現線程?
    在語言層面有兩種方式。java.lang.Thread 類的實例就是一個線程可是它須要調用java.lang.Runnable接口來執行,因爲線程類自己就是調用的Runnable接口因此你能夠繼承java.lang.Thread 類或者直接調用Runnable接口來重寫run()方法實現線程。更多詳細信息請點擊這裏.
4:用Runnable仍是Thread?
    這個問題是上題的後續,你們都知道咱們能夠經過繼承Thread類或者調用Runnable接口來實現線程,問題是,那個方法更好呢?什麼狀況下使用它?這個問題很容易回答,若是你知道Java不支持類的多重繼承,但容許你調用多個接口。因此若是你要繼承其餘類,固然是調用Runnable接口好了。更多詳細信息請點擊這裏。
5:Thread 類中的start(:和 run(:方法有什麼區別?
    這個問題常常被問到,但仍是能今後區分出面試者對Java線程模型的理解程度。start()方法被用來啓動新建立的線程,並且start()內部調用了run()方法,這和直接調用run()方法的效果不同。當你調用run()方法的時候,只會是在原來的線程中調用,沒有新的線程啓動,start()方法纔會啓動新線程。更多討論請點擊這裏
6:Java中Runnable和Callable有什麼不一樣?
    Runnable和Callable都表明那些要在不一樣的線程中執行的任務。Runnable從JDK1.0開始就有了,Callable是在JDK1.5增長的。它們的主要區別是Callable的 call(:方法能夠返回值和拋出異常,而Runnable的run()方法沒有這些功能。Callable能夠返回裝載有計算結果的Future對象。個人博客有更詳細的說明。
7:Java中CyclicBarrier 和 CountDownLatch有什麼不一樣?
    CyclicBarrier 和 CountDownLatch 均可以用來讓一組線程等待其它線程。與 CyclicBarrier 不一樣的是,CountdownLatch 不能從新使用。點此查看更多信息和示例代碼。
8:Java內存模型是什麼?
    Java內存模型規定和指引Java程序在不一樣的內存架構、CPU和操做系統間有肯定性地行爲。它在多線程的狀況下尤爲重要。Java內存模型對一個線程所作的變更能被其它線程可見提供了保證,它們之間是先行發生關係。這個關係定義了一些規則讓程序員在併發編程時思路更清晰。好比,先行發生關係確保了:
        線程內的代碼可以按前後順序執行,這被稱爲程序次序規則。
        對於同一個鎖,一個解鎖操做必定要發生在時間上後發生的另外一個鎖定操做以前,也叫作管程鎖定規則。
        前一個對volatile的寫操做在後一個volatile的讀操做以前,也叫volatile變量規則。
        一個線程內的任何操做必需在這個線程的start()調用以後,也叫做線程啓動規則。
        一個線程的全部操做都會在線程終止以前,線程終止規則。
        一個對象的終結操做必需在這個對象構造完成以後,也叫對象終結規則。
        可傳遞性
    我強烈建議你們閱讀《Java併發編程實踐》第十六章來加深對Java內存模型的理解。
9:Java中的volatile 變量是什麼?
    volatile是一個特殊的修飾符,只有成員變量才能使用它。在Java併發程序缺乏同步類的狀況下,多線程對成員變量的操做對其它線程是透明的。volatile變量能夠保證下一個讀取操做會在前一個寫操做以後發生,就是上一題的volatile變量規則。點擊這裏查看更多volatile的相關內容。
10:什麼是線程安全?Vector是一個線程安全類嗎? 
    若是你的代碼所在的進程中有多個線程在同時運行,而這些線程可能會同時運行這段代碼。若是每次運行結果和單線程運行的結果是同樣的,並且其餘的變量的值也和預期的是同樣的,就是線程安全的。一個線程安全的計數器類的同一個實例對象在被多個線程使用的狀況下也不會出現計算失誤。很顯然你能夠將集合類分紅兩組,線程安全和非線程安全的。Vector 是用同步方法來實現線程安全的, 而和它類似的ArrayList不是線程安全的。
11:Java中什麼是競態條件?
    競態條件會致使程序在併發狀況下出現一些bugs。多線程對一些資源的競爭的時候就會產生競態條件,若是首先要執行的程序競爭失敗排到後面執行了,那麼整個程序就會出現一些不肯定的bugs。這種bugs很難發現並且會重複出現,由於線程間的隨機競爭。一個例子就是無序處理,詳見答案。
12:Java中如何中止一個線程?
    Java提供了很豐富的API但沒有爲中止線程提供API。JDK 1.0原本有一些像stop(), suspend(:和 resume()的控制方法可是因爲潛在的死鎖威脅所以在後續的JDK版本中他們被棄用了,以後Java API的設計者就沒有提供一個兼容且線程安全的方法來中止一個線程。當run(:或者 call(:方法執行完的時候線程會自動結束,若是要手動結束一個線程,你能夠用volatile 布爾變量來退出run()方法的循環或者是取消任務來中斷線程。點擊這裏查看示例代碼。
13:一個線程運行時發生異常會怎樣?
    這是我在一次面試中遇到的一個很刁鑽的Java面試題, 簡單的說,若是異常沒有被捕獲該線程將會中止執行。Thread.UncaughtExceptionHandler是用於處理未捕獲異常形成線程忽然中斷狀況的一個內嵌接口。當一個未捕獲異常將形成線程中斷的時候JVM會使用Thread.getUncaughtExceptionHandler()來查詢線程的UncaughtExceptionHandler並將線程和異常做爲參數傳遞給handler的uncaughtException()方法進行處理。
14:如何在兩個線程間共享數據?
    你能夠經過共享對象來實現這個目的,或者是使用像阻塞隊列這樣併發的數據結構。這篇教程《Java線程間通訊》(涉及到在兩個線程間共享對象)用wait和notify方法實現了生產者消費者模型。
15:Java中notify 和 notifyAll有什麼區別?
    這又是一個刁鑽的問題,由於多線程能夠等待單監控鎖,Java API 的設計人員提供了一些方法當等待條件改變的時候通知它們,可是這些方法沒有徹底實現。notify()方法不能喚醒某個具體的線程,因此只有一個線程在等待的時候它纔有用武之地。而notifyAll()喚醒全部線程並容許他們爭奪鎖確保了至少有一個線程能繼續運行。個人博客有更詳細的資料和示例代碼。
16:爲何wait, notify 和 notifyAll這些方法不在thread類裏面?
    這是個設計相關的問題,它考察的是面試者對現有系統和一些廣泛存在但看起來不合理的事物的見解。回答這些問題的時候,你要說明爲何把這些方法放在Object類裏是有意義的,還有不把它放在Thread類裏的緣由。一個很明顯的緣由是JAVA提供的鎖是對象級的而不是線程級的,每一個對象都有鎖,經過線程得到。若是線程須要等待某些鎖那麼調用對象中的wait()方法就有意義了。若是wait()方法定義在Thread類中,線程正在等待的是哪一個鎖就不明顯了。簡單的說,因爲wait,notify和notifyAll都是鎖級別的操做,因此把他們定義在Object類中由於鎖屬於對象。你也能夠查看這篇文章瞭解更多。
17:什麼是ThreadLocal變量?
    ThreadLocal是Java裏一種特殊的變量。每一個線程都有一個ThreadLocal就是每一個線程都擁有了本身獨立的一個變量,競爭條件被完全消除了。它是爲建立代價高昂的對象獲取線程安全的好方法,好比你能夠用ThreadLocal讓SimpleDateFormat變成線程安全的,由於那個類建立代價高昂且每次調用都須要建立不一樣的實例因此不值得在局部範圍使用它,若是爲每一個線程提供一個本身獨有的變量拷貝,將大大提升效率。首先,經過複用減小了代價高昂的對象的建立個數。其次,你在沒有使用高代價的同步或者不變性的狀況下得到了線程安全。線程局部變量的另外一個不錯的例子是ThreadLocalRandom類,它在多線程環境中減小了建立代價高昂的Random對象的個數。查看答案瞭解更多。
18:什麼是FutureTask?
    在Java併發程序中FutureTask表示一個能夠取消的異步運算。它有啓動和取消運算、查詢運算是否完成和取回運算結果等方法。只有當運算完成的時候結果才能取回,若是運算還沒有完成get方法將會阻塞。一個FutureTask對象能夠對調用了Callable和Runnable的對象進行包裝,因爲FutureTask也是調用了Runnable接口因此它能夠提交給Executor來執行。
19:Java中interrupted 和 isInterruptedd方法的區別?
    interrupted(:和 isInterrupted()的主要區別是前者會將中斷狀態清除然後者不會。Java多線程的中斷機制是用內部標識來實現的,調用Thread.interrupt()來中斷一個線程就會設置中斷標識爲true。當中斷線程調用靜態方法Thread.interrupted()來檢查中斷狀態時,中斷狀態會被清零。而非靜態方法isInterrupted()用來查詢其它線程的中斷狀態且不會改變中斷狀態標識。簡單的說就是任何拋出InterruptedException異常的方法都會將中斷狀態清零。不管如何,一個線程的中斷狀態有有可能被其它線程調用中斷來改變。
20:爲何wait和notify方法要在同步塊中調用?
    主要是由於Java API強制要求這樣作,若是你不這麼作,你的代碼會拋出IllegalMonitorStateException異常。還有一個緣由是爲了不wait和notify之間產生競態條件。
21:爲何你應該在循環中檢查等待條件?
    處於等待狀態的線程可能會收到錯誤警報和僞喚醒,若是不在循環中檢查等待條件,程序就會在沒有知足結束條件的狀況下退出。所以,當一個等待線程醒來時,不能認爲它原來的等待狀態仍然是有效的,在notify()方法調用以後和等待線程醒來以前這段時間它可能會改變。這就是在循環中使用wait()方法效果更好的緣由,你能夠在Eclipse中建立模板調用wait和notify試一試。若是你想了解更多關於這個問題的內容,我推薦你閱讀《Effective Java》這本書中的線程和同步章節。
22:Java中的同步集合與併發集合有什麼區別?
    同步集合與併發集合都爲多線程和併發提供了合適的線程安全的集合,不過併發集合的可擴展性更高。在Java1.5以前程序員們只有同步集合來用且在多線程併發的時候會致使爭用,阻礙了系統的擴展性。Java5介紹了併發集合像ConcurrentHashMap,不只提供線程安全還用鎖分離和內部分區等現代技術提升了可擴展性。更多內容詳見答案。
23:Java中堆和棧有什麼不一樣?
    爲何把這個問題歸類在多線程和併發面試題裏?由於棧是一塊和線程緊密相關的內存區域。每一個線程都有本身的棧內存,用於存儲本地變量,方法參數和棧調用,一個線程中存儲的變量對其它線程是不可見的。而堆是全部線程共享的一片公用內存區域。對象都在堆裏建立,爲了提高效率線程會從堆中弄一個緩存到本身的棧,若是多個線程使用該變量就可能引起問題,這時volatile 變量就能夠發揮做用了,它要求線程從主存中讀取變量的值。
24:什麼是線程池? 爲何要使用它?
    建立線程要花費昂貴的資源和時間,若是任務來了才建立線程那麼響應時間會變長,並且一個進程能建立的線程數有限。爲了不這些問題,在程序啓動的時候就建立若干線程來響應處理,它們被稱爲線程池,裏面的線程叫工做線程。從JDK1.5開始,Java API提供了Executor框架讓你能夠建立不一樣的線程池。好比單線程池,每次處理一個任務;數目固定的線程池或者是緩存線程池(一個適合不少生存期短的任務的程序的可擴展線程池)。更多內容詳見這篇文章。
25:如何寫代碼來解決生產者消費者問題?
    在現實中你解決的許多線程問題都屬於生產者消費者模型,就是一個線程生產任務供其它線程進行消費,你必須知道怎麼進行線程間通訊來解決這個問題。比較低級的辦法是用wait和notify來解決這個問題,比較讚的辦法是用Semaphore 或者 BlockingQueue來實現生產者消費者模型,這篇教程有實現它。
26:如何避免死鎖?
    Java多線程中的死鎖
    死鎖是指兩個或兩個以上的進程在執行過程當中,因爭奪資源而形成的一種互相等待的現象,若無外力做用,它們都將沒法推動下去。這是一個嚴重的問題,由於死鎖會讓你的程序掛起沒法完成任務,死鎖的發生必須知足如下四個條件:
        互斥條件:一個資源每次只能被一個進程使用。
        請求與保持條件:一個進程因請求資源而阻塞時,對已得到的資源保持不放。
        不剝奪條件:進程已得到的資源,在末使用完以前,不能強行剝奪。
        循環等待條件:若干進程之間造成一種頭尾相接的循環等待資源關係。
    避免死鎖最簡單的方法就是阻止循環等待條件,將系統中全部的資源設置標誌位、排序,規定全部的進程申請資源必須以必定的順序(升序或降序)作操做來避免死鎖。這篇教程有代碼示例和避免死鎖的討論細節。
27:Java中活鎖和死鎖有什麼區別?
    這是上題的擴展,活鎖和死鎖相似,不一樣之處在於處於活鎖的線程或進程的狀態是不斷改變的,活鎖能夠認爲是一種特殊的飢餓。一個現實的活鎖例子是兩我的在狹小的走廊碰到,兩我的都試着避讓對方好讓彼此經過,可是由於避讓的方向都同樣致使最後誰都不能經過走廊。簡單的說就是,活鎖和死鎖的主要區別是前者進程的狀態能夠改變可是卻不能繼續執行。
28:怎麼檢測一個線程是否擁有鎖?
    我一直不知道咱們居然能夠檢測一個線程是否擁有鎖,直到我參加了一次電話面試。在java.lang.Thread中有一個方法叫holdsLock(),它返回true若是當且僅當當前線程擁有某個具體對象的鎖。你能夠查看這篇文章瞭解更多。
29:你如何在Java中獲取線程堆棧?
    對於不一樣的操做系統,有多種方法來得到Java進程的線程堆棧。當你獲取線程堆棧時,JVM會把全部線程的狀態存到日誌文件或者輸出到控制檯。在Windows你能夠使用Ctrl + Break組合鍵來獲取線程堆棧,Linux下用kill -3命令。你也能夠用jstack這個工具來獲取,它對線程id進行操做,你能夠用jps這個工具找到id。
30:JVM中哪一個參數是用來控制線程的棧堆棧小的
    這個問題很簡單, -Xss參數用來控制線程的堆棧大小。你能夠查看JVM配置列表來了解這個參數的更多信息。
31:Java中synchronized 和 ReentrantLock 有什麼不一樣?
    Java在過去很長一段時間只能經過synchronized關鍵字來實現互斥,它有一些缺點。好比你不能擴展鎖以外的方法或者塊邊界,嘗試獲取鎖時不能中途取消等。Java 5 經過Lock接口提供了更復雜的控制來解決這些問題。 ReentrantLock 類實現了 Lock,它擁有與 synchronized 相同的併發性和內存語義且它還具備可擴展性。你能夠查看這篇文章瞭解更多
32:有三個線程T1,T2,T3,怎麼確保它們按順序執行?
    在多線程中有多種方法讓線程按特定順序執行,你能夠用線程類的join()方法在一個線程中啓動另外一個線程,另一個線程完成該線程繼續執行。爲了確保三個線程的順序你應該先啓動最後一個(T3調用T2,T2調用T1),這樣T1就會先完成而T3最後完成。你能夠查看這篇文章瞭解更多。
33:Thread類中的yield方法有什麼做用?
    Yield方法能夠暫停當前正在執行的線程對象,讓其它有相同優先級的線程執行。它是一個靜態方法並且只保證當前線程放棄CPU佔用而不能保證使其它線程必定能佔用CPU,執行yield()的線程有可能在進入到暫停狀態後立刻又被執行。點擊這裏查看更多yield方法的相關內容。
34:Java中ConcurrentHashMap的併發度是什麼?
    ConcurrentHashMap把實際map劃分紅若干部分來實現它的可擴展性和線程安全。這種劃分是使用併發度得到的,它是ConcurrentHashMap類構造函數的一個可選參數,默認值爲16,這樣在多線程狀況下就能避免爭用。欲瞭解更多併發度和內部大小調整請閱讀個人文章How ConcurrentHashMap works in Java。
35:Java中Semaphore是什麼?
    Java中的Semaphore是一種新的同步類,它是一個計數信號。從概念上講,從概念上講,信號量維護了一個許可集合。若有必要,在許可可用前會阻塞每個 acquire(),而後再獲取該許可。每一個 release()添加一個許可,從而可能釋放一個正在阻塞的獲取者。可是,不使用實際的許可對象,Semaphore只對可用許可的號碼進行計數,並採起相應的行動。信號量經常用於多線程的代碼中,好比數據庫鏈接池。更多詳細信息請點擊這裏。
36:若是你提交任務時,線程池隊列已滿。會時發會生什麼?
    這個問題問得很狡猾,許多程序員會認爲該任務會阻塞直到線程池隊列有空位。事實上若是一個任務不能被調度執行那麼ThreadPoolExecutor’s submit()方法將會拋出一個RejectedExecutionException異常。
37:Java線程池中submit(:和 execute()方法有什麼區別?
    兩個方法均可以向線程池提交任務,execute()方法的返回類型是void,它定義在Executor接口中, 而submit()方法能夠返回持有計算結果的Future對象,它定義在ExecutorService接口中,它擴展了Executor接口,其它線程池類像ThreadPoolExecutor和ScheduledThreadPoolExecutor都有這些方法。更多詳細信息請點擊這裏。
38:什麼是阻塞式方法?
    阻塞式方法是指程序會一直等待該方法完成期間不作其餘事情,ServerSocket的accept()方法就是一直等待客戶端鏈接。這裏的阻塞是指調用結果返回以前,當前線程會被掛起,直到獲得結果以後纔會返回。此外,還有異步和非阻塞式方法在任務完成前就返回。更多詳細信息請點擊這裏。
39:Swing是線程安全的嗎? 爲何?
    你能夠很確定的給出回答,Swing不是線程安全的,可是你應該解釋這麼回答的緣由即使面試官沒有問你爲何。當咱們說swing不是線程安全的經常提到它的組件,這些組件不能在多線程中進行修改,全部對GUI組件的更新都要在AWT線程中完成,而Swing提供了同步和異步兩種回調方法來進行更新。點擊這裏查看更多swing和線程安全的相關內容。
41:Java中invokeAndWait 和 invokeLater有什麼區別?
    這兩個方法是Swing API 提供給Java開發者用來從當前線程而不是事件派發線程更新GUI組件用的。InvokeAndWait()同步更新GUI組件,好比一個進度條,一旦進度更新了,進度條也要作出相應改變。若是進度被多個線程跟蹤,那麼就調用invokeAndWait()方法請求事件派發線程對組件進行相應更新。而invokeLater()方法是異步調用更新組件的。更多詳細信息請點擊這裏。
42:Swing API中那些方法是線程安全的?
    這個問題又提到了swing和線程安全,雖然組件不是線程安全的可是有一些方法是能夠被多線程安全調用的,好比repaint(), revalidate()。 JTextComponent的setText()方法和JTextArea的insert(:和 append(:方法也是線程安全的。
43:如何在Java中建立Immutable對象?
    這個問題看起來和多線程沒什麼關係, 但不變性有助於簡化已經很複雜的併發程序。Immutable對象能夠在沒有同步的狀況下共享,下降了對該對象進行併發訪問時的同步化開銷。但是Java沒有@Immutable這個註解符,要建立不可變類,要實現下面幾個步驟:經過構造方法初始化全部成員、對變量不要提供setter方法、將全部的成員聲明爲私有的,這樣就不容許直接訪問這些成員、在getter方法中,不要直接返回對象自己,而是克隆對象,並返回對象的拷貝。個人文章how to make an object Immutable in Java有詳細的教程,看完你能夠充滿自信。
44:Java中的ReadWriteLock是什麼?
    通常而言,讀寫鎖是用來提高併發程序性能的鎖分離技術的成果。Java中的ReadWriteLock是Java 5 中新增的一個接口,一個ReadWriteLock維護一對關聯的鎖,一個用於只讀操做一個用於寫。在沒有寫線程的狀況下一個讀鎖可能會同時被多個讀線程持有。寫鎖是獨佔的,你能夠使用JDK中的ReentrantReadWriteLock來實現這個規則,它最多支持65535個寫鎖和65535個讀鎖。
45:多線程中的忙循環是什麼?
    忙循環就是程序員用循環讓一個線程等待,不像傳統方法wait(), sleep(:或 yield(:它們都放棄了CPU控制,而忙循環不會放棄CPU,它就是在運行一個空循環。這麼作的目的是爲了保留CPU緩存,在多核系統中,一個等待線程醒來的時候可能會在另外一個內核運行,這樣會重建緩存。爲了不重建緩存和減小等待重建的時間就能夠使用它了。你能夠查看這篇文章得到更多信息。
46)volatile 變量和 atomic 變量有什麼不一樣?
    這是個有趣的問題。首先,volatile 變量和 atomic 變量看起來很像,但功能卻不同。Volatile變量能夠確保先行關係,即寫操做會發生在後續的讀操做以前, 但它並不能保證原子性。例如用volatile修飾count變量那麼 count++ 操做就不是原子性的。而AtomicInteger類提供的atomic方法可讓這種操做具備原子性如getAndIncrement()方法會原子性的進行增量操做把當前值加一,其它數據類型和引用變量也能夠進行類似操做。
47:若是同步塊內的線程拋出異常會發生什麼?
    這個問題坑了不少Java程序員,若你能想到鎖是否釋放這條線索來回答還有點但願答對。不管你的同步塊是正常仍是異常退出的,裏面的線程都會釋放鎖,因此對比鎖接口我更喜歡同步塊,由於它不用我花費精力去釋放鎖,該功能能夠在finally block裏釋放鎖實現。
48:單例模式的雙檢鎖是什麼?
    這個問題在Java面試中常常被問到,可是面試官對回答此問題的滿意度僅爲50%。一半的人寫不出雙檢鎖還有一半的人說不出它的隱患和Java1.5是如何對它修正的。它實際上是一個用來建立線程安全的單例的老方法,當單例實例第一次被建立時它試圖用單個鎖進行性能優化,可是因爲太過於複雜在JDK1.4中它是失敗的,我我的也不喜歡它。不管如何,即使你也不喜歡它可是仍是要了解一下,由於它常常被問到。你能夠查看how double checked locking on Singleton works這篇文章得到更多信息。
49:如何在Java中建立線程安全的Singleton?
    這是上面那個問題的後續,若是你不喜歡雙檢鎖而面試官問了建立Singleton類的替代方法,你能夠利用JVM的類加載和靜態變量初始化特徵來建立Singleton實例,或者是利用枚舉類型來建立Singleton,我很喜歡用這種方法。你能夠查看這篇文章得到更多信息。
50:如何強制啓動一個線程?
    這個問題就像是如何強制進行Java垃圾回收,目前尚未以爲方法,雖然你能夠使用System.gc()來進行垃圾回收,可是不保證能成功。在Java裏面沒有辦法強制啓動一個線程,它是被線程調度器控制着且Java沒有公佈相關的API。
51:Java中的fork join框架是什麼?
    fork join框架是JDK7中出現的一款高效的工具,Java開發人員能夠經過它充分利用現代服務器上的多處理器。它是專門爲了那些能夠遞歸劃分紅許多子模塊設計的,目的是將全部可用的處理能力用來提高程序的性能。fork join框架一個巨大的優點是它使用了工做竊取算法,能夠完成更多任務的工做線程能夠從其它線程中竊取任務來執行。你能夠查看這篇文章得到更多信息。
52:Java多線程中調用wait(:和 sleep()方法有什麼不一樣?
    Java程序中wait 和 sleep都會形成某種形式的暫停,它們能夠知足不一樣的須要。wait()方法用於線程間通訊,若是等待條件爲真且其它線程被喚醒時它會釋放鎖,而sleep()方法僅僅釋放CPU資源或者讓當前線程中止執行一段時間,但不會釋放鎖。

 

10.使用線程併發庫?

java.util.current包對於線程優化。管理各項操做。使線程變得駕輕就熟。包括線程的運行、線程池的建立、線程生命週期的控制

 Java經過Executors四種靜態方法建立四種線程池

newCachedThreadPool()                                                                                                                                          -緩存型池子,先查看池中有沒有之前創建的線程,若是有,就 reuse.若是沒有,就建一個新的線程加入池中
-緩存型池子一般用於執行一些生存期很短的異步型任務
所以在一些面向鏈接的daemon型SERVER中用得很少。但對於生存期短的異步任務,它是Executor的首選。
-能reuse的線程,必須是timeout IDLE內的池中線程,缺省     timeout是60s,超過這個IDLE時長,線程實例將被終止及移出池。
 注意,放入CachedThreadPool的線程沒必要擔憂其結束,超過TIMEOUT不活動,其會自動被終止。 

 

 

newFixedThreadPool(int) -newFixedThreadPool與cacheThreadPool差很少,也是能reuse就用,但不能隨時建新的線程
-其獨特之處:任意時間點,最多隻能有固定數目的活動線程存在,此時若是有新的線程要創建,只能放在另外的隊列中等待直到當前的線程中某個線程終止直接被移出池子
-和cacheThreadPool不一樣,FixedThreadPool沒有IDLE機制(可能也有,但既然文檔沒提,確定很是長,相似依賴上層的TCP或UDP IDLE機制之類的),因此FixedThreadPool多數針對一些很穩定很固定的正規併發線程,多用於服務器
-從方法的源代碼看,cache池和fixed 池調用的是同一個底層 池,只不過參數不一樣:
fixed池線程數固定,而且是0秒IDLE(無IDLE)    
cache池線程數支持0-Integer.MAX_VALUE(顯然徹底沒考慮主機的資源承受能力),60秒IDLE  

 

 

newScheduledThreadPool(int) -調度型線程池
-這個池子裏的線程能夠按schedule依次delay執行,或週期執行
SingleThreadExecutor() -單例線程,任意時間池中只能有一個線程
-用的是和cache池和fixed池相同的底層池,但線程數目是1-1,0秒IDLE(無IDLE)

10.1線程池的做用?

1.限制線程的個數,不會致使因爲線程過多致使系統運行緩慢或崩潰

2.線程池不須要每次都去建立或銷燬。節約了資源

3.線程池不須要每次都去建立。響應時間更快。

11.經常使用的設計模式有哪些?

設計模式就是應該前任無數次實踐總結出的。設計過程當中能夠反覆使用的。能夠解決待定問題的設計方法

單例模式(飽漢模式,飢漢模式)

1.構造方法私有化。讓出本身類建立其餘地方都不能建立

2.在本身類中建立一個單實例(飽漢模式是一出來就建立單例,而飢漢模式須要時候才建立)

3.提供一個方法獲取實例對象

飽漢模式
package Jzen.Util;

public class PersionFactory {
    
    private PersionFactory(){
        
    }
    
    private static PersionFactory instance = new PersionFactory();
    
    public static PersionFactory getInstance(){
        return instance;
    }

}
飢漢模式
package Jzen.Util;

public class PersionFactory {
    
    private PersionFactory(){
        
    }
    
    private static PersionFactory instance = null;
    
    public synchronized static PersionFactory getInstance(){
        if(instance == null){
            instance = new PersionFactory();
        }
        return instance;
    }

}

工廠模式  Spring ioc使用工廠模式

     對象建立交給一個工廠去建立。

代理模式  Spring aop就是使用的動態代理   

12.http get和Post請求區別?

1.get與post不一樣的請求對yrl不一樣的操做。GET通常用於獲取查詢信息,而POST通常用於更新資源信息

2.GET 請求提交參數會在地址欄顯示而POST不會再地址欄顯示出來。

3.傳輸數據大小

4.安全性。POST的安全性比GET 高

13.Servlet 的理解。或者Servlet是什麼?

主要用於交互式遊覽和修改數據。是Java服務端的程序。

HTTPServlet重寫doGet或者DoPost重寫來處理。

14.Servlet生命週期?

Servlet有良好的生命週期。包括加載與實例化、初始化、處理請求、服務結束。

這個生命週期有init、services和destroy方法表達。

1. init()方法

      在Servlet的生命週期中,僅執行一次init()方法,它是在服務器裝入Servlet時執行的,能夠配置服務器,以在啓動服務器或客戶機首次訪問Servlet時裝入Servlet。不管有多少客戶機訪問Servlet,都不會重複執行init();

2. service()方法

      它是Servlet的核心,每當一個客戶請求一個HttpServlet對象,該對象的Service()方法就要調用,並且傳遞給這個方法一個「請求」(ServletRequest)對象和一個「響應」(ServletResponse)對象做爲參數。在HttpServlet中已存在Service()方法。默認的服務功能是調用與HTTP請求的方法相應的do功能。

3. destroy()方法

      僅執行一次,在服務器端中止且卸載Servlet時執行該方法,有點相似於C++的delete方法。一個Servlet在運行service()方法時可能會產生其餘的線程,所以須要確認在調用destroy()方法時,這些線程已經終止或完成。

     下面來談談Servlet的生命週期,Servlet的生命週期是由Servlet容器來控制的,它始於裝入Web服務器的內存時,並在終止或從新裝入Servlet時結束。這項操做通常是動態執行的。然而,Server一般會提供一個管理的選項,用於在Server啓動時強制裝載和初始化特定的Servlet。

15.Servlet 中Forword() 與Redirect()區別?

1.從地址欄顯示來講 
forward是服務器請求資源,服務器直接訪問目標地址的URL,把那個URL的響應內容讀取過來,而後把這些內容再發給瀏覽器.瀏覽器根本不知道服務器發送的內容從哪裏來的,因此它的地址欄仍是原來的地址.
redirect是服務端根據邏輯,發送一個狀態碼,告訴瀏覽器從新去請求那個地址.因此地址欄顯示的是新的URL.

2.從數據共享來講 
forward:轉發頁面和轉發到的頁面能夠共享request裏面的數據.
redirect:不能共享數據.

3.從運用地方來講 
forward:通常用於用戶登錄的時候,根據角色轉發到相應的模塊.
redirect:通常用於用戶註銷登錄時返回主頁面和跳轉到其它的網站等.

4.從效率來講 
forward:高.
redirect:低.

轉發是服務器行爲,重定向是客戶端行爲

轉發過程:客戶瀏覽器發送http請求----》web服務器接受此請求--》調用內部的一個方法在容器內部完成請求處理和轉發動做----》將目標資源 發送給客戶;在這裏,轉發的路徑必須是同一個web容器下的url,其不能轉向到其餘的web路徑上去,中間傳遞的是本身的容器內的request。在客 戶瀏覽器路徑欄顯示的仍然是其第一次訪問的路徑,也就是說客戶是感受不到服務器作了轉發的。轉發行爲是瀏覽器只作了一次訪問請求。 

重定向過程:客戶瀏覽器發送http請求----》web服務器接受後發送302狀態碼響應及對應新的location給客戶瀏覽器--》客戶瀏覽器發現 是302響應,則自動再發送一個新的http請求,請求url是新的location地址----》服務器根據此請求尋找資源併發送給客戶。在這裏 location能夠重定向到任意URL,既然是瀏覽器從新發出了請求,則就沒有什麼request傳遞的概念了。在客戶瀏覽器路徑欄顯示的是其重定向的 路徑,客戶能夠觀察到地址的變化的。重定向行爲是瀏覽器作了至少兩次的訪問請求的。 

 

15.1 直接轉發和間接轉發的原理及區別是什麼?

答:Forward和Redirect表明了兩種請求轉發方式:直接轉發和間接轉發。對應到代碼裏,分別是RequestDispatcher類的forward()方法和HttpServletRequest類的sendRedirect()方法。

  對於間接方式,服務器端在響應第一次請求的時候,讓瀏覽器再向另一個URL發出請求,從而達到轉發的目的。它本質上是兩次HTTP請求,對應兩個request對象。

  對於直接方式,客戶端瀏覽器只發出一次請求,Servlet把請求轉發給Servlet、HTML、JSP或其它信息資源,由第2個信息資源響應該請求,兩個信息資源共享同一個request對象。

 

16.Jsp和Servlet 相同點和不一樣點。

Jsp是Servlet的擴展。jsp文件都會繼承HTTPServlet服務(tomcat進行)。也就是jsp最終也是一個Servlet.

這個Servlet對外提供服務。這就是相同點

Servlet要實現html部分必須使用writer輸出html比較麻煩。

Servlet的應用邏輯是在Java中。而且徹底從變現層中分離出來。

Jsp是Java+Html組合一個擴展名爲jsp文件。JSP側重於視圖。Servlet側重控制邏輯

 

17.Jsp內置對象做用以及用法?

out對象:用來傳送回應的輸出。

request對象:封裝了來自客戶端、瀏覽器的請求信息。

response對象:封裝了服務器的響應信息。

exception對象:封裝了jsp程序執行過程當中發生的異常和錯誤信息。

config對象:封裝了應用程序的配置信息。

page對象:指向了當前jsp程序自己。

session對象:與請求有關的會話期

application對象:正在執行的內容

pageContext對象:頁面屬性管理

四大做用域

  1.PageContext

  2.request

  3.session

  4.application

能夠經過jstl從自大做用域取值。jsp傳遞值。request、session、application、cookie也能傳值。

 

18.Session  Cookie 區別。使用點?

Session  和 Cookie都是會話跟蹤技術。

Cookie經過客戶端記錄信息確認用戶身份。

Session經過服務端記錄信息確認用戶身份。

可是Session實現依賴於Cookie。SessionId(Session惟一標識存放在客戶端)

Session  Cookie 區別

1.Cookie 數據存放在客戶端。Session數據存放在服務端。

2.Cookie很不安全。別人能夠解析存放在本地的Cookie並進行Cookie欺騙考慮到安全應當使用Session

3.Session必定時間內保存服務器上。訪問增多。會佔用服務器性能。考慮性能則使用Cookie

4.單個cookie保存數據不能超過4k。不少遊覽器控制一個站點最多保存20個cookie

購物車最好使用Cookie。可是Cookie遊覽器是能夠禁用的。這時候咱們要使用cookie+數據庫的形式。

當從Cookie取不出數據。則從數據庫獲取。

 

數據庫

1.數據庫分類及經常使用數據庫

   數據庫分爲關係型數據庫與非關係性數據庫

  關係型:mysql oracle SqlServer等。

  菲關係型:Redis  mogodb hadoop等。

2.關係型數據庫與非關係性數據庫區別

非關係型數據庫的優點:
1. 性能
NOSQL是基於鍵值對的,能夠想象成表中的主鍵和值的對應關係,並且不須要通過SQL層的解析,因此性能很是高。
2. 可擴展性
一樣也是由於基於鍵值對,數據之間沒有耦合性,因此很是容易水平擴展。

關係型數據庫的優點:
1. 複雜查詢
能夠用SQL語句方便的在一個表以及多個表之間作很是複雜的數據查詢。
2. 事務支持
使得對於安全性能很高的數據訪問要求得以實現

3.事務四大特性、什麼是事務?
 
事務是併發控制單位。是用戶定義的一個操做序列。這些操做要麼都作要麼都不作。是一個不可分割的單位、
事務必須知足四大特徵,原子性,一致性,隔離性,持久性。
原子性:表示事務操做不可分割。要麼都成功。要麼都失敗。
一致性:要麼成功要麼失敗。後面失敗後面也一樣回滾。保存一致。
隔離性:一個事務開始。不會被其餘事務所幹擾。
持久性:表示事務開始就不能終止。
4.Mysql數據庫默認最大鏈接數?
特定服務器只能支持必定數目同時鏈接。這時候須要咱們設置最大鏈接數。
在數據庫安裝時有一個默認的最大鏈接數。mysql默認最大鏈接數100
 
5.數據庫分頁?

Mysql  limit m,n分頁語句:

select * from dept order by deptno desc limit 3,3;
select * from dept order by deptno desc limit m,n;

Oracle 分頁

select * from (select a1.*,rownum rn from (select * from student) a1 where rownum <=5) where rn>=2;

select a1.* from (select student.*,rownum rn from student where rownum <=5) a1 where rn >=3;

select a1.* from (select student.*,rownum rn from student) a1 where rn between 3 and 5;

6.存儲過程的優勢

1.存儲過程值在建立時進行編譯。之後每次執行存儲過程都不須要從新編譯。而通常SQL語言每執行一次

就編譯一次。所以使用存儲過程能夠大大提升數據庫執行速度。

2.複雜的業務邏輯須要多天SQL語句。會產生大量網絡傳輸。若是使用存儲過程會大大減小。

3.存儲過程能夠重複使用。減小開發工做量

4.安全性高。存儲過程屏蔽底層數據庫對象的直接訪問。

7.經過JDBC調用存儲過程?

package xzg;
 
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
 
public class JDBCtest {
    public static void main(String[] args) {
        //test();
        //test2();
        test3();
    }
   /*
    * 命令行建立的存儲過程函數爲: create procedure all_user() select * from user;
    *    建立一個查詢全部內容的存儲過程
    * 調用無參存儲過程
    */
    static void test() {
        Connection conn = Dbutil.open();
        try {
            //存儲過程函數固定格式:{call xxx}
            CallableStatement cs = conn.prepareCall("{call all_user()}");
            ResultSet rs = cs.executeQuery();
            while (rs.next()) {
                int id = rs.getInt(1);
                String name = rs.getString(2);
                int age = rs.getInt(3);
                System.out.println(id + "," + name + "," + age);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            Dbutil.close(conn);
        }
    }
       /*
        * 命令行建立的存儲過程函數爲:
        * create procedure insert_user(in myname varchar(20),
        * in myage tinyint(20)) insert user(username,age) values(myname,myemail);
*  表示建立一個插入myname,數據類型爲varchar(20); myage,數據類型爲tinyint(20)的存儲過程
        * 調用輸入帶參存儲過程
        */
    static void test2() {
        Connection conn = Dbutil.open();
        try {
            CallableStatement cs = conn.prepareCall("{call insert_user(?,?)}");
            cs.setString(1, "jack");
            cs.setInt(2, 10);
            cs.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            Dbutil.close(conn);
        }
    }
       /*
        * 命令行建立的存儲過程函數爲:
        *  create procedure getnamebyid(in cid int,
        * out return_name varchar(20)) select username into return_name
        * from user where id =cid;
        * 表示建立一個若是id爲cid,那麼就輸出返回一個return_name
        * 調用輸入、輸出帶參存儲過程
        */
    static void test3() {
        Connection conn = Dbutil.open();
        try {
            CallableStatement cs = conn.prepareCall("{call getnamebyid(?,?)}");
            cs.setInt(1, 3);  //索引1,第3個id
            //輸出參數的話要註冊
            cs.registerOutParameter(2, Types.CHAR);
            //註冊後要更新
            cs.execute();
            String name =cs.getString(2);  //這個是索引的意思
            cs.executeQuery();
            System.out.println(name);
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            Dbutil.close(conn);
        }
    }
}

8.對於JDBC的理解

Java databases connection  Java數據庫鏈接。數據庫關係系統是不少。每一個數據庫管理系統支持測令是不同的。

Java之定義接口讓數據庫廠商本身實現接口,只須要導入廠商開發的實現就可。

9.寫一個訪問JDBC的程序?

加載驅動、獲取參數、設置參數、執行、釋放鏈接。

10.JDBC中的PreparedStatement相比Statement的好處

 

 

 11.數據庫鏈接池做用

1.限定數據庫的個數。不會致使因爲數據庫鏈接過多致使程序緩慢或者崩潰、

2. 數據庫鏈接不須要每次都去建立或銷燬,節約資源。

3.數據庫鏈接不須要每次都去建立。響應更快。

 

前段部分

1.HTML css JavaScript 在網頁開發的定位?

2.簡單介紹一下Ajax

 什麼是Ajax? AJax就是異步的JavaScript和xml。能夠不用刷新頁面就能夠完成數據交互

    做用是什麼? 經過Ajax與服務器進行數據交換。AJax實現頁面局部更新。也就是說能夠在不從新加載

  頁面狀況下。對網頁部分進行更新。

 怎麼來實現?XmlHttpRequest對象。使用這個對象能夠異步向服務器發送請求。獲取響應完成拒不更新。

3.JS與JQuery區別?

  Jquery是js 的一個框架。封裝js的屬性和方法。加強js的功能。開發更加方便。

       js須要處理一些兼容問題。Jquery進行封裝就能夠不用處理兼容問題、

  元素js的dom和事件綁定操做麻煩。Jquery封裝後操做方便。

 

 框架部分
1.什麼是框架?
框架(framework) 是一個框子  指其約束性,也是一個架子指其支撐性。
2.什麼是MVC模式?
MVC是Model View Controller 是模型 視圖 控制器的縮寫。
最經典的的就是jsp + Servlet + JavaBean
3.什麼是MVC框架?
未了解決傳統的MVC模式的問題而出現的框架。
什麼是傳統MVC模式的問題?
1.全部Servlet 和Servlet映射配置都要在web.xml  項目太大。web.xml就更加龐大。而且不能實現模塊化管理
2.Servlet主要功能就是接受參數,調用邏輯,跳轉頁面。
3.接受參數比較麻煩。須要不斷的request.getParameter.並且不能經過model接收。只能單個接收,接受完後轉換封裝model/
4.跳轉頁面方式比較單一(forward  redirect)。而且當我頁面名稱改變是須要修改Servlet源碼
 
如今比較經常使用的MVC框架:
  Struts2
  Hibernate
  Spring
  SpringMVC
4.Struts2 執行流程?
.

在Struts2框架中的處理大概分爲如下的步驟 
1 用戶發送請求;

2 這個請求通過一系列的過濾器(Filter)(這些過濾器中有一個叫作ActionContextCleanUp的可選過濾器,這個過濾器對於Struts2和其餘框架的集成頗有幫助,例如:SiteMesh Plugin)
3 接着FilterDispatcher被調用,FilterDispatcher詢問ActionMapper來決定這個請求是否須要調用某個Action ;

4  若是須要處理,ActionMapper會通知FilterDispatcher,須要處理這個請求,FilterDispatcher會中止過濾器鏈之後的部分,(這也就是爲何,FilterDispatcher應該出如今過濾器鏈的最後的緣由)。FilterDispatcher把請求的處理交給ActionProxy ;

5 ActionProxy經過Configuration Manager詢問框架的配置文件struts.xml,找到須要調用的Action類 。(在服務器啓動的時候,ConfigurationManager就會把struts.xml中的全部信息讀到內存裏,並緩存,當ActionProxy帶着URL向他詢問要運行哪一個Action的時候,就能夠直接匹配、查找並回答了)
6 ActionProxy建立一個ActionInvocation的實例。 
7 ActionInvocation實例使用命名模式來調用,在調用Action的過程先後,涉及到一系列相關攔截器(Intercepter)的調用。 
8 一旦Action執行完畢,ActionInvocation負責根據struts.xml中的配置找到對應的返回結果。返回結果一般是(但不老是,也可 能是另外的一個Action鏈)一個須要被表示的JSP或者FreeMarker的模版。在表示的過程當中能夠使用Struts2 框架中繼承的標籤。

 9 最後,ActionInvocation對象倒序執行攔截器。

10.ActionInvocation對象執行完畢後,響應用戶。

 

注意:2.1.3以後的核心過濾器由FilterDispatcher換成StrutsPrepareAndExecuteFilter。

 

談談攔截器與過濾器的區別:

一、攔截器是基於java反射機制的,而過濾器是基於函數回調的。

二、過濾器依賴於servlet容器,而攔截器不依賴於servlet容器。
三、攔截器只能對Action請求起做用,而過濾器則能夠對幾乎全部請求起做用。
四、攔截器能夠訪問Action上下文、值棧裏的對象,而過濾器不能。
五、在Action的生命週期中,攔截器能夠屢次調用,而過濾器只能在容器初始化時被調用一次。

5.Sturts2 攔截器是用來作什麼?
  經過動態配置方式能夠 在執行Action 的方法先後執行相關邏輯也是就是一種====-OP思想;
struts2中的功能都是經過系統攔截器實現的。固然咱們也能夠自定義攔截器,進行可插拔配置,在執行Action方法的先後,加入相關邏輯完成業務。
好比:用戶登陸判斷,在執行Action的前面進行判斷。若是沒有登陸進行調整登陸界面。或者權限控制
 
6.SpringMVC原理?

 

SpringMVC流程

一、  用戶發送請求至前端控制器DispatcherServlet。

二、  DispatcherServlet收到請求調用HandlerMapping處理器映射器。

三、  處理器映射器找到具體的處理器(能夠根據xml配置、註解進行查找),生成處理器對象及處理器攔截器(若是有則生成)一併返回給DispatcherServlet。

四、  DispatcherServlet調用HandlerAdapter處理器適配器。

五、  HandlerAdapter通過適配調用具體的處理器(Controller,也叫後端控制器)。

六、  Controller執行完成返回ModelAndView。

七、  HandlerAdapter將controller執行結果ModelAndView返回給DispatcherServlet。

八、  DispatcherServlet將ModelAndView傳給ViewReslover視圖解析器。

九、  ViewReslover解析後返回具體View。

十、DispatcherServlet根據View進行渲染視圖(即將模型數據填充至視圖中)。

十一、 DispatcherServlet響應用戶。

7.struts2 和SpringMVC有什麼不一樣?
1.核心控制器不一樣:SpringMVC核心控制器是Servlet,Struts2是Filter。
2.控制器實例:SpringMVC是基於方法設計。而Struts2是基於對象,每次發一次請求都會實例一個action,每一個都會被注入屬性,而Spring更像Servlet同樣。
而SpringMVc更像Servlet只有一個實例,每次請求執行對應的方法便可(因爲是單列實例,因此硬蛋避免全局變量的修改,這樣會產生線程安全問題)
3.管理方式大多數使用SPring ,Spring可能對SpringMVc控制更加簡單方便。
4.參數傳遞:ValueStack 和SpringMVC經過方法進行接收 。ValueStack 過於龐大。
6.SpringMVC 對Ajax能夠直接返回數據。經過RequestBody 進行對數據JSon轉換。
 
8.Spring 兩大核心?
   Spring 是一個輕量級IOC和AOP的容器框架。主要針對JavaBean的生命週期進行管理的輕量級容器。也能夠單獨使用。
  主要是:
  IOC:
  IoC的一個重點是在系統運行中,動態的向某個對象提供它所須要的其餘對象。這一點是經過DI(Dependency Injection,依賴注入)來實現的
  AOP:
  這種在運行時,動態地將代碼切入到類的指定方法、指定位置上的編程思想就是面向切面的編程。
 
10.spring的事務有幾種方式?談談spring事務的隔離級別和傳播行爲。

聲明事務和編程事務

隔離級別:

- DEFAULT使用數據庫默認的隔離級別

- READ_UNCOMMITTED會出現髒讀,不可重複讀和幻影讀問題

- READ_COMMITTED會出現重複讀和幻影讀

- REPEATABLE_READ會出現幻影讀

- SERIALIZABLE最安全,可是代價最大,性能影響極其嚴重

和傳播行:

- REQUIRED存在事務就融入該事務,不存在就建立事務

- SUPPORTS存在事務就融入事務,不存在則不建立事務

- MANDATORY存在事務則融入該事務,不存在,拋異常

- REQUIRES_NEW老是建立新事務

- NOT_SUPPORTED存在事務則掛起,一直執行非事務操做

- NEVER老是執行非事務,若是當前存在事務則拋異常

- NESTED嵌入式事務

 
高級部分
 
1.作過什麼數據庫優化?
  1.定位查找慢查詢並優化
  2.創建索引  建立合適的索引。咱們就能夠在索引中查詢到記錄。
  3.分表    當一張表數據比較多或者某些字段值比較多,而且不多使用採用水平或者垂直分表進行優化
  4.讀寫分離  當一臺服務器不能知足,採用讀寫分離的形式進行分離 
  5.緩存redis  使用redis來進行緩存
 
 2.如何定位慢查詢?
   在項目自驗或啓動時。在啓動Mysql時開啓慢查詢,而且把執行慢的數據記錄到日誌。經過查看日誌找到對應的慢查詢語句。
參數詳情:
  slow_query_log 慢查詢開啓狀態
  slow_query_log_file 慢查詢日誌存放的位置(這個目錄須要MySQL的運行賬號的可寫權限,通常設置爲MySQL的數據存放目錄)
  long_query_time 查詢超過多少秒才記錄
  

查看慢查詢相關參數

複製代碼
mysql> show variables like 'slow_query%';
+---------------------------+----------------------------------+
| Variable_name             | Value                            |
+---------------------------+----------------------------------+
| slow_query_log            | OFF                              |
| slow_query_log_file       | /mysql/data/localhost-slow.log   |
+---------------------------+----------------------------------+

mysql> show variables like 'long_query_time';
+-----------------+-----------+
| Variable_name   | Value     |
+-----------------+-----------+
| long_query_time | 10.000000 |
+-----------------+-----------+
複製代碼

設置方法
方法一:全局變量設置
將 slow_query_log 全局變量設置爲「ON」狀態

mysql> set global slow_query_log='ON'; 

設置慢查詢日誌存放的位置

mysql> set global slow_query_log_file='/usr/local/mysql/data/slow.log';

查詢超過1秒就記錄

mysql> set global long_query_time=1;

方法二:配置文件設置
修改配置文件my.cnf,在[mysqld]下的下方加入

[mysqld]
slow_query_log = ON
slow_query_log_file = /usr/local/mysql/data/slow.log
long_query_time = 1

重啓MySQL服務

service mysqld restart

查看設置後的參數

複製代碼
mysql> show variables like 'slow_query%';
+---------------------+--------------------------------+
| Variable_name       | Value                          |
+---------------------+--------------------------------+
| slow_query_log      | ON                             |
| slow_query_log_file | /usr/local/mysql/data/slow.log |
+---------------------+--------------------------------+

mysql> show variables like 'long_query_time';
+-----------------+----------+
| Variable_name   | Value    |
+-----------------+----------+
| long_query_time | 1.000000 |
+-----------------+----------+
複製代碼

測試

1.執行一條慢查詢SQL語句

mysql> select sleep(2);

2.查看是否生成慢查詢日誌

ls /usr/local/mysql/data/slow.log
 
 
 
3.數據庫優化  遵循範式?
   數據表設計須要遵循方式
  首先要符合1NF 才能知足2NF 進一步知足3MF
  1NF:原子性,不能夠在分解
  2NF:表中的記錄是唯一的,一般咱們設計一個主鍵來實現。
  3NF:表中不要亢餘數據,就是說表的信息,若是被推導出來,就不該該單獨的設計一個字段來存放(外鍵)
 
 4.選擇合適的存儲引擎
   合適存儲引擎:myisam / innodb / memory
  myisam 存儲引擎:
    若是引擎對事務要求不高。一查詢和添加爲主。考慮myisam 
   innodb 存儲引擎:
    對事物要求高,保存數據爲重要數據。
  memory存儲引擎:
    數據變化頻繁,不須要入庫,同時又頻繁的查詢或修改,咱們考慮memory
 
 4.1myisam 與innodb 區別?
   1.事務安全myisam 不支持
  2.查詢添加速度myisam 更快由於不支持事務
  3.支持全文索引    myisam 支持 innodb 不支持
  4.鎖機制  myisam 支持表鎖 而innodb 支持行鎖
  5.外鍵  myisam 不支持外鍵

 

 5.數據庫優化創建合適的索引?
   索引是幫助DBMS高效獲取數據的數據結構
  普通索引:容許重複的值出現
  惟一索引:不能重複值
  主鍵索引:是隨着主鍵而建立的。也就是把某個列設爲主鍵的時候。數據庫就會把這個列建立索引。主鍵索引惟一併且沒有NULL值
  全文索引:用來對錶中的文本域進行索引
 
6.索引的一些小技巧?
  
 索引弊端
  1.佔用磁盤空間
  2.對dml操做有影響,變慢
使用場景:
  1.若是不作查詢就沒有意義
  2.該字段的內容不是惟一的幾個值
  3.字段內容不頻繁變化
 

 

7.數據庫分表技術?
分表分爲水平分表和垂直分表處理。
根據經驗:mysql表中數據通常達到百萬級別,查詢效率會很低。容易形成表鎖。甚至堆積不少銜接。直接掛掉;水平份表能很大程度減小這些壓力
若是一張表字段很是多在少數狀況會查詢。這樣就能夠這部分字段單獨放在一個表,進行外鍵關聯起來。這種事垂直分表
水平分表策略:
  1.按時間分表 
    時間分表會有侷限性,當數據具備較強的實效性,這種不多有用戶查詢幾個月前的數據就能夠進行時間分表
  2.按區間範圍分表
    有必定嚴格的自增ID需求上  好比:100-200 200-300
  3.Hash區別
     經過一個原始目標ID或者名稱經過必定的Hash算法計算出數據存儲標的表名而後進行訪問相應的表
 
 8.數據庫的讀寫分離?
 
   對於數據存儲層高併發問題,最早想到的可能就是讀寫分離,在網站訪問量大而且讀寫不平均的狀況下,將存儲分爲master,slave兩臺,全部的寫都路由到master上,全部的讀都路由到slave上,而後master和slave同步。
在設計讀寫分離的時候,有幾種解決方案:
    1. 將讀寫分離放在dao層,在dao層, 全部的insert/update/delete都訪問master庫,全部的select 都訪問salve庫,這樣對於業務層是透明的。 
    2. 將讀寫分離放在ORM層,好比mybatis能夠經過mybatis plus攔截sql語句,全部的insert/update/delete都訪問master庫,全部的select 都訪問salve庫,這樣對於dao層都是透明。 
    3. 放在代理層,好比MySQL-Proxy,這樣針對整個應用程序都是透明的。 
主從同步
  數據庫最終會把數據持久化到硬盤,若是集羣必須確保每一個數據庫服務器的數據是一致的,能改變數據庫數據的操做都是主數據庫來作。而其餘的數據庫從主數據庫同步數據。
讀寫分離
  使用複雜均衡來實現寫的操做都往主數據庫,而讀的操做往從服務器去。
 
 9.數據庫值緩存
   在持久層和數據庫之間添加一個緩存層。如數據訪問數據以及緩存起來。那麼用戶直接在緩存中獲取。不用訪問數據庫。
而緩存 是在操做內存級,訪問速度快。
  做用:減小數據庫服務器壓力,減小訪問時間。
Java常見二級緩存:
  hibernate二級緩存,該緩存不能完成分佈式緩存
  能夠使用redis做爲中央緩存。
 
JVM 
1.Minor GC 與 Major GC的區別與意義
 
Minor GC新生代GC:指發生在新生代的垃圾收集動做。由於Java對象大多數都具備朝生夕滅的特徵。因此Minor GC很是頻繁,通常回收速度較快。
Major GC/Full GC老年代GC:指發生在老年代的GC,出現了Major  GC至少伴隨一次Minor GC(但非絕對的,在Parallerl Scavenge收集器的收集策略裏就有直接進行Major GC的策略選擇過程),Major GC的速度通常比Minor GC慢10倍以上。
 
2.JVM堆的三部分:年輕代  老年代  永久代(元數據區)
 
1.年輕代:主要是用來存放新生的對象。內存大小相對會比較小,通常佔據堆的1/3空間。因爲頻繁建立對象,因此新生代會頻繁觸發MinorGC進行垃圾回收。

新生代又分爲 Eden區、ServivorFrom、ServivorTo三個區。

Eden區:Java新對象的出生地(若是新建立的對象佔用內存很大,則直接分配到老年代)。當Eden區內存不夠的時候就會觸發MinorGC,對新生代區進行一次垃圾回收。

ServivorTo:保留了一次MinorGC過程當中的倖存者。

ServivorFrom:上一次GC的倖存者,做爲這一次GC的被掃描者。

MinorGC的過程:MinorGC採用複製算法。首先,把Eden和ServivorFrom區域中存活的對象複製到ServicorTo區域(若是有對象的年齡以及達到了老年的標準,則賦值到老年代區),同時把這些對象的年齡+1(若是ServicorTo不夠位置了就放到老年區);而後,清空Eden和ServicorFrom中的對象;最後,ServicorTo和ServicorFrom互換,原ServicorTo成爲下一次GC時的ServicorFrom區。

2.老年代:

主要存放應用程序中生命週期長的內存對象。

老年代的對象比較穩定,因此MajorGC不會頻繁執行。在進行MajorGC前通常都先進行了一次MinorGC,使得有新生代的對象晉身入老年代,致使空間不夠用時才觸發。當沒法找到足夠大的連續空間分配給新建立的較大對象時也會提早觸發一次MajorGC進行垃圾回收騰出空間。

MajorGC採用標記—清除算法:首先掃描一次全部老年代,標記出存活的對象,而後回收沒有標記的對象。MajorGC的耗時比較長,由於要掃描再回收。MajorGC會產生內存碎片,爲了減小內存損耗,咱們通常須要進行合併或者標記出來方便下次直接分配。

當老年代也滿了裝不下的時候,就會拋出OOM(Out of Memory)異常。

3.永久代:

指內存的永久保存區域,主要存放Class和Meta(元數據)的信息,Class在被加載的時候被放入永久區域。它和和存放實例的區域不一樣,GC不會在主程序運行期對永久區域進行清理。因此這也致使了永久代的區域會隨着加載的Class的增多而脹滿,最終拋出OOM異常。

在Java8中,永久代已經被移除,被一個稱爲「元數據區」(元空間)的區域所取代。

※:元空間的本質和永久代相似,都是對JVM規範中方法區的實現。不過元空間與永久代之間最大的區別在於:元空間並不在虛擬機中,而是使用本地內存

相關文章
相關標籤/搜索