Java中的数组

news2024/11/19 8:30:15

前言:

本篇博客将为大家介绍Java中的数组的相关知识。

目录

基本介绍

概念相关

数组的使用

数组是引用类型

应用场景

保存数据

作为方法的参数

作为方法的返回值

练习

数组转字符串

数组拷贝

求数组中元素的平均值

查找数组中的指定元素(二分查找+顺序查找)

数组排序(冒泡排序)

数组逆序

二维数组



基本介绍

概念相关

数组可以看成是相同类型元素的集合。在内存中是一段连续的空间,每个空间都有自己的编号,编号从0开始

数组的使用

  • 创建数组:T[] 数组名 = new T[N];
    • T表示数组中存放的元素的数据类型
    • T[]表示数组的类型
    • N表示数组的长度
  • 数组的初始化(一共有三种形式):
    • 动态初始化:在创建数组时,直接指定数组元素的个数
      • int[] arr = new int[10];
    • 静态初始化:在创建数组的时候,不直接指定数组元素个数,而是对元素的具体内容进行指定
      • int[] arr = new int[]{12,23,43,21,43};
      • int[] arr = {12,23,43,21,43};(对上面的写法再次进行简化)
    • 注意:
      • 静态初始化虽然没有指定数组的长度,但是编译器会按照其存放的元素的个数来确定其长度
      • 静态初始化中的后面的new T[]虽然可以省略,但在编译的时候还是会还原的
      • 数组也可以按照C语言中数组的创建方式来创建,但是不推荐。T[]写在一起更加清晰明了,让人立刻就明白T[]是数组的类型
      • 静态初始化和动态初始化都可以写成两步,但是省略后面new T[]的静态静态初始化方法不可以
      • 如果没有对数组初始话,里面存放的是默认值。基本数据类型存基本数据类型的默认值;引用类型存引用类型的默认值。
        • 基本数据类型的默认值:
  • 数组的使用:
    • 数组中元素的访问:数组在内存中是一段连续空间,空间的编号都是从0开始,依次递增,该编号称为数组的下标,数组可以通过其下标访问数组中的任意元素(即,支持随机访问)。其编号是从)开始的,假设数组中共有N个元素,那么编号,也就是下标的大小只能在[0,N)这个范围,大于等于N都会导致数组越界(java.lang.ArrayIndexOutOfBoundsException)。     
    • 遍历数组:所谓遍历,就是把数组中的元素全部访问一遍;访问是指对数组中的元素进行某种操作,这里以打印为例。像数组中的元素的访问的例子那样,arr6中的所有元素都可以通过一个一个地打印出来,从而达到遍历的效果。但是我们不禁思考:如果一个数组有很多元素呢(比如100个),我们也要这样一个一个地去敲每一步的打印吗?这么做的工作量显然十分巨大。仔细思考,我们会发现我们可以通过循环很容易实现遍历,从而减少代码量:
      • 我们可以通过for-each循环来遍历:
      • 就通过for循环来实现:(当然,其他循环也是可以的,这里也可以只是举例)
        • 这时,另外一个疑问又来了:我们要如何去获取数组的长度呢?此处我们自己举例写的arr6数组,且可以看到它的长度(起码我们可以自己数一下),但是总是有一些场景我们是不能确定其长度或者长度在改变的,那么我们要如何获取数组的长度呢?我们可以通过”数组对象.length“来获取其长度

数组是引用类型

首先,我们先基本了解一下JVM:

程序计数器(PC Register):一块很小的空间,保存下一条执行指令的地址。

虚拟机栈(JVM Stack):与方法调用的一些相关信息,每个方法在执行的时候,都会先创建一个栈帧,栈帧中包含有:局部变量表、操作数栈,动态链接,返回地址以及一些其他的信息,保存的都是一些和方法执行时的相关信息。如:局部变量。方法在运行完以后,栈帧就会被销毁,即保存在栈帧中的数据也会被销毁。

本地方法栈(Native Method Stack):本地方法栈和虚拟机栈相似,只不过保存的是Native方法的局部变量。有些版本的JVM(如HotSpot)实现中本地方法栈和虚拟机栈是一起的。

堆(Head):JVM所管理的最大内存区域,使用new创建的对象都是在堆上保存的。堆是随着程序开始运行时而创建的,随着程序的退出而销毁,堆中的数据只要还有在使用的,就不会被销毁。

