java中数组的定义与使用

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[][].

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Javaweb之Maven高级分模块设计与开发的详细解析

1. 分模块设计与开发 1.1 介绍 所谓分模块设计&#xff0c;顾名思义指的就是我们在设计一个 Java 项目的时候&#xff0c;将一个 Java 项目拆分成多个模块进行开发。 1). 未分模块设计的问题 如果项目不分模块&#xff0c;也就意味着所有的业务代码是不是都写在这一个 Java 项…

如何使用最大努力通知实现分布式事务?与本地消息表区别?

什么是最大努力通知&#xff1f; 最大努力通知&#xff08;Best-Effort Notification&#xff09;是一种在分布式系统中处理分布式事务的方法之一&#xff0c;它强调尽力而为&#xff0c;不保证完全的事务一致性&#xff0c;但可以通过一定的机制来提供部分保证。在最大努力通…

程序员有哪些常用的技术网站呢?

在当今信息化时代&#xff0c;程序员们能够通过互联网接触到许多优秀的技术网站&#xff0c;这些网站为他们提供了丰富的学习资源和交流平台。这些技术网站涵盖了各种软件开发、设计、数据分析和人工智能等领域&#xff0c;为程序员们提供了广阔的学习空间和交流机会。在这篇文…

蓝桥杯[OJ 3412]-最小化战斗力差距-CPP-贪心

目录 一、问题描述&#xff1a; 二、整体思路&#xff1a; 三、代码&#xff1a; 一、问题描述&#xff1a; 二、整体思路&#xff1a; 首先每个值都有可能为min(b)&#xff0c;那么对于每个可能为min(b)的值&#xff0c;要使得max(a)尽可能小&#xff0c;因此枚举所有相差最…

每日学习笔记:C++ STL 的List

定义 特点 操作函数 关于c.merge(c2)的分析&#xff0c;详见&#xff1a; 。。。。 C list merge()用法及代码示例 - 纯净天空 (vimsky.com) 异常安全性 运用实例

Python 导入Excel三维坐标数据 生成三维曲面地形图(面) 4-3、线条平滑曲面(原始颜色)去除无效点

环境和包: 环境 python:python-3.12.0-amd64包: matplotlib 3.8.2 pandas 2.1.4 openpyxl 3.1.2 scipy 1.12.0 代码: import pandas as pd import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D from scipy.interpolate import griddata fro…

Arm MMU深度解读

文章目录 一、MMU概念介绍二、虚拟地址空间和物理地址空间2.1、(虚拟/物理)地址空间的范围2.2、物理地址空间有效位(范围) 三、Translation regimes四、地址翻译/几级页表&#xff1f;4.1、思考&#xff1a;页表到底有几级&#xff1f;4.2、以4KB granule为例&#xff0c;页表的…

抽象工厂模式——创建型模式

抽象工厂模式——创建型模式 抽象工厂模式是一种软件设计模式&#xff0c;它解决了在创建一组相关或相互依赖的对象时的一些核心问题。其核心问题包括&#xff1a; 对象的创建与使用分离&#xff1a; 抽象工厂模式通过引入抽象工厂接口以及具体工厂类&#xff0c;将对象的创建与…

高浓度氨氮废水如何处理达标排放

高浓度氨氮废水的处理和达标排放是环境保护工作中的重要任务之一。随着工业化进程的加速和人们环保意识的增强&#xff0c;如何有效处理高浓度氨氮废水已成为一个迫切需要解决的问题。本文将探讨高浓度氨氮废水的处理方法和技术&#xff0c;以确保其达到排放标准&#xff0c;减…

面向IoT物联网的时间序列引擎

1、背景 随着近年来业务的发展&#xff0c;尤其是机器产生的数据占比越来越高的趋势下&#xff0c;时序数据因为其业务价值越来越被更多地关注&#xff0c;也因而催生了专用的时间序列数据库&#xff0c;简称时序数据库&#xff08;TimeSeries Database&#xff0c;TSDB&#x…

leetcode 热题 100_螺旋矩阵

题解一&#xff1a; 模拟&#xff1a;定义四个边界&#xff0c;指针按右下左上的顺序遍历&#xff0c;每遍历一条边&#xff0c;边界就减一&#xff0c;并且在某个方向没有可以遍历的数时直接返回。 import java.util.ArrayList; import java.util.List;class Solution {publi…

Python中的异常处理及最佳实践【第125篇—异常处理】

Python中的异常处理及最佳实践 异常处理是编写健壮、可靠和易于调试的Python代码中不可或缺的一部分。在本文中&#xff0c;我们将深入探讨Python中的异常处理机制&#xff0c;并分享一些最佳实践和代码示例&#xff0c;以帮助您更好地处理错误情况和提高代码的稳定性。 异常…

【2024泰迪杯】C 题:竞赛论文的辅助自动评阅 问题分析及Python 代码实现

【2024泰迪杯】C 题&#xff1a;竞赛论文的辅助自动评阅 Python 代码实现 2024 年(第 12 届)“泰迪杯”数据挖掘挑战赛 C 题&#xff1a;竞赛论文的辅助自动评阅 1 题目 一、问题背景 近年来我国各领域各层次学科竞赛百花齐放&#xff0c;层出不穷&#xff0c;学生参与度也…

NCDA大赛交互网页设计优秀作品有哪些?

现在&#xff0c;越来越多 UX/UI 设计者将互动 / 在其网站设计中添加动画元素(如鼠标悬停状态、音频或视频媒体、滚动交互等。).这样一方面可以让网站本身更加华丽有趣&#xff0c;吸引更多的访问者&#xff0c;激励访问者更加关注和阅读网站内容。这就是为什么互动网站设计已经…

CFINet

文章目录 AbstractIntroductionContributionsRelated Works锚点细化和区域候选小目标检测的特征模拟目标检测的对比学习MethodTowards Better ProposalsLimitations of Cascade RPNCourse-to-fine RPN(CRPN)Loss Function小目标检测的特征模拟范例特征Feat2Embed ModuleLoss …

speexsdp消除回声

这是testecho.c样例的程序。 初始化函数&#xff1a; SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length); 可以看头文件说明&#xff1a;配置frame_size贞大小10-20ms&#xff0c;filter_length滤波长度100-500ms 比如采样频率是16K&#xff0c;fr…

代码签名的等级有哪些?怎么申请?

代码签名有OV,EV两种安全等级的证书&#xff0c;其中OV代码签名证书与EV代码签名证书的主要区别有以下几点&#xff1a; 1. 验证深度&#xff1a; - OV代码签名证书&#xff1a;进行组织验证&#xff0c;即证书颁发机构&#xff08;CA&#xff09;会验证申请者的公司或组织的真…

笔记本电脑已接通电源但未充电怎么办?这里提供8个解决办法

序言 你的笔记本电脑即使插上电源也不会充电吗?虽然大多数情况下,当充电适配器未正确连接时会发生这种情况,但在其他情况下,过时的BIOS或电池驱动程序损坏可能是原因。无论原因是什么,如果笔记本电脑已插入电源但未充电,你可以尝试以下修复程序。 检查笔记本电脑适配器…

视频怎么转成文字?不妨试试这三款AI神器!

在数字化时代&#xff0c;视频内容日益丰富&#xff0c;但有时我们希望能够轻松提取视频中的文字信息&#xff0c;以便快速浏览、编辑或搜索。这时&#xff0c;一款高效、准确的视频转文字应用就显得尤为重要。面对市面上众多的选择&#xff0c;究竟哪款应用能够脱颖而出&#…

SSL---VPN

文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 一.SSL-VPN概述 SLL VPN是一种基于HTTPS&#xff08;即支持SSL的HTTP协议&#xff09;的远程安全接入技术。它充分利用了SSL协议提供的基于证书的身份认证、数据加密和消息完整性验证机制&#…