記錄java相關不清楚的知識點

不斷更新中。

20200530更新;

  • “java”=="java"結果是什麼

他們兩個在常量池裏面是一個東西,所有地址相等,結果是true

  • short s1 = 1; s1 = s1 + 1;有什麼錯?short s1 = 1; s1 += 1;有什麼錯

第一個有問題,第二個沒有問題

  • java裏面的參數傳遞

java裏面都是按值傳遞的,對象傳遞其實是把對象的地址的值傳遞了

  • abstract 的method 是否可同時是static,是否可同時是native,是否可同時是synchronized?

不能

  • sysnchronized方法繼承之後是怎麼樣

1、子類繼承父類時,如果沒有重寫父類中的同步方法,子類同一對象,在不同線程併發調用該方法時,具有同步效果。

2、子類繼承父類,並且重寫父類中的同步方法,但沒有添加關鍵字synchronized,子類同一對象,在不同線程併發調用該方法時,不再具有同步效果,這種情形即是"關鍵字synchronized不能被繼承"的轉述。

  • 代碼塊、靜態代碼塊、構造函數的加載順序

父類--靜態變量
父類--靜態初始化塊

(上面兩個順序其實不是固定的,如果變量寫在了靜態塊下面,那麼靜態塊是最先執行的)
子類--靜態變量
子類--靜態初始化塊
父類--變量
父類--初始化塊
父類--構造器
子類--變量
子類--初始化塊
子類--構造器

  • http1.0 與http1.1的區別

HTTP1.0 :

無狀態、無連接,沒次請求都需要重新建立了tcp連接


HTTP1.1  :  
持久連接
請求管道化
增加緩存處理(新的字段如cache-control)
增加Host字段、支持斷點傳輸等(把文件分成幾部分)


HTTP2.0  :
二進制分幀
多路複用(或連接共享)
頭部壓縮
服務器推送

  • http請求中的內容

1.請求行(描述客戶端的請求方式請求的資源名稱,以及使用的HTTP協議版本號)

2.消息頭(描述客戶端請求哪臺主機,以及客戶端的一些環境信息等)

3.一個空行

4.(不一定有的內容)具體發送的內容

  • http響應中的內容

1.狀態響應行

2.消息頭

3.一個空行

4.響應內容

  • servlet生命週期
  1. 加載Servlet。當Tomcat第一次訪問Servlet的時候,Tomcat會負責創建Servlet的實例
  2. 初始化。當Servlet被實例化後,Tomcat會調用init()方法初始化這個對象
  3. 處理服務。當瀏覽器訪問Servlet的時候,Servlet 會調用service()方法處理請求
  4. 銷燬。當Tomcat關閉時或者檢測到Servlet要從Tomcat刪除的時候會自動調用destroy()方法,讓該實例釋放掉所佔的資源。一個Servlet如果長時間不被使用的話,也會被Tomcat自動銷燬
  5. 卸載。當Servlet調用完destroy()方法後,等待垃圾回收。如果有需要再次使用這個Servlet,會重新調用init()方法進行初始化操作
  6. 簡單總結:**只要訪問Servlet,service()就會被調用。init()只有第一次訪問Servlet的時候纔會被調用。destroy()只有在Tomcat關閉的時候纔會被調用
  • httpServletResponser裏面的print()和writer()

前者參數是字符,後者支持byte

  • forward和redirect

轉發: 訪問 Servlet 處理業務邏輯,然後 forward 到 jsp 顯示處理結果,瀏覽器裏 URL 不變

重定向: 提交表單,處理成功後 redirect 到另一個 jsp,防止表單重複提交,瀏覽器裏 URL 變了

  • 數據庫三範式

第一範式、第二範式、第三範式

第一範式:每列要是屬性不可分割,不能出現某列裏面存了姓名和性別的數據。

第二範式:每條數據要有唯一ID,也就是主鍵。

第三範式:消除冗餘,冗餘數據使用外鍵進行查詢。

實際開發中,不一定完全按照範式來設計數據庫,按照具體的業務來具體分析,破壞的比較多的就是第三範式,有時候加入冗餘字段可以避免很多不必要的多表查詢,實現以空間換時間。

  • 數據庫的樂觀鎖和悲觀鎖

悲觀鎖:使用數據庫的鎖機制進行操作,在查詢完數據的時候就把事務鎖起來,直到提交事務。

樂觀鎖:在修改數據的時候把事務鎖起來,通過version的方式來進行鎖定

  • foreach與正常for循環效率對比

需要循環數組結構的數據時,建議使用普通for循環,因爲for循環採用下標訪問,對於數組結構的數據來說,採用下標訪問比較好。

需要循環鏈表結構的數據時,一定不要使用普通for循環,這種做法很糟糕,數據量大的時候有可能會導致系統崩潰。

 

  • i++和++i

i=i++,此時i還是等於原值,++操作沒用。i =1;i=i++;i=++i+i++*++i;此時要從操作數棧搞起。

  • java方法的傳遞

上圖中右邊是jvm內存模型。都是傳值的,對象傳的是地址。經過函數處理之後的內存圖如下:

 

  • 重寫約束

重寫規則之一:重寫方法不能比被重寫方法限制有更嚴格的訪問級別

重寫規則之二:參數列表必須與被重寫方法的相同

重寫規則之三:返回類型必須與被重寫方法的返回類型相同

重寫規則之四:重寫方法不能拋出新的異常或者比被重寫方法聲明的檢查異常更廣的檢查異常。但是可以拋出更少,更有限或者不拋出異常。

重寫規則之五:不能重寫被標識爲final的方法。
重寫規則之六:如果一個方法不能被繼承,則不能重寫它。

  • 重載約束
  1. 必須具有不同的參數列表;
  2. 可以有不同的返回類型,只要參數列表不同就可以了;
  3. 可以有不同的訪問修飾符;
  4. 可以拋出不同的異常;

也就說參數列表必須不一樣,有這樣的前提才能討論是否重載,然後返回類型、訪問修飾符和異常可以不同,但是不同不能用於判斷重載。

  • hashCode問題

String a = "ab";String b = new String("ab");這個時候a.hashCode() == b.hashCode()

  • TCP連接的三次握手和四次揮手

三次握手指的是建立連接,四次揮手指的是斷開連接。

三次握手通俗理解:

client:我要和你建立連接

server:我收到了你的請求,我同意

client:我收到了你的答覆,我要準備發數據了

爲什麼需要三次而不是兩次呢?client發出的第一個連接請求報文段並沒有丟失,而是在某個網絡結點長時間的滯留了,以致延誤到連接釋放以後的某個時間纔到達server。本來這是一個早已失效的報文段,但是server收到此失效的連接請求報文段後,就誤認爲是client再次發出的一個新的連接請求,於是就向client發出確認報文段,同意建立連接。假設不採用“三次握手”,那麼只要server發出確認,新的連接就建立了,由於client並沒有發出建立連接的請求,因此不會理睬server的確認,也不會向server發送數據,但server卻以爲新的運輸連接已經建立,並一直等待client發來數據。

所以三次握手是爲了:爲了防止已失效的連接請求報文段突然又傳送到了服務端,因而產生錯誤

四次揮手:

爲什麼需要四次揮手呢?TCP是全雙工模式,當client發出FIN報文段時,只是表示client已經沒有數據要發送了,client告訴server,它的數據已經全部發送完畢了;但是,這個時候client還是可以接受來server的數據;當server返回ACK報文段時,表示它已經知道client沒有數據發送了,但是server還是可以發送數據到client的;當server也發送了FIN報文段時,這個時候就表示server也沒有數據要發送了,就會告訴client,我也沒有數據要發送了,如果收到client確認報文段,之後彼此就會愉快的中斷這次TCP連接。

總結:所有的步驟都是爲了安全可靠的連接建立和關閉,如果少了其中一步,就會出現問題。

  • 在new一個對象A時,A繼承了B,此時是否也新建了對象B

不是,只會在堆上面產生A,不會新建B對象。此時如果B的構造函數裏面調用的方法被A重寫了,那麼這個時候B的構造函數是調用的A重寫的方法。

  • 爲什麼重寫了equals(),一定要重寫hashCode()

爲了滿足java規範:如果兩個對象equals相等,那麼這兩個對象的hashCode也相等。加入我們重新了equals,裏面的邏輯通過來一個人的姓名來判斷相等,這個時候如果是兩個對象它對應的姓名是一樣的,這個時候equals是返回true的,hashCode如果不重寫,那麼就返回false,這個時候不滿足規範。

  • hashcode會重複嗎,怎麼產生的

hashcode默認取的是對象的內存地址,它可能出現重複,比如String類,它重寫了hashcode()方法,

String s ="Ea"; 

String d ="FB"; 

System.out.println(s.hashCode());

System.out.println(d.hashCode());

他們兩個的值相等。這也就解釋了爲什麼String判斷相等的時候,想判斷hashcode,在判斷值的具體內容。

 

  • i=i++ 與 i=++i

理解:int i = 5;i=i++;這個時候結果是i=5;

原理:jvm在處理i= i++時, 會建立一個臨時變量來接收i++的的值,然後返回這個臨時變量的值,此時該臨時變量計算出來等於5,臨時變量計算完成之後,此時i = 6,但是,最後一步,臨時變量的值有重新賦值給了i,這樣就是說i雖然自增了但是又被賦值了5,這樣輸出的結果自然就是5了。

i=++i。此時臨時變量的值等於6,臨時變量計算完成之後,此時i =6,最後一步等號右邊的值賦值給i,結果還是6

  • retrun與finally

先了解一下比較系統的原理:https://blog.csdn.net/sinat_22594643/article/details/80509266

//情況一
 public int test1() {
        int a = 0;
        try {
            a = 100;
            return a;//1.代碼執行完這裏面的時候,會在局表變量表裏面新增一個數據,爲了方便理解,暫定爲:returnValue = a = 100,局部變量表存同時也存在a = 100。
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
//2.執行a=200的時候,確實是改了a的值,但是return返回的值是returnValue,這個值並沒有被修改,所以最後返回的還是100
            a = 200;
        }
        return 0;
    }


情況二:
public StringBuilder test2() {
        StringBuilder stringBuilder = new StringBuilder();
        try {
            stringBuilder.append("abcde");
//1.同上,執行完return後面的表達式之後,局表變量表returnValue = 對象的引用(真實對象在堆裏面)
            return stringBuilder;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
//2.這個操作把堆裏面的那個對象的內容修改了,但是並沒有修改returnValue對象的引用,所以最後返回的StringBuilder對象引用沒有任何修改,對象的內容修改成功了,最後打印出來就是:abcdefinally
            stringBuilder.append("finally");
        }
        return null;
    }


//情況三
 public String test3() {
        StringBuilder stringBuilder = new StringBuilder();
        try {
            stringBuilder.append("abcde");
//1.同上,局部變量表裏面returnvalue = 指向abced的對象引用
            return stringBuilder.toString();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
//2.修改了stringbuilder之後,returnvalue裏面的對象引用沒有被修改
           stringBuilder.append("finally");
        }
        return null;
    }


所以,總結如下:
finally執行完成之後,不能修改return 返回的任何數據,注意,返回對象的時候,是返回的對象的引用,對象的引用也不能被修改,除非,在finally裏面寫在一個return。如果finally裏面還有return,那麼這個return就可以把局部變量表的returnValue改掉,但是,這樣寫代碼是不正常的

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章