java数组 初始化
具有使用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
]
;
// See note 1 below
System .
out .
println
(
"ia is "
+ ia.
getClass
(
)
)
;
// See note 2 below
for
(
int i
=
0
; i
< ia.
length
; i
++
)
// See note 3 below
System .
out .
println
(
"ia["
+ i
+
"] = "
+ ia
[ i
]
)
;
// See note 4 below
}
}
让我们来研究最重要的部分。
- 我们很容易发现和声明10个整数ia的数组。
- 在下面的行中,我们看到表达式ia.getClass() 。 是的, ia是属于class的对象 ,并且此代码将使我们知道是哪个类。
- 在此之后的下一行中,我们看到(int i = 0; i <ia.length; i ++)的循环的开始,该循环定义了循环索引变量i ,该变量的序列范围是从零到小于ia的一个。 length ,它是一个表达式,它告诉我们数组ia中定义了多少个元素。
- 接下来,循环的主体将输出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数组从元素零开始,一直扩展到元素<array size> – 1 。 我们可以在上面看到ia的每个元素都设置为零(似乎是通过数组构造函数)。
那是吗? 我们声明类型,使用适当的初始化程序,我们完成了吗?
好吧,不。 还有许多其他方法可以用Java初始化数组。
为什么我要初始化一个数组?
在某些情况下,数组自然会作为一种累加器出现。 例如,假设我们正在编写代码以计算小型办公室中一组电话分机接收和拨打的电话数量。 有八个分机,编号为1到8,加上话务员的分机,编号为零。 因此,我们可以声明两个数组:
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
;
// initialize call counters
callsMade
=
new
int
[
9
]
;
callsReceived
=
new
int
[
9
]
;
// process calls...
// an extension makes a call: callsMade[ext]++
// an extension receives a call: callsReceived[ext]++
// summarize call statistics
System .
out .
printf
(
"%3s%25s%25s \n " ,
"ext" ,
" calls made" ,
"calls received"
)
;
for
(
int ext
=
0
; ext
< callsMade.
length
; 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
=
0
; d
<
3
; d
++
)
m
[ d
]
[ d
]
=
1.0
;
在这种情况下,我们依靠数组初始化器new double [3] [3]将数组设置为零,然后使用循环将对角元素设置为1。 在这种简单情况下,我们可以使用Java提供的快捷方式:
double
[
]
[
] m
=
{
{
1.0 ,
0.0 ,
0.0
} ,
{
0.0 ,
1.0 ,
0.0
} ,
{
0.0 ,
0.0 ,
1.0
}
}
;
这种视觉结构特别适合此类应用程序,在这种情况下,仔细检查数组的实际布局可能会很有用。 但是在仅在运行时确定行数和列数的情况下,我们可能会看到如下所示:
int nrc
;
// some code determines the number of rows & columns = nrc
double
[
]
[
] m
=
new
double
[ nrc
]
[ nrc
]
;
for
(
int d
=
0
; d
< nrc
; d
++
)
m
[ d
]
[ d
]
=
1.0
;
值得一提的是,Java中的二维数组实际上是数组的数组,没有什么能阻止无畏的程序员让这些第二级数组中的每个数组都具有不同的长度。 也就是说,这样的事情是完全合法的:
int
[
]
[
] differentLengthRows
=
{
{
1 ,
2 ,
3 ,
4 ,
5
} ,
{
6 ,
7 ,
8 ,
9
} ,
{
10 ,
11 ,
12
} ,
{
13 ,
14
} ,
{
15
}
}
;
有许多涉及不规则形状矩阵的线性代数应用,可以在其中应用这种类型的结构(有关更多信息,请参阅此Wikipedia文章作为起点)。 除此之外,既然我们了解到二维数组实际上是数组的数组,那么以下内容也就不足为奇了:
differentLengthRows.
length
告诉我们二维数组differentLengthRows中的行数,以及:
differentLengthRows
[ i
] .
length
告诉我们differentLengthRows的第i行中的列数。
使阵列更进一步
考虑到在运行时确定数组大小的想法,我们看到数组在实例化它们之前仍需要我们知道该大小。 但是,如果在处理完所有数据之前不知道大小怎么办? 这是否意味着我们必须处理一次以找出数组的大小,然后再次处理? 这可能很难做到,尤其是如果我们只有一次机会使用数据时。
Java Collections Framework很好地解决了这个问题。 所提供的功能之一是ArrayList类,它类似于一个数组,但可以动态扩展。 为了演示ArrayList的工作原理,让我们创建一个并将其初始化为前20个斐波纳契数 :
import
java.lang.*
;
import
java.util.*
;
public
class Test3
{
public
static
void main
(
String
[
] args
)
{
ArrayList
< Integer
> fibos
=
new ArrayList
< Integer
>
(
)
;
fibos.
add
(
0
)
;
fibos.
add
(
1
)
;
for
(
int i
=
2
; i
<
20
; i
++
)
fibos.
add
( fibos.
get
( i
-
1
)
+ fibos.
get
( i
-
2
)
)
;
for
(
int i
=
0
; i
< fibos.
size
(
)
; i
++
)
System .
out .
println
(
"fibonacci "
+ i
+
" = "
+ fibos.
get
( i
)
)
;
}
}
在上方,我们看到:
- 用于存储Integer的ArrayList的声明和实例化。
- 使用add()追加到ArrayList实例。
- 使用get()通过索引号检索元素。
- 使用size()确定ArrayList实例中已经有多少个元素。
put()方法未显示,该方法将值放置在给定的索引号处。
该程序的输出为:
fibonacci
0 =
0
fibonacci
1 =
1
fibonacci
2 =
1
fibonacci
3 =
2
fibonacci
4 =
3
fibonacci
5 =
5
fibonacci
6 =
8
fibonacci
7 =
13
fibonacci
8 =
21
fibonacci
9 =
34
fibonacci
10 =
55
fibonacci
11 =
89
fibonacci
12 =
144
fibonacci
13 =
233
fibonacci
14 =
377
fibonacci
15 =
610
fibonacci
16 =
987
fibonacci
17 =
1597
fibonacci
18 =
2584
fibonacci
19 =
4181
ArrayList实例也可以通过其他技术进行初始化。 例如,可以将数组提供给ArrayList构造函数,或者在编译时知道初始元素时,可以使用List.of()和Arrays.asList()方法。 我发现自己并没有经常使用这些选项,因为ArrayList的主要用例是我只想读取一次数据。
而且,对于那些喜欢在数据加载后就使用数组的人,可以使用其ArrayList实例的toArray()方法将其转换为数组。 或者,在初始化ArrayList实例后返回当前主题。
Java Collections Framework提供了另一种类似于数组的数据结构,称为Map 。 我所说的“类似数组”是指Map定义了一个对象集合,这些对象的值可以通过键设置或检索,但与数组(或ArrayList )不同的是,该键不必是整数。 它可以是String或任何其他复杂对象。
例如,我们可以创建一个Map,其键为String ,其值为Integer ,如下所示:
然后,我们可以按如下方式初始化此Map :
stoi.
set
(
"one" ,
1
)
;
stoi.
set
(
"two" ,
2
)
;
stoi.
set
(
"three" ,
3
)
;
等等。 稍后,当我们想知道“ three”的数值时,可以将其检索为:
stoi.
get
(
"three"
)
;
在我的世界中, 地图可用于将第三方数据集中出现的字符串转换为我的数据集中的一致代码值。 作为数据转换管道的一部分,我通常会构建一个小型独立程序,以在处理数据之前对其进行清理。 为此,我几乎总是使用一个或多个Map 。
值得一提的是,拥有ArrayLists的ArrayLists和Map的Map很有可能,有时甚至是合理的。 例如,假设我们正在看树,并且对按树种和年龄范围累加树数的计数感兴趣。 假设年龄范围定义是一组字符串值(“年轻”,“中”,“成熟”和“旧”),并且该种类是诸如“道格拉斯冷杉”,“西部红柏”和“等等,那么我们可以定义一个地图 S作为的:
这里需要注意的一件事是,以上内容仅为Map的行创建存储。 因此,我们的累积代码可能类似于:
// assume at this point we have figured out the species
// and age range
if
(
! counter.
containsKey
( species
)
)
counter.
put
( species,
new Map
<
String ,Integer
>
(
)
)
;
if
(
! counter.
get
( species
) .
containsKey
( ageRange
)
)
counter.
get
( species
) .
put
( ageRange,
0
)
;
在这一点上,我们可以开始累积为:
counter.
get
( species
) .
put
( ageRange,
counter.
get
( species
) .
get
( ageRange
)
+
1
)
;
最后,值得一提的是(Java 8中的新增功能)Streams工具还可用于初始化数组, ArrayList实例和Map实例。 有关此功能的详细讨论可以在此处和此处找到。
翻译自: https://opensource.com/article/19/10/initializing-arrays-java
java数组 初始化