文章目录[隐藏]
数组的基础知识
- 数组的创建
- 列表元素的修改
- 普通 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 关键字表示分配新的内存空间来保存数据。
列表元素的修改
int[] arr = {1, 2}; // 直接指定元素 String[] list = {"a", "b"};
list[1] = "lucy"; // 就是修改 list 列表的第二个值
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
逆序遍历数组
有的同学对于arr.length - 1不理解,是这样,数组中的元素索引是从 0 开始的,所以一个数组如果有 3 个元素,索引就是 0 1 2,所有最后一个元素的索引是数组的长度减去 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]; // 假设,第一个元素是最大的 for (int v : arr)
{ if (v > max) // 如果遇到更大的值,就更新最大值 {
max = v;
}
} return max;
}
熟悉了 for-each 循环之后,会发现,这种写法其实更加简洁。
/ 返回最大值 */ public static int max(int[] arr) { int max = arr[0]; // 假设,第一个元素是最大的 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]; // 假设,第一个元素是最小的 for (int v : arr)
{ if (v < min)
{
min = v;
}
} return min;
}
max(arr)
20
min(arr)
1
上面的方法是求数组中元素的最大值和最小值,我们用 for-each 可以简化代码,但是有时候我们想要知道,最大值的索引,就得用普通 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
这个方法返回的是最大值在数组中的索引,而不是最大值本身。在有的算法,比如选择排序中,我们往往需要知道在某些元素中,最大值的位置,就可以用到这个方法。
返回最小值的位置
// 返回最大值的位置 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
查找元素
查找一个元素在数组中的位置,如果不存在就返回 -1;如果存在返回这个元素的索引。
比如说,字符串有indexOf(String s)方法,查找字符串 s,在另外一个字符串第一次出现的位置;如果字符串 s 在另外一个字符串中没有出现,那么就返回 -1。我们可以自定义数组的方法,名称是 find
/ 查找一个值 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
检查元素是否在数组中
我们有的时候并不需要知道一个元素在一个数组中的位置,只是要知道元素是否在数组中存在即可,这个时候可以用普通 for 循环来做;要求返回 true 或者 false。
有的同学,我可以调用上面的 find 方法,然后把结果跟 -1 比较,就能判断在不在了,但是这种方法相对繁琐,我们可以直接定义方法,判断一个元素是否在数组中出现。这类方法的方法名可以是 find,in,contain,have。
/ 查找一个值 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 循环,但是我们这次不关心 value 在数组中的位置,只关心有没有。既然这样的话,我就可以使用 for-each 循环来简化代码,减少代码出错的机会。
for-each 检查元素是否在数组中
public static boolean have(int[] arr, int value) { for (int elt : arr)
{ if (elt == value)
{ return true;
}
} return false;
}
但是,其实在这里,我们不关心,元素在数组中的位置,所以我们可以使用 for-each 简化代码,代码如下:
for (int value : arr)
{
System.out.println(value);
}
2
3
1
字符串的比较
需要的注意是,查找元素是否在数组中,涉及到数组元素的比较。如果是原始类型,比如 int,double,boolean,char 类型,我们是可以直接用==来比较两个元素是否相等;但是对于 String 以及其他的对象类型,我们知道 == 实际上比较的是,两个对象在内存对地址是否一致。
对于字符串来说,== 比较就是两个字符串在内存地址;所以比较字符串或者对象是否相等,我们需要用字符串的 equals 方法。
所以查找字符串是否在字符串数组中的方法,下面写法是错误的:
字符串比较 == 比较内存地址
public static boolean have(String[] arr, String value) { for (String elt : arr)
{ if (elt == value) // 注意比较内容是否一致,不能用 == 要用 equals 方法 { return true;
}
} return false;
}
比较字符串的内容是否相等应该用 equals 方法,正确代码如下:
euqals 比较内容
public static boolean haveEquals(String[] arr, String value) { for (String elt : arr)
{ if (elt.equals(value)) // 注意比较内容是否一致,不能用 == 要用 equals 方法 { return true;
}
} return false;
}
String[] list = {new String("a"), "b", "c"};
have(list, "a")
false
字符串字面量
因为new String("a")是用运算符 new 创建的,也就是要在内存中分配新的内存空间;所以这个字符串对象和字符串字面量 "a" 在内存中的位置是不同的,所以尽管都是 a,也找不到。
String[] list = {"a", "b", "c"};
have(list, "a")
true
因为 "a" 是字符串字面量,内容相同的字符串字面量在 Java 是保存在内存的同一位置的,所以用 have 可以找到。
String[] list = {new String("a"), "b", "c"};
haveEquals(list, "a");
true
因为字符串字面量 "a" 和字符对象 new String("a"),尽管在内存中保存地址不同,但是内容是相同的,都是 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
通过代码的运行结果,观察 @ 之后的内容,发现两个对象其实是在不同的地址。
Point p = p231;
System.out.println(p231 + " " + p)
REPL.$JShell$55$Point@74517d53 REPL.$JShell$55$Point@74517d53
通过观察地址,我们可以知道 p 就是对象 p221 的 alias name,也就是别名,所以用 == 比较结果肯定是 true; 因为我们知道,p 也好,p231 也好本质上是保存了对待在内存中的地址,而不是对象本身。
p == p231
true
p231 == p232
false
p231.equals(p232)
true
对于对象类来说,两个对象比较,判断是否相等或者是相同对象的逻辑是可以自己定义的,就像是 toString 是可以自己定义。我们可以规定,什么样的两个对象是相等的。对于两个长方形,如果左上角的顶点相同,并且长和宽也相同,我们就可以认为这是两个相同的长方形。
自定义 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 // 两个对象在内存中的地址不同
false
r1.equals(r2) // 相等的逻辑是我们自己定义的,只要左上角坐标和长款一致,就是相同的长方形
true
r1
2 3 2 3
r2
2 3 2 3
语雀导出的 markdown 可以包含换行和 wrap,对于代码来说排版尤为重要,否则普通的无法导入到公众号。 2023 对自己好点,但行好事,莫问前程。