前言:
上节我们讲到了方法的,方法在Java中也是非常紧张的内容,那么这期我将为带来Java中的数组的基础和利用的内容
一、创建数组及初始化
1.数组的创建
数组:我们可以将其当作为相同范例元素的一种聚集
数组的界说有3种:
- public class TestDemo {
- public static void main(String[] args) {
- //数组定义1
- int[] array = {1,2,3,4};
- //int[]是整型数组,array是数组变量(名)
- //则下标为 0 1 2 3
- //数组定义2
- int[] array2 = new int[10];
- //这种定义是属于定义了一个大小为10的整型数组
- //上述初始化为动态初始化:通过new关键字
- //在C语言中,数组通常会是随机值,但是在Java中,这么定义,数组中会是0;
- //数组定义3
- int[] array3 = new int[]{1,2,3,4,5,7};
- //这种定义是指的是给数组进行赋值之后
- //那么等号后面的int[]中的[]不能进行空间的大小的填写
-
- //上述初始化为静态初始化:
- //静态初始化虽然没有指定数组的长度,
- //编译器在编译时会根据{}中元素个数来确定数组的长度。
-
- //静态初始化时, {}中数据类型必须与[]前数据类型一致。
- //静态初始化可以简写,省去后面的new T[]。T为数据类型
- //实际中我们不用管那么多,直接写就可以了
- //静态和动态初始化也可以分为两步,但是省略格式不可以
- int[] array1;
- array1 = new int[10];
- int[] array4;
- array4 = new int[]{10, 20, 30};
- //但是我们不可以分两步直接进行赋值
- //如:
- int array5;
- array5 = {1,2,3,4,5,6};
- //这种会报错,只能在定义是同时赋值
- System.out.println(array);
- System.out.println(array2);
- System.out.println(array3);
- //打印出来是“地址”,但是它不是真正的地址,这是哈希值,
- //Java太安全了,但是这个哈希值也是唯一的
- }
- }
复制代码
" [ " 表示的是数组范例,“ I ”表示的是为整形;
这些地址是放在堆上,引用变量 --> 储存”地址“的变量。
2.数组的初始化
- // 如果没有对数组进行初始化,数组中元素有其默认值
- // 如果数组中存储元素类型为基本类型,默认值为基类类型对应的默认值,比如:
- public static void main2(String[] args) {
- char[] array1 = new char[10];
- double[] array3 = new double[10];
- float[] array4 = new float[10];
- boolean[] array5 = new boolean[10];
- //布尔初始化,值全为初始化为false
- String[] string = new String[10];
- //string类型数组初始化全为null
- //string为引用类型
- }
复制代码 3.数组的利用
(1).数组中元素的访问
- public static void main3(String[] args) {
- int[]array = new int[]{1, 2, 3, 4};
- array[0] = 100;//可以直接而对于某一项那个值去修改
- System.out.println(array[0]);
- System.out.println(array[1]);
- System.out.println(array[2]);
- System.out.println(array[3]);
- //System.out.println(array[4]);
- //数组没有第五个元素,所以下标4就代表越界访问
- // Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 4
- // at TestDemo.main(TestDemo.java:69)
- // Disconnected from the target VM, address: '127.0.0.1:49482', transport: 'sock
- //这个异常是代表数组越界访问的异常
- System.out.println(array.length);
- //C语言中得用sizeof来计算数组的长度,Java不用
- //int sz = sizeof(array) / sizoef(array[0]);//数组的长度
- //注意事项:
- // 1. 数组是一段连续的内存空间,因此支持随机访问,即通过下标访问快速访问数组中任意位置的元素
- // 2. 下标从0开始,介于[0, N)之间不包含N,N为元素个数,不能越界,否则会报出下标越界异常。
- }
复制代码
- public static void main3(String[] args) {
- int[]array = new int[]{1, 2, 3, 4};
- array[0] = 100;//可以直接而对于某一项那个值去修改
- System.out.println(array[0]);
- System.out.println(array[1]);
- System.out.println(array[2]);
- System.out.println(array[3]);
- System.out.println(array[4]);
- }
复制代码
这个时间就出现了非常:数组没有第五个元素,以是下标4就代表越界访问
这个非常代表数组越界访问
注意事项:
数组是一段连续的内存空间,因此支持随机访问,即通过下标访问快速访问数组中恣意位置的元素
下标从0开始,介于[0, N)之间不包含N,N为元素个数,不能越界,否则会报出下标越界非常
(2).数组的遍历
- public static void main(String[] args) {
- int[] array1 = new int[]{1,2,3,4,5,6,7,8};
- //数组的遍历
- for (int i = 0; i < array1.length; i++) {
- System.out.print(array1[i] + " ");
- }
- System.out.println();//换行回车
- //范围for语法for each
- //这种语法我们拿不到数组元素的下标
- for (int x: array1) {
- System.out.print(x+" ");
- }
- System.out.println();
- }
- //对于下标的依赖,看情况和个人
复制代码
二、数组的引用范例
引用范例:什么叫引用范例,在这个变量中,储存的是"地址”
JVM将内存分别几个区:
1.方法区,2.虚拟机区,3.当地方法栈区,4.堆,5.步调计数器
在Java SE 中我们需要重点了解堆和虚拟机区
平时所说的栈,实在指的就是Java虚拟机栈
如:局部变量存在栈里
堆:一样平常用来存储对象的
当地方法栈一样平常利用C语言和C++来写的
堆(Heap): JVM所管理的最大内存区域. 利用 new 创建的对象都是在堆上保存 (例如前面的 new int[]{1, 2,3} ),
堆是随着步调开始运行时而创建,随着步调的退出而销毁,堆中的数据只要还有在利用,就不会被销毁。
每一块内存都有自己的使命,堆和方法区是全部线程共享的数据区 当地方法栈和虚拟机区以及步调计数器是处于线程隔离区
- public static void func() {
- int[] array1 = new int[3];
- array1[0] = 10;
- array1[1] = 20;
- array1[2] = 30;
- int[] array2 = new int[]{1,2,3,4,5};
- array2[0] = 100;
- array2[1] = 200;
- array1 = array2;
- array1[2] = 300;
- array1[3] = 400;
- array2[4] = 500;
- }
复制代码 谈一下对这段代码的理解:
首先这个数组1,在main方法中,先指向了堆中的数组1的对象,分别是10,20,30;假设这个对象的地址是0x18,虚拟机上的main方法栈中保存了array1这些地址,array2界说为了1,2,3,4,5;这时间堆中array2的对象的值1,2,3,4,5;但是又对array2[0]和[1]修改,以是这时间堆中array2的对象的值变成了100,200,3,4,5;再通过了array1=array2赋值,假设array2的地址是0x78,以是虚拟机中的main方法栈中两者的保留的地址均是0x78.以是这个时间array2的对象中的值就会变成了100,200,300,400,500。以是这两个引用均同时指向了一个对象,以是不管通过哪个引用,都可以把数组对象当中的值进行修改,那么array1的对象10,20,30,没有人再指向它了,那么JVM会主动把它回收掉 ;当func方法实行完毕,此时array1和array2是局部变量,此时就会被回收,那么array2所指向的对象没有别的引用所指向的,以是它也会被JVM而主动回收掉
- //null 在 Java 中表示 "空引用" , 也就是一个不指向对象的引用.
- public static void main3(String[] args) {//null
- //int[] array = 0;
- //通常把数组直接赋值为0是错误的
- //因为它指的是引用类型,而零是整数类型,两者是不同的
- int[] array3 = null;
- //array3这个引用不指向任何对象
- System.out.println(array3.length);
- //这个时候会发生报错,因为array3不指向任何数组对象,所以也就无法就计算长度
- //这个时候就会出现空指针异常的报错提醒:NullPointerException
- //这个异常会伴随你的一生在我们学习过程中
- //如果以后遇到空指针异常那么我们需要定位,看看那个引用是空的
- }
复制代码 三、数组的应用
1.保存数据
- public static void main(String[] args) {
- int[] array = {1, 2, 3};
- for (int i = 0; i < array.length; ++i) {
- System.out.println(array[i] + " ");
- }
- }
复制代码 2.作为函数的参数
2(1).参数传基本数据范例
- public static void main(String[] args) {
- int num = 0;
- func(num);
- System.out.println("num = " + num);
- }
- public static void func(int x) {
- x = 10;
- System.out.println("x = " + x);
- }
复制代码
总结: 发现在func方法中修改形参 x 的值, 不影响实参的 num 值。
2(2).参数传数组范例(引用数据范例)
- /**
- * 这种是改变了形参的指向(引用)
- * 在这种情况下,并不会影响到实参的指向
- */
- public static void func1(int[] array) {
- array = new int[10];//属于是对数组重新创建一个,这时候就会是改变了形参的指向
- }
- /**
- * 这时候是array得到了array2的地址,
- * 那么这个形参的array指向了栈上array2的对象,
- * 所以这个时候改变了形参array的数值,地址一样,那么也就是两者指向了一个对象
- * 所以对谁修改都会改变最后的对象的值
- * @param array
- */
- public static void func2(int[] array) {
- array[0] = 99;
- }
- //总结: 所谓的 "引用" 本质上只是存了一个地址. Java 将数组设定成引用类型, 这样的话后续进行数组参数传参, 其实
- //只是将数组的地址传入到函数形参中. 这样可以避免对整个数组的拷贝(数组可能比较长, 那么拷贝开销就会很大).
- public static void main(String[] args) {
- int[] array1 = {1,2,3,4};
- func1(array1);
- for (int i = 0; i < array1.length; i++) {
- System.out.print(array1[i] + " ");
- }
- System.out.println();
- int[] array2 = {1,2,3,4};
- func2(array2);
- for (int i = 0; i < array2.length; i++) {
- System.out.print(array2[i] + " ");
- }
- System.out.println();
- }
- //总结: func1也就是改变了形参的指向(引用)
- //当然,你不要以为传了引用,就万事大吉了,你要想想你拿引用干些什么了
复制代码
func1在我原来的理解或许会打印为1,2,3,4,0,0···等
由于array1在main方法中,以是他会创建了array1,来保存它指向的地址,这个引用会指向array1的对象
但是当它进入到func1中,这时间也会在虚拟机的栈的func1方法上创建一个array(理解为载体),在array中存进的array1(是地址)指向的对象也没有发生变化,
但是这个时间func1我们会创建一个新的变量array(这个array的地址存进了谁人载体中去),那么来储存array1(地址)的array(载体)的指向的对象就会发生变化,
那么它储存的地址也就会发生变化。以是末了的通过的func1的方法array1没有什么变化(实在变化也跟它没有相干的),以是末了是1,2,3,4.
实在一句话:就是改变了形参的指向,要不变,就是原来的,要不是原来的,那就是改变了指向的对象
说了这么多:我的理解,类比C语言的指针,array[数字],是对于同一块内存的中的内容发生改变,就是*p
array指向的改变,是地址的改变,便是从p = &a 改变到了 p = &b。
3.作为函数的返回值
- /**
- * 在这个方法中首先创建了一个数组,在堆上就会显示它的对象的值,此时通过引用获得了地址,这个地址存在了虚拟机栈上
- * 再通过return,返回的array的地址
- * @return
- */
- public static int[] func3 (){
- int[] array = new int[]{1,2,3,4,5,6};
- return array;
- }
- public static void main(String[] args) {
- int[] ret = func3();
- //再通过ret接受func3所返回的array的地址,这时候通过地址指向了array的对象
- for (int i = 0; i < ret.length; i++) {
- System.out.print(ret[i] + " ");
- }
- //对象一定是在堆上,但是引用变量不一定是在栈上(后期会讲)
- }
复制代码
好了,这节我们先到这里,下一期博主将会为大家带来Java中的数组快速操纵的方法及二维数组,当然,这节内容上如果有哪些地方的不敷,欢迎大家在批评区指出!
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |