<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          深入理解 Java 數(shù)組

          共 7008字,需瀏覽 15分鐘

           ·

          2021-02-28 19:10

          雖然在平常開(kāi)發(fā)中,使用集合(容器)的頻率比數(shù)組高得多,不過(guò)集合的底層也是通過(guò)數(shù)組來(lái)實(shí)現(xiàn)的。而且,盡管集合相比數(shù)組來(lái)說(shuō)強(qiáng)大得多,但是其執(zhí)行效率遠(yuǎn)不及數(shù)組。所以在講集合之前,非常有必要深入了解一下數(shù)組。全文脈絡(luò)思維導(dǎo)圖如下:

          1. 一維數(shù)組詳解

          所謂數(shù)組,就是「相同數(shù)據(jù)類(lèi)型的元素按一定順序排列而成的集合」。先來(lái)看看一維數(shù)組的三種聲明和賦值方式:

          第一種:

          int[] a = {123};

          第二種:

          int[] b = new int[] {123};

          第三種:

          int[] c = new int[3];
          c[0] = 1;
          c[1] = 2;
          c[2] = 3;

          以上這三種方式的效果都是一樣的,創(chuàng)建了一個(gè)存儲(chǔ) 1、2、3 這三個(gè)整數(shù)的數(shù)組。

          ?

          可以使用下面兩種形式聲明數(shù)組 :

          int[] a; 或  int a[];

          通常都會(huì)使用第一種風(fēng)格, 因?yàn)樗鼘㈩?lèi)型 int[] ( 整型數(shù)組)與變量名分開(kāi)了。

          ?

          我們來(lái)反編譯一下這三段代碼的 .class 文件,你就會(huì)發(fā)現(xiàn)其實(shí)「在底層它們的創(chuàng)建方式都是一樣的」,編譯器自動(dòng)的給我們加上了 new 關(guān)鍵字,甚至還把 c 的聲明和賦值一體化了。

          另外,需要注意的是:new int[3]; 這條語(yǔ)句會(huì)創(chuàng)建一個(gè)能夠存儲(chǔ) 3 個(gè)元素的數(shù)組,不過(guò)該數(shù)組的最后一個(gè)元素的下標(biāo)是 2(因?yàn)橄聵?biāo)從 0 開(kāi)始計(jì)數(shù),相信我,刷算法題的時(shí)候,這個(gè)鬼東西經(jīng)常會(huì)讓你腦子短路)。并且這條語(yǔ)句會(huì)自動(dòng)的初始化所有元素,比如對(duì)于 int 數(shù)組來(lái)說(shuō)就是全部初始化為 0,對(duì)于 boolean 數(shù)組來(lái)說(shuō)就會(huì)全部初始化為 false, 對(duì)象數(shù)組就會(huì)初始化為 null 等。

          從上面這些代碼和分析中,我們也不難看出,「數(shù)組創(chuàng)建之后是無(wú)法改變其存儲(chǔ)空間大小的」(存儲(chǔ)能力),盡管它可以改變每一個(gè)數(shù)組元素。

          我們通過(guò) IDEA 的聯(lián)想功能來(lái)看看數(shù)組能夠調(diào)用什么東西:

          可以發(fā)現(xiàn),數(shù)組擁有 Object 類(lèi)的所有方法,并且還會(huì)新增一個(gè)屬性 length(注意是屬性,而不是方法),用來(lái)表示這個(gè)數(shù)組的長(zhǎng)度,我們可以這樣調(diào)用:a.length

          ?

          注意區(qū)別于 String 類(lèi)的 length() 「方法」,數(shù)組擁有的是 length 「屬性」,而非方法。

          ?

          綜上,數(shù)組不僅能夠封裝數(shù)據(jù),還能調(diào)用屬性和方法,那這和對(duì)象有啥區(qū)別?沒(méi)錯(cuò),這也就是為什么說(shuō)「數(shù)組的本質(zhì)是對(duì)象」了。回顧一下我們之前總結(jié)的 Java 中方法參數(shù)的使用情況(按值調(diào)用):

          • 一個(gè)方法不能修改一個(gè)基本數(shù)據(jù)類(lèi)型的參數(shù)(即數(shù)值型或布爾型)。
          • 一個(gè)方法可以改變一個(gè)對(duì)象參數(shù)的狀態(tài)。
          • 一個(gè)方法不能讓對(duì)象參數(shù)引用一個(gè)新的對(duì)象。

          而因?yàn)閿?shù)組的本質(zhì)是對(duì)象,因此,將數(shù)組作為參數(shù)傳遞給方法,這個(gè)數(shù)組是可以被改變的。

          OK,接下來(lái),以下面這段代碼為例,我們來(lái)看看一維數(shù)組在內(nèi)存中的存儲(chǔ)方式:

          int[] b = new int[] {123};

          int 數(shù)組對(duì)象 b 存儲(chǔ)在 棧中,而數(shù)組元素既然是 new 出來(lái)的,那當(dāng)然是存儲(chǔ)在堆中。只有當(dāng) JVM 執(zhí)行 new int[] 時(shí),才會(huì)在堆中開(kāi)辟相應(yīng)的內(nèi)存區(qū)域。

          2. 多維數(shù)組詳解

          我們?cè)賮?lái)看看多維數(shù)組,就以二維數(shù)組為例,同樣的三種聲明與賦值方式:

          第一種:

          double[][] a = { 
              {163213}, 
              {510118}, 
              {96712}, 
              {415141
          };

          第二種:

          // 構(gòu)造一個(gè) 4 行 4 列的二維數(shù)組
          double[][] b = new double[4][4] { 
              {163213}, 
              {510118}, 
              {96712}, 
              {415141
          };

          第三種:

          double[][] c = new double[4][4];
          c[0][0] = 16// 第一行第一列值為 16
          c[0][1] = 3// 第一行第二列值為 3
          c[0][2] = 2;
          c[0][3] = 13;
          c[1][0] = 5// 第二行第一列值為 5
          c[1][1] = 10;
          c[1][2] = 1;
          c[1][3] = 8;
          ......

          同樣的,我們來(lái)反編譯一下這三段代碼的 .class 文件,底層它們的創(chuàng)建方式基本也都是一樣的,不過(guò)有些細(xì)微的差別。編譯器還是自動(dòng)的給我們加上了 new 關(guān)鍵字,不過(guò)沒(méi)有像一維數(shù)組那樣把 c 的聲明和賦值一體化了。

          到目前為止,我們所看到的數(shù)組與其他程序設(shè)計(jì)語(yǔ)言中提供的數(shù)組沒(méi)有多大區(qū)別。但實(shí)際存在著一些細(xì)微的差異, 而這正是 Java 的優(yōu)勢(shì)所在:「Java 實(shí)際上沒(méi)有多維數(shù)組,只有一維數(shù)組」。多維數(shù)組被解釋為「數(shù)組的數(shù)組」。請(qǐng)看下圖:

          由于可以單獨(dú)地存取數(shù)組的某一行, 所以可以讓兩行交換。

          int[] temp = b[1];
          b[1] = b[2];
          b[2] = temp;

          3. for each 循環(huán)

          Java 有一種功能很強(qiáng)的循環(huán)結(jié)構(gòu), 可以用來(lái)依次處理數(shù)組中的每個(gè)元素而不必為指定下標(biāo)值而分心。這種增強(qiáng)的 for 循環(huán)的語(yǔ)句格式為:

          for(variable : collection){
              // todo
          }

          collection這一集合表達(dá)式必須是一個(gè)數(shù)組或者是一個(gè)實(shí)現(xiàn)了 Iterable 接口的類(lèi)對(duì)象」,例如 ArrayList

          下面我們來(lái)對(duì)比一下使用下標(biāo)遍歷數(shù)組和使用 for each 循環(huán)遍歷數(shù)組這兩種方式:

          // 使用下標(biāo)遍歷數(shù)組
          int[] a = new int[100];
          for(int i = 0; i < 100; i++) {
              a[i] = i;
          }

          // 使用 for each 循環(huán)遍歷數(shù)組
          for(int element: a){
              System.out.println(element);
          }

          for each 循環(huán)語(yǔ)句的循環(huán)變量將會(huì)遍歷數(shù)組中的每個(gè)元素, 而不需要使用下標(biāo)值。

          不過(guò),需要注意的是,「for each 循環(huán)語(yǔ)句不能自動(dòng)處理多維數(shù)組的每一個(gè)元素,它是按照行, 也就是一維數(shù)組處理的」。以二維數(shù)組為例,要想訪(fǎng)問(wèn)二維數(shù)組的所有元素, 需要使用兩個(gè)嵌套的循環(huán), 如下所示:

          int[][] a = { 
            {163213},
            {510118}, 
            {96712}, 
            {415141
          };

          for(int[] row : a) { // 遍歷每一行
            for(int value : row) { // 遍歷每一列
             System.out.println(value);
            }
          }

          4. 可變參數(shù)

          「JDK 1.5」 之后,如果我們定義一個(gè)方法需要接受多個(gè)參數(shù),并且「多個(gè)參數(shù)類(lèi)型一致」,我們可以對(duì)其簡(jiǎn)化成如下格式:

          修飾符 返回值類(lèi)型 方法名 (參數(shù)類(lèi)型... 形參名){  }

          ... 用在參數(shù)上,稱(chēng)之為「可變參數(shù)」,它「表明這個(gè)方法可以接收任意數(shù)量的參數(shù)」。其實(shí)這個(gè)寫(xiě)法完全等價(jià)與

          修飾符 返回值類(lèi)型 方法名 (參數(shù)類(lèi)型[] 形參名){  }

          雖然同樣是代表數(shù)組,但是在調(diào)用這個(gè)帶有可變參數(shù)的方法時(shí),不用創(chuàng)建數(shù)組,直接將數(shù)組中的元素作為實(shí)際參數(shù)進(jìn)行傳遞,這就是簡(jiǎn)單之處。當(dāng)然,其實(shí)這種方式的底層實(shí)現(xiàn)也是將這些元素先封裝到一個(gè)數(shù)組中,在進(jìn)行傳遞,不過(guò)這些動(dòng)作都在編譯 .class 文件時(shí)就自動(dòng)完成了。

          代碼演示:

          public class ChangeArgs {
              
              //可變參數(shù)寫(xiě)法
              public static int getSum(int... arr) {
                  int sum = 0;
                  for (int a : arr) {
                      sum += a;
                  }
                  return sum;
              }
              
              public static void main(String[] args) {
                  int[] arr = { 14624312 };
                  int sum = getSum(arr);
                  System.out.println(sum);
                  
                  int sum2 = getSum(672122121);
                  System.out.println(sum2);
              }
          }
          ?

          需要注意的是:如果在方法書(shū)寫(xiě)時(shí),這個(gè)方法擁有多個(gè)參數(shù),并且參數(shù)中包含可變參數(shù),「可變參數(shù)一定要寫(xiě)在參數(shù)列表的末尾」

          ?

          5. Arrays 類(lèi)

          Java 中,提供了一個(gè)很有用的數(shù)組工具類(lèi):java.util.Arrays。它提供的主要操作有:

          1)Arrays.toString - 將一維數(shù)組轉(zhuǎn)成字符串類(lèi)型(打印一維數(shù)組的所有元素)

          2)Arrays.deepToString - 將二維數(shù)組轉(zhuǎn)成字符串類(lèi)型(打印二維數(shù)組的所有元素)

          3)Arrays.copyOf - 數(shù)組拷貝。舉個(gè)例子,將 a 數(shù)組中的元素全部拷貝給 c 數(shù)組:

          int[] c = Arrays.copyOf(a, 2 * a.length());

          第 2 個(gè)參數(shù)是新數(shù)組的長(zhǎng)度。這個(gè)方法通常用來(lái)增加新數(shù)組的大小:如果數(shù)組元素是數(shù)值型,那么多余的元素將被賦值為 0 ; 如果數(shù)組元素是布爾型,則將賦值為 false 等。相反,如果長(zhǎng)度小于原始數(shù)組的長(zhǎng)度,則只拷貝最前面的數(shù)據(jù)元素。

          4)Arrays.sort - 對(duì)數(shù)組中的元素進(jìn)行排序

          5)Arrays.equals -  Arrays 類(lèi)提供了重載后的 equals 方法,用來(lái)基于內(nèi)容比較數(shù)組,數(shù)組相等的條件是元素個(gè)數(shù)和對(duì)應(yīng)位置的元素都相等。

          6. 總結(jié)

          不可否認(rèn),在 Java 中,數(shù)組是一種效率最高的存儲(chǔ)和隨機(jī)訪(fǎng)問(wèn)對(duì)象引用序列的方式。數(shù)組就是一個(gè)簡(jiǎn)單的線(xiàn)性序列,在內(nèi)存中采用「連續(xù)空間分配」的存儲(chǔ)方式,這使得通過(guò)下標(biāo)訪(fǎng)問(wèn)元素非常快速。但是代價(jià)就是「一旦創(chuàng)建了數(shù)組, 就不能再改變它的大小」(盡管可以改變每一個(gè)數(shù)組元素)。

          如果「經(jīng)常需要在運(yùn)行過(guò)程中擴(kuò)展數(shù)組的大小, 可以使用集合 ArrayList 。它可以通過(guò)創(chuàng)建一個(gè)新實(shí)例,然后把舊實(shí)例中所有的引用移到新實(shí)例中,從而實(shí)現(xiàn)更多空間的自動(dòng)分配。但是這種彈性需要開(kāi)銷(xiāo),因此,ArrayList 的效率比數(shù)組低很多。當(dāng)然,無(wú)論數(shù)組還是集合,如果越界,都會(huì)得到一個(gè) RuntimeException異常。

          關(guān)于集合會(huì)寫(xiě)成一個(gè)系列,下篇文章就會(huì)陸續(xù)開(kāi)更,內(nèi)容沒(méi)啥難度,不過(guò)要記的東西非常多,啃完集合后面還有個(gè)硬骨頭多線(xiàn)程,這倆學(xué)完 Java 基礎(chǔ)部分基本就沒(méi)啥了。

          參考資料

          • 《Java 核心技術(shù) - 卷 1 基礎(chǔ)知識(shí) - 第 10 版》
          • 《Thinking In Java(Java 編程思想)- 第 4 版》
          • 《On Java 8》中文版(《Java 編程思想》- 第 5 版)
          • 清淺池塘 - Java 中的數(shù)組-Java那些事兒:https://juejin.cn/post/6844903498207756295



          ?? 點(diǎn)擊下方卡片關(guān)注公眾號(hào)「飛天小牛肉」(專(zhuān)注于分享計(jì)算機(jī)基礎(chǔ)、Java 基礎(chǔ)和面試指南的相關(guān)原創(chuàng)技術(shù)好文,幫助讀者快速掌握高頻重點(diǎn)知識(shí),有的放矢),與小牛肉一起成長(zhǎng)、共同進(jìn)步 

          ?? 并向大家強(qiáng)烈推薦我維護(hù)的 Gitee 倉(cāng)庫(kù) 「CS-Wiki」(Gitee 推薦項(xiàng)目,目前已 1.0k+ star。致力打造完善的后端知識(shí)體系,在技術(shù)的路上少走彎路。相比公眾號(hào),該倉(cāng)庫(kù)擁有更健全的知識(shí)體系,歡迎給位小伙伴前來(lái)交流學(xué)習(xí),倉(cāng)庫(kù)地址 https://gitee.com/veal98/CS-Wiki。也可直接下方掃碼訪(fǎng)問(wèn)


          原創(chuàng)不易,讀完有收獲不妨點(diǎn)贊|分享|在看支持

          瀏覽 54
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  樱桃 码一区二区三区 | 亚洲少妇网 | 精品无人区一区二区三区聊斋艳谭 | 日韩日屄视频 | 超碰日韩在线 |