方法区(Method Area):用于存储已经被虚拟机加载的类信息,常量、静态变量、即时编译器编译后的代码等数据。方法编译出的字节码就是保存在这个区域的。

接下来,我们将主要涉及两个部分:堆和虚拟机。

基本数据类型创建的变量,称为基本变量,该变量空间存放的就是其保存的值;

而引用数据类型创建的变量,一般称为对象的引用,其空间存放的对象的地址

举例:

注意:

  • 对于这种写法(如下图),我们不能说一个引用指向了一个引用(这句话是错的,引用不能指向引用),我们应该说,一个引用指向了另一个引用所指向的对象

图解:

  • 在Java中,null表示空引用,也就是不指向任何对象的引用
  • Java中并没有约定null和0有任何关系。

应用场景

保存数据

作为方法的参数

图解:

作为方法的返回值

把func3方法中返回的arr的地址给了ret,使得ret指向了ret这个引用指向的地址(func3中的代码也可以直接简化成return new int[]{1,2,3};)

注意:对象一定是在堆上的,引用变量不一定是在栈上的。


练习

数组转字符串

记得要导包:import java.util.Arrays;(java.util.Arrays包里面包含了一些操作数组的常用方法)

我们也可以自己尝试实现一下这个方法:

public class Demo3 {    
    public static  String myToString(int[] arr){
        String ret ="[";
        for (int i = 0; i < arr.length; i++) {
            ret += arr[i];
            if(i != arr.length -1){
                ret += ",";
            }
        }
        ret += "]";
        return ret;
    }
    public static void main(String[] args) {
        int[] arr = {1,2,3};
        System.out.println(myToString(arr));
    }
}

数组拷贝

单纯的拷贝:

这里要注意,不能直接int[] copy = arr; 这样不是拷贝,是让copy拿到了arr里面放的地址,从而指向了它指向的引用,并没有创建新的数组,不是拷贝

法二:

直接利用Arrays自带的拷贝方法(copyOf(原数组,新数组长度)):

值得注意的是:copyOf方法有很多方法和它构成重载,我们只需要在选择满足自己需求的那个即可。

copyOf方法还可以改变新的数组的长度:

拷贝一定范围的数据:

copyOfRang(原数组,初始拷贝下标,结束拷贝下标):

如果拷贝的范围超出了原来数组的长度,就只能能拷贝多少拷贝多少,那些没拷贝到的就还是初始值0。 

System.arraycopy(原数组,原数组开始被拷贝的下标,新数组,新数组开始拷贝的下标,拷贝的长度);

注意:方法中的最后一个数是从原数组中拷贝过来的数据的长度格外小心是否越界要注意在起始拷贝下标的基础上新数组是否能接收这么长的数据,原数组是否能给出这么多的数据供拷贝

求数组中元素的平均值

import java.util.Arrays;
public class Demo3 {
public static double avg(int[] arr){
        int sum = 0;
        for (int i = 0; i < arr.length; i++) {
            sum += arr[i];
        }
        return sum/(double)arr.length;//注意类型转换
    }
    public static void main(String[] args) {
        int[] arr = {1,2,3,4,5,6,7,8,21};
        System.out.println(avg(arr));
    }
}

查找数组中的指定元素(二分查找+顺序查找)

顺序查找:

import java.util.Arrays;  
public class Demo3 {
 //顺序查找:
    public static int findVal(int[] arr, int i){
        for (int j = 0; j < arr.length; j++) {
            if(arr[j] == i){
                return j;
            }
        }
        return -1;//数组下标不可能是负数,返回负数说明没有找到

    }
    public static void main(String[] args) {
        int[] arr = {1,2,3,4};
        int ret = findVal(arr,2);
        System.out.println(ret);
    }
}

二分查找:针对有序数组,我们还可以通过二分查找来找出要查找的数据的下标:

public class Demo3 {
//    二分查找:
    public static int binarySearch(int[] arr, int i){
        int left = 0;
        int right = arr.length - 1;

        while(left <= right){
            int mid = (right + left)/2;
            if(arr[mid] < i){
                left = mid + 1;
                mid = (right + left)/2;
            }else if(arr[mid] > i){
                right = mid - 1;
                mid = (right + left)/2;
            }else if(arr[mid] == i){
                return mid;
            }
        }
        return -1;
    }
    public static void main(String[] args) {
        int[] arr = {12,34,45,51,54,65,76,87,97,99};
        int ret = binarySearch(arr,51);
        System.out.println(ret);
    }
}

图解:

当然,我们也可以通过二分查找查找无序的数组的特定元素:先通过Arrays里面的sort方法对数组进行排序(升序),然后再通过二分查找查出排序好以后的特定数组的下标,不过这样做的意义其实并不大,因为经过排序,数组的下标早已不是原来的样子了。

数组排序(冒泡排序)

import java.util.Arrays; 
public class Demo3 {  
  //冒泡排序:
    public static void bubbleSort(int[] arr){
        for (int i = 0; i < arr.length-1; i++) {
            //一共要排arr.length-1次序,每排一次都会让数组中的一个数有序(此处以最大值为例)
            for (int j = 0; j < arr.length-i-1; j++) {
                //每一次排序内部要走arr.length-1-i次排序,才能实现让数组中为排好序的数里面的最大值排到最后
                if(arr[j]>arr[j+1]){
                    int tmp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = tmp;
                }
            }
        }
    }
    public static void main(String[] args) {
        int[] arr = {12,45,97,76,51,34,87,54,65,99};
        bubbleSort(arr);
        System.out.println(Arrays.toString(arr));
    }
}

由图可知,在i=4开始,数组就已经是有序的了,后面的比较就是冗余的了,所以我们可以再对这个代码进行优化:在方法中加一个变量用来判断是否发生了交换,且每有一趟循环走完开始下一趟循环的时候就要让这个变量变回到它原来的值。一旦发现不再发生交换的时候,就直接跳出循环。

import java.util.Arrays; 
public class Demo3 {     
 //冒泡排序:
    public static void bubbleSort(int[] arr){
        for (int i = 0; i < arr.length-1; i++) {
            //一共要排arr.length-1次序,每排一次都会让数组中的一个数有序(此处以最大值为例)
            boolean flg = false;//每一趟开始的时候都要让flg为false
            for (int j = 0; j < arr.length-i-1; j++) {
                //每一次排序内部要走arr.length-1-i次排序,才能实现让数组中为排好序的数里面的最大值排到最后
                if(arr[j]>arr[j+1]){
                    int tmp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = tmp;
                    flg = true;//若发生交换,则改变flg的值,通过flg的值来确定是否发生交换,若未发生交换,则直接跳出循环
                }
            }
            if(flg == false){
                break;
            }
        }
    }
    public static void main(String[] args) {
        int[] arr = {12,45,97,76,51,34,87,54,65,99};
        bubbleSort(arr);
        System.out.println(Arrays.toString(arr));
    }
}

数组逆序

此处介绍的是直接通过交换对应下标的元素来实现数组逆序的效果。

import java.util.Arrays; 
public class Demo3 {     
    //数组逆序:
    public static void reserve(int[] arr){
        int left = 0;
        int right = arr.length-1;
        while(left < right){
            //不用管相等的情况,因为当right和left相等时就表明相等的那个数就是中间的那个,
            // 既然在最中间,也没有交换的必要了
            int tmp = arr[left];
            arr[left] = arr[right];
            arr[right] = tmp;
            left++;
            right--;
        }
    }
    public static void main(String[] args) {
        int[] arr = {12,45,97,76,51,34,87,54,65,99};
        reserve(arr);
        System.out.println(Arrays.toString(arr));
    }
}

二维数组

  • 语法:数据类型[][] 数组名称 = new 数据类型[行数][列数]{初始化数据};
    • int[][] arr =  new int[][]{{1,2,3},{4,5,6}};
    • int[][] arr = {{1,2,3},{4,5,6}};
    • int[][] arr = new int[2][3];(默认这两行三列里面存的全是0)
  • 二维数组本质上也是一个数组,只不过每个数组里面又是一个数组。行里面存放的是各个列组成的的数组的地址
  • 遍历二维数组:
    • 我们很容易想到一个最简单粗暴的方法:通过两层循环来遍历整个数组:
    • 但是很明显,对于这种方法,我们是自己手动置入其行和列的长度的。有没有办法可以获取到其行和列的长度吗?当然是有的。结合前面介绍的二维数组的元素其实就是一维数组,我们可以很好地理解下面这种写法:
  • 顺便一提,要想直接打印出二维数组,我们使用的方法不再是toString,而是deepToString
  • 不规则的二维数组:
    • 注意,未对不规则二维数组初始化的时候不能打印它。因为二位数组里面存的是一维数组,而数组是引用类型,引用类型未初始化默认存储的是null,也就是不指向任何地址,所以会报空指针异常的错误。

   Arrays中的其他方法的介绍:

  1. equals:判断两个数组是否一样:
  2. fill:帮助数组填充数据:同时,fill方法有很多重载方法,可以根据需求选择,如:把某个值从数组的n1下标填充到n2下标

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1099281.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

传输线感性耦合和距离的关系

传输线感性耦合和距离的关系 传输线感性耦合是指两条或多条传输线之间由于磁场或电场的相互作用而产生的耦合现象。这种耦合现象对于传输线的信号质量和完整性有很大的影响。其中&#xff0c;传输线之间的距离是一个重要的影响因素。本文将从传输线感性耦合的基本概念入手&…

新年学新语言Go之一

一、前言 搜索相关知识后续内容等上班后再继续&#xff0c;新年新气象&#xff0c;从今天开始学习一下Go语言&#xff0c;第一次听说这门语言还是2016年的时候&#xff0c;然后2018年买了一本书 Go In Action&#xff0c;然后就没有然后了&#xff0c; 转眼这么多年过去了&am…

输入字符串,判断里面有多少个大写字母,多少小写字母,多少数字

public static void main(String[] args) {//输入字符串&#xff0c;判断里面有多少个大写字母&#xff0c;多少小写字母&#xff0c;多少数字countVary("fsdfsD4f4sf&#xffe5;#&#xffe5;%~&*&#xff01;sg9tssfffSFSFS");}public static void countVary(…

【网络】总览(待更新)

网络Ⅰ 零、概述0. 网络协议1. 网络协议分层OSI 七层模型TCP/IP 五层模型 2. 协议报头3. 通信过程 一、应用层1.1 &#x1f517;HTTP 协议1.2 &#x1f517;HTTPS 协议 二、传输层2.1 端口号2.2 netstat - - 查询网络状态2.3 pidof - - 查看服务器的进程 id2.4 &#x1f517;UD…

亚马逊云科技正式发布Amazon DataZone,一项新的数据管理服务

Amazon DataZone现已正式发布。作为一项新的数据管理服务&#xff0c;它能够在组织中对数据生产者和消费者之间产生的数据进行编目、发现、分析、共享和管理。 早在2022年的亚马逊云科技re:Invent上&#xff0c;就预告了Amazon DataZone产品的发布&#xff0c;并在2023年3月对其…

常见场景面试题(二)

typora-copy-images-to: imgs theme: cyanosis 敏感词库的设计&#xff0c;要求增删改查敏感词。敏感词文本匹配&#xff0c;敏感词一万个&#xff0c;文本长度在 20 - 1000 答&#xff1a;使用 trie 树来实现敏感词库的设计&#xff0c;可以利用字符串公共前缀来节约存储空间。…

webrtc gcc算法(1)

老的webrtc gcc算法,大概流程&#xff1a; 这两个拥塞控制算法分别是在发送端和接收端实现的&#xff0c; 接收端的拥塞控制算法所计算出的估计带宽&#xff0c; 会通过RTCP的remb反馈到发送端&#xff0c; 发送端综合两个控制算法的结果得到一个最终的发送码率&#xff0c;并以…

记次好玩的XXX模式

看到很多框架里都用了这种方式

深入了解Java位运算符

1.前言 位运算在我们刷题时候&#xff0c;对于效率和空间都是很大的提升&#xff0c;所以位运算符&#xff0c;对于我们的作用也是不可或缺的。 里面就存在一个很重要的思想就是位图&#xff0c;此次我讲解位运算符的作用主要是为他服务的 位图的原理:通过一个整数模拟&#xf…

Dubbo的整体框架和主要模块

1 整体框架 Dubbo的整体框架如下图所示&#xff1a; 上层依赖下层提供的功能&#xff0c;下层的改变对上层不可见。 2 主要模块 &#xff08;1&#xff09;主要模块如下所示&#xff1a; &#xff08;2&#xff09;各子模块描述如下所示&#xff1a; 3 参考文献 &#xff08…

CN论文编写提示词-示例

建议用GPT-4或者Bing 现在开始你是一位计算机学科的研究员!教授!擅长研究和撰写论文!我需要你协助我一起研究一个课题:《计算机信息技术在智能交通系统中的应用》!你认为这个题目如何!有哪些参考资料!这个题目作为论文题目的话有哪些创新意义和价值! 你扮演计算机信息技…

第六章 应用层 | 计算机网络(谢希仁 第八版)

文章目录 第六章 应用层6.1 域名系统DNS6.1.1 域名系统概述6.1.2 互联网的域名结构6.1.3 域名服务器 6.2 文件传送协议6.2.1 FTP概述6.2.2 FTP的基本工作原理6.2.3 简单文件传送协议TFTP 6.3 远程终端协议TELNET6.4 万维网www6.4.1 万维网概述6.4.2 统一资源定位符URL6.4.3 超文…

VBA技术资料MF70:从单元格文本中取消或删除上标

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。我的教程一共九套&#xff0c;分为初级、中级、高级三大部分。是对VBA的系统讲解&#xff0c;从简单的入门&#xff0c;到…

力扣刷题 day46:10-16

1.最大整除子集 给你一个由 无重复 正整数组成的集合 nums &#xff0c;请你找出并返回其中最大的整除子集 answer &#xff0c;子集中每一元素对 (answer[i], answer[j]) 都应当满足&#xff1a; answer[i] % answer[j] 0 &#xff0c;或 answer[j] % answer[i] 0 如果存在…

2.SpringSecurity - 处理器简单说明

文章目录 SpringSecurity 返回json一、登录成功处理器1.1 统一响应类HttpResult1.2 登录成功处理器1.3 配置登录成功处理器1.4 登录 二、登录失败处理器2.1 登录失败处理器2.2 配置登录失败处理器2.3 登录 三、退出成功处理器3.1 退出成功处理器3.2 配置退出成功处理器3.3 退出…

前端需要了解的浏览器缓存知识

文章目录 前言为什么需要缓存&#xff1f;DNS缓存缓存读写顺序缓存位置memory cache&#xff08;浏览器本地缓存&#xff09;disk cache&#xff08;硬盘缓存&#xff09;重点&#xff01;&#xff01;&#xff01; 缓存策略 - 强缓存和协商缓存1&#xff09;强缓存ExpiresCach…

认识测试---什么是测试?

文章目录 测试软件测试的性质测试人员的基本素养什么是需求什么是BUG 开发模型和测试模型软件的生命周期开发模型瀑布模型螺旋模型增加&#xff0c;迭代敏捷开发scrume 测试模型V模型W模型&#xff08;双V模型&#xff09; 测试 一个好的开发者&#xff0c;不仅要懂技术也要懂…

【cpu_entry_area mapping】SCTF2023-sycrop

前言 也算学习到了&#xff0c;这样对 DB_stack 的利用与 pt_regs 很相似。都是利用在用户态切换在内核态时&#xff0c;会保存用户态的上下文信息在内核栈中&#xff0c;所以我们就可以控制部分内核栈中的数据&#xff0c;以此为我们栈迁移做好准备。 程序分析 启动脚本啥的…

14-k8s-基本存储之EmptyDir、HostPath、NFS

文章目录 一、相关概念二、EmptyDir存储三、HostPath存储四、NFS存储 一、相关概念 概述 Volumn定义在Pod上&#xff0c;然后被该Pod里面的多个容器挂载到具体的文件目录下。实现同一个Pod中不同容器之间的数据共享以及数据的持久化存储。Volume的生命周期不和Pod中的单个容器的…

出海 SaaS 企业增长修炼手册:聊聊 PLG 的关键指标、技术栈和挑战

产品驱动增长 Product-Led Growth (PLG) 近几年可谓火遍海外 SaaS 圈&#xff0c;但想要真正落地 PLG 还是存在不少挑战的。了解 PLG 背后的增长指标&#xff0c;不仅可以帮助企业跟上发展节奏&#xff0c;更能从纷繁复杂的业务细节中获取有价值洞察。那么&#xff0c;如何高效…