java-数组

一.数组基本用法

1.何为数组?

      所谓数组,就是相同类型元素的集合。数组的本质无疑就是让我们能 "批量" 创建和操作相同类型的变量。

      例如:

            如果需要表示两个数据, 那么直接创建两个变量即可 int a; int b

            如果需要表示五个数据, 那么可以创建五个变量 int a1; int a2; int a3; int a4; int a5;

            但是如果需要表示一万个数据, 那么就不能创建一万个变量了. 这时候就需要使用数组, 帮我们批量创建。

注意事项: 在 Java 中, 数组中包含的变量必须是 相同类型

  2.创建数组

           基本语法:

                        1>动态初始化:数据类型[] 数组名称 = new 数据类型 [ ] { 初始化数据 };

int[] arr1 = new int[]{1, 2, 3};
int[] arr2 = new int[4];

【注意】

  • 数组名字,即上面的arr1、arr2都是一个引用,用来存放对象的地址;这里的对象就是new产生的。

  •     定义数组时,带初始化一定不能制定数组长度。例如arr1数组后面初始化了三个元素,长度默认是3,不需要指定。

  •     定义数组时,没有初始化的数组一定要指定长度。例如arr2数组后面没有初始化,此时就必须指定数组长度,否则在开辟空间时,并不知道数组的大小,会报如下错误:

Error:(16, 29) java: 缺少数组维
  • arr2数组初始化只能通过for循环来初始化

  • 数组定义后没有初始化默认值是0,如果数组里的元素是引用类型则默认值是null。

                 2>静态初始化:数据类型[ ] 数组名称 = { 初始化数据 };

int[] arr = {1, 2, 3};

      3.数组的长度

               1>数组的长度一般通过两种方式来指定:

              2>在定义时一旦指定了长度,后面是不能修改的

int[] arr4={};
arr4[0]={4};//错误,企图将arr4的长度改为1

             3>访问数组的长度:

                            使用length属性来访问,即 数组名.length;

int[] arr5={1,2,3};
//通过arr5.length访问数组长度
System.out.print(arr5.length);//3

【注意】

  • 区分字符串中的length和数组中的length,数组中的length是一个属性,而字符串中的length是一个方法,使用时用一定的区别。
//数组长度(属性):arr5.length
int[] arr5={1,2,3};
System.out.print(arr5.length);

//字符串长度(方法):str.length()
String str="qwer";
System.out.print(str.length());
  • ·在初始化数组或者字符串为NULL时,会报空指针异常的错误 

代码

int[] arr6=null;
System.out.print(arr6.length);
String str=null;
System.out.print(str.length());

错误

Exception in thread "main" java.lang.NullPointerException

所以在初始化数组和字符串的时候一定要注意正确赋值及定义长度!!

 4、访问数组元素

                1>使用 [ ] 按下标取数组元素. 需要注意, 下标从 0 开始计数,[ ] 操作既能读取数据, 也能修改数据

int[] arr = {1, 2, 3};

// 访问数组中的元素
System.out.println(arr[0]);         // 执行结果: 1 
System.out.println(arr[1]);         // 执行结果: 2

//修改最后一个元素的数据
arr[2] = 100; 
System.out.println(arr[2]);         // 执行结果: 100

          2>下标访问操作不能超出有效范围 [0, length - 1] , 如果超出有效范围, 会出现下标越界异常

int[] arr = {1, 2, 3}; 
System.out.println(arr[100]);

// 执行结果 
Exception in thread"main"java.lang.ArrayIndexOutOfBoundsException: 100  at Test.main(Test.java:4)

抛出了 java.lang.ArrayIndexOutOfBoundsException 异常. 使用数组一定要下标谨防越界.

  3> 遍历数组

                所谓 "遍历" 是指将数组中的所有元素都访问一遍, 不重不漏. 通常需要搭配循环语句.

for循环遍历临时数组:

int[] arr = {1, 2, 3}; 
for (int i = 0; i < arr.length; i++) {  
  System.out.println(arr[i]);
 }
// 执行结果
 1
 2 
 3

for-each 遍历数组

int[] arr = {1, 2, 3}; 
for (int x : arr) {  
  System.out.println(x);
 }
// 执行结果 
1 
2 
3
  •  x变量的类型时数组的类型,代表数组中的每一个元素,冒号后面是数组名
  •  for-each 是 for 循环的另外一种使用方式. 能够更方便的完成对数组的遍历. 可以避免循环条件和更新语句写错.
  •   for-each 和 for的区别:for循环时通过下标来访问数组,而 for-each只能通过默认的方式从左往右依次遍历,不能够通过下标任意访问某个元素。

 

toString()方法遍历打印数组

int[] arr = {1, 2, 3}; 
//调用方法打印数组
System.out.print(Arrays.toString(arr5));
//执行结果
[1, 2, 3]

在使用此方法时需要导入import java.util.Arrays包,在idea软件中,如果没有导入包,可以将鼠标放在Arrays上点击ALt并回车即可引入工具包。

二,数组作为参数使用

  基本用法:打印数组内容

public static void main(String[] args) {
    int[] arr = {1, 2, 3};
    printArray(arr);
 }
public static void printArray(int[] a) {
     for (int x : a) { 
     System.out.println(x); 
   } 
}
// 执行结果 
 1
 2
 3
  •  int[] a 是函数的形参, int[] arr 是函数实参. 
  • 如果需要获取到数组长度, 同样可以使用 a.length

 

三、数组作为方法的返回值

 代码示例: 写一个方法, 将数组中的每个元素都 *2

       第一种:直接修改原数组

class Test {
     public static void main(String[] args) { 
        int[] arr = {1, 2, 3};
         transform(arr);
         printArray(arr);
     }
//打印数组的元素
    public static void printArray(int[] arr) {
         for (int i = 0; i < arr.length; i++) {
             System.out.println(arr[i]);
         }
     }
// 直接修改原数组的方法
    public static void transform(int[] arr) {
         for (int i = 0; i < arr.length; i++) { 
            arr[i] = arr[i] * 2;         
          }    
     } 
}

//执行结果
2
4
6

     这个代码固然可行,直接将原始数组地址传过来,对原始数组进行修改。 

     但是破坏了原有数组. 有时候我们不希望破坏原数组, 就需要在方法内部创建一个新的数组, 并由方法返回出来。

 第二种:直接修改原数组

 class Test {
     public static void main(String[] args) {
         int[] arr = {1, 2, 3};
         int[] output = transform(arr);
         printArray(output);
     }
    public static void printArray(int[] arr) {
         for (int i = 0; i < arr.length; i++) {
             System.out.println(arr[i]);
         }
     }
// 返回一个新的数组
    public static int[] transform(int[] arr) {
         int[] ret = new int[arr.length];
         for (int i = 0; i < arr.length; i++) {
             ret[i] = arr[i] * 2;
         }
         return ret;
     }
 }

     在函数内部新定义了一个数组,并且将他的值初始化为原始数组的2倍。相当于是新开辟了一段空间,两个数组各自有各自的空间,这样的话就不会破坏原有数组了. 

    另外由于数组是引用类型, 返回的时候只是将这个数组的首地址返回给函数调用者, 没有拷贝数组内容, 从而比较高效.

四、数组的拷贝

  数组拷贝有四种方式:

            1.System.arraycopy(原始数组,从哪拷,目的数组,拷向哪,拷贝的长度);

int[] arr5 = {1, 2, 3};
System.out.println(Arrays.toString(arr5));
int[] arr6=new int[3];
//调用拷贝函数
System.arraycopy(arr5,0,arr6,0,arr5.length);

System.out.print(Arrays.toString(arr6));
//执行结果
[1, 2, 3]
[1, 2, 3]

上面代码是将数组arr5 的数据拷贝到数组  arr6中,并且拷贝arr5的长度。

               2.Arrays.copyOf(原始数组,原始数组长度);

