热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

java数组初始化个数_Java中初始化数组

数组是一种有用的数据类型,用于管理在连续内存位置中建模最好的集合元素。下面是如何有效地使用它们。Coffeebeansandacupofcoffee有使用C或者FOR

数组是一种有用的数据类型,用于管理在连续内存位置中建模最好的集合元素。下面是如何有效地使用它们。

1b5bef66b2f2

Coffee beans and a cup of coffee

有使用 C 或者 FORTRAN 语言编程经验的人会对数组的概念很熟悉。它们基本上是一个连续的内存块,其中每个位置都是某种数据类型:整型、浮点型或者诸如此类的数据类型。

Java 的情况与此类似,但是有一些额外的问题。

一个数组的示例

让我们在 Java 中创建一个长度为 10 的整型数组:

int[] ia = new int[10];

上面的代码片段会发生什么?从左到右依次是:

最左边的 int[] 将变量的类型声明为 int 数组(由 [] 表示)。

它的右边是变量的名称,当前为 ia。

接下来,= 告诉我们,左侧定义的变量赋值为右侧的内容。

在 = 的右侧,我们看到了 new,它在 Java 中表示一个对象正在被初始化中,这意味着已为其分配存储空间并调用了其构造函数(请参见此处以获取更多信息)。

然后,我们看到 int[10],它告诉我们正在初始化的这个对象是包含 10 个整型的数组。

因为 Java 是强类型的,所以变量 ia 的类型必须跟 = 右侧表达式的类型兼容。

初始化示例数组

让我们把这个简单的数组放在一段代码中,并尝试运行一下。将以下内容保存到一个名为 Test1.java 的文件中,使用 javac 编译,使用 java 运行(当然是在终端中):

import java.lang.*;

public class Test1 {

public static void main(String[] args) {

int[] ia = new int[10];                              // 见下文注 1

System.out.println("ia is " + ia.getClass());        // 见下文注 2

for (int i = 0; i

System.out.println("ia[" + i + "] = " + ia[i]);  // 见下文注 4

}

}

让我们来看看最重要的部分。

我们声明和初始化了长度为 10 的整型数组,即 ia,这显而易见。

在下面的行中,我们看到表达式 ia.getClass()。没错,ia 是属于一个类的对象,这行代码将告诉我们是哪个类。

在紧接的下一行中,我们看到了一个循环 for (int i = 0; i

接下来,循环体打印出 ia 的每个元素的值。

当这个程序编译和运行时,它产生以下结果:

me@mydesktop:~/Java$ javac Test1.java

me@mydesktop:~/Java$ java Test1

ia is class [I

ia[0] = 0

ia[1] = 0

ia[2] = 0

ia[3] = 0

ia[4] = 0

ia[5] = 0

ia[6] = 0

ia[7] = 0

ia[8] = 0

ia[9] = 0

me@mydesktop:~/Java$

ia.getClass() 的输出的字符串表示形式是 [I,它是“整数数组”的简写。与 C 语言类似,Java 数组以第 0 个元素开始,扩展到第 - 1 个元素。如上所见,我们可以看到数组 ia 的每个元素都(似乎由数组构造函数)设置为零。

所以,就这些吗?声明类型,使用适当的初始化器,就完成了吗?

好吧,并没有。在 Java 中有许多其它方法来初始化数组。

为什么我要初始化一个数组,有其它方式吗?

像所有好的问题一样,这个问题的答案是“视情况而定”。在这种情况下,答案取决于初始化后我们希望对数组做什么。

在某些情况下,数组自然会作为一种累加器出现。例如,假设我们正在编程实现计算小型办公室中一组电话分机接收和拨打的电话数量。一共有 8 个分机,编号为 1 到 8,加上话务员的分机,编号为 0。 因此,我们可以声明两个数组:

int[] callsMade;

int[] callsReceived;

然后,每当我们开始一个新的累计呼叫统计数据的周期时,我们就将每个数组初始化为:

callsMade = new int[9];

callsReceived = new int[9];

在每个累计通话统计数据的最后阶段,我们可以打印出统计数据。粗略地说,我们可能会看到:

import java.lang.*;

import java.io.*;

public class Test2 {

public static void main(String[] args) {

int[] callsMade;

int[] callsReceived;

// 初始化呼叫计数器

callsMade = new int[9];

callsReceived = new int[9];

// 处理呼叫……

//   分机拨打电话:callsMade[ext]++

//   分机接听电话:callsReceived[ext]++

// 汇总通话统计

System.out.printf("%3s%25s%25s\n", "ext", " calls made",

"calls received");

for (int ext = 0; ext

System.out.printf("%3d%25d%25d\n", ext,

callsMade[ext], callsReceived[ext]);

}

}

}

这会产生这样的输出:

me@mydesktop:~/Java$ javac Test2.java

me@mydesktop:~/Java$ java Test2

ext               calls made           calls received

0                        0                        0

1                        0                        0

2                        0                        0

3                        0                        0

4                        0                        0

5                        0                        0

6                        0                        0

7                        0                        0

8                        0                        0

me@mydesktop:~/Java$

看来这一天呼叫中心不是很忙。

在上面的累加器示例中,我们看到由数组初始化程序设置的零起始值可以满足我们的需求。但是在其它情况下,这个起始值可能不是正确的选择。

例如,在某些几何计算中,我们可能需要将二维数组初始化为单位矩阵(除沿主对角线———左上角到右下角——以外所有全是零)。我们可以选择这样做:

double[][] m = new double[3][3];

for (int d &#61; 0; d <3; d&#43;&#43;) {

m[d][d] &#61; 1.0;

}

在这种情况下&#xff0c;我们依靠数组初始化器 new double[3][3] 将数组设置为零&#xff0c;然后使用循环将主对角线上的元素设置为 1。在这种简单情况下&#xff0c;我们可以使用 Java 提供的快捷方式&#xff1a;

double[][] m &#61; {

{1.0, 0.0, 0.0},

{0.0, 1.0, 0.0},

{0.0, 0.0, 1.0}};

这种可视结构特别适用于这种应用程序&#xff0c;在这种应用程序中&#xff0c;它便于复查数组的实际布局。但是在这种情况下&#xff0c;行数和列数只在运行时确定时&#xff0c;我们可能会看到这样的东西:

int nrc;

// 一些代码确定行数和列数 &#61; nrc

double[][] m &#61; new double[nrc][nrc];

for (int d &#61; 0; d

m[d][d] &#61; 1.0;

}

值得一提的是&#xff0c;Java 中的二维数组实际上是数组的数组&#xff0c;没有什么能阻止无畏的程序员让这些第二层数组中的每个数组的长度都不同。也就是说&#xff0c;下面这样的事情是完全合法的&#xff1a;

int [][] differentLengthRows &#61; {

{1, 2, 3, 4, 5},

{6, 7, 8, 9},

{10, 11, 12},

{13, 14},

{15}};

在涉及不规则形状矩阵的各种线性代数应用中&#xff0c;可以应用这种类型的结构(有关更多信息&#xff0c;请参见此 Wikipedia 文章)。除此之外&#xff0c;既然我们了解到二维数组实际上是数组的数组&#xff0c;那么以下内容也就不足为奇了&#xff1a;

differentLengthRows.length

可以告诉我们二维数组 differentLengthRows 的行数&#xff0c;并且&#xff1a;

differentLengthRows[i].length

告诉我们 differentLengthRows 第 i 行的列数。

深入理解数组

考虑到在运行时确定数组大小的想法&#xff0c;我们看到数组在实例化之前仍需要我们知道该大小。但是&#xff0c;如果在处理完所有数据之前我们不知道大小怎么办&#xff1f;这是否意味着我们必须先处理一次以找出数组的大小&#xff0c;然后再次处理&#xff1f;这可能很难做到&#xff0c;尤其是如果我们只有一次机会使用数据时。

Java 集合框架很好地解决了这个问题。提供的其中一项是 ArrayList 类&#xff0c;它类似于数组&#xff0c;但可以动态扩展。为了演示 ArrayList 的工作原理&#xff0c;让我们创建一个 ArrayList 对象并将其初始化为前 20 个斐波那契数字&#xff1a;

import java.lang.*;

import java.util.*;

public class Test3 {

public static void main(String[] args) {

ArrayList fibos &#61; new ArrayList();

fibos.add(0);

fibos.add(1);

for (int i &#61; 2; i <20; i&#43;&#43;) {

fibos.add(fibos.get(i - 1) &#43; fibos.get(i - 2));

}

for (int i &#61; 0; i

System.out.println("fibonacci " &#43; i &#43; " &#61; " &#43; fibos.get(i));

}

}

}

上面的代码中&#xff0c;我们看到&#xff1a;

用于存储多个 Integer 的 ArrayList 的声明和实例化。

使用 add() 附加到 ArrayList 实例。

使用 get() 通过索引号检索元素。

使用 size() 来确定 ArrayList 实例中已经有多少个元素。

这里没有展示 put() 方法&#xff0c;它的作用是将一个值放在给定的索引号上。

该程序的输出为&#xff1a;

fibonacci 0 &#61; 0

fibonacci 1 &#61; 1

fibonacci 2 &#61; 1

fibonacci 3 &#61; 2

fibonacci 4 &#61; 3

fibonacci 5 &#61; 5

fibonacci 6 &#61; 8

fibonacci 7 &#61; 13

fibonacci 8 &#61; 21

fibonacci 9 &#61; 34

fibonacci 10 &#61; 55

fibonacci 11 &#61; 89

fibonacci 12 &#61; 144

fibonacci 13 &#61; 233

fibonacci 14 &#61; 377

fibonacci 15 &#61; 610

fibonacci 16 &#61; 987

fibonacci 17 &#61; 1597

fibonacci 18 &#61; 2584

fibonacci 19 &#61; 4181

ArrayList 实例也可以通过其它方式初始化。例如&#xff0c;可以给 ArrayList 构造器提供一个数组&#xff0c;或者在编译过程中知道初始元素时也可以使用 List.of() 和 array.aslist() 方法。我发现自己并不经常使用这些方式&#xff0c;因为我对 ArrayList 的主要用途是当我只想读取一次数据时。

此外&#xff0c;对于那些喜欢在加载数据后使用数组的人&#xff0c;可以使用 ArrayList 的 toArray() 方法将其实例转换为数组&#xff1b;或者&#xff0c;在初始化 ArrayList 实例之后&#xff0c;返回到当前数组本身。

Java 集合框架提供了另一种类似数组的数据结构&#xff0c;称为 Map(映射)。我所说的“类似数组”是指 Map 定义了一个对象集合&#xff0c;它的值可以通过一个键来设置或检索&#xff0c;但与数组(或 ArrayList)不同&#xff0c;这个键不需要是整型数&#xff1b;它可以是 String 或任何其它复杂对象。

例如&#xff0c;我们可以创建一个 Map&#xff0c;其键为 String&#xff0c;其值为 Integer 类型&#xff0c;如下&#xff1a;

Map stoi &#61; new Map();

然后我们可以对这个 Map 进行如下初始化&#xff1a;

stoi.set("one",1);

stoi.set("two",2);

stoi.set("three",3);

等类似操作。稍后&#xff0c;当我们想要知道 "three" 的数值时&#xff0c;我们可以通过下面的方式将其检索出来&#xff1a;

stoi.get("three");

在我的认知中&#xff0c;Map 对于将第三方数据集中出现的字符串转换为我的数据集中的一致代码值非常有用。作为数据转换管道的一部分&#xff0c;我经常会构建一个小型的独立程序&#xff0c;用作在处理数据之前清理数据&#xff1b;为此&#xff0c;我几乎总是会使用一个或多个 Map。

值得一提的是&#xff0c;ArrayList 的 ArrayList 和 Map 的 Map 是很可能的&#xff0c;有时也是合理的。例如&#xff0c;假设我们在看树&#xff0c;我们对按树种和年龄范围累计树的数目感兴趣。假设年龄范围定义是一组字符串值(“young”、“mid”、“mature” 和 “old”)&#xff0c;物种是 “Douglas fir”、“western red cedar” 等字符串值&#xff0c;那么我们可以将这个 Map 中的 Map 定义为&#xff1a;

Map> counter &#61; new Map>();

这里需要注意的一件事是&#xff0c;以上内容仅为 Map 的行创建存储。因此&#xff0c;我们的累加代码可能类似于&#xff1a;

// 假设我们已经知道了物种和年龄范围

if (!counter.containsKey(species)) {

counter.put(species,new Map());

}

if (!counter.get(species).containsKey(ageRange)) {

counter.get(species).put(ageRange,0);

}

此时&#xff0c;我们可以这样开始累加&#xff1a;

counter.get(species).put(ageRange, counter.get(species).get(ageRange) &#43; 1);

最后&#xff0c;值得一提的是(Java 8 中的新特性)Streams 还可以用来初始化数组、ArrayList 实例和 Map 实例。关于此特性的详细讨论可以在此处和此处中找到。

本文由 LCTT 原创编译&#xff0c;Linux中国 荣誉推出



推荐阅读
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • 本文介绍了Python高级网络编程及TCP/IP协议簇的OSI七层模型。首先简单介绍了七层模型的各层及其封装解封装过程。然后讨论了程序开发中涉及到的网络通信内容,主要包括TCP协议、UDP协议和IPV4协议。最后还介绍了socket编程、聊天socket实现、远程执行命令、上传文件、socketserver及其源码分析等相关内容。 ... [详细]
  • SpringBoot uri统一权限管理的实现方法及步骤详解
    本文详细介绍了SpringBoot中实现uri统一权限管理的方法,包括表结构定义、自动统计URI并自动删除脏数据、程序启动加载等步骤。通过该方法可以提高系统的安全性,实现对系统任意接口的权限拦截验证。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • 本文介绍了为什么要使用多进程处理TCP服务端,多进程的好处包括可靠性高和处理大量数据时速度快。然而,多进程不能共享进程空间,因此有一些变量不能共享。文章还提供了使用多进程实现TCP服务端的代码,并对代码进行了详细注释。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 本文探讨了C语言中指针的应用与价值,指针在C语言中具有灵活性和可变性,通过指针可以操作系统内存和控制外部I/O端口。文章介绍了指针变量和指针的指向变量的含义和用法,以及判断变量数据类型和指向变量或成员变量的类型的方法。还讨论了指针访问数组元素和下标法数组元素的等价关系,以及指针作为函数参数可以改变主调函数变量的值的特点。此外,文章还提到了指针在动态存储分配、链表创建和相关操作中的应用,以及类成员指针与外部变量的区分方法。通过本文的阐述,读者可以更好地理解和应用C语言中的指针。 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
author-avatar
mobiledu2502883785
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有