文章目录[隐藏]
数组的基础知识
- 数组的创建
- 列表元素的修改
- 普通 for 循环遍历数组
- for-each loop 遍历数组
- 逆序遍历数组
- 用 for-each 循环求数组最大值
- 求数组最小值
- 返回最大值的位置
- 返回最小值的位置
- 查找元素
- 检查元素是否在数组中
- for-each 检查元素是否在数组中
- 字符串的比较
- 字符串比较 == 比较内存地址
- euqals 比较内容
- 字符串字面量
- 自定 equals 方法比较对象
- Point 类比较
- 自定义 equals 的比较逻辑
数组的创建
数组是就是,一系列的值;数组创建之后大小不能变化。
ArrayList 也叫做动态数组,创建之后可以动态增删元素。
int[] arr =newint[3];// 默认值 0String[] colors =newString[4];// 默认值 nulldouble[] c =newdouble[4];// 默认值是 0.0boolean[] bs =newboolean[4];// false
new 关键字表示分配新的内存空间来保存数据。
列表元素的修改
int[] arr = {1,2};// 直接指定元素String[] list = {"a","b"};
list[1] ="lucy";// 就是修改 list 列表的第二个值
lucy
普通 for 循环遍历数组
// 遍历数组for(inti =0; i < list.length; i++) { System.out.println(list[i]); }
a lucy
for-each loop 遍历数组
// for-each loopfor(String s : list) { System.out.println(s); }
a lucy
int[] arr = {1,2,3,4,6,10,20};
遍历数组是最基本的操作,但是有时候需要按照相反的顺序遍历数组
for(inti = 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.
publicstaticvoidreverseDisplay(int[] arr){for(inti = arr.length -1; i >=0; i--) { System.out.println(arr[i]); } }
reverseDisplay(arr)
20 10 6 4 3 2 1
用 for-each 循环求数组最大值
/ 返回最大值 */publicstaticintmaxForEachLoop(int[] arr){intmax = arr[0];// 假设,第一个元素是最大的for(intv : arr) {if(v > max)// 如果遇到更大的值,就更新最大值{ max = v; } }returnmax; }
熟悉了 for-each 循环之后,会发现,这种写法其实更加简洁。
/ 返回最大值 */publicstaticintmax(int[] arr){intmax = arr[0];// 假设,第一个元素是最大的for(inti =0; i < arr.length; i++) {if(arr[i] > max) { max = arr[i]; } }returnmax; }
很明显,利用 regular for loop 要比 for-each loop 稍微麻烦一点。
求数组最小值
/ 返回最小值 */publicstaticintminForEachLoop(int[] arr){intmin = arr[0];// 假设,第一个元素是最小的for(intv : arr) {if(v < min) { min = v; } }returnmin; }
max(arr)
20
min(arr)
1
上面的方法是求数组中元素的最大值和最小值,我们用 for-each 可以简化代码,但是有时候我们想要知道,最大值的索引,就得用普通 for 循环了。
返回最大值的位置
// 返回最大值的位置publicstaticintposOfMaxValue(int[] arr){intmaxIndex =0;// 假设最大值的索引是 maxIndexfor(inti =0; i < arr.length; i++) {if(arr[i] > arr[maxIndex]) { maxIndex = i; } }returnmaxIndex; }
int[] arr = {1,2,3,4,6,10,20}; posOfMaxValue(arr)
6
这个方法返回的是最大值在数组中的索引,而不是最大值本身。在有的算法,比如选择排序中,我们往往需要知道在某些元素中,最大值的位置,就可以用到这个方法。
返回最小值的位置
// 返回最大值的位置publicstaticintposOfMinValue(int[] arr){intminIndex =0;// 假设最大值的索引是 maxIndexfor(inti =0; i < arr.length; i++) {if(arr[i] < arr[minIndex]) { minIndex = i; } }returnminIndex; }
int[] arr = {1,2,3,4,6,10,20}; posOfMinValue(arr)
0
查找元素
查找一个元素在数组中的位置,如果不存在就返回 -1;如果存在返回这个元素的索引。
比如说,字符串有indexOf(String s)方法,查找字符串 s,在另外一个字符串第一次出现的位置;如果字符串 s 在另外一个字符串中没有出现,那么就返回 -1。我们可以自定义数组的方法,名称是 find
/ 查找一个值 value 在数组 arr 中的位置;如果不存在返回 -1*/publicstaticintfind(int[] arr,intvalue){for(inti =0; i < arr.length; i++) {if(arr[i] == value) {returni;// 如果找到了直接返回位置} }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*/publicstaticbooleanhave(int[] arr,intvalue){for(inti =0; i < arr.length; i++) {if(arr[i] == value) {returntrue;// 如果找到了直接返回位置} }returnfalse;// 如果找不到返回 -1}
int[] arr = {2,3,1}; have(arr,200)
false
have(arr,3)
true
上面的代码用的是普通 for 循环,但是我们这次不关心 value 在数组中的位置,只关心有没有。既然这样的话,我就可以使用 for-each 循环来简化代码,减少代码出错的机会。
for-each 检查元素是否在数组中
publicstaticbooleanhave(int[] arr,intvalue){for(intelt : arr) {if(elt == value) {returntrue; } }returnfalse; }
但是,其实在这里,我们不关心,元素在数组中的位置,所以我们可以使用 for-each 简化代码,代码如下:
for(intvalue : arr) { System.out.println(value); }
2 3 1
字符串的比较
需要的注意是,查找元素是否在数组中,涉及到数组元素的比较。如果是原始类型,比如 int,double,boolean,char 类型,我们是可以直接用==来比较两个元素是否相等;但是对于 String 以及其他的对象类型,我们知道 == 实际上比较的是,两个对象在内存对地址是否一致。
对于字符串来说,== 比较就是两个字符串在内存地址;所以比较字符串或者对象是否相等,我们需要用字符串的 equals 方法。
所以查找字符串是否在字符串数组中的方法,下面写法是错误的:
字符串比较 == 比较内存地址
publicstaticbooleanhave(String[] arr, String value){for(String elt : arr) {if(elt == value)// 注意比较内容是否一致,不能用 == 要用 equals 方法{returntrue; } }returnfalse; }
比较字符串的内容是否相等应该用 equals 方法,正确代码如下:
euqals 比较内容
publicstaticbooleanhaveEquals(String[] arr, String value){for(String elt : arr) {if(elt.equals(value))// 注意比较内容是否一致,不能用 == 要用 equals 方法{returntrue; } }returnfalse; }
String[] list = {newString("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 = {newString("a"),"b","c"}; haveEquals(list,"a");
true
因为字符串字面量 "a" 和字符对象 new String("a"),尽管在内存中保存地址不同,但是内容是相同的,都是 a,所以可以正确的的找到。要注意对象类型的比较,equals 才是比较是否是相同的类型。
自定 equals 方法比较对象
Point 类比较
classPoint{privateintx, y;publicPoint(intx,inty){this.x = x;this.y = y; }publicintgetX(){returnx;}publicintgetY(){returny;}publicbooleanequals(Point other){if(other ==null) {returnfalse; }returnx == other.getX() && y == other.getY(); } }
Point p231 =newPoint(2,3); Point p232 =newPoint(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 的比较逻辑
classRect{privatePoint point;privateintw, h;publicRect(Point p,intw,inth){this.w = w;this.h = h;this.point = p; }publicPointgetPoint(){returnpoint;}publicintgetW(){returnw;}publicintgetH(){returnh;}publicbooleanequals(Rect other){if(other ==null) {returnfalse;}// return point == other.getPoint() && w == other.getW() && h == other.getH();returnpoint.equals(other.getPoint()) && w == other.getW() && h == other.getH(); }publicStringtoString(){returnpoint.getX() +" "+ point.getY() +" "+ w +" "+ h; } }
Rect r1 =newRect(newPoint(2,3),2,3); Rect r2 =newRect(newPoint(2,3),2,3);
r1 == r2// 两个对象在内存中的地址不同
false
r1.equals(r2)// 相等的逻辑是我们自己定义的,只要左上角坐标和长款一致,就是相同的长方形
true
r1
2 3 2 3
r2
2 3 2 3
语雀导出的 markdown 可以包含换行和 wrap,对于代码来说排版尤为重要,否则普通的无法导入到公众号。2023 对自己好点,但行好事,莫问前程。













