小知识,大挑战!本文正在参与“程序员必备小知识”创作活动
基础知识
很多道理往往可以用简单的话说明白。 关于 Java 数组,你只需要记住两句话:
1. 数组是相同类型数据的有序集合;
2. 数组也是对象。
展开的版本:
- 长度确定且不可改;
- 类型不可改;
- 类型可基本可引用;
- 数据的变量属于引用类型,数组也是对象,数据的元素相当于对象的属性。
Java 数组初始化的三种方式:
- 静态初始化:一开始就把值给好了;
- 动态初始化:一开始给个长度,然后再逐个赋值;
- 默认初始化:动态初始化前一步,然后就用这个系统默认给的值:0、0.0、false、null。
练习点:
Array.toString([]);
System.arraycopy(
原数组, 原数组开始的索引, 要拷贝到的数组, 目标数组开始拷贝的索引, 从原数组拷贝的长度)
;for(type i: array)
来逐个遍历;- 初始化方法;
练习代码如下:
public class CopyArray {
public static void main(String[] args) {
String[] companies = new String[]{"alibaba", "bytedance",
"pinduoduo", "dingdong", "souhu"};
String[] copy2 = new String[3];
System.arraycopy(companies, 0, copy2, 0, 3);
for (String s: copy2) {
System.out.println(s);
}
}
}
/** 结果:
* alibaba
* bytedance
* pinduoduo
*/
复制代码
public class Test02 {
public static void main(String[] args) {
// 静态初始化要在声明后直接初始化。
Man m = new Man(20,"SuperKris");
// Man[] mans = new Man[6]; 这一行相当于没有用了
Man[] mans = new Man[]{
new Man(10, "Kris0"),
new Man(11, "Kris1"),
new Man(13, "Kris3"),
new Man(12, "Kris2"),
new Man(15, "Kris5"),
};
mans[4] = m;
for (int i=0; i<mans.length; i++) {
System.out.println(mans[i].getName());
}
// 增强 for 循环,把每一个元素取出来,放给这个变量。
for (Man man: mans) {
System.out.println(man);
}
}
}
class Man {
private int id;
private String name;
public Man() {
}
public Man(int id, String name) {
this.id = id;
this.name = name;
}
@Override
public String toString() {
return "id = " + id + ", name = " + name;
}
//省略了 JavaBean()
}
复制代码
public class Test03 {
public static void main(String[] args) {
int[] a = {100, 200, 300};
int[] b = {1,2,3,4234,22,45,765};
System.out.println(Arrays.toString(a));
Arrays.sort(b);
System.out.println(b.toString());
// 二分查找
System.out.println("b: " + Arrays.toString(b));
// 存在的话,就返回索引
System.out.println("该元素的索引是: " + Arrays.binarySearch(b, 22));
// 这个数不存在的话,返回负数
System.out.println("该元素的索引是: " + Arrays.binarySearch(b, 555));
// 把 b 从 fromIndex,到 toIndex-1 对应的位置,复制为最后一个参数 [) 区间一般都是左开右闭
Arrays.fill(b, 0,3,500);
System.out.println(Arrays.toString(b));
}
}
复制代码
运行结果如下图:
小技巧
源码(在 IDEA 里按住 Alt/command 键,然后鼠标悬在想看的地方就可以访问到)
扫描二维码关注公众号,回复: 13166104 查看本文章
有两个要注意的地方:
1. Array.toString()
和之前 String里,Object里的 toString 不一样。
这个是普通的 toString 方法:
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
复制代码
这个是 Array.toString()的源码,是有参数的,而且声明了 static
:
public static String toString(int[] a) {
if (a == null)
return "null";
int iMax = a.length - 1;
if (iMax == -1)
return "[]";
StringBuilder b = new StringBuilder();
b.append('[');
for (int i = 0; ; i++) {
b.append(a[i]);
if (i == iMax)
return b.append(']').toString();
b.append(", ");
}
}
复制代码
2. 为什么自带的二分法,如果一个数找不到,返回的索引是 -6
呢?
这个时候我们就可以去看一眼源码一窥真相。
二分查找的源码:
private static int binarySearch0(int[] a, int fromIndex, int toIndex,
int key) {
int low = fromIndex;
int high = toIndex - 1;
while (low <= high) {
int mid = (low + high) >>> 1;
int midVal = a[mid];
if (midVal < key)
low = mid + 1;
else if (midVal > key)
high = mid - 1;
else
return mid; // key found
}
return -(low + 1); // key not found.
}
复制代码
然后你就会发现在最后一行:没找到的话,默认取了左边最靠近的索引+1,再取负数。
而且还有一个地方非常的细节,二分法取中间的话,源码用了位移的操作,没有写公式,有效的防止了溢出。(关于二分法的更多内容,可以阅读这篇「如何优雅的实现二分查找」:juejin.cn/post/701598… )
我犯的非常简单的错误:
在类里包了其他类,导致类型报错;
没有 main 方法,就写 System.arraycopy,也报错了。