引用类型——Java数组

数组:
一组相关数据的集合,实际上就是一连串的变量,可以分为:一维数组、二维数组、多维数组
默认值为null,暂时还没有任何指向的内存空间
Java中的数组必须先初始化,然后才可以使用。
所谓初始化,就是为数组的数组元素分配内存空间,并为每个数组元素赋初始值。
一、数组初始化
1,静态初始化
静态初始化:初始化时由程序员显式指定每个数组元素的初始值,由系统决定需要的数组长度。
静态初始化语法格式:
arrayName=new type[]{element1,element2,element3,element4...};
type:数组元素的数据类型,此处的type必须与定义数组变量时所使用的type相同,也可以是定义数组时所使用的type的子类;并使用花括号把所有的数组元素括起来,多个元素之间以逗号(,)隔开,定义初始化值的花括号紧跟[]之后。
代码示例:
//定义一个int数组类型的变量,变量名为intArr
int[] intArr;     //声明一维数组
//使用静态初始化,初始化数组时只指定数组元素的初始值,不指定数组长度。
intArr=new int[]{5,6,8,20};
//定义一个Object数组类型的变量,变量名为objArr
Object[] objArr;
//使用静态初始化,初始化数组时数组元素的类型是定义数组时数组元素类型的子类
objArr=new String[]{"Java","李钢"};
Object[] objArr2;
//使用静态初始化
objArr2=new Object[]{"java","鲤鱼"};
arrayName={element1,element2,element3,element4...}
代码示例:
int scorep[]={23,56,89,75,68};        //数组声明并附初值
2,动态初始化
动态初始化:初始化时程序员只指定数组长度,由系统为数组元素分配初始值
动态初始化语法格式:
arrayName=new type[length];    //分配内存给数组
length指定了数组的长度,也就是可以容纳数组元素的个数。
代码示例:
//数组的定义和初始化同时完成,使用动态初始化语法
int[] prices=new int[5];
//数组的定义和初始化同时完成,初始化数组时元素的类型是定义数组时元素类型的子类。
Object[] books=new String[4];
指定初始值时,系统按如下规则分配初始值:
(1)数组元素的类型是基本类型中的整数类型(byte、short、int和long),则数组元素的值是0.
(2)数组元素的类型是基本类型中的浮点类型(float、double),则数组元素的值是0.0.
(3)数组元素的类型是基本类型中的字符类型(char),则数组元素的值是'\u0000'.
(4)数组元素的类型是基本类型中的布尔类型(boolean),则数组元素的值是false.
(5)数组元素的类型是引用类型(类、接口和数组),则数组元素的值是null.
注意:
不要静态初始化和动态初始化同时使用。
数组初始化完成后就可以使用数组了。
二、使用数组
数组最常用的用法就是访问数组元素,包括对数组元素进行赋值和访问数组元素的值。
Java语言的数组索引是从0开始的,第一个数组元素的索引值为0,最后一个数组元素的索引为数组长度减1.
代码如下:
//输出objArr数组的第二个元素,将输出字符串“李钢”
System.out.println(objArr[1]);
//为objArr2的第一个数组元素赋值
objArr[0]="Spring";
如果访问数组元素时指定的索引小于0,或者大于等于数组的长度,编译程序不会出现任何错误,将运行时出现异常:java.lang.ArrayIndexOutOfBoundsException:2(数组索引越界异常),这个异常提示信息后的一个int整数,就是程序员视图访问的数组索引。
代码示例:
//访问数组元素指定的索引等于数组长度,所以下面代码将在运行时出现异常
System.out.println(objArr2[2]);
遍历数组:
//使用循环输出pricese数组的每个数组元素的值
for(int i=0;i<prices.length[i];i++)
{
    System.out.println(prices[i]);
}
三、foreach循环
从JDK1.5之后,Java提供了一种更简单的循环:foreach循环,这种循环遍历数组和集合更加简洁。
foreach循环的语法格式:
for(type variableName : array | collection)
{
    //variableName自动迭代访问每个元素...
}
type 数组元素或集合元素的类型
variableName 形参名,foreach循环将自动将数组元素、集合元素依次赋给该变量。
代码示例:
String[] books={"轻量级J2EE","权威指南","Ajax宝典"};
//使用foreach循环来遍历数组元素,其中book将会自动迭代每个数组元素
for(String book:books)
{
    //使用foreach循环来迭代输出数组元素或集合元素时,通常不要对循环变量进行赋值
    //book="Ruby On Rails敏捷开发最佳实践";    
    System.out.println(book);
}
注意:
使用foreach循环迭代数组元素时,并不能改变数组元素的值,因此不要对foreach的循环变量进行赋值。
四、数组在内存中的运行机制
1,数组的运行介质
数组是一种引用数据类型,数组饮用变量只是一个引用,数组元素和数组变量在内存里是分开的。
实际的数组元素被存储在堆(heap)内存中;数组引用变量是一个引用类型的变量,被存储在栈(stack)内存中。
为什么有栈内存和堆内存之分?
       当一个方法执行时,每个方法都会建立自己的内存栈,在这个方法内定义的变量将会逐个放入这块栈内存里,随着方法的执行结束,这个方法的内存栈随之销毁。因此,所有在方法中定义的变量都是放在栈内存中的;当我们在程序中创建一个对象时,这个对象将被保存在运行时数据区中,以便反复利用(因为对象的创建成本通常较大),这个运行时数据区就是堆内存。堆内存的独享不会随方法的结束而销毁,即使方法结束后,这个对象还可能被另一个引用变量引用,则这个对象依然不会被销毁。只有当一个对象没有任何引用变量引用它时,系统的垃圾回收机制才会在合适的时候回收它。
