总的来说这篇文章比较简单。
数组到底和其他的容器有什么不同
1.数组是一个线性序列,这使得数组的访问非常的快速,当然数组的灵活性也比不上ArrayList但是实现ArrayList这样的弹性的开销非常的大,所以其速度远远比不上数组。
2.容器使用的泛型导致容器很多时候必须面临运行时检查,但是数组对于类型的检查却总是在编译期。
下面用一段代码来展示一下两者的区别与联系:
import java.util.*;
import static net.mindview.util.Print.*;
class BerylliumSphere
{
private static long counter;
private final long id = counter++;
public String toString(){
return "Sphere " + id;
}
}
public class ContainerComparison
{
public static void main(String[] args){
BerylliumSphere[] spheres = new BerylliumSphere[10];
for(int i=0; i<5; i++){
spheres[i] = new BerylliumSphere();
}
print(Arrays.toString(spheres));
//输出:[Sphere 5, Sphere 6, Sphere 7, Sphere 8, Sphere 9]
print(spheres[4]);
//输出:Sphere 9
List<BerylliumSphere> sphereList =
new ArrayList<BerylliumSphere>();
for(int i=0; i<5; i++){
sphereList.add(new BerylliumSphere());
}
print(sphereList);
//输出:[Sphere 2, Sphere 2, Sphere 2, Sphere 2, Sphere 2]
print(sphereList.get(4));
//输出:Sphere 2
int[] integers = {0,1,2,3,4,5};
print(Arrays.toString(integers));
//输出:[0, 1, 2, 3, 4, 5]
print(integers[4]);
//输出:4
List<Integer> intList = new ArrayList<Integer>(
Arrays.asList(0,1,2,3,4,5));
intList.add(97);
print(intList);
//输出:[0, 1, 2, 3, 4, 5, 97]
print(intList.get(4));
//输出:4
}
}
可以发现起码数组和ArrayList的区别并不大。
数组是个第一级对象
先上代码:
import java.util.*;
import static net.mindview.util.Print.*;
class BerylliumSphere
{
private static long counter;
private final long id = counter++;
public String toString(){
return "Sphere " + id;
}
}
public class ArrayOptions
{
public static void main(String[] args){
BerylliumSphere[] a;
BerylliumSphere[] b = new BerylliumSphere[5];
print("b: " + Arrays.toString(b));
//输出:b: [null, null, null, null, null]
BerylliumSphere[] c = new BerylliumSphere[4];
for(int i=0; i<c.length; i++){
if(c[i] == null) c[i] = new BerylliumSphere();
}
BerylliumSphere[] d = {new BerylliumSphere(),
new BerylliumSphere(), new BerylliumSphere()
};
a = new BerylliumSphere[]{
new BerylliumSphere(),new BerylliumSphere(),
};//请注意a最后还有一个小逗号
print("a.length = " + a.length);
//输出:a.length = 2,可见后面的小逗号并没有增加a数组的长度
print("b.length = " + b.length);
//输出:b.length = 5,空引用也算引用,如果想要打印出具体类的名称必须要在指定索引位置创建对象
print("c.length = " + c.length);
//输出:c.length = 4
print("d.length = " + d.length);
//输出:d.length = 3
a = d;
print("a.length = " + a.length);
int[] e;
int[] f = new int[5];
print("f:"+Arrays.toString(f));
//输出:f:[0, 0, 0, 0, 0],当没有明确数组中的元素时,默认为0
int[] g = new int[4];
for(int i=0; i<g.length; i++){
g[i] = i*i;
}
int[] h = { 11,47,93};//可以理解为直接引用一个现有的数组
//print("e.length = " + e.length);
//因为e现在是一个空引用,所以不能对其使用方法
print("f.length = " + f.length);
//输出:f.length = 5
print("g.length = " + g.length);
//输出:g.length = 4,同33行
print("h.length = " + h.length);
//输出:h.length = 3
e = h;
print("e.length = " + e.length);
//输出:e.length = 3
e = new int[]{1,2};//创建一个新的数组,可以看到此时不需要指明长度
print("e.length = " + e.length);
//输出:e.length = 2
}
}
对上面的代码有几个需要说明的地方:
第一个是数组大小的问题:
int[] i = new int[5];
print(i.length);//5
length只能代表数组能够容纳某个特定类型的容量,但并不知道到底有多少元素在数组中。
第二个是数组初始值的问题
int[] a = new int[2];
char[] b = new char[2];
boolean[] c = new boolean[2];
print(Arrays.toString(a));//[0, 0]
print(Arrays.toString(b));//[ , ]两个空格
print(Arrays.toString(c));//[false, false]
第三个是数组的创建
int[] a1 = new int[5];
Object[] a2 = new Object[5];
int[] b1 = {1};
int[] b2 = {1,};//特别需要注意这里b2的数组长度为1
Object[] b3 = {new Object()};
Object[] b4 = {1};//这里是由于自动装箱的原因,1转型为Integer然后又向上转型为Obejct
Object[] d;
d = new Object[]{new Object()};//这里可以和b数组的创建进行比较
当引用同一个数组时
int[] a = {1,2,3};
int[] b;
b = a;
b[1] = 5;
print(Arrays.toString(a));//[1, 5, 3]
print(Arrays.toString(b));//[1, 5, 3]
b=a就意味着b获得了a的引用,此时修改b也会修改a。
将数组返回
这个很简单,直接上代码
import java.util.*;
public class IceCream
{
private static Random rand = new Random(47);
static final String[] FLAVORS = {
"Chocolate", "Strawberry", "Vanilla Fudge Swirl",
"Mint Chip", "Mocha Almond Fudge", "Rum Raisin",
"Praline Cream", "Mud Pie"
};
public static String[] flavorSet(int n){
if(n > FLAVORS.length)
throw new IllegalArgumentException("Set too big");
String[] results = new String[n];
boolean[] picked = new boolean[FLAVORS.length];
for(int i=0; i<n; i++){
int t;
do{
t = rand.nextInt(FLAVORS.length);
}while(picked[t]);
results[i] = FLAVORS[t];
picked[t] = true;
}
return results;
}
public static void main(String[] args){
for(int i=0; i<7; i++){
System.out.println(Arrays.toString(flavorSet(3)));
}
}
}
/*输出:
[Rum Raisin, Mint Chip, Mocha Almond Fudge]
[Chocolate, Strawberry, Mocha Almond Fudge]
[Strawberry, Mint Chip, Mocha Almond Fudge]
[Rum Raisin, Vanilla Fudge Swirl, Mud Pie]
[Vanilla Fudge Swirl, Chocolate, Mocha Almond Fudge]
[Praline Cream, Strawberry, Mocha Almond Fudge]
[Mocha Almond Fudge, Strawberry, Mint Chip]
*/
多维数组
首先是如何创建一个多维数组:
import java.util.*;
public class MultidimenssionalPrimitiveArray
{
public static void main(String[] args){
int[][] a = {
{1,2,3,},
{4,5,6,}
};
//Array.deepToString()是JavaSE5的方法
System.out.println(Arrays.deepToString(a));
}
}
/*输出:
[[1, 2, 3], [4, 5, 6]]
*/
java多维数组的创建如上所示,也不是什么很麻烦的事情,我们也可以用new来创建数组:
import java.util.*;
public class ThreeDwithNew
{
public static void main(String[] args){
int[][][] a = new int[2][2][4];
System.out.println(Arrays.deepToString(a));
}
}
/*输出:
[[[0, 0, 0, 0], [0, 0, 0, 0]], [[0, 0, 0, 0], [0, 0, 0, 0]]]
基本类型的数组被自动初始化,对象数组初始化为null
*/
在文章开头的一部分我们就已经总结过数组初始化的三种方式,对一维数组可用的方法,同样对多维数组可用。下面介绍一下粗糙数组的概念:数组中构成矩阵的每个向量都具有任意的长度,下面用代码展示一下这个问题:
import java.util.*;
public class RaggedArray
{
public static void main(String[] args){
Random rand = new Random(47);
int[][][] a = new int[rand.nextInt(7)][][];
for(int i=0; i<a.length; i++){
a[i] = new int[rand.nextInt(5)][];
for(int j=0; j<a[i].length; j++){
a[i][j] = new int[rand.nextInt(5)];
}
}
System.out.println(Arrays.deepToString(a));
}
}
/*输出:
[[], [[0], [0], [0, 0, 0, 0]], [[], [0, 0], [0, 0]],
[[0, 0, 0], [0], [0, 0, 0, 0]],
[[0, 0, 0], [0, 0, 0], [0], []], [[0], [], [0]]]
*/
从上面的代码可以发现,在Java中创建一个多维数组可以是一个动态的过程,并不一定要在一开始使用时就固定好数组的长度,我们可以在后来使用的时候在动态的进行创建,当然不仅仅是基本类型数组可以通过这种方式创建,这种创建方式对于非基本类型的对象数组同样适用:
import java.util.*;
public class MultidimensionalObjectArrays {
public static void main(String[] args) {
BerylliumSphere[][] spheres = {
{ new BerylliumSphere(), new BerylliumSphere() },
{ new BerylliumSphere(), new BerylliumSphere(),
new BerylliumSphere(), new BerylliumSphere() },
{ new BerylliumSphere(), new BerylliumSphere(),
new BerylliumSphere(), new BerylliumSphere(),
new BerylliumSphere(), new BerylliumSphere(),
new BerylliumSphere(), new BerylliumSphere() },
};
System.out.println(Arrays.deepToString(spheres));
}
} /*输出:
[[Sphere 0, Sphere 1], [Sphere 2, Sphere 3, Sphere 4, Sphere 5],
[Sphere 6, Sphere 7, Sphere 8, Sphere 9, Sphere 10, Sphere 11, Sphere 12, Sphere 13]]
*/
上面的spheres也是粗糙数组。当然我们也可以逐步的构建一个非基本类型的数组:
import java.util.*;
public class RaggedArray
{
public static void main(String[] args){
Integer[][] a;
a = new Integer[3][];
for(int i=0; i<a.length; i++){
a[i] = new Integer[3];
for(int j=0; j<a[i].length; j++){
a[i][j] = i*j;
}
}
System.out.println(Arrays.deepToString(a));
}
}
/*输出:
[[0, 0, 0], [0, 1, 2], [0, 2, 4]]
*/
逐步的构建一个非基本类型的对象数组也是可行的。从上面的代码我们可以看出来,Arrays.deepToString()方法对于基本类型数组和对象数组都适用
自动包装机制用于数组
直接上实例
import java.util.*;
public class AutoboxingArrays {
public static void main(String[] args) {
Integer[][] a = { //自动包装
{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 },
{ 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 },
{ 51, 52, 53, 54, 55, 56, 57, 58, 59, 60 },
{ 71, 72, 73, 74, 75, 76, 77, 78, 79, 80 },
};
System.out.println(Arrays.deepToString(a));
}
} /*输出:
[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [21, 22, 23, 24, 25, 26, 27, 28, 29, 30],
[51, 52, 53, 54, 55, 56, 57, 58, 59, 60],
[71, 72, 73, 74, 75, 76, 77, 78, 79, 80]]
*/
非常简单的例子,不用多说,但是我们能不能将Integer自动装箱成int呢?
import java.util.*;
public class AutoBoxing {
public static void main(String[] args) {
int[] a = { //自动包装
new Integer(1),new Integer(2),
};
System.out.println(Arrays.toString(a));
}
} /*输出:
[1, 2]
*/
可以看到Integer也可以通过自动包装的机制变成int类型的数组。