Java 数组

数组。

1.数组是一种引用类型,不是基本的数据类型。

2.数组是一种简单的数据结构,线性的结构。

3.数组是一个容器,可以用来存储其他元素。

数组是可以存储任意数据类型的元素。

4.数组分为:一维数组,二维数组,三维数组,多维数组... 

5.数组中存储的元素类型统一。

6.数组长度不可以改变,数组一旦创建,元素不可改变,是固定的。结合以下例子来看,

public class ArrayTest01{
 public static void main(String[] args){
 int[] a={100,200,150,300};  // 这种方式称为“静态初始化一维数组”
   boolean[] b={true,false,true,true};
   String[] strs={"ABC","CS","DAD"};
   byte[] t={1,2,3};
 char[] c={'q','a','c'};
 //Object类型数组
 Object o1=new Object();
 Object o2=new Object();
 Object o3=new Object();
 //数组存的是每个对象在堆里的内存地址,不是对象。
 Object[] objs={o1,o2,o3};
 }
}

上面的代码声明了不同类型的数组,并且对数组进行了初始化。我们可以结合下面这张图来理解。

从上面的图可以看出,数组拿首元素的内存地址作为数组对象的内存地址,并且里面存的是每一个对象在堆中的内存地址。 此外,数组中每一个元素都是有索引的,从0开始,任何一个数组都有一个length属性来获取数组中元素的个数,数组最后一个元素的下标是数组的长度减1。那么我们就知道了取得数组的第一个元素即a[0],最后一个元素即a[a.length-1]。

 

使用数组的优点是什么呢?数组中存储元素的类型是统一的,每一个元素在内存中所占的空间大小是相同的,知道数组的首元素的内存地址,要查找的元素只要知道下标就可以快速地计算出偏移量,通过首元素内存地址加上偏移量快速计算出要查找元素的内存地址,通过内存地址快速定位该元素,所以数组查找元素的效率较高。

 

当然了,它的缺点就是增删元素的效率很低。随意地对数组进行增删元素,当增加元素的时候,为了保证数组数组中元素在空间存储上是有序的,所以被添加元素位置后面的所有元素都要向后移动,删除元素也是,后面所有的元素都要向前移动,因此数组的增删元素的效率很低。

 

接下来看初始化一维数组的方式,有两种,静态初始化和动态初试化,静态初始化很简单,上面的代码中已经解释说明了,那么如何进行动态初试化一维数组呢?看下面例子,

public class ArrayTest03{
 public static void main(String[] args){
   //动态声明一个int类型的数组,最多可以存储4个元素
   int[] a1=new int[4];
   //遍历
   for(int i=0;i<a1.length;i++){
     System.out.println(a1[i]);
   }
   //赋值
   a1[0]=1;
   a1[1]=2;
   a1[2]=3;
   a1[3]=4;
   //赋值之后遍历
   for(int i=0;i<a1.length;i++){
     System.out.println(a1[i]);
   }
 }
}

编译运行后输出:

0
0
0
0
1
2
3
4

从上面的代码可以看出,未给数组赋值之前动态初试化数组后遍历输出为0,这是因为,动态初始化一维数组会在堆内存中分配这个数组,并且数组中每一个元素都采用默认值,而int类型的默认值为0.给数组赋值之后,遍历输出数组值才改变。

 

知道了静态初始化和动态初试化,那么如何进行初始化方式的选择?

1.无论是动态初始化还是静态初始化,最终的内存分布都是一样的;

2.如果在创建数组的时候,知道数组中应该存储什么数据,这个时候采用静态初始化方式;

如果在创建数组的时候,无法预测到数组中存储什么数据,只是先开辟空间,则使用动态初始化方式。

深入了解一维数组。

public class ArrayTest05{
 public static void main(String[] args){
   Animal[] as=new Animal[4];  
   Cat c1=new Cat();
   Cat c2=new Cat();
   Dog d1=new Dog();
   Dog d2=new Dog();
   as[0]=c1;
   as[1]=c2;
   as[2]=d1;
   as[3]=d2;
   //遍历数组,取出每个对象,如果是Cat类,执行move()方法,如果是Dog()类,执行eat()方法。
   for(int i=0;i<as.length;i++){
     Animal a=as[i];
     //强制类型转换,向下转型,用instanceof判断a所属的类型
     if (a instanceof Cat){
       Cat c=(Cat)a;
       c.move();
     }else if(a instanceof Dog){
       Dog d=(Dog)a;
       d.eat();
     }
   }
 }
}
class Animal{}
class Cat extends Animal{
 public void move(){
   System.out.println("Cat move");
 }
}
class Dog extends Animal{
 public void eat(){
   System.out.println("Dog eat");
 }
}

 

编译运行后输出:

 

Cat move
Cat move
Dog eat
Dog eat

 

在上述代码中,我们首先动态声明一个Animal类型的数组,并且最多可以存储4个元素,之后new出两个Cat类型的对象c1,c2,两个Dog类型的对象d1,d2,并将它们赋值给Animal类型的数组as,接着使用一个for循环遍历数组,遍历数组,取出每个对象,如果是Cat类,执行move()方法,如果是Dog()类,执行eat()方法。其中用到了向下转型中的instanceof判断父类对象是否属于某一个子类。上述代码是一个比较综合的小程序,可以顺便回忆一下之前讲过的内容。

 

