JavaSE -- 数组

一丶数组概念&基本格式

(1)概念

首先,何为数组?

所谓数组,是相同元素的一个集合,在内存当中是一段连续的空间

那么这段特殊的集合有什么特点呢?

<1>数组里面的元素都是同类型的
<2>储存元素的空间是连续的
<3>每个空间都有属于自己的编号 ---- 数组的下标

(2)基本格式

数组的基本格式是:

数据类型[] 数组名 = new 数据类型[N]

在这个基本格式里面有什么需要注意的呢?

1 > 数组名命名采用小驼峰式
2 > 这里的new是一个用来申请数组空间的关键字,该关键字申请的都在堆上
3 > 后面 [ ] 的 N代表数组元素个数

二丶数组的使用

(1)数组的初始化

数组进行定义之后要进行显式初始化

<1>动态初始化

//动态初始化,例:
int[] arr1 = new int[3];
//分步写
int[] arr1;
arr1 = new int[3];

<2>静态初始化

//静态初始化,例:
int[] arr2 = new int[]{1,2,3}
//分步格式:
int[] arr2;
arr2 = new []{1,2,3}
//省略格式
int[] arr1 = {1,2,3};

这里的话有几个需要注意的点:

1.静态初始化编译器在编译的时会根据{}中元素个数来确定数组长度。

2.静态初始化的时候,{ } 里的数据类型和数组名前面的数据类型一定要一致
3.如果没有对数组初始化,其实数组里面已经有了默认值(看下面)

动态初始化的时候,数组并不是空的,里面有默认值!这一点,我们来验证一下:

首先代码截图验证:

在这里插入图片描述
可以看出当我们动态创建数组的时候,里面其实已经有了默认值,每种类型的默认值都不一样,具体区别如下:

在这里插入图片描述
这里的话,具体来总结一下,就是:
在这里插入图片描述
引用类型统一是:NULL

(2)数组元素的访问与遍历

对于数组来说, 其内存是一段连续的空间,空间编号从0下标开始,依次递增,所以这意味着可以通过数组的下标来访问位置,也就是说:数组支持随机访问

int[] a = {1,2,3,4,5};
System.out.println(a[3]);
//输出4
/*
所以数组下标编排是: (0,N]
N:数组元素个数
*/

这里的话,对于随机访问是知道下标打印值,那么如果知道了值打印下标呢?
我们又该怎么办呢?

   public static int findDate(String[] str,String s){
        int key = -1; //定义钥匙用来记录相同字符串所在下标数
        for (int i = 0; i < str.length; i++) {
            if(str[i] == s){
                key = i;
            }
        }
        if(key == -1){//如果没有的话返回 -1
            return -1;
        }
        //如果有的话返回下标
        return key;
    }

所谓遍历,是将数组元素全部打印一遍,这里的话先介绍一下最最基本的循环打印:

 public static void main(String[] args) {
        int[] arr = {1,2,3,4,5};
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + " ");
        }
    }
//输出:1 2 3 4 5 

PS:这里注意一下:

我对于数组打印的循环判断条件是:i < arr.length
这里说明一下,[ 数组名.length ]代表的就是数组的长度

然后这里介绍中比较简洁不容易出错的遍历方式:

for(int i : arr){
	System.out.println(i);
}

这是:for - each 循环遍历
注意:这里的 i 和打印语句中的 i 要是同一个字母,打印语句 i 表示的是a [ i ] ,arr这里表示的是数组名。
好处:for - each 循环虽然功能没有for循环打印功能强大,但是可以很有效的避免数组越界和循环条件写错等 Exception 错误

三丶引用类型 – 数组

(1)内存介绍

前面也说了,数组在内存是一段连续的空间,是怎样的内存间呢?这里简略说一下:

所有的程序在没有运行的时候,就是保存在磁盘上的一段数据,但是当他们运行之后,程序的代码以及数组就需要加载到内存当中,而所谓内存是一段连续的存储空间,主要用来存储程序运行时数据的。比如:

  1. 程序运行时代码需要加载到内存
  2. 程序运行产生的中间数据要存放在内存
  3. 程序中的常量也要保存
  4. 有些数据可能需要长时间存储,而有些数据当方法运行结束后就要被销毁。

所以就要对内存严加管理,就像一房间一样,如果不好好整理:
在这里插入图片描述
如果好好整理:

在这里插入图片描述

所以JVM对内存按照功能进行了划分:
在这里插入图片描述
这里对这五个区域进行简略叙述

线程共享的数据区:

方法区 :用于保存已被虚拟机加载的变量,常量,类信息,即时编译器便器之后产生的代码等。方法编译的字节码就是保存在这个区域

堆 : new 出来的都在堆上,也就是引用类型的数据就保存在堆上。堆随着程序开始而创建,随着程序结束而销毁。只要堆中数据还在用,就不会销毁。

线程私有的数据区:

程序计数器 : 保存下一条执行的指令的地址

