java第五章学习笔记:数组---以不变应万变的哲学

【因为每一章都篇幅比较长(10多页,难免有的地方会写错字,如发现请指正,本人不胜感激)】

数组是一种数据结构,它的功能是存储同一类型的值,本章介绍数组的声明,创建,初始化以及其实现机制

5.1 数组的声明与创建

【数组本身是对象,这是java数组与其他语言最大的差别】
【访问数组对象必须通过数组对象,数组对象是真正存放元素的仓库,而数组对象引用是唯一访问仓库的方式】
数组中的基本元素可以是基本数据类型,也可以是引用类型。
5.1.1 声明数组引用
需提供数组将要保存元素的数据类型以及该数组的维度两方面信息,维数通过方括号对数来指出,方括号对可以位于数组的左边,也可以位于数组的右边 eg:

        int k[];//声明int类型数组
        String[] s;//声明string类型数组,最佳声明方式
        int[][][] b;//声明int型的三维数组引用b   b为数组引用

又得数组在声明的时候可以指定数组长度,eg:int[5] i;但是java中不可以在声明是指定数组长度
5.1.2 创建数组对象
最常用方式:使用new关键字,和创建类对象一样
基本语法:
new 元素类型[第一维数组][第二维数组]……
提示:创建数组时一定要给出第一位数组所需要的长度,否则系统无法为其分配内存空间,至于第二维长度可以给可以不给;eg:

        int[] k;//声明int型一维数组引用K
        k=new int[3];// object=new int[3];  将引用k指向长度为5的int型的一位数组对象
        String[][] s=new String[5][];
        int[] i=new int[]{1,2,3};

这样就可以通过数组引用对其指向的数组对象进行操作了,eg:访问元素,获取长度等,小心数组越界问题,eg:int[2]表示只能有两个元素,0和1;
这里写图片描述
与其他语言一样,java数组一旦创建,其大小容量不能更改,为了解决数组变长问题,在java中数组的引用的声明和数组对象的创建时分开的,eg:
这里写图片描述

5.2 java中数组的实现机制

【java中的数组本质是一个对象,他只能通过指向其的引用才能对其访问】
1、基本数据类型的数组实现情况:(数组中存放数组对象)
这里写图片描述
以上代码的实现机制如下:
这里写图片描述
1》、图中用椭圆表示数组对象,K则是指向数组对象的引用
2》、数组1,2,3,默认初始值为0
2、引用类型的数组——String是引用类型。
【数组中存放的并不是String对象,而是指向String对象的引用】eg:

        String[] s=new String[3];
        s[0]="C++";
        s[1]="python";
        s[2]="java";

实现机制:
这里写图片描述

多维数组的从逻辑上看可以看成数组的数组,而java中的多维数组与String一样都是对象,所以在java中n维数组实际上是一维的n-1维数组引用型数组,即:n维数组是由n层的一位数组搭建而成的;
java中实质只有一维数组,无论多少维都是由一维数组组成:

        int[][] k;
        k=new int[2][3];
        k[0][0]=3;//k[0][1],k[0][2]都是0
        k[1][2]=4;

这里写图片描述
从图中得到:
1)k这个二维数组引用并没有指向二维数组对象,而是指向一维数组对象;
2)K所指向的一维数组对象的元素又是一维数组,其元素是int型
3)二维数组只是数组中的数组,可看做是一堆的对象数组,但每一个元素保存不是其他引用,而是一维数组对象的引用
可以自定义

        double[][] d;
        d=new double[2][];
        d[0]=new double[3];
        d[1]=new double[4];
        System.out.println(d.length);//注意这里的长度不是7,而是一维数组的长度
        System.out.println(d[0].length);//3
        System.out.println(d[1].length);//4

5.3 数组的初始化

5.3.1 默认初始化
基本数据类型数组默认值
这里写图片描述
提示‘\u0000’是不可见字符
对于引用类型数组,无论其元素是何种类型,初值都是null eg:
这里写图片描述
5.3.2 利用循环初始化
eg:

        String[] s=new String[3];
        int[] a=new int[2];
        for(int i=0;i<s.length;i++)
        {
            s[i]=""+i;//没有“”会报错,或者是i+""都可以
            System.out.print("s["+i+"]="+s[i]+"  ");
        }
        System.out.println("----");//打印换行
        for(int i=0;i<a.length;i++)
        {
            a[i]=i*5;
            System.out.print("a["+i+"]="+a[i]+"  ");
        }

运行结果:
这里写图片描述
java SE5.0以后,java中增强了for循环对数组和集合的处理能力即 增强for循环
基本语法为:
for(定义暂存变量标识:需要循环的数组引用标识){语句系列}
eg:以上代码更新为:

        int[] b=new int[]{0,5,10};
        for(int i:b)
        {
            System.out.print("b["+i+"]="+i+"  ");
        }

运行结果:
这里写图片描述
1、增强for循环可以用来依次处理数组中的每一个元素,而不必为下标分心
2、不希望遍历整个数组,或在循环体中需要操作下标值等,还是得需要传统for循环
java中的增强for类似于C#中的foreach,只是将in变为了: eg:

foreach (KeyValuePair<string, string> kv in ascdic)
{
   Console.WriteLine("方法一升序以后的key列表为:" + kv.Key + ", value为:" + kv.Value);
}

5.3.3 枚举初始化
使用场景:
1、初始值与默认值不同;//否则用5.3.1方法
2、没有明显规律;//否则用5.3.2方法
3、数量不多
两种语法:
基本语法
省略语法
1、基本语法
创建数组对象的时候逐一列举除所有元素的初始值
基本语法:数组类型[ ] 数组引用标识符=new 数组类型[ ]{第一个元素值,第二个元素值…..}
提示:在采用普通数组创建对象的时候需要制定数组长度,但这种不可以给出数组长度,其长度是由列出来的数组个数决定的。
2、省略语法因(只有枚举有)
基本语法中的“new 数组类型[ ]”没有什么用,还显得累赘,所以java还提供了省略语法
数组类型[ ] 数组引用标识付={第一个元素,第二个元素。。。。。。}eg:

        int[] b=new int[]{0,5,10};//未省略
        int[] c={2,4,7,8};//省略语法
        String[] skyColor={"blue","34","green","beautiful"};
        int[][] d={{2,5,7},{3,4},{1,7,9},{0,6,7}}; //多维数组枚举

5.4 数组的相互赋值

实际上是数组引用间的相互赋值,数组是对象,对象时“看不见”的,只有对象引用可以拿在“手中”
5.4.1 基本类型数组赋值规则
数组的位数要相等。
数组元素的类型要完全相同。eg
这里写图片描述
5.4.2 引用型数组赋值规则:
数组维数要相等;
数组元素类型要兼容;eg:

        String[][][][] s4=new String[2][][][];
        String[][][] s3=new String[3][][];
        String[][] s2=new String[4][];
        Object[] o=new Object[3];
        s3=s4[0];
        s2=s3[3];
        o=s[2];//错误,不兼容的类型

5.5 数组的常用操作

5.5.1 数组复制
java中将一个数组引用赋给另一个数组引用后,这两个数组引用指向的是同一个数组对象 如下图:
这里写图片描述
这样必然会导致对任何一个引用对数组对象进行操作,都会导致其他指向此数组对象的引用感觉到变化,因为其引用的是同一个对象;这与基本数据类型的变量赋值不同,基本百年来那个赋值不会相互影响。eg:
这里写图片描述
由于存在上述问题,在实际开发中需要经常拷贝数组对象,然后在拷贝上操作,才能不影响原数组,所以java中提供了数组拷贝的工具方法,如下表所列:

public static void arrayCopy(Object src,int srcPos,Object dest,int destPos,int length)
    {
        //src:源数组引用
        //srcPos:拷贝的起始下标
        //dest:与src的同类型引用,指向目标数组
        //destPos:目标数组放置元素的起始下标
        //length:拷贝元素个数【小于等于源数组长度】
        //数组越界时会抛出:IndexOutOfBoundsException
    }
    public static String[] copyOf(xxx[] original,int newLength)
    {
        //XXX[],表示任意类型
        //original:源数组引用,即指向原数组
        //newLength:拷贝数组的长度,若拷贝长度大于源数组长度会用0或null填充,反之,截取源数组一部分拷贝到新数组中,返回值为指向数组的引用
    }
    public static int[] copyOfRange(xxx[] original,int from,int to)
    {
        //同上xxx[],表示任意类型
        //original:源数组引用,即指向原数组
        //from:开始位置
        //to:结束位置
        //返回值为指向新数组的引用
    }

这里写图片描述
使用方法:

//类前面加上:import java.util.Arrays;

        //创建数组
        int[] a={0,1,2,3,4,5,6,7,8};
        int[] dest1=new int[9];
        //arraycopy()方法拷贝数组
        System.arraycopy(a, 0, dest1, 0, 9);//直接调用此方法,不用写b=,因为返回void,所以不能赋值
        dest1[2]=66;

        //copyOf()方法拷贝数组
        int[] dest2=Arrays.copyOf(a, 7);
        dest2[3]=99;

        //copyOfRange方法拷贝数组
        int[] dest3=Arrays.copyOfRange(a,3,11);
        dest3[5]=88;
        for(int i:a)
        {
            System.out.print("源数组:"+i+"  ");
        }
        System.out.println("----换行-----");
        for(int i:dest1)
        {
            System.out.print("1的新数组:"+i+" ");//修改a[1]的值
        }
        System.out.println("----换行-----");
        for(int i:dest2)
        {
            System.out.print("2的新数组:"+i+" ");//修改a[4]的值,并去掉了最后两个数
        }
        System.out.println("----换行-----");
        for(int i:dest3)
        {
            System.out.print("3的新数组:"+i+" ");//修改了a[6]的值,并去掉前四个数,增加了两个数
        }

运行结果:
这里写图片描述
只有copyOf和copyOfRange方法的目标数组可以根据拷贝方法参数设定,arraycopy()方法中的参数length要小于等于源数组长度,不然抛异常 eg:
这里写图片描述
5.5.2 数组排序
排序方法介绍:
这里写图片描述

这两个方法也可以对引用型数组进行排序,但要求所在类的对象必须有特定的自然顺序,也就是说引用所在类必须实现了Comparable接口

public static void sort(xxx[] a)
    {
        //此处的xxx[]为,任意类型
        //对指定数组排序,排完结果仍然放在 原来的数组中
    }
    public static void sort(xxx[] a,int fromIndex,int toIndex)
    {
        //此处的xxx[]即,任意类型
        //对指定区间进行排序
        //排完结果仍然放在 原来的数组中
    }

使用:

        //创建数组
        int[] a={3,5,6,9,0,2};
        int[] b=Arrays.copyOf(a, 7);//复制数组
        for(int i:b)        
        {
            System.out.print("排序前:"+i+" ");
        }
        System.out.println();
        System.out.println("开始排序-----------");

        Arrays.sort(b);
        int[] c=Arrays.copyOf(a, 5);
        Arrays.sort(c,1,5);
        for(int i:b)
        {
            System.out.print("全部排序后:"+i+" ");
        }
        System.out.println();
        System.out.println("-----指定区间排序排序-----------");
        for(int i:c)
        {
            System.out.print("除去第一个数排序结果:"+i+" ");//第一个数3没有参与排序,然后将五个数遍历出来
        }

运行结果:
这里写图片描述
提示:对对象引用型数组进行排序还有一种特定方法,其方法签名位:

public static void sort(Object[] a,Comparator c)
    {
        //a为要排序数组对象的引用
        //c为指定的比较器,Comparator这么写会报错
    }