接下来我们看看在方法调用中如何传递数组,看以下程序:

 

/*在方法调用中传递数组*/
public class ArrayTest06{
 public static void main(String[] args){
   int[] a={1,2,12,3,3};
   m1(a);
   System.out.println("---------------");
   m1(new int[]{3,42,4,5535});
 }
 public static void m1(int[] a){
   for (int i=0;i<a.length;i++){
     System.out.println(a[i]);
   }
 }
}

 

编译运行后输出:

 

1
2
12
3
3
---------------
3
42
4
5535

 

从以上代码中可以看出,在方法调用中传递数组可以用两种方式,一种是先定义一个数组int[] a={1,2,12,3,3};然后将a作为参数在m1()方法中调用,另一种是直接在参数的位置new一个数组,也就是m1(new int[]{3,42,4,5535});的形式。

 

最后来看看数组的拷贝,即数组的扩容方式。其实数组的拷贝,在JDK中已经提供了写好的方法,直接调用即可,看以下代码:

 

public class ArrayTest08{
 public static void main(String[] args){
   //System.arraycopy(Object src,int srcPos,int destPos,int length);
   //System.out.println(源数组,原数组的开始下标,目标数组,目标数组的开始下标,拷贝的长度);
  int[] src={2,3,4,5,6,7,8};
 int[] dest={10,11,12,13,14,15,16};
 //把src中的4,5,6拷贝到dest数组从13开始
 System.arraycopy(src,2,dest,3,3);
 //遍历
 for(int i=0;i<dest.length;i++){
   System.out.println(dest[i]);
 }
 }
}

 

编译运行后输出:

 

10
11
12
4
5
6
16

二维数组是一个特殊的一维数组,特殊在这个一维数组中每一个元素都是“一维数组”。结合以下代码了解一下二维数组的静态初始化方法。

 

public class ArrayTest09{
 public static void main(String[] args){
   //静态初始化二维数组
   int[][] a={
            {1,2,3},
            {45,34},
          {0},
          {10,23,85,99}
   };
       //以上这个数组有多少个一维数组
       System.out.println(a.length+"个一维数组");
       //获取第一个一维数组
       int[] a0=a[0];
       int a00=a0[0];
       System.out.println(a00);
   //获取第一个一维数组的第一个元素
       System.out.println(a[0][0]);  
       //获取最后一个一维数组中的最后一个元素
       System.out.println(a[3][3]);
       System.out.println(a[a.length-1][a[a.length-1].length-1]);  
     //遍历
   //纵向循环在外
   for(int i=0;i<a.length;i++){
     for(int j=0;j<a[i].length;j++){
       System.out.print(a[i][j]+" ");
     }
       System.out.println();
   }
   }
}

 

编译运行后输出:

 

4个一维数组
1
1
99
99
1 2 3
45 34
0
10 23 85 99

 

上述代码中实现了二维数组的静态初试化以及二维数组的遍历方法,原理跟之前讲的一维数组的一样,只要把二维数组当作特殊的一维数组就可以了。每一句代码前面都跟着注释,理解了之前的一位数组,二维数组的相关方法也是很容易理解的。

 

接下来看看二维数组的动态初始化,结合以下代码来看。

 

/*
关于二维数组的动态初始化
*/
public class ArrayTest10{
 public static void main(String[] args){
   //3个一维数组,每个一维数组中有4个元素
   int[][] a=new int[3][4];
   //遍历
   for(int i=0;i<a.length;i++){
     for(int j=0;j<a[i].length;j++){
       System.out.print(a[i][j]+" ");
     }
     System.out.println();
   }
               System.out.println("----------");
   //赋值
   a[1][2]=10;
   //遍历
   for(int i=0;i<a.length;i++){
     for(int j=0;j<a[i].length;j++){
       System.out.print(a[i][j]+" ");
     }
     System.out.println();
   }
 }
}

 

编译运行后输出:

 

0 0 0 0 
0 0 0 0 
0 0 0 0 
----------
0 0 0 0 
0 0 10 0 
0 0 0 0

 

从以上代码看出,数组初始化未赋值之前每个元素的默认值为0。二维数组进行遍历的时候依靠两个for循环来实现,并且纵向循环在外,也就是写for循环的时候外层循环指的是二维数组中有几个一维数组,之后在内层循环中实现一维数组的元素的读取。上面的代码对二维数组进行遍历之后,对数组中的第一行第二列的元素重新赋值,之后重新遍历输出数组中的每一个元素值。

 

最后看看在方法调用中传递二维数组的方式。

 

public class ArrayTest11{
 public static void main(String[] args){
   //在方法调用中传递数组
   m1(new int[][]{{1,2,2},{23,232,24},{343,45}});
 }
 public static void m1(int[][] a){
   for(int i=0;i<a.length;i++){
     for(int j=0;j<a[i].length;j++){
       System.out.print(a[i][j]+" ");
     }
   System.out.println();
   }
 }
}

 

跟一维数组的实现方式一样,只不过要注意二维数组的写法。

搜索微信公众号“程序员考拉”,欢迎关注!

转载于:https://www.cnblogs.com/naihuangbao/p/9444547.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值