文章目錄[隱藏]
數組的基礎知識
- 數組的創建
- 列表元素的修改
- 普通 for 循環遍曆數組
- for-each loop 遍曆數組
- 逆序遍曆數組
- 用 for-each 循環求數組最大值
- 求數組最小值
- 返回最大值的位置
- 返回最小值的位置
- 查找元素
- 檢查元素是否在數組中
- for-each 檢查元素是否在數組中
- 字符串的比較
- 字符串比較 == 比較內存地址
- euqals 比較內容
- 字符串字麵量
- 自定 equals 方法比較對象
- Point 類比較
- 自定義 equals 的比較邏輯
數組的創建
數組是就是,一係列的值;數組創建之後大小不能變化。
ArrayList 也叫做動態數組,創建之後可以動態增刪元素。
int[] arr = new int[3]; // 默認值 0 String[] colors = new String[4]; // 默認值 null double[] c = new double[4]; // 默認值是 0.0 boolean[] bs = new boolean[4]; // false
new 關(guan) 鍵字表示分配新的內(nei) 存空間來保存數據。
列表元素的修改
int[] arr = {1, 2}; // 直接指定元素 String[] list = {"a", "b"};
list[1] = "lucy"; // 就是修改 list 列表的第二個(ge) 值
lucy
普通 for 循環遍曆數組
// 遍曆數組 for (int i = 0; i < list.length; i++)
{
System.out.println(list[i]);
}
a
lucy
for-each loop 遍曆數組
// for-each loop for (String s : list)
{
System.out.println(s);
}
a
lucy
int[] arr = {1, 2, 3, 4, 6, 10, 20};
遍曆數組是最基本的操作,但是有時候需要按照相反的順序遍曆數組
for (int i = arr.length - 1; i >= 0; i--) { System.out.println(arr[i]); }
20
10
6
4
3
2
1
逆序遍曆數組
有的同學對於(yu) arr.length - 1不理解,是這樣,數組中的元素索引是從(cong) 0 開始的,所以一個(ge) 數組如果有 3 個(ge) 元素,索引就是 0 1 2,所有最後一個(ge) 元素的索引是數組的長度減去 1.
public static void reverseDisplay(int[] arr) { for (int i = arr.length - 1; i >= 0; i--) { System.out.println(arr[i]); } }
reverseDisplay(arr)
20
10
6
4
3
2
1
用 for-each 循環求數組最大值
/ 返回最大值 */ public static int maxForEachLoop(int[] arr) { int max = arr[0]; // 假設,第一個(ge) 元素是最大的 for (int v : arr)
{ if (v > max) // 如果遇到更大的值,就更新最大值 {
max = v;
}
} return max;
}
熟悉了 for-each 循環之後,會(hui) 發現,這種寫(xie) 法其實更加簡潔。
/ 返回最大值 */ public static int max(int[] arr) { int max = arr[0]; // 假設,第一個(ge) 元素是最大的 for (int i = 0; i < arr.length; i++) { if (arr[i] > max) { max = arr[i]; } } return max; }
很明顯,利用 regular for loop 要比 for-each loop 稍微麻煩一點。
求數組最小值
/ 返回最小值 */ public static int minForEachLoop(int[] arr) { int min = arr[0]; // 假設,第一個(ge) 元素是最小的 for (int v : arr) { if (v < min) { min = v; } } return min; }
max(arr)
20
min(arr)
1
上麵的方法是求數組中元素的最大值和最小值,我們(men) 用 for-each 可以簡化代碼,但是有時候我們(men) 想要知道,最大值的索引,就得用普通 for 循環了。
返回最大值的位置
// 返回最大值的位置 public static int posOfMaxValue(int[] arr) { int maxIndex = 0; // 假設最大值的索引是 maxIndex for (int i = 0; i < arr.length; i++) { if (arr[i] > arr[maxIndex]) { maxIndex = i; } } return maxIndex; }
int[] arr = {1, 2, 3, 4, 6, 10, 20};
posOfMaxValue(arr)
6
這個(ge) 方法返回的是最大值在數組中的索引,而不是最大值本身。在有的算法,比如選擇排序中,我們(men) 往往需要知道在某些元素中,最大值的位置,就可以用到這個(ge) 方法。
返回最小值的位置
// 返回最大值的位置 public static int posOfMinValue(int[] arr) { int minIndex = 0; // 假設最大值的索引是 maxIndex for (int i = 0; i < arr.length; i++) { if (arr[i] < arr[minIndex]) { minIndex = i; } } return minIndex; }
int[] arr = {1, 2, 3, 4, 6, 10, 20};
posOfMinValue(arr)
0
查找元素
查找一個(ge) 元素在數組中的位置,如果不存在就返回 -1;如果存在返回這個(ge) 元素的索引。
比如說,字符串有indexOf(String s)方法,查找字符串 s,在另外一個(ge) 字符串第一次出現的位置;如果字符串 s 在另外一個(ge) 字符串中沒有出現,那麽(me) 就返回 -1。我們(men) 可以自定義(yi) 數組的方法,名稱是 find
/ 查找一個(ge) 值 value 在數組 arr 中的位置;如果不存在返回 -1*/ public static int find(int[] arr, int value) { for (int i = 0; i < arr.length; i++) { if (arr[i] == value) { return i; // 如果找到了直接返回位置 } } return -1; // 如果找不到返回 -1 }
int[] arr = {2, 3, 1};
find(arr, 2)
0
int[] arr = {2, 3, 1};
find(arr, 3)
1
find(arr, 100)
-1
檢查元素是否在數組中
我們(men) 有的時候並不需要知道一個(ge) 元素在一個(ge) 數組中的位置,隻是要知道元素是否在數組中存在即可,這個(ge) 時候可以用普通 for 循環來做;要求返回 true 或者 false。
有的同學,我可以調用上麵的 find 方法,然後把結果跟 -1 比較,就能判斷在不在了,但是這種方法相對繁瑣,我們(men) 可以直接定義(yi) 方法,判斷一個(ge) 元素是否在數組中出現。這類方法的方法名可以是 find,in,contain,have。
/ 查找一個(ge) 值 value 在數組 arr 中的位置;如果不存在返回 -1*/ public static boolean have(int[] arr, int value) { for (int i = 0; i < arr.length; i++) { if (arr[i] == value) { return true; // 如果找到了直接返回位置 } } return false; // 如果找不到返回 -1 }
int[] arr = {2, 3, 1};
have(arr, 200)
false
have(arr, 3)
true
上麵的代碼用的是普通 for 循環,但是我們(men) 這次不關(guan) 心 value 在數組中的位置,隻關(guan) 心有沒有。既然這樣的話,我就可以使用 for-each 循環來簡化代碼,減少代碼出錯的機會(hui) 。
for-each 檢查元素是否在數組中
public static boolean have(int[] arr, int value) { for (int elt : arr) { if (elt == value) { return true; } } return false; }
但是,其實在這裏,我們(men) 不關(guan) 心,元素在數組中的位置,所以我們(men) 可以使用 for-each 簡化代碼,代碼如下:
for (int value : arr) { System.out.println(value); }
2
3
1
字符串的比較
需要的注意是,查找元素是否在數組中,涉及到數組元素的比較。如果是原始類型,比如 int,double,boolean,char 類型,我們(men) 是可以直接用==來比較兩(liang) 個(ge) 元素是否相等;但是對於(yu) String 以及其他的對象類型,我們(men) 知道 == 實際上比較的是,兩(liang) 個(ge) 對象在內(nei) 存對地址是否一致。
對於(yu) 字符串來說,== 比較就是兩(liang) 個(ge) 字符串在內(nei) 存地址;所以比較字符串或者對象是否相等,我們(men) 需要用字符串的 equals 方法。
所以查找字符串是否在字符串數組中的方法,下麵寫(xie) 法是錯誤的:
字符串比較 == 比較內存地址
public static boolean have(String[] arr, String value) { for (String elt : arr) { if (elt == value) // 注意比較內(nei) 容是否一致,不能用 == 要用 equals 方法 { return true; } } return false; }
比較字符串的內(nei) 容是否相等應該用 equals 方法,正確代碼如下:
euqals 比較內容
public static boolean haveEquals(String[] arr, String value) { for (String elt : arr) { if (elt.equals(value)) // 注意比較內(nei) 容是否一致,不能用 == 要用 equals 方法 { return true; } } return false; }
String[] list = {new String("a"), "b", "c"};
have(list, "a")
false
字符串字麵量
因為(wei) new String("a")是用運算符 new 創建的,也就是要在內(nei) 存中分配新的內(nei) 存空間;所以這個(ge) 字符串對象和字符串字麵量 "a" 在內(nei) 存中的位置是不同的,所以盡管都是 a,也找不到。
String[] list = {"a", "b", "c"}; have(list, "a")
true
因為(wei) "a" 是字符串字麵量,內(nei) 容相同的字符串字麵量在 Java 是保存在內(nei) 存的同一位置的,所以用 have 可以找到。
String[] list = {new String("a"), "b", "c"}; haveEquals(list, "a");
true
因為(wei) 字符串字麵量 "a" 和字符對象 new String("a"),盡管在內(nei) 存中保存地址不同,但是內(nei) 容是相同的,都是 a,所以可以正確的的找到。要注意對象類型的比較,equals 才是比較是否是相同的類型。
自定 equals 方法比較對象
Point 類比較
class Point { private int x, y; public Point(int x, int y) { this.x = x; this.y = y; } public int getX() {return x;} public int getY() {return y;} public boolean equals(Point other) { if (other == null) { return false; } return x == other.getX() && y == other.getY(); } }
Point p231 = new Point(2, 3);
Point p232 = new Point(2, 3);
System.out.println(p231 + " " + p232)
REPL.$JShell$55$Point@74517d53 REPL.$JShell$55$Point@7a969da9
通過代碼的運行結果,觀察 @ 之後的內(nei) 容,發現兩(liang) 個(ge) 對象其實是在不同的地址。
Point p = p231;
System.out.println(p231 + " " + p)
REPL.$JShell$55$Point@74517d53 REPL.$JShell$55$Point@74517d53
通過觀察地址,我們(men) 可以知道 p 就是對象 p221 的 alias name,也就是別名,所以用 == 比較結果肯定是 true; 因為(wei) 我們(men) 知道,p 也好,p231 也好本質上是保存了對待在內(nei) 存中的地址,而不是對象本身。
p == p231
true
p231 == p232
false
p231.equals(p232)
true
對於(yu) 對象類來說,兩(liang) 個(ge) 對象比較,判斷是否相等或者是相同對象的邏輯是可以自己定義(yi) 的,就像是 toString 是可以自己定義(yi) 。我們(men) 可以規定,什麽(me) 樣的兩(liang) 個(ge) 對象是相等的。對於(yu) 兩(liang) 個(ge) 長方形,如果左上角的頂點相同,並且長和寬也相同,我們(men) 就可以認為(wei) 這是兩(liang) 個(ge) 相同的長方形。
自定義 equals 的比較邏輯
class Rect { private Point point; private int w, h; public Rect(Point p, int w, int h) { this.w = w; this.h = h; this.point = p; } public Point getPoint() {return point;} public int getW() {return w;} public int getH() {return h;} public boolean equals(Rect other) { if (other == null) {return false;} // return point == other.getPoint() && w == other.getW() && h == other.getH(); return point.equals(other.getPoint()) && w == other.getW() && h == other.getH(); } public String toString() { return point.getX() + " " + point.getY() + " " + w + " " + h; } }
Rect r1 = new Rect(new Point(2, 3), 2, 3);
Rect r2 = new Rect(new Point(2, 3), 2, 3);
r1 == r2 // 兩(liang) 個(ge) 對象在內(nei) 存中的地址不同
false
r1.equals(r2) // 相等的邏輯是我們(men) 自己定義(yi) 的,隻要左上角坐標和長款一致,就是相同的長方形
true
r1
2 3 2 3
r2
2 3 2 3
語雀導出的 markdown 可以包含換行和 wrap,對於(yu) 代碼來說排版尤為(wei) 重要,否則普通的無法導入到公眾(zhong) 號。 2023 對自己好點,但行好事,莫問前程。
評論已經被關(guan) 閉。