代码示例:
//定义并初始化数组,使用静态初始化
int[] a={5,7,20};
//定义并初始化数组,使用动态初始化
int[] b=new int[4];
//输出b数组的长度
System.out.println("b数组的长度为:"b.length);
//循环输出a数组的元素
for(int i=0;i<a.length;i++)
{
    System.out.println(a[i]);
}
//循环输出b数组的元素
for(int i=0;i<b.length;i++)
{
    System.out.println(b[i]);
}
//因为a是int[]类型,b是int[]类型,所以可以将a的值赋给b
//也就是让b引用指向a引用指向的数组
b=a;
//再次输出b数组的长度
System.out.println("b数组的长度为:"b.length);
运行结果:
b数组的长度为:4
5
7
20
0
0
0
0
b数组的长度为:3
       定义并初始化一个数组后,在内存里分配了两个空间,一个用于存放数组的引用变量,一个用于存放数组本身。
当程序定义并初始化了a、b两个数组时,系统内存中实际产生了4块内存区,其中栈内存中有两个引用变量:a和b;堆内存中也有两块内存区,分别用于存储a和b引用所指向的数组本身。
内存的存储示意图如下图所示:

当b=a代码时,系统将会把a的值赋给b,a和b都是引用类型变量,存储的是地址。因此把a的值赋给b后,就是让b指向a所指向的地址。此时计算机内存的存储示意图如下所示:
当执行了b=a之后,堆内存中第一个数组中具有了两个引用:a变量和b便来那个都指向了第一个数组。
此时第二个数组失去了作用,变成垃圾,只有等待垃圾回收来回收它——但它的长度依然不会改变,直到它彻底消失。

2,基本类型数组的初始化
对于基本类型数组而言,数组元素的值直接存储在对应的数组元素中,因此,初始化数组时,先为该数组分配内存控件,然后直接将数组元素的值存入对应数组元素中。
代码示例如下:
//定义一个int[]类型的数组常量
int[] iArr;  //仅定义一个数组变量此时内存示意图如下:

//动态初始化数组,数组长度为5
iArr=new int[5];  // 动态初始化后,系统将负责为该数组分配内存空间,并分配默认的初始值:所有数组元素都被赋为0,此时内存中的存储示意图为:

//采用循环方式为每个数组元素赋值
for(int i=0;i<iArr.length;i++) 
{
    iArr[i]=i+10;
}
// 当循环为该数组的每个数组元素依次赋值后,此时每个数组元素的值都变成程序制定的值。显式制定数组元素值后存储示意图如下所示:
从上图中可以看到基本类型数组的存储示意图,每个数组元素的值直接存储在对应的内存里。
操作基本数据类型数组的数组元素时,实际上就是操作基本类型的变量。
3,引用类型数组的初始化
引用类型数组的数组元素是引用:每个数组元素里存储还是引用,它指向另一块内存,这块内存里存储了有效数据。
class Person
{
    //年龄
    public int age;
    //身高
    public double height;
    //定义一个info方法
    public void info()
    {
        System.out.println("我的年龄是:"+age+" 我的身高是:"+height);
    }
}

//定义一个students数组变量,其类型是Person[]
Person[] students;   // 这行代码仅仅在栈内存中定义了一个引用变量,也就是一个指针,这个指针并未指向任何有效的内存区。此时内存中存储示意图如下所示:

//执行动态初始化
students =new Person[2]; //

//创建一个Person示例,并将这个Person示例赋给zhang变量
Person zhang=new Person();
//为zhang所引用的Person对象的属性赋值
zhang.age=15;
zhang.height=158;
//创建一个Person示例,并将这个Person实例赋值给lee变量
Perosn lee=new Person();
//为lee所引用的Person对象的属性赋值
lee.age=16;
lee.height=161;
//定义两个Person实例,定义这两个实例实际上分配了4块内存,在栈内存中存储了zhang和lee两个引用变量,还在堆内存中存储了两个Person实例。此时的内存存储示意图如下所示:

//将zhang变量的值赋给第一个数组元素
students[0]=zhang;
//将lee变量的值赋给第二个数组元素
students[1]=lee;
//当程序把张赋给students数组的第一个元素,把lee赋给students数组的第二个元素,students数组的两个数组元素将会指向有效的内存区。此时的内存存储示意图如下所示:
从上面图可以看出:此时zhang和students[0]指向同一个内存区,而且它们都是引用类型变量,因此通过zhang和student[0]来访问Person实例的属性和方法的效果完全一样,不论修改students[0]所指向的Person实例的属性,还是修改zhang变量所指向的Person实例的属性,所修改的其实是同一个内存区,所以必然互相影响。同理,lee和students[1]也有相同的效果。

//下面两行代码的结果完全一样,因为lee和students[1]指向的是同一个Person实例
lee.info();
students[1].info();
运行结果:
我的年龄是:16 我的身高是:161.0
我的年龄是:16 我的身高是:161.0
五、操作数组的工具类
java.util.Arrays
Java提供的Arrays类里包含了一些static修饰的方法可以直接操作数组,这个Arrays类里包含了如下几个static修饰的方法(static修饰的方法可以直接通过类名调用)。
binarySearch(type[] a,type key):
使用二分法查询key元素值在a数组中出现的索引;如果a数组不包含key元素值,则返回负数。
调用该方法时要求数组中元素已经按生序排列,这样才能得到正确结果。
binarySearch(type[] array, int fromIndex, int toIndex, type value):
与前面的方法类似,但它只搜索a数组中fromIndex到toIndex索引的元素。
调用该方法时要求数组中元素已经按生序排列,这样才能得到正确结果。
copyOf(type[] original, int newLength):
这个方法会把original数组复制成一个新数组,其中length是新数组的长度。
如果length小于original数组的长度,则新数组就是原数组的前面length个元素;如果length大于original数组的长度,
则新数组的前面元素就是原数组的所有元素,后面补充0(数值型)、false(布尔型)或者null(引用型)。
 copyOfRange(type[] original, int from, int to):
这个方法与前面方法类似,但这个方法只复制original数组的from索引到to索引的元素。
equals(type[] array1, type[] array2):
如果把array1数组和array2数组的长度相等,而array1数组和array2数组的数组元素一一相同,该方法返回true。
fill(type[] array, type value):
该方法将会把a数组所有元素值都赋值为value。
fill(type[] array, int fromIndex, int toIndex, type value):
这个方法与前面方法类似,区别是该方法仅仅对fromIndex到toIndex索引的数组元素赋值为value。
sort(type[] array):
该方法对数组array的数组元素进行排序。
sort(type[] array, int fromIndex, int toindex):
这个方法与前面方法类似,区别是该方法仅仅对fromIndex到toIndex索引的元素进行排序。
toString(type[] array):
该方法将一个数组转换成一个字符串。该方法按顺序把多个数组元素连缀在一起,
多个数组元素使用英文逗号(,)和空格隔开。
代码示例:
//定义一个a数组
int[] a=new int[]{3,4,5,6};
//定义一个a2数组
int[] a2=new int[]{3,4,5,6};
//a数组和a2数组的长度相等,每个元素依次相等,将输出true
System.out.println("a数组和a2数组是否相等:"+Arrays.equals(a,a2));
//通过赋值a数组,生成一个新的b数组
int[] b=Arrays.copyOf(a,6);
System.out.println("a数组和a2数组是否相等:"+Arrays.equals(a,b));
//输出b数组的元素,将输出{3,4,5,6,0,0}
System.out.println("b数组的元素为::"+Arrays.toString(b));
//将b数组的第3个元素(包括)到第五个元素(不包括)赋为1
Arrays.fill(b,2,4,1);
//输出b数组的元素,将输出{3,4,1,1,0,0}
System.out.println("b数组的元素为::"+Arrays.toString(b));
//对b数组进行排序
Arrays.sort(b);
//输出b数组的元素,将输出{0,0,1,1,3,4}
System.out.println("b数组的元素为::"+Arrays.toString(b));
运行结果:
a数组和a2数组是否相等:true
a数组和a2数组是否相等:false
b数组的元素为::[3, 4, 5, 6, 0, 0]
b数组的元素为::[3, 4, 1, 1, 0, 0]
b数组的元素为::[0, 0, 1, 1, 3, 4]
为了在程序中使用Arrays类,必须在程序中导入java.util.Arrays类。
System类的一个方法:
static void arraycopy(Object arc,int srcPos,Object dest,int destPos,int length):
该方法可以将src数组里的元素值赋给dest数组的元素,其中srcPos指定从src数组的第几个元素开始复制,
length参数指定将src数组的多少个元素赋给dest数组的元素。
六、其他
二维数组
    数据类型 数组名[]=null;        //声明一维数组
    数组名=new 数据类型[行的个数][列的个数];    //分配内存给数组
多维数组
    int a[][][][]=new int[][][][];

代码实例:
public class JavaArray {
    public static void main(String args[])
    {
        //一维数组
        int score[]={52,1,26,89,75,5,6,78,90,23};
        int max=0;
        int min=0;
        max=min=score[0];
        for (int i = 0; i < score.length; i++) {
            if(score[i]>max)
            {
                max=score[i];
            }
            if(score[i]<min)
            {
                min=score[i];
            }
        }
        System.out.println("最大数值:"+max);
        System.out.println("最小数值:"+min);

        //动态定义
        int a[]=new int[3];
        a[0]=3;
        a[1]=3;
        a[2]=3;
        for (int i = 0; i < a.length; i++) {
            System.out.print(score[i]+"\t");
        }

        System.out.println();

        //给数组进行排序
        for (int i = 1; i < score.length; i++) {
            for (int j = 0; j < score.length; j++) {
                if(score[i]<score[j])
                {
                    int temp=score[i];
                    score[i]=score[j];
                    score[j]=temp;
                }
            }
        }
        for (int i = 0; i < score.length; i++) {
            System.out.print(score[i]+"\t");
        }

        //二维数组
        int aEr[][]=new int[4][3]; 
        aEr[0][0]=30;
        aEr[1][1]=28;
        aEr[0][2]=45;
        aEr[2][0]=28;
        aEr[3][2]=8;
        for (int i = 0; i < aEr.length; i++) {
            for (int j = 0; j < aEr[i].length; j++) {
                System.out.print(aEr[i][j]+"\t");
            }
            System.out.println("");
        }
    }
}


©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页