虚拟机(JVM)栈 : 每一个方法执行时都会创建一个栈帧,栈帧里面有局部变量表,操作数栈,动态链接,返回地址等其他一些信息,栈帧随着方法的运行而创建,随着方法的结束而销毁。

本地方法栈 : 保存的是Native方法的局部变量

(2)关于引用数据类型

数据类型分为基础数据类型和引用数据类型。
所谓基础数据类型,就是那四类八种,这里不做过多说明,主要介绍介绍引用数据类型。

基础数据类型的存储在栈上,而引用数据类型的存储在堆上,引用类型栈上存储的是堆上的地址。

引用数据类型目前的话认识到两种,一个是String,还有一个就是本节课的数组。
首先,先认识一下存储问题:
在这里插入图片描述
这里左边是代码,右边是字节码展示,现在画一下具体图示:
在这里插入图片描述
所有方法的执行都是从main()开始,然后在虚拟机栈创建对应栈帧,然后main一行一行执行到memory()方法,此方法在栈上创建栈帧,然后保存t a b c的值,接着到引用类型的时候,它没有这样干,而是在堆上保存了数据,然后把数据的开头地址给保存在了栈上。
这里注明一下:引用类型数组如String类型它的初始值是NULL,这个NULL和C语言中的空指针类似,都是一个无效的内存地址,不能进行读写!

四丶数组的应用

(1)作为方法返回值

一般情况下,方法的返回值只能有一个,比如整形和浮点型的数字,布尔类型的对错,如果说想要返回多个数字,那么我们可以通过数组来实现:

  public static void main(String[] args) {
        int[] arr = ret(5);
        for (int i:arr) {
            System.out.print(i + " ");//打印数组元素
        }
    }

    public static int[]  ret(int a){//接收a,确定数组长度
       if(a <= 0){
           return null; //确定数组元素不为空
       }
       int[] arr = new int[a];
        for (int i = 0; i < a; i++) {
            arr[i] = i + 1;//对数组进行赋值
        }
        return arr;
    }

//最后结果是: 1 2 3 4 5 

(2)作为参数传参

 public static void main(String[] args) {
        int[] arr = {1,2,3,4,5};
        func(arr);
        System.out.println("arr[0] = " + arr[0]);
    }
    public static int[] func(int[] a){
        a[0] = 10;
        System.out.println("a[0] = " + a[0]);
        return a;
    }

//运行结果:
a[0] = 10
arr[0] = 10

事实证明,所谓的 “引用” 本质上只是存了一个地址. Java 将数组设定成引用类型, 这样的话后续进行数组参数传参, 其实只是将数组的地址传入到函数形参中. 这样可以避免对整个数组的拷贝(数组可能比较长, 那么拷贝开销就会很大).

五丶拓展应用

(1)数组转字符串

这里的话就是单纯的记忆就好,看代码:

import java.util.Arrays

public static void main(String[] args) {
        int[] arr = {1,2,3,4,5,6};
        System.out.println(Arrays.toString(arr));
    }
// 执行结果
[1, 2, 3, 4, 5, 6]

(2)数组拷贝

1> 深拷贝,浅拷贝

数组拷贝分为深拷贝和浅拷贝,这里分别来说一下(只针对引用类型):

浅拷贝是指不开辟新的内存空间,仅仅只是复制对象的引用地址,新旧对象都指向同一个地址,对其中一个的值得修改也会引起另外一个的改变。

例如:

 int[] arr = {1,2,3,4,5,6};
 int[] newArr = arr;
 newArr[0] = 10;
 System.out.println("newArr: " + Arrays.toString(arr));

//运行结果:
	newArr: [10, 2, 3, 4, 5, 6]

深拷贝是指在内存上开辟一块新的空间,然后在上面把复制一个一模一样的对象,新旧对象不指向同一块内存,修改其中一个不影响另外一个。

这里特别标注一下,Arrays.copyOf(数组名,数组长度) 就是拷贝语句

 // 深拷贝---copyOf方法在进行数组拷贝时,创建了一个新的数组
 // arr和newArr引用的不是同一个数组
  public static void main(String[] args) {
        int[] arr = {1,2,3,4,5,6};
        int[] newArr = Arrays.copyOf(arr, arr.length);
        System.out.println("newArr: " + Arrays.toString(newArr));
    }

//运行结果:
  newArr: [1, 2, 3, 4, 5, 6]

2> 拷贝特定范围

可以指定拷贝几号位到几号位的元素,这里注意,拷贝的范围是:[a,b)

  public static void main(String[] args) {
        int[] arr = {1,2,3,4,5,6};
		int[] newArr2 = Arrays.copyOfRange(arr, 2, 4);
 		System.out.println("newArr2: " + Arrays.toString(newArr2));
 	}

//运行结果 :
newArr2: [3, 4]

PS1:这里的范围就是 [2,4),也就是 2 ,3号下标,就是[3,4] 。
PS2:拷贝可以自己写。

六丶 二维数组

特殊的一维数组,数组里面存着数组,这里的话二维数组不太出现,所以暂时不写。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值