5.5.3 搜索指定元素
常用的搜索方法:
这里写图片描述

public static int binarySearch(xxx[] a,xxx key)
    {
        //xxx表示,任意类型
        //从数组中搜索第一个指定值的位置,key是要找的元素
        //a指被搜索的数组
        //返回值为搜索到位置的索引,没有找到则返回负数
    }
    public static int binarySearch(xxx[] a,int fromIndex,int toIndex,xxx key)
    {
        //xxx表示,任意类型
        //fromIndex、toIndex为搜索区间
        //返回值为搜索到位置的索引,没有找到则返回负数
    }

这两个方法都是基于二元搜索算法的,要求被搜索的数组是已经排好序,可以在搜索前用sort系列方法排序
使用方法:

        int[] a={1,3,4,5,6,8,9,12,14,15};
        int indexall=Arrays.binarySearch(a, 6);//4
        int indexpart=Arrays.binarySearch(a, 8, 9, 8);//2
        System.out.println("整个数组中6的位置为:"+indexall);
        System.out.println("截取的数组中8的位置为:"+indexpart);

运行结果:
这里写图片描述
提示:对于对象引用数组的元素搜索还有特定方法,方法签名为:

public static int binarySearch(Object[] a,Object key,Comparator c)
    {
        //a为要搜索对象数组的引用
        //key为要搜索的键
        //c为知道那个的比较器
        //注意,数组比较的时候使用的哪个比较器,搜索的时候还是使用同样的比较器,否则可能会产生错误结果
    }

5.5.4 比较数组中的元素
实际开发中会需要比较两个数组中的元素值是否相等,只需要调用Arrays类中的equals方法即可。eg:

        int[] a={1,3,4,5,6,8,9,12,14,15};
        int[] b={1,2,4,5,6,8,9,12,14,15};
        //比较两个数组元素
        boolean flag=Arrays.equals(a, b);
        System.out.println("数组a与数组b的元素比较结果为:"+((flag)?"两个数组相等":"两个数组不相等"));

运行结果为:
这里写图片描述
说明:equals方法的参数有两个,分别是参加比较的数组的引用,返回值是boolean型的,true表示相同,false表示不同

5.6 关于args[ ]

其实Main是一个特定方法,是java执行的入口点,是加载java程序后由java的运行时系统自动调用的。
提示:main方法是系统自动调用的,写错就会变成普通的方法,执行时会报错。
而“String[] args”表示main方法的入口参数,是一个字符串数组,此字符串数组中的元素就是在执行程序时输入的命令行参数,有几个参数数组的长度就是几。输入命令行参数的格式如下:
java 类名 参数1 参数2 参数3
说明:参数间用空格作分隔符 eg:

        public static void main(String[] args)
        {
            if(args.Length<2)
            {
                System.out.println("命令格式不对,在执行时请输入两个参数!");
            }
            else
            {
                System.out.println("接收的参数为:");//打印所有的参数内容
                for(String s:args)
                {
                    System.out.println(s + "");
                }

            }
        }

提示:如果在应用程序中要使用命令行参数,在使用前一定要加上类似if判断那样的
容错判断代码,防止用户在使用程序时没有输入足够的参数,导致程序出错。
运行结果:
这里写图片描述
在没有输入参数的情况下,入口参数args的值为null,null表示没有数组,但其实是用户就算没有输入任何命令行参数,系统一样也会自动创建一个String数组对象,将此对象的引用传给args,只不过这个数组对象很特殊,其长度为0。eg:

        public static void mian(String[] args)
        {
            System.out.println("args:" + args);
            System.out.println("args数组的长度为:" + args.Length);
        }

运行结果:
这里写图片描述
从图中可以看出,args的值并不是null,说明其指向了一个数组对象,但是特殊的是,数组对象的长度为0;
提示:允许长度为0的数组存在,是java的一个特色,许多其他语言没有。
第五章完!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值