Java數組與堆棧相關知識總結

一、數組創建

1.1 聲明並賦值

int[] a = {1,2,3};

1.2 聲明數組名開辟空間並且賦值

int[] a;
a = new int[]{1,2,3};

1.3 聲明數組時指定元素個數然後賦值

int[] a= new int[3];

這裡Java會默認數組元素值為0

1.4 在以上的基礎上創建多維數組

int[][] a = {{1,2,3},{4,5,6},{7,8,9}}; //每個子數組元素個數不要求均相同
int[][] a = new int[m][n]; //其中n可以省略,在創建的時候可以指定
int[][][] a = new int[m][n][q]; //同樣其中n、q可以省略

同樣的,在new一個數組時,如不初始化,Java會默認數組元素值為0。

二、數據類型

Java中的數據類型有兩種:

2.1 八種基本數據類型

  • int
  • short
  • long
  • byte
  • float
  • double
  • boolean
  • char

這種類型的定義是通過諸如int a = 3; long b = 255L;的形式來定義的,稱為自動變量。
自動變量存的是字面值,這些字面值固定定義在某個程序塊裡面,程序塊退出後,字段值就消失瞭,出於追求速度的原因,就存在於棧中。

2.2 包裝類數據

包裝類的數據是如 Integer, String, Double等將相應的基本數據類型包裝起來的類。這些類數據全部存在於堆中,Java用new()語句來顯式地告訴編譯器,在運行時才根據需要動態創建,因此比較靈活,但缺點是要占用更多的時間。
String是一個特殊的包裝類數據。即可以用String str = "abc";的形式來創建,也可以用String str = new String("abc");的形式來創建。String str = "abc";中,並沒有通過new()來創建實例,因為String str = "abc"; 是存儲在字符串常量池中。 字符串常量池則存在於方法區。
JVM為瞭提高性能和減少內存開銷,在實例化字符串常量的時候進行瞭一些優化。

1.為字符串開辟一個字符串常量池,類似於緩存區。

2.創建字符串常量時,首先堅持字符串常量池是否存在該字符串。存在該字符串,

3.返回引用實例,不存在,實例化該字符串並放入池中。

String str1 = "abc"; 
String str2 = "abc";
System.out.println(str1==str2); //true

可以看到結果是true,結果說明,JVM創建瞭兩個引用str1和str2,但隻創建瞭一個對象,而且兩個引用都指向瞭這個對象。

String str1 = "abc";
String str2 = "abc";
str1 = "bcd";
System.out.println(str1 + "," + str2); //bcd, abc
System.out.println(str1==str2); //false

參考上面的代碼可以知道,賦值的變化導致瞭類對象引用的變化,str1指向瞭另外一個新對象!而str2仍舊指向原來的對象。上例中,當我們將str1的值改為”bcd”時,JVM發現在棧中沒有存放該值的地址,便開辟瞭這個地址,並創建瞭一個新的對象,其字符串的值指向這個地址。
事實上,String類被設計成為不可改變(immutable)的類。如果你要改變其值,可以,但JVM在運行時根據新值悄悄創建瞭一個新對象,然後將這個對象的地址返回給原來類的引用。這個創建過程雖說是完全自動進行的,但它畢竟占用瞭更多的時間。在對時間要求比較敏感的環境中,會帶有一定的不良影響。
因此,並沒有與String是不可變的相矛盾。
繼續修改代碼:

String str1 = "abc";
String str2 = "abc";
str1 = "bcd";
String str3 = str1;
System.out.println(str3); //bcd
String str4 = "bcd";
System.out.println(str1 == str4); //true

可以看出,str3 這個對象的引用直接指向str1所指向的對象(註意,str3並沒有創建新對象)。當str1改完其值後,再創建一個String的引用str4,並指向因str1修改值而創建的新的對象。可以發現,這回str4也沒有創建新的對象,從而再次實現棧中數據的共享。
繼續修改代碼:

String str1 = new String("abc");
String str2 = "abc";
System.out.println(str1==str2); //false