int[] arr5 = {1, 2, 3};
System.out.println(Arrays.toString(arr5));
//创建并以拷贝的方式初始化数组
int[] arr6=Arrays.copyOf(arr5,arr5.length);
System.out.print(Arrays.toString(arr6));
//执行结果
[1, 2, 3]
[1, 2, 3]

              3. clone()方法;

int[] arr5 = {1, 2, 3};
System.out.println(Arrays.toString(arr5));

//创建并以拷贝的方式初始化数组
int[] arr6=arr5.clone();
System.out.print(Arrays.toString(arr6));


//执行结果
[1, 2, 3]
[1, 2, 3]

           4. for循环遍历拷贝;

int[] arr5 = {1, 2, 3};
System.out.println(Arrays.toString(arr5));
int[] arr6=new int[arr5.length];

//通过for循环遍历拷贝
for(int k=0;k<arr5.length;k++)
{
     arr6[k]=arr5[k];
}

System.out.print(Arrays.toString(arr6));

//执行结果
[1, 2, 3]
[1, 2, 3]

【注意】

  深拷贝当数组当中为简单类型的时候,上述前三种拷贝方法都为深拷贝,拷贝完修改值不会影响数组当中的值。

  浅拷贝当数组中的元素为引用类型的时候,只拷贝地址,上述前三种方法叫做浅拷贝,浅拷贝修改数据之后会影响原对象的值。浅拷贝要想拷贝完后修改值仍然不影响原数组的值,则需要将数组中的对象再拷贝一份放在目的数组中。

 

当数组中元素为引用类型时,浅拷贝修改数据之后会影响原对象的值。

浅拷贝要想拷贝完后修改值仍然不影响原数组的值,则需要将数组中的对象再拷贝一份放在目的数组中,即由浅拷贝达到深拷贝。见下图:

五、查找数组中指定元素(二分查找)

    针对有序数组, 可以使用更高效的二分查找. 

    啥叫有序数组?

        有序分为 "升序" 和 "降序" 如 1 2 3 4 , 依次递增即为升序. 如 4 3 2 1 , 依次递减即为降序.

   以升序数组为例, 二分查找的思路是先取中间位置的元素, 看要找的值比中间元素大还是小. 如果小, 就去左边找; 否则 就去右边找.

1.自定义函数实现二分查找

public static void main(String[] args) {
     int[] arr = {1,2,3,4,5,6};
     System.out.println(binarySearch(arr, 6));
}
public static int binarySearch(int[] arr, int toFind) {
     int left = 0;
      int right = arr.length - 1;
     while (left <= right) {
         int mid = (left + right) / 2;
         if (toFind < arr[mid]) {
             // 去左侧区间找
             right = mid - 1;
         } else if (toFind > arr[mid]) {
             // 去右侧区间找
             left = mid + 1;
         } else {
             // 相等, 说明找到了
             return mid;
         }
     }
     // 循环结束, 说明没找到
     return -1;
}
// 执行结果
5

除了自己写二分查找的代码,还可以使用系统内的二分查找的方法:binarySearch(数组名, 要查找的数);

2.binarySearch(数组名, 要查找的数)方法

class Test {
     static int count = 0; // 创建一个成员变量, 记录二分查找循环次数
    public static void main(String[] args) {
         int[] arr = makeBigArray();
         int ret = binarySearch(arr, 9999);
         System.out.println("ret = " + ret + " count = " + count);
     }
    public static int[] makeBigArray() {
         int[] arr = new int[10000];
         for (int i = 0; i < 10000; i++) { 
            arr[i] = i;
         }
         return arr;
     }

3.递归实现二分查找

public static int halfLocate(int[] arr,int left,int right,int key){
    int mid=(left+right)/2;
    if(key==arr[mid])
    {
        return mid;
    }else if(arr[mid]>key)
    {
        return halfLocate(arr,left,mid-1,key);
    }else{
        return halfLocate(arr,mid+1,right,key);
    }
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值