[???] /
[Java FAQ] / [S006]
S006: 配列 - array
[S006-Q01]
Java の配列はどのようなものですか?
[S006-A01]
配列はオブジェクトの一種で、同じ型の変数の並びであり、
個々の変数は0から始まる整数値によって特定されます。
いくつか例を挙げます。
(1)int[] a = new int[100];
整数の配列型の変数aを、100個の要素を持つように初期化しています。
(2)String[] messages;
文字列の配列型の変数 messages を定義しています。
このままでは初期化されていないので配列として使用することができません。
例えば以下のように初期化してから使用します。
messages = new String[10];
(3)int a[100];
誤りです。Java ではこのような表記はできません。
配列の要素数は new したときに決まります。上記(1)の場合は、
要素数は100で、a[0]〜a[99] で個々の要素にアクセスします。
初期化や参照する際の[]内の値に変数や式を使うことも可能です。
この値に範囲外の数値を指定すると、
ArrayIndexOutOfBoundsException が発生します。
配列はオブジェクトですので、java.lang.Object 型として
扱うことができます。たとえば、java.lang.Object のメソッドは配列型の
変数に対しても呼ぶことができます。
Foo[] foo = new Foo[5]; // Foo 型の配列型 Foo[] の変数 foo を初期化
int hash = foo.hashCode(); // foo のハッシュ値を得る
配列を初期化した場合、各要素の値は S012-01 にしたがって初期化されます。
int[] bar = new int[10]; // bar[0]〜bar[9]は 0 となる
Button[] baz = new Button[5]; // baz[0]〜baz[4]は null となる
[S006-Q02]
配列を一括して初期化するにはどうすれば良いですか?
[S006-A02]i
要素を ',' (カンマ) で区切って並べ、'{'、'}' (中括弧) で括ります。
オブジェクトをnewで生成して含ませることもできます。
以下のようにすれば配列を一括して初期化することができます。
class Foo {
String name;
Foo (String name) {
this.name = name;
}
}
class Table {
static Foo[] bar = { //一括して初期化する
new Foo( "C" ),
new Foo( "C++" ),
new Foo( "COBOL" ),
new Foo( "PASCAL" )
};
static int[] baz = { //一括して初期化する
1,
2,
3,
4
};
}
参考記事 [JavaHouse-Brewers:2317]
[S006-Q03]
配列の内容をメソッドに渡したいのですが?
[S006-A03]
普通のオブジェクトと同様に渡すことができます。
具体的には、次のように記述します。
public class ArrayPassingTest {
// String の配列(String[] 型のオブジェクト)を引数に取るメソッド
static void passed(String[] array) {
for (int i = 0; i < array.length; i++)
System.out.println(array[i]);
}
public static void main(String[] args) {
String[] a = { "foo", "bar", "baz" };
passed(a); // 配列を引数として passed メソッドを呼ぶ
}
}
参考記事 [JavaHouse-Brewers:2750]
[S006-Q04]
配列の要素数を知るには?
[S006-A04]
配列のlengthフィールドによって参照できます。
String[] array = {"first", "second", "third"};
int lengthOfArray = array.length;
とすれば array の要素の個数 3 が lengthOfArray に入ります。
参考記事 [JavaHouse-Brewers:1621]
[S006-Q05]
配列をコピーしたいのですが?
配列を宣言するときは String theString[] と String[] theString のどちらが
いいですか?
[S006-A05]
clone() を使いましょう。
class ArrayCopyTestByClone {
public static void main(String[] argv) {
String[] source = { "foo", "bar", "baz" }; // コピー元の配列
// source のコピーを作成する。
String[] destination = (String[])source.clone();
// 結果を確認する
for (int i = 0; i < destination.length; i++) {
System.out.println(destination[i]);
}
}
}
for や arraycopy を使うことで、部分的にコピーすることもできます。
class ArrayCopyTestByFor {
public static void main(String[] argv) {
String[] source = { "foo", "bar", "baz" }; // コピー元の配列
String[] destination = new String[source.length];
for (int i = 0; i < source.length; i++) { // コピー元の個数分ループする
destination[i] = source[i];
}
// 結果を確認する
for (int j = 0; j < destination.length; j++) {
System.out.println(destination[j]);
}
}
}
class ArrayCopyTestByArraycopy {
public static void main(String[] argv) {
String[] source = { "foo", "bar", "baz" }; // コピー元の配列
// コピー先の配列を用意する
String[] destination = new String[source.length];
// source の 0 番目から source.length 個を destination の 0 番目からへコピーする
System.arraycopy(source, 0, destination, 0, source.length);
// 結果を確認する
for (int i = 0; i < destination.length; i++) {
System.out.println(destination[i]);
}
}
}
S006-09 も参照してください。
[S006-Q06]
Java で多次元配列はどう書くのですか?
[S006-A06]
配列の配列を使用します。
int[][] array = new int[3][]; // int[] の配列
array[0] = new int[4];
array[1] = new int[4];
array[2] = new int[4];
各要素の長さを変えて、
int[][] array = new int[3][]; // int[] の配列
array[0] = new int[5];
array[1] = new int[2];
array[2] = new int[7];
のようなこともできます。
前者のように、各配列の要素数が同じ場合、
int[][] array = new int[3][4];
のように書くことができます。
参考記事 [JavaHouse-Brewers:22163]
[S006-Q07]
連想配列を使いたいのですが?
[S006-A07]
java.util.Hashtable を使ってください。
参考記事 [JavaHouse-Brewers:3881] [JavaHouse-Brewers:4051]
[S006-Q08]
配列の要素を参照しようとするとNullPointerExceptionが発生するのですが?
[S006-A08]
配列自身が new されていないか、配列の要素が new されていないからです。
次は前者の例です。
class Foo {
String[] array;
Foo() {
array[0] = "bar";
}
}
次のようにしてください。
class Foo {
String[] array = new String[10];
Foo() {
array[0] = "bar";
}
}
次は後者の例です。
class Foo {
String[] array = new String[10];
Foo() {
System.out.println(array[0].length());
}
}
次のように、あらかじめ値を代入してください。
class Foo {
String[] array = new String[10];
Foo() {
for (int i = 0; i < array.length; i++) {
array[i] = "baz";
}
System.out.println(array[0].length());
}
}
[S006-Q09]
コピーした配列の要素を書き換えると元の配列でも書き換わってしまうのですが?
[S006-A09]
配列をコピーした際に、配列の要素がコピーされていないからです。
オブジェクトのコピーには Shallow コピーと、 Deep コピーの2つがあります。
どちらのコピーを行っているのかを意識して使用する必要があります。
例えば、System#arraycopy() は Shallow コピーです。
以下にコード例を示します。
import java.awt.Point;
class ShallowDeep {
public static void main(String[] args) {
Point[] points = new Point[2];
points[0] = new Point(10, 10);
points[1] = new Point(20, 20);
Point[] shallow = new Point[2];
System.arraycopy(points, 0, shallow, 0, 2);
Point[] deep = new Point[2];
for (int i = 0; i < points.length; i++) {
deep[i] = (Point)points[i].clone();
}
show("points", points);
show("shallow", shallow);
show("deep", deep);
System.out.println("");
System.out.println("--- modify shallow ---");
System.out.println("");
shallow[0].x = 30;
deep[1].x = 40;
show("points", points);
show("shallow", shallow);
show("deep", deep);
}
static void show(String label, Point[] array) {
System.out.println(label + " ----");
for (int i = 0; i < array.length; i++) {
System.out.println("\t[" + i + "].x: " + array[i].x);
}
}
}
実行結果は以下のようになります。
points----
[0].x:10
[1].x:20
shallow----
[0].x:10
[1].x:20
deep----
[0].x:10
[1].x:20
--- modify shallow ---
points----
[0].x:30
[1].x:20
shallow----
[0].x:30
[1].x:20
deep----
[0].x:10
[1].x:40
このように、Shallow コピーを行った場合、コピー先の配列の内容を変更すると
コピー元の配列の値も書き換わってしまいますので注意しましょう。
[S006-Q10]
配列の長さを変更したいのですが?
[S006-A10]
できないので、新しい配列を new するか、java.util.Vector などを使います。
int[] array = new int[10]; // 長さ10の配列
...
array = new int[20]; // 長さ20の配列を作り直す
Vector vector = new Vector();
System.out.println(vector.size()); // この時点では vector のサイズは 0
vector.add("foo"); // vector のサイズを 1 増やし、最初の要素を "foo" にする。
System.out.println(vector.size()); // この時点では vector のサイズは 1
System.out.println(vector.elementAt(0)); // 最初の要素である "foo" を出力する
[S006-Q11]
配列の new ではその各要素の new まではなされないのですか?
[S006-A11]
されません。
String[] theStringArray = new String[10];
上のように配列をインスタンス化してもその要素まではインスタンス化され
ません。なぜなら、配列とは変数を並べたものであり、配列の new は並べ
られた変数の領域を確保するだけだからです。また、それらの変数の値は null
にセットされます(参照型の配列の場合)。
参考記事 [JavaHouse-Brewers:1880]
[S006-Q12]
配列の初期化とはどういう意味ですか?
[A2]
Java では配列の初期化は要素の変数領域を確保しているだけです。
HogeClass[] foo = new HogeClass[N];
とした場合、N 個の領域を確保することが初期化を意味します。
S006-11 も参照してください。
参考記事 [JavaHouse-Brewers:6192]
[S006-Q13]
配列を宣言するときの [] の書き方は?
配列を宣言するときは String theString[] と String[] theString のどちらが
いいですか?
[S006-A13]
配列の宣言は以下のようにどちらの書き方もできます。
String[] a;
String b[];
上のa、bどちらの書き方も可能ですが、インスタンス化するときには
String[] s = new String[3];
^^^^^^^^^
というように String[] 型をインスタンス化するのですから
クラス名[] 変数名;
と書くほうが自然であると言えます。同様の理由で関数を宣言するときも、
public String getString()[] {...}
よりも
public String[] getString() {...}
の方が良いでしょう。
参考記事 [JavaHouse-Brewers:4419]
[S006-Q14]
配列 a の要素数を調べるには「a.length」と「a.length()」のどちらを使えば良いですか?
[S006-A14]
a.length を使います。a.length には配列 a の要素数が格納されています。
配列 a に対して a.length() は一般的に出来ません。何故なら、配列型に
length() というメソッドは存在しないからです。
class NoneLengthMethod {
public static void main(String[] args) {
NoneLengthMethod[] o = new NoneLengthMethod[4];
System.out.println("length: " + o.length);
//System.out.println("length: " + o.length());//これはエラー
}
}
実行結果
>java NoneLengthMethod
length: 4
参考記事 [JavaHouse-Brewers:5708]
[S006-Q15]
配列オブジェクトに対してclone()できますか?
[S006-A15]
出来ることは出来ますが、このとき、内部データ構造のコピーが必要な場合
もあります。
S006-11 も参照してください。
参考記事 [JavaHouse-Brewers:24157], [JavaHouse-Brewers:7720], [JavaHouse-Brewers:7993]
[S006-Q16]
二次元配列に対して arraycopy は使えるのでしょうか?
[S006-A16]
使えません。Javaでは二次元配列は配列の配列なので以下の方法で代用できます。
class TwoDimensionArray {
public static void main(String[] args) {
String[][] srcArray = new String[10][10];
String[][] dstArray;
dstArray = new String[srcArray.length][];
for (int i=0; i<srcArray.length; i++) {
dstArray[i] = new String[srcArray[i].length];
System.arraycopy(srcArray[i], 0, dstArray[i], 0, srcArray[i].length);
}
}
}
参考記事 [JavaHouse-Brewers:22109]
[S006-Q17]
二次元配列で列のコピーはどうすれば良いですか?
[S006-A17]
以下の方法でコピーできます。
class ColumnCopy {
public static void maint(String[] args) {
String[][] theArray = new String[10][10];
int theColumn = 3;//コピー元の列
String[] recvArray = new String[theArray.length];
for (int i=0; i<theArray.length; i++) {
recvArray[i] = new String(theArray[i][theColumn]);
}
}
}
参考記事 [JavaHouse-Brewers:22113]
[S006-Q18]
長さが 0 の配列も作れるのですか?
[S006-A18]
はい、作れます。
class ZeroArray {
public static void main(String[] args) {
String[] theArray;
theArray = new String[0];
}
}
とやれば長さが 0 の配列を作れます。使い道としては余りありませんが、
あえて利用するなら以下のようにでしょう。
class EchoArgs {
public EchoArgs(String[] args) {
if (args.length == 0) {//長さ 0 の配列ができたとき
printUsage();
}
else {
printArgs(args);
}
}
public void printUsage() {
System.out.println("Usage: Please input more than one args...");
}
public void printArgs(String[] args) {
for (int i=0; i<args.length; i++) {
System.out.println(args[i]);
}
}
public static void main(String[] args) {
new EchoArgs(args);
}
}
実行結果:
>java EchoArgs one two
one
two
>java EchoArgs
Usage: Please input more than one args...
参考記事 [JavaHouse-Brewers:7184]
contributor: YAMADA Yoshihiko
コメントの送り先:Java FAQ BBS