1. 程式人生 > 其它 >7Java基礎補充

7Java基礎補充

1.標準Java bean寫法

包括:private修飾的成員變數、getter和setter以及無參和有多個引數的有參構造方法

2.String原理

String底層是位元組陣列byte[]。

String不可變,但可以被共享。

3.Java中三種常量池:

(1)字串常量池(全域性字串池):由於字串本身具有不可變性,因此使用字串常量池對於同樣的字串可以起到一個快取的作用,防止多次記憶體分配,從而提供記憶體的利用率

(2)執行時常量池:當程式執行到某個類的時候,class檔案中的資訊就會被解析到記憶體的方法區的執行時常量池中,每個類都有一個執行時常量池。

(3)class檔案常量池:class常量池是在編譯後每個class檔案都有的,class檔案中除了包含類的版本 欄位 方法 介面等描述資訊,還有一項資訊就是常量池,用於存放編譯器生成的各種字面量和符號的引用。

4.細化Java記憶體模型

從大的方面來說,JVM記憶體分為幾個方面:

堆記憶體是JVM中最大的一塊區域,被所有執行緒共享,在JVM啟動時建立。幾乎所有物件的空間分配都在堆區來進行。

堆又分為新生代和老年代記憶體,兩者的記憶體大小的比例大概是1:2。

新生代又分為Eden、From區和To區,三者的記憶體大小的比例大概是8:1:1。幾乎所有新物件的記憶體分配都在Eden區完成。

劃分不同的區,分別儲存不同的資料,其記憶體回收策略也不相同。

在GC中,Eden區活躍的物件會被移動到survivor區,不活躍的會被GC清理掉。Survivor區中的物件達到一定的年齡,就會被移動到老年代中。

堆記憶體可以在物理上不連續,但是邏輯上要連續。

方法區又被稱為永久代,也是被所有的執行緒所共享的,該區域主要儲存類的資訊,靜態變數,常量和編譯器編譯後的程式碼等資料。

jdk7中,將永久代中的字串常量池移動到堆中。jdk8 撤銷了永久代 ,引入了元空間

方法區不需要連續的記憶體,可以選擇固定大小或者可擴充套件,並且還可以選擇不實現垃圾回收,相對而言,垃圾收集行為在這個區域是比較少見的,但並非資料進入方法區就如永久代的名字一樣永久存在了。這個區域的記憶體回收目標主要是針對常量池的回收和對型別的解除安裝,圾回收機制的條件是相當苛刻的。

5.字串的比較

public static void main(String[] args) {
   String s1 
= "abc"; String s2 = "abc"; System.out.println(s1 == s2);//true,s1指向常量池中建立的物件地址,s2指向常量池中已經存在的物件地址,這個物件是相同的 // 使用字元陣列構造一個字串 char[] c = {'a','b','c'}; String s3 = new String(c); String s4 = new String(c); System.out.println(s3 == s4);//false,堆中不同物件 String s5 = new String("abc"); String s6 = new String ("abc"); System.out.println(s5==s6);// false,堆中不同物件 System.out.println(s1 == s3);//false,s1指向常量池中建立的物件地址,s3指向堆中物件 System.out.println(s4 == s5);//false,堆中不同物件 }
String str1 = "abc";//在常量池中建立物件並得到引用
String str2 = new String("abc");//在堆中建立物件並引用,然後檢視常量池,此時已經有物件,所以不用再建立
public static void main(String[] args) {
        String s1 = "hello";//常量池中建立hello的引用
        String s2 = "world";//常量池中建立world的引用
        String s3 = "hello" +"world";//常量池中建立helloworld的引用
        String s4 = s1 +"world";//堆中建立的物件的引用,相當於new StringBuilder(s1).append("world").toString();toString()建立一個新的堆物件。
        String s5 = s1 + s2;//堆中建立物件的引用,相當於//new StringBuilder(s1).append(s2).toString();
    String s6 = (s1 + s2).intern(); //該值在常量池中已經存在,返回s3的引用
    String s7
= "helloworld"; //該值在常量池中已經存在,返回s3的引用
    System.out.println(s3==s4);// false
    System.out.println(s3 == s7);//true
    System.out.println(s3==s5);//false
    System.out.println(s4==s5);//false
    System.out.println(s3==s6);//true }

+連線字串:

常量+常量:編譯器直接優化生成結果,不需要生成StringBuilder。

常量+變數:需要生成StringBuilder,一行語句需要一個StringBuilder,append的數量基於變數和常量的個數,但當多個常量連在一起時,編譯器會優化直接生成常量運算結果,算作一個append處理。

變數和變數:需要生成StringBuilder,一行語句需要一個StringBuilder,append的數量基於常量的個數

public static void main(String[] args) {
        String str1 = new StringBuilder("計算機").append("軟體開發").toString();
        System.out.println(str1.intern()== str1);//true,str1.intern()在常量池中建立一個指向str1的引用,所以相等
        String str2 = new StringBuilder("ja").append("va").toString();//java是一個特殊的字串 在jdk的底層,存在很多“java”字串
        System.out.println(str2.intern()==str2);//false,雖然沒有人為建立,但是常量池中存在java物件,所以intern()返回的結果是常量池中的變數且不是ss堆物件的引用
 }
 public static void main(String[] args) {
      String str1 = new String("str") + new String("01");
      str1.intern();//intern()方法本質相當於把呼叫它的物件放入常量池,如果有就不放,而且放的是地址不是副本。
      String str2 = "str01";
        System.out.println(str1 == str2);//true
    }
  public static void main(String[] args) {
       String s1 = new String("he") +new String("llo");
       String s2 = new String("h") +new String("ello");
       String s3 = s1.intern();
       String s4 = s2.intern();
       System.out.println(s1==s3);//true
       System.out.println(s2 == s4);//false
       System.out.println(s3 == s4);//true
    }