目次 | | | 索引 Java言語規定
第2版

6. 名前

名前は,プログラムで宣言した実体を参照するために使用する。宣言した実体 (6.1) は,パッケージ,クラス型,インタフェース型,参照型のメンバ(クラス,インタフェース,フィールド又は,メソッド),(メソッド,コンストラクタ又は例外ハンドラに対する)仮引数又は局所変数とする。

プログラムにおける名前は,単一の識別子で構成される単純名又は"."トークンで区切られる識別子の並びから構成される限定名 (6.2)のいずれかとする。

宣言によって導入したすべての名前は, 有効範囲(scope) (6.3)をもつ。有効範囲とは,その中から,宣言した実体が単純名によって参照できるプログラムテキストの一部分とする。

パッケージ及び参照型(つまり,クラス型,インタフェース型及び配列型)は,メンバ(6.4)をもつ。メンバは,限定名 N.x を使用して参照可能とする。 ここで Nは単純名又は限定名とし,x は識別子とする。N がパッケージに名前付けをしていれば,x はそのパッケージのメンバ,つまり,クラス型,インタフェース型又は下位パッケージのいずれかとする。N が参照型又は参照型の変数に名前付けしていれば,x はその型のメンバ,すなわちフィールド又はメソッドに名前付けする。

名前の意味の決定(6.5)においては,同じ名前をもったパッケージ,型,変数及びメソッドの間のあいまいさを解消するために,名前が出現する文脈を使用する。

アクセス制御(6.6)は,メンバへのアクセス(access)が許可されるときを制御するために,クラス,インタフェース,メソッド又はフィールドの宣言で指定できる。アクセスは,有効範囲とは異なる概念とする。アクセスは,宣言した実体が,限定名,フィールドアクセス式(15.11)又はメソッドを単純名で指定しない場合のメソッド呼出し式(15.12) によって参照できる,プログラムテキストの部分を指定する。 デフォルトアクセスでは,メンバ宣言を含んでいるパッケージ内のどこからでも,そのメンバにアクセスできる。その他には,publicprotected 及び private がありうる。

完全限定及び正準名(6.7)及び名前付け規約(6.8)についてもこの章で述べる。

フィールド,仮引数又は局所変数の名前は,式(15.14.1)として使用できる。 メソッドの名前は,メソッド呼出し式(15.12)の一部としてだけ式に出現してよい。クラス又はインタフェース型の名前は,クラスリテラル(15.8.2),限定this式(15.8.4),クラスインスタンス生成式(15.9),配列生成式(15.10),キャスト式(15.16),若しくは instanceof(15.20.2)の一部分,又はフィールド若しくはメソッドに対する限定名の一部としてだけ式に出現してよい。パッケージの名前は,クラス型又はインタフェース型の限定名の一部としてだけ式に出現してよい。

6.1 宣言

宣言(declaration) は,プログラムに実体を導入し,この実体を参照するために名前として使用できる識別子(3.8)を取り入れる。宣言される実体は,次のいずれかとする。

コンストラクタ(8.8)もまた宣言によって導入される。しかし,新しい名前を導入せずに,宣言されているクラスの名前を使用する。

6.2 名前及び識別子

名前(name)は,プログラムで宣言した実体を参照するために使用する。

名前には,単純名及び限定名の二つの形式が存在する。単純名(simple name) は,単一の識別子とする。限定名(qualified name) は,名前,"." トークン及び識別子から構成する。

名前の意味の決定 (6.5)においては,名前が出現する文脈を考慮する。規則(6.5)は,どの文脈で,名前が,パッケージ(6.5.3),型(6.5.5),式(6.5.6),又はメソッド(6.5.7) における変数若しくは値を表示(参照)しなければならないかを識別する。

プログラムにおける識別子すべてが,名前の一部になるとは限らない。識別子は,次の状況においても使用する。

次に例を示す。

class Test {
	public static void main(String[] args) {
		Class c = System.out.getClass();
		System.out.println(c.toString().length() +
					args[0].length() + args.length);
	}
}
識別子 Testmain 並びに最初に出現する args 及び c は名前ではない。これらは,宣言した実体の名前を指定するために使用されている。名前 String, Class, System.out.getClass, System.out.println, c.toString, args 及び args.lengthが例の中に出現している。length の最初の出現は名前とはしない。メソッド呼出し式(15.12)で出現する識別子とする。二番目に出現する length も名前とはしない。 メソッド呼出し式 (15.12)で出現する識別子とする。

ラベル付き文,並びにそれに関連のある break 及び continue 文で使用する識別子は,宣言で使用する識別子とは完全に区別する。したがって次に示すコードは正しい。

class TestString {
	char[] value;
	int offset, count;
	int indexOf(TestString str, int fromIndex) {
		char[] v1 = value, v2 = str.value;
		int max = offset + (count - str.count);
		int start = offset + ((fromIndex < 0) ? 0 : fromIndex);
	i:
		for (int i = start; i <= max; i++)
		{
			int n = str.count, j = i, k = str.offset;
			while (n-- != 0) {
				if (v1[j++] != v2[k++])
					continue i;
			} 
			return i - offset;
		}
		return -1;
	}
}
このコードは,クラス String 及びそのメソッド indexOfのある版からもって来た。元の版では,ラベルは test と呼ばれていた。ラベルを,局所変数 iと同じ名前をもつように変更しても,iの宣言の有効範囲においてそのラベルを不明瞭化(6.3.2)しない。識別子 maxも,文ラベルとして使用できた。つまり,ラベルは,ラベル付き文内の局所変数 max を隠ぺいしない。

6.3 宣言の有効範囲

宣言の有効範囲(scope) は,宣言によって宣言した実体が,単純名を(可視(6.3.1)である場合に)使って参照可能なプログラムの領域とする。宣言がプログラムの特定の箇所で有効範囲にある(in scope) 必要十分条件は,宣言の有効範囲がその箇所を含むこととする。

各構成要素の有効範囲規則は,その構成要素について記述する節で与える。便宜上,それらの規則をここで繰り返して述べる。

観察可能な(7.4.3)最上位パッケージの宣言の有効範囲は,すべての観察可能コンパイルユニット(7.3)とする。観察可能でないパッケージの宣言は,有効範囲に入らない。下位パッケージの宣言は,有効範囲に入らない。

単一の型インポート宣言 (7.5.1) 又は要求時の型インポート宣言(7.5.2) によってインポートした型の有効範囲は,そのインポート宣言が出現するコンパイル単位におけるすべてのクラス及びインタフェース型宣言(7.6)とする。

最上位型の有効範囲は,その最上位型が宣言されているパッケージにおけるすべての型宣言とする。

ラベル文によって宣言されたラベルの有効範囲は,そのラベル文で直接取り囲まれた文とする。

クラス型Cにおいて宣言又は継承したメンバ宣言の有効範囲は,入れ子になった型宣言を含めて,C本体の全体とする。

インタフェース型I において宣言又は継承したメンバ宣言の有効範囲は,入れ子になった型宣言を含めて,I 本体の全体とする。

メソッド(8.4.1)又はコンストラクタ(8.8.1)の仮引数の有効範囲は,そのメソッド又はコンストラクタの本体の全体とする。

ブロック(14.4.2)における局所変数宣言の有効範囲は,宣言が出現したブロックの残りの部分とする。これは,それ自体の初期化子(14.4)で始まり,その局所変数の宣言文中で,さらに右側に続く宣言子を含む。

ブロックで宣言された局所クラスの有効範囲は,直ちに取り囲むブロックの残りとする。これは,それ自身のクラス宣言を含む。

for(14.13)ForInit 部において宣言した局所変数の有効範囲は,次のすべてを含む。

try(14.19)catch 節で宣言した例外ハンドラの仮引数の有効範囲は,catch と関連するブロックの全体とする。

これらの規則は,クラス及びインタフェース型の宣言が,型の使用前に出現する必要がないことを示唆している。

次に例を示す。

package points;
class Point {
	int x, y;
	PointList list;
	Point next;
}
class PointList {
	Point first;
}
クラス PointPointListの使用は正しい。これはクラス型の名前PointListの有効範囲が,パッケージ points の他のコンパイル単位 における他の型宣言でも同様に,クラス Point 及びクラス PointListの両方を含むからとする。

6.3.1 宣言のおおい隠し

宣言は,同じ名前の他の宣言によって,有効範囲の一部をおおい隠される(shadowed) ことがある。この場合,単純名は宣言した実体を参照するために使用できない。

名前n の型宣言d は,d が出現した時点ならびにd の有効範囲にある他のすべての名前n の型宣言をおおい隠す。

名前nのフィールド,局所変数,メソッド仮引数,コンストラクタ仮引数,又は例外ハンドラ仮引数の宣言d は,d が出現した時点ならびにd の有効範囲にある他のすべての名前n のフィールド,局所変数,メソッド仮引数,コンストラクタ仮引数,又は例外ハンドラ仮引数の宣言をおおい隠す。

名前n のラベルの宣言d は,d が出現した時点ならびにd の有効範囲にある他のすべての名前n のラベルの宣言をおおい隠す。

名前n のメソッド宣言d は,d が出現した時点ならびにd の有効範囲にある他のすべての名前n のメソッド宣言をおおい隠す。

パッケージ宣言は,他の宣言を決しておおい隠さない。

名前n の型を輸入するパッケージp のコンパイル単位c の単一の型インポート宣言d は,c の中の次の宣言をおおい隠す。

要求時の型インポート宣言は,他のどのような宣言もおおい隠さない。

宣言dプログラム中時点p で可視(visible)であるための条件は,d の有効範囲がpを含み,かつ,p での他の宣言によってd がおおい隠されないこととする。文脈から論じているプログラム時点が明白な場合には,単に宣言が可視であるという。

このおおい隠すことが隠ぺい(8.3, 8.4.6.2, 8.5, 9.3, 9.5)とは,異なることに注意。本規定において定義された技術的意味での隠ぺいは,下位クラスでの宣言という理由ではなく,さもなくば継承されたであろうメンバにのみ適用される。おおい隠すことは,また不明瞭化(6.3.2)とも異なる。

次に,局所変数によりフィールド宣言のおおい隠された例を示す。

class Test {
	static int x = 1;
	public static void main(String[] args) {
		int x = 0;
		System.out.print("x=" + x);
		System.out.println(", Test.x=" + Test.x);
	}
}
これは次を出力する。

x=0, Test.x=1
この例は,次のものを宣言している。

クラス変数の有効範囲は,クラス(8.2) の本体の全体を含むので,クラス変数 x はメソッド main の本体の全体を通して普通に利用できる。しかし,この例では,局所変数 x の宣言によって,クラス変数 x はメソッド main の本体内でおおい隠される。

局所変数は,宣言(14.4.2)されたブロックの残りの部分を有効範囲とする。この例の場合,これはメソッド main の本体の残りの部分,つまり,初期化子"0" 並びに print 及び println の呼出しの部分とする。

これは次を意味する。

次の例は,ある型宣言が他のによっておおい隠されることを示す。
import java.util.*;
class Vector {
	int val[] = { 1 , 2 };


}

class Test { public static void main(String[] args) { Vector v = new Vector(); System.out.println(v.val[0]); } }

これはコンパイルされ、次を出力する。

1
ここで宣言したクラス Vectorは,要求時にインポートするかもしれないクラス java.util.Vector よりも優先して使用される。

6.3.2 不明瞭化された宣言

単純名は,変数,型,又はパッケージの名前として解釈される可能性のある文脈で出現する。この状況で,6.5の規則は,変数が型よりも優先して選ばれ,型が,パッケージよりも優先して選ばれるものと規定する。したがって,その単純名を用いて,可視な型又はパッケージ宣言を参照することが,時には不可能となる。このような宣言は,不明瞭だ(obscured)と言う。

不明瞭化は,おおい隠されること(6.3.1) とは異なり,かつ,隠ぺい(8.3, 8.4.6.2, 8.5, 9.3, 9.5)とも異なる。6.8の名前規約は,不明瞭さを減少させるのに役立つ。

6.4 メンバ及び継承

パッケージ及び参照型は, メンバ(member) をもつ。

6.4では,限定名の議論及び名前の意味の決定についての背景として,パッケージ及び参照型のメンバの概要を示す。メンバの完全な説明については,7.1, 8.2, 9.2, 及び 10.7を参照のこと。

6.4.1 パッケージのメンバ

パッケージ(7.)のメンバは,7.1で規定される。便宜上,ここにその規定を繰り返す。

パッケージのメンバは,下位パッケージ又はそのパッケージのすべてのコンパイル単位(7.3) で宣言された最上位(7.6)クラス型(8.)若しくは最上位インタフェース(9.) 型とする。

一般に,あるパッケージの下位パッケージは,ホストシステム(7.2)によって決定される。しかし,パッケージ java は,常に 下位パッケージlang 及びio を含み,さらに,その他の下位パッケージを含んでもよい。同じパッケージの二つの異なるメンバは,同じ単純名(7.1)をもってはならない。しかし異なるパッケージのメンバは,同じ単純名をもってもよい。

例えば,次のパッケージ宣言は可能とする。

package vector;
public class Vector { Object[] vec; }
これは標準パッケージ java.util が,Vector という名前のクラスを宣言しているのにもかかわらず,Vector という名前のpublicクラスをメンバとしてもつ。これら二つのクラス型は,これらが異なる完全限定名(6.7)をもつ事実によって分かるように,異なっている。この例の Vector の完全限定名は vector.Vectorとする。これに対して java.util.Vector が,標準クラス Vector の完全な限定名である。パッケージ vectorVector という名前のクラスを含むので,Vectorという名前の下位パッケージをもつことはできない。

6.4.2 クラス型のメンバ

クラス型(8.2) のメンバは,クラス(8.5, 9.5),インタフェース(8.5, 9.5),フィールド(8.3, 9.3, 10.7)及びメソッド(8.4, 9.4)とする。メンバは,その型で宣言されるか継承されるものとする。それは,private,隠ぺい,又は上書きされていない(8.4.6)上位クラス又は上位インタフェースのアクセス可能メンバであるという理由による。

クラス型のメンバは,次に示すものすべてとする。

コンストラクタ(8.8) はメンバとしない。

同じ単純名をもつクラス型のフィールド及びメソッドに対する制限は存在しない。同様に,そのクラス型のフィールド又はメソッドとして同じ単純型を持つクラス型のメンバクラス又はメンバインタフェースに対しては何の制限もない。

異なるインタフェースで宣言され継承されるならば,クラスは同じ名前で二つ以上のフィールドをもってよい。そのフィールドを単純名で参照しようとすると,コンパイル時エラーを生じる(6.5.7.2, 8.2)。

次に例を示す。

interface Colors {
	int WHITE = 0, BLACK = 1;
}
interface Separates {
	int CYAN = 0, MAGENTA = 1, YELLOW = 2, BLACK = 3;
}
class Test implements Colors, Separates {
	public static void main(String[] args) {
		System.out.println(BLACK); // compile-time error: ambiguous
	}
}
メソッド main 内の名前BLACK はあいまいである。 クラス Test は,BLACK という名前の二つのメンバ,Colors から継承されたもの及び Separates から継承されたもの,をもつからである。

クラス型は,メソッドが異なるシグネチャ(8.4.2)をもてば,つまり,仮引数の数が違うか,又は少なくとも一つの仮引数の型が違うならば,同じ単純名で二つ以上のメソッドをもってもよい。このようなメソッドのメンバ名は, オーバロードされる(overloaded) という。

クラス型は,上位クラス又は上位インタフェースから別途継承され得るメソッドと同じ名前及び同じシグネチャをもつメソッドの宣言を含んでいてもよい。この場合,その上位クラス又は上位インタフェースのメソッドは,継承されない。継承されないメソッドが abstract であれば,新しい宣言はそれを 実装(implement)するという。継承されないメソッドが abstract でなければ,新しい宣言はそれを 上書き(override) するという。

次に例を示す。

class Point {
	float x, y;
	void move(int dx, int dy) { x += dx; y += dy; }
	void move(float dx, float dy) { x += dx; y += dy; }
	public String toString() { return "("+x+","+y+")"; }
}
クラス Point は,同じ名前 move をもつメソッドを二つもつ。特定のメソッド呼出しで選択されるクラス Point のオーバロードされたメソッドmove は,15.12で与えられたオーバロード解決手順によってコンパイル時に決定される。

この例では,クラス Point のメンバは,Point で宣言された floatインスタンス変数 x 及びy ,二つの宣言されたメソッド move,宣言されたメソッド toString,並びにメソッド hashCodeのような Point がその暗黙の直接的上位クラス Object (4.3.2) から継承するメンバとする。Point はクラス Object のメソッド toStringを継承していないことに注意すること。これは,そのメソッドがクラス Point 内のメソッド toString の宣言によって上書きされているからである。

6.4.3 インタフェース型のメンバ

インタフェース型(9.2) のメンバは,クラス(8.5, 9.5),インタフェース(8.5, 9.5), フィールド(8.3, 9.3, 10.7)及びメソッド(8.4, 9.4)とする。インタフェースのメンバは,次のすべてとする。

インタフェースは,異なるインタフェースで宣言及び継承されるならば,同じ単純名をもつ二つ以上のフィールドをもってよい。そのようなフィールドを単純名で参照しようとするとコンパイル時エラーが発生する(6.5.6.1, 9.2)。

次に例を示す。

interface Colors {
	int WHITE = 0, BLACK = 1;
}
interface Separates {
	int CYAN = 0, MAGENTA = 1, YELLOW = 2, BLACK = 3;
}
interface ColorsAndSeparates extends Colors, Separates {
	int DEFAULT = BLACK;		 // compile-time error: ambiguous
}
インタフェース ColorsAndSeparates のメンバは,Colors から継承したメンバ及びSeparates から継承したメンバ,つまり,WHITE, BLACK (二つの内の最初),CYAN, MAGENTA, YELLOW,及び BLACK (二つの内の二番目)を含む。メンバ名 BLACK はインタフェース ColorsAndSeparates ではあいまいとする。

6.4.4 配列型のメンバ

配列型のメンバは,10.7で規定する。便宜上,次に同じものを示す。

配列型のメンバは,次のすべてとする。

次に例を示す。

class Test {
	public static void main(String[] args) {
		int[] ia = new int[3];
		int[] ib = new int[6];
		System.out.println(ia.getClass() == ib.getClass());
		System.out.println("ia has length=" + ia.length);
	}
}
これは次の出力を生成する。

true
ia has length=3
この例は,クラスObjectから継承したメソッド getClass 及びフィールドlength を使用する。最初の println におけるオブジェクトClass の比較結果は,構成要素を型int とするすべての配列が同じ配列型int[]のインスタンスであることを示す。

6.5 名前の意味の決定

名前の意味は,それが使われる文脈に依存する。名前の意味の決定は,三段階を必要とする。第一に,文脈は構文的に名前を6分類,つまり,パッケージ名(PackageName)型名(TypeName)式名(ExpressionName)メソッド名(MethodName)パッケージ又は型名(PackageOrTypeName) 又はあいまい名(AmbiguousName)のうちの一つに分類する。第二に,最初に文脈によって AmbiguousName 又はPackageOrTypeName に分類された名前は,PackageNameTypeName 又はExpressionName に再分類される。第三に,分類結果が名前の意味を最終的に決定する。(名前が意味をもたなければ,コンパイル時エラーとする。)

文脈の使用は,異なる種類の実体間の名前の衝突を最小にすることを助ける。6.8 で説明される名前付け規約に従っていれば,このような衝突が発生することはほとんどない。それにもかかわらず,名前の衝突は,違うプログラマ又は違う組織での開発の進展の典型として,故意ではなく発生することがある。たとえば,型,メソッド及びフィールドが同じ名前をもつことがある。使用文脈から,メソッドが意図されているかどうかは明らかになるため,同じ名前をもつメソッドとフィールドの間の識別は,常に可能となる。



6.5.1 文脈に従った名前の構文上の分類

次の文脈では,名前を構文上, PackageNameとして分類する。

次の文脈では,名前を構文上, TypeName として分類する。

次の文脈では,名前を構文上,ExpressionName として分類する。

次の文脈では,名前を構文上,MethodNameとして分類する。

次の文脈では,名前を構文上,PackageOrTypeNameとして分類する。

次の文脈では,名前を構文上,AmbiguousName として分類する。

6.5.2 文脈的にあいまいな名前の再分類

AmbiguousName は次のとおりに再分類する。

package org.rpgpoet;
import java.util.Random;
interface Music { Random[] wizards = new Random[4]; }
さらに,他のパッケージ内での次の例を考える。

package bazola;
class Gabriel {
	static int n = org.rpgpoet.Music.wizards.length;
}
まず最初に,名前 org.rpgpoet.Music.wizards.lengthは, ExpressionName として分類する。その理由は,それはPostfixExpression として機能するからである。したがって,次の各名前,

org.rpgpoet.Music.wizards
org.rpgpoet.Music
org.rpgpoet
org 
は,最初は AmbiguousName として分類する。これらはその後再分類する。

6.5.3 パッケージ名の意味

PackageNameとして分類した名前の意味は,次のとおりに決める。

6.5.3.1 単純パッケージ名

パッケージ名が単一の Identifier で構成されていれば,この識別子は,その識別子によって名前付けられた最上位のパッケージ名を表示する。有効範囲(7.4.4)内にその名前をもつパッケージが存在しなければ,コンパイル時エラーが発生する。

6.5.3.2 限定パッケージ名

パッケージ名が形式 Q.Id ならば,Q もパッケージ名でなければならない。パッケージ名 Q.Id は, Q という名前のパッケージ内の,Id という名前のメンバのパッケージに名前付けする。Qが観察可能なパッケージ(7.4.3)を名前付けしないか,又は Id がそのパッケージの観察可能な下位パッケージの単純名でなければ,コンパイル時エラーが発生する。

6.5.4 パッケージ又は型名の意味

6.5.4.1 単純パッケージ又は型名

PackageOrTypeName QQという名の型の有効範囲に出現するなら, その PackageOrTypeNameは,TypeNameとして再分類される。

そうでなければ,その PackageOrTypeNamePackageName として再分類される。その PackageOrTypeNameの意味は,再分類された名前の意味とする。

6.5.4.2 限定パッケージ又は型名(PackageOrTypeName)

形式Q.Id の限定 PackageOrTypeNameが与えられた時は, Q で表記される型又はパッケージがメンバ型名 Idを持つならば,限定 PackageOrTypeNameQ.Id は,TypeName として再分類される。

そうでなければ, PackageNameとして再分類される。 限定PackageOrTypeNameの意味は,再分類名の意味とする。

6.5.5 型名の意味

TypeName として分類した名前の意味は,次のとおりに決定する 。

6.5.5.1 単純型名

型名が単一のIdentifier で構成されていれば,その識別子は,この名前をもつ型の宣言の有効範囲内に出現しなければならない 。そうでなければ,コンパイル時エラーが発生する。

識別子は,その名前をもつ複数の型の有効範囲内に出現可能とする 。この場合,その名前が表す型は,次のとおり決定する。

型宣言を考察するこの順番は,二つ以上の適用可能な型宣言の内の最 も明示的なものを選択するよう設計されている。

6.5.5.2 限定型名

型名が形式Q.Id ならば,Q は型名又はパッケージ名でなければなら ない。Id が,名前がQ で表される型又はパッケージのメンバである正確に一つの型の名前であるなら,限定型名は,その型を表す。IdQ 内のメンバ型(8.5, 9.5) の名前でないか,Q内のメンバ型名Id がアクセス可能(6.6)でないか,IdQ 内の複数のメンバ型の名前ならば ,コンパイル時エラーが発生する。

次に例を示す。

package wnj.test;
class Test {
	public static void main(String[] args) {
		java.util.Date date =
			new java.util.Date(System.currentTimeMillis());
		System.out.println(date.toLocaleString());
	}
}
これは,最初の実行時に次の出力を生成した。

Sun Jan 21 22:56:29 1996
この例では,名前java.util.Date は,型を表していなければならない。そこでまず最初に,java.util がアクセス可能な型又はパッケージであるかどうかを決めるために,その手順を再帰的に使用し,実際アクセス可能なので,次に,型Date がこのパッケージ内でアクセス可能かどうかを確認する。

6.5.6 式名の意味

ExpressionName として分類した名前の意味は,次のとおりに決定する。

6.5.6.1 単純式名

式名が単一の Identifier から構成されている場合。

次に例を示す。

class Test {
	static int v;
	static final int f = 3;
	public static void main(String[] args) {
		int i;
		i = 1;
		v = 2;
		f = 33;		// compile-time error
		System.out.println(i + " " + v + " " + f);
	}
}
i, v及びfへの代入の左辺で使用している名前は,局所変数 i,フィールド v及びfの値(変数fではない。その理由は,ffinal 変数だからとする。)を表す。したがって,最後の代入の左辺が変数で はないために,この例はコンパイル時エラーを生じる。エラーとなる代入を削除すれば,修正したコードはコンパイルでき,次の結果を出力する。

1 2 3

6.5.6.2 限定式名

式名が形式Q.Idならば,Q は既に,パッケージ名,型名又は式名として分類されている。

次に例を示す。

class Point {
	int x, y;
	static int nPoints;
}
class Test {
	public static void main(String[] args) {
		int i = 0;
		i.x++;		// compile-time error
		Point p = new Point();
		p.nPoints();	// compile-time error
	}
}
二つのコンパイル時エラーが生じる。これは int変数 iがメンバをもたないこと,及びnPointsがクラス Pointのメソッドでないこと のためである。

6.5.7 メソッド名の意味

MethodName は,メソッド呼出し式(15.12)の中にだけ出現できる。MethodName として分類した名前の意味は,次のとおりに決定する。

6.5.7.1 単純メソッド名

メソッド名が単一の Identifier から構成されていれば,そのIdentifier はメソッド呼出しで使用するメソッド名とする 。そのIdentifier は,そのIdentifier が出現する宣言内のクラス又はインタフェースのメソッドの少なくとも一つを名前付けしなければならない。メソッド呼出し式における単純メソッド名の解釈についての詳細な解説は15.12 を参照のこと。

6.5.7.2 限定メソッド名

メソッド名が形式Q.Id ならば,Qは,パッケージ名,型名又は式名 として既に分類されている。Qがパッケージ名ならば,コンパイル時 エラーが発生する。そうでなければ,Id はメソッド呼出しのために使用するメソッド名とする。Qが型名ならば,Id は型 Qstaticメソッドを少なくとも一つ名前付けしなければならない。Qが式名ならば,T を式 Qの型とする。Id は型 T のメソッドを少なくとも一つ名前付けしなければならない。メソッド呼出し式における限定メソッド名の解釈の詳細な解説は15.12を参照のこと。

6.6 アクセス制御

Javaプログラム言語は,パッケージ又はクラスのユーザが,そのパッケージ又はクラスの実装の不必要な詳細に依存することを防ぐために,アクセス制御 (access control) の機構を提供する。アクセスが許可されるならば,アクセスされる実体はアクセス可能(accessible) という。

アクセス可能性は,コンパイル時に決定可能な静的特性であることに注意せよ。それは,型及び宣言修飾子にのみ依存する。限定名は,パッケージ及び参照型のメンバへのアクセスの方法とする。関係するアクセスの方法は,フィールドアクセス式(15.11) 及びメソッド呼出し式 (15.12)を含む。三つのすべては,パッケージ,型又は型をもつ式の指示が先行し,"." が出現し,パッケージ又は型のメンバを名前付けするIdentifier が続くという点で構文的に類似する。これらは,まとめて限定アクセス(qualified access) のための構文要素として知られる。

アクセス制御は,限定アクセス並びにクラスインスタンス生成式 (15.9)及び明示的なコンストラクタ呼出し (8.8.5)に適用する。アク セス可能性は,隠ぺい及びメソッド上書き(8.4.6.1)を含めて,クラスメンバの継承(8.2)にも影響する。

6.6.1 アクセス可能性の決定

6.6.2 protectedアクセスの詳細

あるオブジェクトのprotectedメンバ又はコンストラクタは,そのオブジェクトの実装に対して責任があるコードによってだけ,それを宣言したパッケージの外部からアクセスしてよい。

6.6.2.1 protectedメンバへのアクセス

Cprotected メンバmを宣言しているクラスとする。Cの下位クラスS の本体内からのみアクセスが許される。さらに,Id をインスタンスフィールド又はインスタンスメソッドの表記とした場合,次のとおりとする。

6.6.2.2 protectedコンストラクタへの限定アクセス

Cをその内部で protected コンストラクタを宣言しているクラスとし,Sをその中の宣言でprotectedコンストラクタが出現する最内クラスとする。この場合に次となる。

6.6.3 アクセス制御の例

アクセス制御の例のために,二つのコンパイル単位を考える。

package points;
class PointVec { Point[] vec; }
及び

package points;
public class Point {
	protected int x, y;
	public void move(int dx, int dy) { x += dx; y += dy; }
	public int getX() { return x; }
	public int getY() { return y; }
}
パッケージpoints内では,二つのクラス型を宣言する。

protected アクセス修飾子がアクセスを制限する方法の例については6.6.7を参照のこと。

6.6.4 public 及び非publicクラスへのアクセスの例

クラスが修飾子 public をもたなければ,そのクラス宣言へのアクセスは,それを宣言したパッケージに制限される(6.6)

package points;
public class Point {
	public int x, y;
	public void move(int dx, int dy) { x += dx; y += dy; }
}
class PointList {
	Point next, prev;
}
二つのクラスがコンパイル単位内で宣言されている。クラス Pointはパッケージ pointsの外で使用できる。一方,クラス PointList はパッケージ内でだけ使用できる。

したがって,他のパッケージ内のコンパイル単位は,points.Pointを,次の二つの方法でアクセスできる。 まず,完全限定名を使用する例を次に示す。

package pointsUser;
class Test {
	public static void main(String[] args) {
		points.Point p = new points.Point();
		System.out.println(p.x + " " + p.y);
	}
}
さらに,完全限定名を記述する単一の型インポート宣言(7.5.1)を使用し,その結果,それ以降単純名が使用できる例を次に示す。

package pointsUser;
import points.Point;
class Test {
	public static void main(String[] args) {
		Point p = new Point();
		System.out.println(p.x + " " + p.y);
	}
}
しかし,このコンパイル単位は,points.PointListを使用又はインポートできない。これは public 宣言をしていないので,パッケージpointsの外からはアクセス可能ではないからである。

6.6.5 フィールド,メソッド及びコンストラクタのデフォルトアクセスの例

アクセス修飾子public, protected又はprivate をいずれも指定していなければ,クラスメンバ又はコンストラクタは,そのクラスメンバを宣言しているクラスの宣言を含むパッケージの全体からアクセス可能とする。しかし,そのクラスメンバ又はコンストラクタは,他のパッケージからはアクセス不能とする。

publicクラスが,デフォルトアクセスのメソッド又はコンストラクタをもてば,このメソッド又はコンストラクタは,このパッケージの外で宣言した下位クラスによってアクセス又は継承されることはない。

次に例を示す。

package points;
public class Point {
	public int x, y;
	void move(int dx, int dy) { x += dx; y += dy; }
	public void moveAlso(int dx, int dy) { move(dx, dy); }
}
他のパッケージ内の下位クラスは同じシグネチャ(8.3.2)及び返却値の型をもつ関連のないメソッド moveを宣言してよい。元のメソッド move はパッケージ morepointsからアクセスできないので,superを使用してはならない。

package morepoints;
public class PlusPoint extends points.Point {
	public void move(int dx, int dy) {
		super.move(dx, dy);			// compile-time error
		moveAlso(dx, dy);
	}
}
Point の move が PlusPoint 内のmoveによって上書きされないため,Point 内のメソッド moveAlsoPlusPoint 内のメソッド move を呼ぶことは決してない。

したがって,PlusPoint からsuper.moveを削除してテストプログラムを実行すれば,正常に終了する。

import points.Point;
import morepoints.PlusPoint;
class Test {
	public static void main(String[] args) {
		PlusPoint pp = new PlusPoint();
		pp.move(1, 1);
	}
}
PointmovePlusPoint内の move によって上書きされれば,このプログラムは,StackoverflowErrorが発生するまで無限に再帰するであろう。

6.6.6 publicフィールド,メソッド及びコンストラクタの例

publicクラスのメンバ又はコンストラクタは,それを宣言しているパッケージの全体から,及びそれを宣言している他のパッケージが可視(7.4.3)ならば,そのパッケージから,アクセス可能とする。例えば,次のコンパイル単位を考える。

package points;
public class Point {
	int x, y;
	public void move(int dx, int dy) {
		x += dx; y += dy;
		moves++;
	}
	public static int moves = 0;
}
publicクラスPointは,メソッドmove及びフィールドmovespublicメンバとしてもつ。これらのpublicメンバは,パッケージ pointsにアクセスする他の任意のパッケージに対してアクセス可能とする。フィールドx及びypublicではなく,パッケージpoints内からでだけアクセス可能とする。

6.6.7 protectedフィールド,メソッド及びコンストラクタの例

パッケージpoints を宣言する次の例を考える。

package points;
public class Point {
	protected int x, y;
	void warp(threePoint.Point3d a) {
		if (a.z > 0)		// compile-time error: cannot access a.z
			a.delta(this);
	}
}
さらに,パッケージthreePointを次のとおり宣言する。

package threePoint;
import points.Point;
public class Point3d extends Point {
	protected int z;
	public void delta(Point p) {
		p.x += this.x;		// compile-time error: cannot access p.x
		p.y += this.y;		// compile-time error: cannot access p.y
	}
	public void delta3d(Point3d q) {
		q.x += this.x;
		q.y += this.y;
		q.z += this.z;
	}
}
これは,クラスPoint3dを定義する。このメソッドdelta で,コンパイル時エラーが発生する。つまり,仮引数 pの protected メンバx 及びy にはアクセスできない。その理由は,Point3d(フィールドx 及びy への参照が発生するクラス)は,Pointx 及びy を宣言するクラス)の下位クラスだが,これは,Point(仮引数pの型)の実装には含まれないためである。メソッドdelta3dは,仮引数qの protected メンバにアクセス可能とする。その理由は,クラスPoint3dは,Pointの下位クラスであって,Point3dの実装に含まれるからである。

メソッド deltaは,その仮引数をPoint3dとするキャスト(5.5, 15.16) を試みることはできるが,実行時の pのクラスがPoint3dでなければ,このキャストは失敗し,例外を発生する。

メソッド warp でもコンパイル時エラーが発生する。仮引数aの protected メンバzにアクセスできない。その理由は,クラス Point(フィールド zへの参照が発生するクラス)は,Point(仮引数aの型)の実装に関連しているが,Point3dzを宣言したクラス)の下位クラスでないからである。

6.6.8 privateフィールド,メソッド及びコンストラクタの例

privateクラスのメンバ又はコンストラクタは,それを宣言したクラス本体の中だけでアクセスでき,下位クラスによって継承されない。次に例を示す。

class Point {
	Point() { setMasterID(); }
	int x, y;
	private int ID;
	private static int masterID = 0;
	private void setMasterID() { ID = masterID++; }
}
privateメンバ,ID, masterID及びsetMasterIDは,クラ スPointの本体内でだけ使用可能となる。これらは,Point 宣言の本体の外側では,限定名,フィールドアクセス式又はメソッド呼出し式によってアクセスできない。

private コンストラクタの使用例は,8.8.8を参照のこと。

6.7 完全限定名及び正準名

すべてのパッケージ,最上位クラス,最上位インタフェース及びプリミティブ型は,完全限定名(fully qualified name)をもつ。配列型が完全限定名を持つための必要十分条件は,要素型が完全限定名であることとする。

次に例を示す。

次に例を示す。

package points;
class Point { int x, y; }
class PointVec {
	Point[] vec;
}
Pointの完全限定名は"points.Point",型PointVecの 完全限定名は"points.PointVec"及びクラスPointVecvecフィールドの型の完全限定名は"points.Point[]"とする。

すべてのパッケージ,最上位クラス,最上位インタフェース及びプリミティブ型は,正準名を持つ。配列型が正準名を持つ必要十分条件は,その要素型が正準名を持つこととする。 他のクラスCのメンバクラス又はメンバインタフェース M が正準名を持つ必要十分条件は,C が正準名を持つこととする。この場合,M の正準名は,C の正準名, ".",M の単純名の連なったものとする。すべてのパッケージ,最上位クラス,最上位インタフェース及びプリミティブ型は,正準名を完全限定名と同じとする。配列型の正準名は,配列の要素型が正準名を持つ場合に限り定義される。この場合,配列型の正準名は,配列型の構成要素の型の正準名に"[]"を続けたもので構成する。

完全限定名と正準名との相違は,次の例で示す。

package p;
class O1 { class I{}}
class O2 extends O1{};

この例で,p.O1.I 及び p.O2.I は共に同じクラスを表す完全限定名となる。しかし,p.O1.Iだけが正準名となる。

6.8 名前付け規約

Javaプラットフォームのクラスライブラリでは,可能な限りここで説明する規約にそって選択された名前を使用する。これらの規約は,コードをより読み易くし,ある種の名前の競合を回避することを支援する。

すべてのJavaプログラムで,以下の規約を使用することが望ましい。しかし,長期間にわたり使用してきた,慣用的な使用法が本規約と異なるならば,本規約に,無条件に従う必要はない。例えば,クラス v のメソッド sin 及びメソッド cosは,短く,動詞ではないという理由でJavaの規約を守っていないが,数学の規約に従う。

6.8.1 パッケージ名

パッケージの名前を広く利用可能にするには,7.7で述べる形式に従うことが望ましい。そのような名前は,常にその最初の識別子が,com, edu, gov, mil, net, orgのようなインターネットドメインを示す2文字又は3文字の小文字,又は uk 若しくは jp のような2文字のISO国名コードで構成する限定名とする。この規約にしたがって作成した架空の一意な名前の例を次に示す。

com.JavaSoft.jag.Oak
org.npr.pledge.driver
uk.ac.city.rugby.game


局所使用だけを意図したパッケージの名前は,小文字で始まる識別子をもつことが望ましい。しかし,その最初の識別子を javaとするのは望ましくない。識別子 javaで始まるパッケージ名は,Javaプラットフォームパッケージを名前付けするためにSunが予約している。

式にパッケージ名が出現するときは,次のとおりとする。

パッケージ名の最初の構成要素を,型名と間違えることは通常はあまりない。これは型名は,普通1文字の大文字で始まるからである。(Java言語は,実際には,名前がパッケージ 名又は型名を決定するために大文字及び小文字の違いには依存しない。)

6.8.2 クラス及びインタフェース型名

クラス型の名前は,各単語の先頭文字を大文字とし,大文字 及び小文字を混在させた,過度に長くない,記述的な名詞又は名詞句であることが望ましい。 次に例を示す。

ClassLoader
SecurityManager
Thread
Dictionary
BufferedInputStream
同様に,インタフェース型の名前は,各単語の先頭文字を大文字とし,大文字及び小文字を混在させ,短く,記述的で過度に長くないことが望ましい。その名前は,記述的な名詞又は名詞句であってよい。これは,インタフェースjava.io.DataInput及びjava.io.DataOutputのように,インタフェースを,抽象上位クラスであるかのように使用するときに適している。名前は,インタフェースRunnable及びCloneableのように,振る舞いを記述する形容詞としてもよい。

クラス及びインタフェース型の名前を不明瞭化することはほとんどない。規約により,フィールド,仮引数及び局所変数の名前は小文字で始まるのに対して,型名は大文字で始まるので,普通は,型名を隠ぺいしない。

6.8.3 メソッド名

メソッド名は,先頭文字を小文字とし,それに続く各単語の先頭文字を大文字とする,大文字及び小文字を混在させた動詞又は動詞句とすることが望ましい。メソッド名に対する付加的規約を次に示す。

可能及び適切なときはいつでも,新しいクラスのメソッドの名前は,類似した既存のクラス,特に標準Javaアプリケーションプログラミングインタフェースクラスの名前をもとにすると使いやすくなる。

メソッド名は,他の名前を不明瞭化したり,他の名前で不明瞭化できない(6.5.7)

6.8.4 フィールド名

finalでないフィールドの名前は,先頭文字は小文字で始まり,それに続く単語の先頭文字を大文字とすることが望ましい。適切に設計されたJavaクラスは,定数のフィールド(final staticフィールド) (6.8.5)を除くと,public又はprotectedフィールドは非常に少ないことに注意すること。

フィールドは,名詞,名詞句又は名詞の省略形の名前をもつことが望ましい。この規約の例としては,クラスjava.io.ByteArrayInputStreamのフィールドbuf, pos及びcount並びにクラス java.io.InterruptedIOExceptionのフィールドbytesTransferredがある。

フィールド名を含む不明瞭化はほとんどない。

6.8.5 定数名

インタフェース型における定数の名前は,下線"_"で区切られた構成要素をもつ,すべて大文字の,一つ以上の単語 ,頭文字又は略語の並びとすることが望ましい。クラス型のfinal変数も,慣例として,同じ並びとしてよい。定数名は,記述的であって,不必要に省略しないことが望ましい。慣例的に,それらは言葉の適切な一部としてよい。 定数名の例には,クラスCharacterMIN_VALUE, MAX_VALUE, MIN_RADIX及びMAX_RADIXを含む。

集合の選択肢の値,又は,それほど多くはないが,整数値におけるビットマスクを表す定数群は,時々便利なのだが ,次のとおり前置名として共通の頭文字で指示することがある。

interface ProcessStates {
	int PS_RUNNING = 0;
	int PS_SUSPENDED = 1;
}
定数名を含む不明瞭化は少ない。

6.8.6 局所変数及び仮引数名

局所変数及び仮引数名は,短いが意味のあるものとすることが望ましい。これらは,普通,単語ではない短い小文字の列とする。 次に例を示す。

一時変数及びループ変数,又は変数が型の特別でない値を保持する場合を除いて,1文字の局所変数名又は仮引数名は避けることが望ましい。 慣例的な1文字の名前は次のとおり

2個又は3個の小文字だけから構成される局所変数又は仮引数名は,一意なパッケージ名(7.7)の先頭構成要素としての国名コード又はドメイン名との衝突を避けるために,使用しないことが望ましい。

目次 | | | 索引 Java言語規定
第2版