可以發現此時返回false,這是因為通過new出來的放在瞭中,而第二個存於棧中,所以不相等。
另外:數據類型包裝類的值不可修改。不僅僅是String類的值不可修改,所有的數據類型包裝類都不能更改其內部的值。

三、棧、棧、方法區

是一種連續儲存的數據結構,具有先進後出的性質。
是一種非連續的樹形儲存數據結構,每個節點有一個值,整棵樹是經過排序的。特點是根結點的值最小(或最大),且根結點的兩個子樹也是一個堆。常用來實現優先隊列,存取隨意。
(stack)與(heap)都是Java用來在Ram中存放數據的地方。與C++不同,Java自動管理棧和堆,程序員不能直接地設置棧或堆。

3.1 棧

1.每個線程包含一個棧區,棧中隻保存基礎數據類型的對象和自定義對象的引用(不是對象)。

2.每個棧中的數據(原始類型和對象引用)都是私有的。

3.棧分為3個部分:基本類型變量區、執行環境上下文、操作指令區(存放操作指令)

4.數據大小和生命周期是可以確定的,當沒有引用指向數據時,這個數據就會自動消失。

通常的操作有入棧(壓棧),出棧和棧頂元素。想要讀取棧中的某個元素,就是將其之間的所有元素出棧才能完成。

棧的優勢是,存取速度比堆要快,僅次於直接位於CPU中的寄存器。但缺點是,存在棧中的數據大小與生存期必須是確定的,缺乏靈活性。
另外,棧數據可以共享
類似於int a = 3;等都是存放於棧中,當新創建值時Java會判斷棧中是否已存在,若存在則引用該地址,不存在則創建。例如:

 int a = 3; int b = 3;

編譯器先處理int a = 3;首先它會在棧中創建一個變量為a的引用,然後查找有沒有字面值為3的地址,沒找到,就開辟一個存放3這個字面值的地址,然後將a指向3的地址。接著處理int b = 3;在創建完b的引用變量後,由於在棧中已經有3這個字面值,便將b直接指向3的地址。這樣,就出現瞭a與b同時均指向3的情況。
特別註意的是,這種字面值的引用與類對象的引用不同。假定兩個類對象的引用同時指向一個對象,如果一個對象引用變量修改瞭這個對象的內部狀態,那麼另一個對象引用變量也即刻反映出這個變化。相反,通過字面值的引用來修改其值,不會導致另一個指向此字面值的引用的值也跟著改變的情況。如上例,我們定義完a與 b的值後,再令a=4;那麼,b不會等於4,還是等於3。在編譯器內部,遇到a=4;時,它就會重新搜索棧中是否有4的字面值,如果沒有,重新開辟地址存放4的值;如果已經有瞭,則直接將a指向這個地址。因此a值的改變不會影響到b的值。

3.2 堆

的優勢是可以動態地分配內存大小,生存期也不必事先告訴編譯器,Java的垃圾收集器會自動收走這些不再使用的數據。但缺點是,由於要在運行時動態分配內存,存取速度較慢。

1.存儲的是對象,每個對象都包含一個與之對應的class。

2.JVM隻有一個堆區(heap)被所有線程共享,堆中不存放基本類型和對象引用,隻存放對象本身。

3.對象的由垃圾回收器負責回收,因此大小和生命周期不需要確定。

3.3 方法區

1.靜態區,跟堆一樣,被所有的線程共享。

2.方法區中包含的都是在整個程序中永遠唯一的元素,如class,static變量

字符串常量池則存在於方法區

在這裡插入圖片描述

 字

符串對象的創建 面試題

面試題:String str4 = new String(“abc”) 創建多少個對象?

1、在常量池中查找是否有“abc”對象。

1)有則返回對應的引用實例;

2)沒有則創建對應的實例對象。

2、在堆中 new 一個 String(“abc”) 對象。

3、將對象地址賦值給str4,創建一個引用。

所以,常量池中沒有“abc”字面量則創建兩個對象,否則創建一個對象,以及創建一個引用。

到此這篇關於Java數組與堆棧相關知識總結的文章就介紹到這瞭,更多相關Java數組與堆棧內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: