java中数组的定义与使用

news2024/11/15 22:45:30

Java中的数组跟c语言的数组几乎不一样,我们要区分对待。在之后你就能理解到我为什么说这句话了。 

1.java中数组的创建与初始化

数组的创建

如下,皆为数组的创建。

double[] a;
int[] b;

创建时的[]里面绝对不能填数字。

 数组的初始化

主要分为动态初始化以及静态初始化。

1. 动态初始化:在创建数组时,直接指定数组中元素的个数

int[] array = new int[10]; 

动态初始化只是分配了一个数组空间,里面的值并没初始化赋值,像平时如果创建一个变量没将其初始化就使用,Java是会直接报错的。

而在这数组里其值也没初始化,但系统却会自动帮助其数组给它们一个基础值。

如果数组中存储元素类型为基类类型,默认值为基类类型对应的默认值,比如:

 

如果数组中存储元素类型为引用类型(类型于c语言的指针),默认值为null  。

在动态初始化时,java语法允许可以new int[n]  :n为变量,这样就更加方便。

2. 静态初始化:在创建数组时不直接指定数据元素个数,而直接将具体的数据内容进行指定。

int[] array1 = new int[]{0,1,2,3,4,5,6,7,8,9};
double[] array2 = new double[]{1.0, 2.0, 3.0, 4.0, 5.0};
String[] array3 = new String[]{"hell", "Java", "!!!"};

【注意事项】

静态初始化虽然没有指定数组的长度,编译器在编译时会根据{}中元素个数来确定数组的长度。

静态初始化时, {}中数据类型必须与[]前数据类型一致。

静态初始化可以简写,省去后面的new T[]。 本质还是一样的。

// 注意:虽然省去了new T[], 但是编译器编译代码时还是会还原
int[] array1 = {0,1,2,3,4,5,6,7,8,9};
double[] array2 = {1.0, 2.0, 3.0, 4.0, 5.0};
String[] array3 = {"hell", "Java", "!!!"};

但是简写在一些时候也是用不了的, 如我们数组的创建和初始化可以分成两步,在分为两步时,静态初始化的简写就用不了了。

int[] array1;
array1 = new int[10];
 
int[] array2;
array2 = new int[]{10, 20, 30};
 
// 注意省略格式不可以拆分, 否则编译失败
// int[] array3;
// array3 = {1, 2, 3};

数组也可以按照依照C语言创建数组的方法去创建,但不推荐,不要这么写 

/*
该种定义方式不太友好,容易造成数组的类型就是int的误解
[]如果在类型之后,就表示数组类型,因此int[]结合在一块写意思更清晰
*/
int arr[] = {1, 2, 3};

作者自己的思考理解

对于a和b这些数组名是引用变量,它们都是存地址的变量(数组是引用类型)。所以为了方便理解记忆,我们可以把[]理解成C语言的*,从而类型就是 double *或int *。

从而还可以这么理解,在初始化时,如new int[]{1,2}或着 new int[10]就在系统已经分配了一个数组空间,其还返回了这数组的最起始地址,从而让数组名(接收地址的变量)去接收,从而就创建了一个完整的数组。

不知道我这个思路理解是不是正确的,但这样确实更方便理解记忆。

 2.遍历数组

 第一种方法

这是第一种方法,很简单。值得注意的是 数组对象名.length就可以得到数组所含的元素个数 

 第二种方法

我们可以使用 for-each遍历数组,for-each就是一个加强版的for循环,其专门用在数组上(目前来看)。

其语法格式是这样。

for(数据类型 变量;数组名)
{}

其最开始是讲数组第一个元素赋值给变量。从而之后就是第二个元素赋值给变量。直到最后一个元素赋值给变量。然后就结束循环。

从而可以用该for-each循环遍历数组。代码如下:

int[] array = {1, 2, 3};
for (int x : array) {
    System.out.println(x);
}

for-each 是 for 循环的另外一种使用方式(专门用于数组). 能够更方便的完成对数组的遍历. 可以避免循环条件和更新语句写错.  

3.数组是引用类型

初始JVM的内存分布

 

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

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

本地方法栈(Native Method Stack): 本地方法栈与虚拟机栈的作用类似. 只不过保存的内容是Native方法的局部变量等. 在有些版本的 JVM 实现中(例如HotSpot), 本地方法栈和虚拟机栈是一起的(native方法是使用其他语言如c/c++编写的方法,它可以在java程序中被调用),我们现在使用的方法创建的栈帧都是在虚拟机栈中。

堆(Heap): JVM所管理的最大内存区域. 使用 new 创建的对象都是在堆上保存 (例如前面的 new int[]{1, 2, 3} ),堆是随着程序开始运行时而创建,随着程序的退出而销毁,堆中的数据只要还有在使用,就不会被销毁。

在c语言中堆中申请的内存在使用完后要用free释放。而在java中当我们申请的内存没有引用类型引用时(可以理解为没指针指向其申请的内存区域),它就会自动销毁。

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

现在我们只简单关心堆 和 虚拟机栈这两块空间,后序JVM中还会更详细介绍。

基本类型变量与引用类型变量的区别 

基本数据类型创建的变量,称为基本变量,该变量空间中直接存放的是其所对应的值;

而引用数据类型创建的变量,一般称为对象的引用,其空间中存储的是对象所在空间的地址。 

public static void func() {
    int a = 10;
    int b = 20;
    int[] arr = 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;
    for (int i = 0; i < array2.length; i++) {
       System.out.println(array2[i]);
   }
}

 

 4.认识null

null 在 Java 中表示 "空引用" , 也就是一个不指向对象的引用.

int[] arr = null;
System.out.println(arr[0]);
 
// 执行结果
Exception in thread "main" java.lang.NullPointerException
 at Test.main(Test.java:6)

 null 的作用类似于 C 语言中的 NULL (空指针), 都是表示一个无效的内存位置. 因此不能对这个内存进行任何读写操作. 一旦尝试读写, 就会抛出 NullPointerException.

注意: Java 中并没有约定 null 和 0 号地址的内存有任何关联.

4.数组的应用场景 

 保存数据 

public static void main(String[] args) {
    int[] array = {1, 2, 3};
    
    for(int i = 0; i < array.length; ++i){
        System.out.println(array[i] + " ");
   }
}

作为函数的参数 

之前已经讲过这个作为函数的参数,但由于当时没学习数组,所以参数传数组类型并没很清楚的讲述,现在学了,就清楚的讲述一遍 

参数传基本数据类型

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);
}
 
// 执行结果
x = 10
num = 0

发现在func方法中修改形参 x 的值, 不影响实参的 num 值.

参数传数组类型(引用数据类型) 

public static void main(String[] args) {
    int[] arr = {1, 2, 3};
    func(arr);
    System.out.println("arr[0] = " + arr[0]);
}
 
public static void func(int[] a) {
    a[0] = 10;
    System.out.println("a[0] = " + a[0]);
}
 
// 执行结果
a[0] = 10
arr[0] = 10

发现在func方法内部修改数组的内容, 方法外部的数组内容也发生改变.

因为数组是引用类型,按照引用类型来进行传递,是可以修改其中存放的内容的。(其实将其看作c语言的指针就更好理解了,将int []看作int*不就一下子就理解了)  

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

作为函数的返回值 

在c语言中不存在将数组类型当作返回值类型处理,但java可以。(同理,将其看作指针就好理解了)

获取斐波那契数列的前N项就是一个很好的例子

public class TestArray {
    public static int[] fib(int n){
        if(n <= 0){
            return null;
       }
 
        int[] array = new int[n];
        array[0] = array[1] = 1;
        for(int i = 2; i < n; ++i){
            array[i] = array[i-1] + array[i-2];
       }
 
        return array;
   }
 
    public static void main(String[] args) {
        int[] array = fib(10);
        for (int i = 0; i < array.length; i++) {
            System.out.println(array[i]);
       }
   }
}

5.数组练习

Java 中提供了 java.util.Arrays 包, 其中包含了一些操作数组的常用方法,里面就有sort方法,toString方法,full方法,equals方法。 

 现在我们先了解下fill方法和equals方法

fill 方法

public class one {
    public static void main(String[] args) {
        int[] a=new int[10];
        Arrays.fill(a,9);
        for(int x :a){
            System.out.println(x);
        }

在这代码中fill是将9全部填充到数组中 ,当然也可以部分填充,如下在中间添加了两个参数,从而就实现了部分填充。

public class one {
    public static void main(String[] args) {
        int[] a=new int[10];
        Arrays.fill(a,0,4,9);
        //第二个是起始位置,第三个是最终位置,左闭右开

        for(int x :a){
            System.out.println(x);
        }

 

 equals方法

 即使不用Arrays它也存在equals方法,之前讲过,那个是针对字符串去比较的。而Arrays中的equals方法是针对于数组去比较的。其区别如下

public class one {
    public static void main(String[] args) {
        int[] a=new int[10];
        int[] b=new int[10];

        System.out.println("das".equals("das"));//不属于Arrays里的
         System.out.println(Arrays.equals(a,b));//属于Arrays里的

所以两者存在区别,一个只适用于字符串,一个只适用于数组 。

1.数组转字符串

toString其参数类型为数组类型,返回值为字符串类型。所以能通过它将数组转为字符串类型。

import java.util.Arrays
 
int[] arr = {1,2,3,4,5,6};
 
String newArr = Arrays.toString(arr);
System.out.println(newArr);
 
// 执行结果
[1, 2, 3, 4, 5, 6]

使用这个方法后续打印数组就更方便一些.  

 2.数组拷贝

copyOf

该函数返回值为拷贝出的数组类型,所以需要用数组去接收。 

public class one {
    public static void main(String[] args) {
        int[]arr=new int[]{0,1,5,4};
     int[] arr2=  Arrays.copyOf(arr,arr.length);
       int[]arr3= Arrays.copyOf(arr,arr.length-1);
       int[]arr4= Arrays.copyOf(arr,arr.length*2);
       //拷贝的数组在堆区分配内存
       //当新数组长度等于原数组时,完全拷贝
        //当新数组长度小于原数组时,原数组会将最前面一部分拷贝到新数组中
    //当新数组长度大于原数组时,原数组会将其全部都拷贝到新数组中,新数组的其余部分为0(基础值)
       for(int x:arr2){
           System.out.print(x);
       }
        System.out.println();
        for(int x:arr3){
           System.out.print(x);
       }
        System.out.println();
        for(int x:arr4){
            System.out.print(x);
        }
    }
}

 

copyOfRange 

 同理返回值为数组类型,要用数组接收。

该函数作用是拷贝数组的某个范围。如下应该简而易懂。

public class one {
    public static void main(String[] args) {
        int[]arr=new int[]{1,4,6,8,5};
   int[]arr2= Arrays.copyOfRange(arr,2,5);
        for (int x:arr2
             ) {
            System.out.println(x);
        }
    }
}

 

 代码及文案

文案中提及拷贝分为深浅拷贝,其拷贝需要考虑深浅拷贝的问题。关于这个问题我们等到讲到接口时再讲 。

3.求数组中元素的平均值 

给定一个整型数组, 求平均值。(这个较简单,就直接看代码吧)

public static void main(String[] args) {
    int[] arr = {1,2,3,4,5,6};
    System.out.println(avg(arr));
}
 
public static double avg(int[] arr) {
    int sum = 0;
    for (int x : arr) {
        sum += x;
   }
    return (double)sum / (double)arr.length;
}
 
// 执行结果
3.5

4. 查找数组中指定元素(顺序查找) 

很简单,就不详细讲述了,直接看文案

5.查找数组中指定元素(二分查找) 

这个在c语言里也学过,这里就不过多讲述了,直接看文案。

 6.数组排序(冒泡排序)

之前在c语言里学过了,这里直接看文案,就不讲了。

 

 冒泡排序性能较低. Java 中内置了更高效的排序算法,其中sort用的就是更高效的排序算法。

public static void main(String[] args) {
    int[] arr = {9, 5, 2, 7};
    Arrays.sort(arr);
    System.out.println(Arrays.toString(arr));
}

sort还可以指定部分进行排序。如 

  Arrays.sort(a,0,6);

java中都是左闭右开,所以在这里是[0,6),从而是对数组中的下标为0到下标为5中的这部分进行排序。 

关于 Arrays.sort 的具体内部实现算法, 我们在后面的排序算法课上再详细介绍. 到时候我们会介绍很多种常见排序算法.

sort对数组是进行升序排列,sort并不能对数组进行降序排列 (如果要实现降序可以先用sort进行升序排列,再将数组逆序)

7.数组逆序 

这个很简单,在c语言中学过,这里直接看文案吧 

 6.二维数组

二维数组的内存图

 

 此时创建3个一维数组,这三个一维数组并不是连续分布的,三个一维数组分别有三个内存地址值,此时二维数组存放的就是这3个内存地址值。在二维数组通过3个地址值就可以找到3块空间,此时二维数组才算创建完毕,也会有一个对应的地址值(图上的0x0011),并把这个地址值赋值给arr。

此时如果输出arr[0]就会出现第一个一维数组的地址值,输出arr即输出二维数组的地址值。

所以说二维数组是个特殊的一维数组。

通过这java的二维数组的内存图也就能很好解释之后的二维数组代码了。

在c语言中二维数组的内存图也跟java的内存图差不多。(之前我对c语言二维数组的内存图理解有误,现在改正跟这个Java的内存图分布差不多,只是c语言数组是全部分布在栈区)

 二维数组的创建和初始化

这是二维数组的正常初始化 :分为三种,实则两种。

不规则的二维数组 

这是java特有的,c语言中二维数组不可能存在这种不规则的。 

public class one {
    public static void main(String[] args) {
        int[][] a = new int[3][]; //不规则二维数组必须要用这样的格式,列不能显示出来
//该代码先创建好存放一维数组地址的二维数组,子数组并没创建
        for(int i = 0; i < 3; i++)//再创建并初始化每个子数组
        {
            a[i] = new int[i + 1];
        }

    }//之后的代码就可以使用不规则的二维数组了,否则不能使用。

这就是不规则的二维数组。

个人对于二维数组的理解

int[][] arr=new int[4][3]

此时arr类型为int[][]  。[]可以理解为c语言的*,所以可以理解arr类型为int**,根据内存图不难发现arr是二维数组的地址,而二维数组存放的是存放整形的一维数组的地址,所以可以用int**表示.从而在java中arr类型是int[][].

同理, 还存在 "三维数组", "四维数组" 等更复杂的数组, 只不过出现频率都很低. 其道理跟二维数组是一样的(用二维数组可以推出来)

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

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

相关文章

【Python】一文带你了解如何获取 Python模块 安装路径

【Python】一文带你了解如何获取 Python模块 安装路径 &#x1f308; 个人主页&#xff1a;高斯小哥 &#x1f525; 高质量专栏&#xff1a;Matplotlib之旅&#xff1a;零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程&#x1f448; 希望得到您的订阅…

MyBatis进阶篇

MyBatis MyBtias工具类参数入参参数是单个参数参数是多个参数入参是POJO对象入参是Map类型 自动主键增长#{}和${}两种获取参数方式结果映射动态SQLMyBatis多表查询MyBatis注解开发 MyBtias工具类 SessionUtils.java import org.apache.ibatis.io.Resources; import org.apache…

当HR问你:“什么事会让你有成就感”你该怎么回答?【文章底部添加进大学生就业交流群】

当HR问你“什么事会让你有成就感”时&#xff0c;你可以通过以下方式回答&#xff1a; 强调目标实现&#xff1a; 表达你在达成挑战性目标时感到的满足感。举例说明你在过去的工作或项目中如何设定并成功实现了目标。 强调对团队成功的贡献&#xff1a; 谈论你与团队合作取得成…

力扣每日一题 将标题首字母大写 模拟 String API

Problem: 2129. 将标题首字母大写 文章目录 思路复杂度Code 思路 &#x1f468;‍&#x1f3eb; 灵神题解 复杂度 ⏰ 时间复杂度: O ( n ) O(n) O(n) &#x1f30e; 空间复杂度: O ( n ) O(n) O(n) Code class Solution {public String capitalizeTitle(String title)…

leetcode 25、k个一组翻转链表

给你链表的头节点 head &#xff0c;每 k 个节点一组进行翻转&#xff0c;请你返回修改后的链表。 k 是一个正整数&#xff0c;它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍&#xff0c;那么请将最后剩余的节点保持原有顺序。 你不能只是单纯的改变节点内部的值…

C++程序设计-练手题集合【期末复习|考研复习】

前言 总结整理不易&#xff0c;希望大家点赞收藏。 给大家整理了一下C程序设计中的练手题&#xff0c;以供大家期末复习和考研复习的时候使用。 C程序设计系列文章传送门&#xff1a; 第一章 面向对象基础 第四/五章 函数和类和对象 第六/七/八章 运算符重载/包含与继承/虚函数…

项目实战-tpshop商城项目

项目实战-tpshop商城项目 环境部署准备软件工具准备远程连接测试远程连接测试-查看虚拟机IP地址远程连接测试-检测本机与虚拟机是否连通远程连接测试-通过远程工具连接linux服务器 常见问题处理 环境部署项目技术架构介绍部署tpshop项目-tpshop验证数据库验证用户信息表熟悉商品…

API接口数据集接口pytorch api接口获取数据

API是应用程序的开发接口&#xff0c;在开发程序的时候&#xff0c;我们有些功能可能不需要从到到位去研发&#xff0c;我们可以拿现有的开发出来的功能模块来使用&#xff0c;而这个功能模块&#xff0c;就叫做库(libary)。比如说&#xff1a;要实现数据传输的安全&#xff0c…

这五款高性能骨传导耳机入手不后悔!附带骨传导耳机选购攻略!

随着健康生活的逐渐流行&#xff0c;越来越多的人开始注重运动和健身&#xff0c;在这一背景下&#xff0c;骨传导耳机作为当下最热门的健身装备&#xff0c;已成为市场上最受欢迎的产品之一&#xff0c;随着骨传导耳机的热度增高&#xff0c;与此同时也引发了一些不良商家和劣…

第八十天 WAF攻防-漏洞利用HPP污染分块传输垃圾数据

第80天 WAF攻防-漏洞利用&HPP污染&分块传输&垃圾数据 参考点&#xff1a; #将MySQL注入函数分为几类 拆分字符串函数&#xff1a;mid、1eft、1pad等 编码函数&#xff1a;ord、hex、a3ci等 运算函数&#xff1a;*/&^&#xff01;1 ike rlike reg等 空格替换部…

如何制作产品介绍二维码(一):编辑二维码内容

本篇主要以官方模板「产品详情介绍」为例&#xff0c;教大家如何从0开始制作单个产品介绍二维码&#xff0c;在掌握操作技巧后&#xff0c;你也能快速制作出一个效果不错的二维码。 该教程主要分以下4个部分&#xff1a; 编辑内容&#xff1a;指的是如何把图片、文件、音视频…

算法刷题day28

目录 引言一、截断数组二、双端队列三、日期统计 引言 这几道题是周赛里的几道题目&#xff0c;第一道题目我没用这种方法&#xff0c;但还是做出来了&#xff0c;用的一种比较特殊的思考方法&#xff0c;就是把每一个点都判断出来&#xff0c;不满足要求的就舍弃&#xff0c;…

ElasticSearchLinux安装和springboot整合的记录和遇到的问题

前面整合遇到的一些问题有的记录在下面了&#xff0c;有的当时忘了记录下来&#xff0c;希望下面的能帮到你们 1&#xff1a;Linux安装ES 下载安装&#xff1a; 参考文章&#xff1a;连接1 连接2 wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch…

如何关闭微软的Edge浏览器右击提示的:“使用copilot重写“的提示?

最近在使用微软的edge浏览器写文档的时候&#xff0c;总是不小心右击鼠标&#xff0c;提示 有时候挺烦人的&#xff0c;那怎么关闭呢&#xff1f; 打开edge浏览器的设置 在设置中搜索AI&#xff0c;并关闭AI书写的选项就好了 这样就可以获得一个干净的界面了&#xff0c;不…

SPEL表达式及注入漏洞

SPEL,全称为Spring表达式语言&#xff0c;是一个由 Spring 框架提供的表达式语言。它是一种基于字符串的表达式语言&#xff0c;可以在运行时对对象进行查询和操作。 SpEL 支持在XML和注解配置中使用&#xff0c;它可以在Spring框架的各种组件中使用&#xff0c;如Spring MVC …

Visual grounding-视觉定位任务介绍

&#x1f380;个人主页&#xff1a; https://zhangxiaoshu.blog.csdn.net &#x1f4e2;欢迎大家&#xff1a;关注&#x1f50d;点赞&#x1f44d;评论&#x1f4dd;收藏⭐️&#xff0c;如有错误敬请指正! &#x1f495;未来很长&#xff0c;值得我们全力奔赴更美好的生活&…

知识图谱技术综述

作者简介:徐增林(1980 − ),男,博士,教授,主要从事机器学习及其在社会网络分析、互联网、计算生物学、信息安全等方面的研究. 【摘要】 知识图谱技术是人工智能技术的重要组成部分,其建立的具有语义处理能力与开放互联能力的知识库,可在智能搜索、智能问答、个性化推…

Java中抽象类和接口有什么区别?

1、典型回答 接口和抽象类都是用来定义对象公共行为的&#xff0c;二者的主要区别有以下几点不同&#xff1a; 类型扩展不同&#xff1a;抽象类是单继承&#xff0c;而接口是多继承&#xff08;多实现&#xff09;方法/属性访问控制符不同&#xff1a;抽象类方法和属性使用访问…

Yolov8-车辆跟踪(BoT-SORT和ByteTrack算法)

这两种代码都是成熟的&#xff0c;直接调佣即可&#xff0c;下面是使用这两种算法的代码。 直观感受&#xff1a;ByteTrack预测的速度感觉比BoT-SORT快一些&#xff0c;流畅一些。 from ultralytics import YOLOmodel YOLO(yolov8n.pt)# results model.track(source".…

人工智能迷惑行为大赏

文章目录 每日一句正能量前言人工智能的“幽默”瞬间美好愿景背后的潜规则人工智能应用人脸识别视频监控分析自动驾驶/驾驶辅助 后记 每日一句正能量 把坚持当成一种习惯&#xff0c;别人光鲜的背后&#xff0c;都有加倍的付出&#xff0c;没有谁比谁更容易&#xff0c;只有谁比…