[Java] 数组的备忘录
目标
由于对Java数组的处理方法分布在多个类中,因此需要整理一下。
这里不会对每个方法进行详细解释。
基本的事情 de
-
- 配列はオブジェクト
-
- 多次元配列は、配列の配列であらわす
-
- 配列は共変(covariant)
- Iterableではないけど、拡張forループに使用可能
数组的浅拷贝
将现有数组的整体或部分复制
java.lang.System类的arraycopy()方法
创建一个新的相同数组实例
数组对象的克隆操作
-
- キャスト不要
- CloneNotSupportedExceptionもキャッチ不要
private int[] values;
public void setValues(int[] values) {
// 防御的コピー
this.values = values.clone();
}
通过指定大小或生成新的子数组。
-
- java.util.Arrays#copyOf()
- java.util.Arrays#copyOfRange()
将数组列表化
java.util.Arrays#asList()的汉语本地化表达只有一个选项 : “java.util.Arrays#asList()”。
-
- リストのサイズが変わる操作は不可(add,remove,clearなど)
-
- 要素の値が変わる操作はOK。
-
- リストの要素を変えると、配列の要素も変わる
- 要素がプリミティブ型の場合には、可変引数で渡すことはできるけど、配列として渡すことはできないので注意。
对原始类型数组进行列表化(提案)
我可以为必要的原始类型数组准备以下的实用方法,但是每次都会进行自动装箱操作。
public static List<Integer> asList(final int[] array) {
return new AbstractList<Integer>() {
@Override
public Integer get(int index) {
return array[index];
}
@Override
public Integer set(int index, Integer element) {
int oldValue = array[index];
array[index] = element;
return oldValue;
}
@Override
public int size() {
return array.length;
}
};
}
或许应该实现java.util.RandomAccess。
将列表转换为数组
-
- java.util.List#toArray()
- java.util.List#toArray(T[])
请按照以下描述进行汉语的本土化改写,只需要一个选项:
例1:
List<String> list = getList();
// 引数無しは Object[] を返す
Object[] array = list.toArray();
例2:请帮我预定一张明天下午5点的火车票。
// 十分なサイズの配列を渡せば、その配列が返ってくる
String[] strings = list.toArray(new String[list.size()]);
请帮我把以下句子用中文进行本地化改写,只需要一个版本:
例3:
private static final String[] EMPTY_STRINGS = new String[0];
// ...
// サイズが足りない場合には、新しい配列を生成して返してくれる
String[] strings = list.toArray(EMPTY_STRINGS);
将数组和流进行相互转换。
-
- java.util.Arrays#stream() – 配列のストリーム化
- java.util.stream.Stream#toArray() – ストリームの配列化
还有针对原始类型的支持,例如IntStream#toArray()等。
反思
似乎不能通过Class#getDeclaredFields()或Class#getDeclaredMethods()等方法获取数组对象的length字段或clone()方法。
不过,为了处理数组反射,可以使用 java.lang.reflect.Array 类。
判断对象是否为数组。
java.lang.Class的isArray()
获取数组元素的类型
java.lang.Class类的getComponentType()方法
获取数组的长度
java.lang.reflect.Array#getLength() 的含义是获取数组的长度。
获取、设置数组的元素
-
- java.lang.reflect.Array#get()
- java.lang.reflect.Array#set()
使用get()和set()方法处理原始类型会自动进行装箱和拆箱。
还有一些用于处理原始类型的getInt()、getLong()、setInt()、setLong()等方法。
生成一个数组
创建一个新的数组实例。
将数组转化为字符串
如果想要显示数组的内容等情况,可以使用java.util.Arrays类的方法,其toString()方法与Object类的相同。
-
- 1次元配列
-
- java.util.Arrays#toString()
-
- 多次元配列
- java.util.Arrays#deepToString()
如果传递给 deepToString() 的数组对象是一个具有自我循环引用的数组,则可能会发生严重问题(如堆栈溢出、无限循环等)。
排序
在Java中,可以通过`java.util.Arrays`类的方法来进行排序。
-
- java.util.Arrays#sort()
- java.util.Arrays#parallelSort()
混合
使用java.util.Arrays#asList()和java.util.Colllections#shuffle()可以实现与排序类似的功能。
List<String> list = Arrays.asList(array);
Collections.shuffle(list);
如果是原始类型,可能只能自行努力了。
其他
其他实用方法基本上都在 java.util.Arrays 类中。
-
- fill : 値埋め
-
- equals : 一致チェック
-
- deepEquals : ネスト配列の一致チェック
-
- binarySearch : バイナリサーチ(ソート済みである必要あり)
-
- hashCode : ハッシュ値計算
- deepHashCode : ネスト配列のハッシュ値計算
如果需要的话,可以使用上述的Arrays#equals()或Arrays#hashCode()方法,因为配列对象的equals()和hashCode()与Object类的实现相同。
而对于 deep~() 系列方法来说,需要确保不传递自己循环引用的参数。
数组类的名称
尝试获取数组类的各种名称后,可以得到以下感觉:
Integer[][] array = new Integer[0][0];
Class<?> clazz = array.getClass();
System.out.println("Name : " + clazz.getName());
System.out.println("SimpleName : " + clazz.getSimpleName());
System.out.println("CanonicalName: " + clazz.getCanonicalName());
System.out.println("TypeName : " + clazz.getTypeName());
Name : [[Ljava.lang.Integer;
SimpleName : Integer[][]
CanonicalName: java.lang.Integer[][]
TypeName : java.lang.Integer[][]
一个长度为0的数组。
通常,数组是可修改的对象,即使将其声明为final也可以进行修正。
然而,由于没有可更改的部分,零个数组是一个不可变的对象。因此,可以将其视为常量,也可以在多线程中共享使用而没有问题。
private static final Object[] EMPTY_OBJS = new Object[0];
位或布尔值数组
应该说 java.util.BitSet 的内存效率更好。