| 目次 | 前 | 次 | 索引 | Java言語規定 第2版 |
名前は,プログラムで宣言した実体を参照するために使用する。宣言した実体 (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) によって参照できる,プログラムテキストの部分を指定する。 デフォルトアクセスでは,メンバ宣言を含んでいるパッケージ内のどこからでも,そのメンバにアクセスできる。その他には,public,protected 及び 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)の一部分,又はフィールド若しくはメソッドに対する限定名の一部としてだけ式に出現してよい。パッケージの名前は,クラス型又はインタフェース型の限定名の一部としてだけ式に出現してよい。
package 宣言(7.4)で宣言したパッケージ。
abstract なメソッドの仮引数。
try 文(14.19) の catch 節で宣言した例外ハンドラの仮引数。
名前には,単純名及び限定名の二つの形式が存在する。単純名(simple name) は,単一の識別子とする。限定名(qualified name) は,名前,"." トークン及び識別子から構成する。
名前の意味の決定 (6.5)においては,名前が出現する文脈を考慮する。規則(6.5)は,どの文脈で,名前が,パッケージ(6.5.3),型(6.5.5),式(6.5.6),又はメソッド(6.5.7) における変数若しくは値を表示(参照)しなければならないかを識別する。
プログラムにおける識別子すべてが,名前の一部になるとは限らない。識別子は,次の状況においても使用する。
."トークンの前に出現するキーワードsuper の値とするオブジェクトのメンバを示すために,"."トークンの後に識別子が出現してもよい。
."トークンの前に出現するキーワード super の値とするオブジェクトに対して呼び出されたメソッドを示すために,"."トークンの後及び "("トークンの前に識別子が出現してもよい。
break (14.14) 及び continue (14.15)文の中のラベル。
class Test {
public static void main(String[] args) {
Class c = System.out.getClass();
System.out.println(c.toString().length() +
args[0].length() + args.length);
}
}
識別子 Test,main 並びに最初に出現する 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 を隠ぺいしない。各構成要素の有効範囲規則は,その構成要素について記述する節で与える。便宜上,それらの規則をここで繰り返して述べる。
観察可能な(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 部において宣言した局所変数の有効範囲は,次のすべてを含む。
for 文の ForInit 部内の,それ自体の右側に続くすべての宣言子。
for 文の 式(Expression) 及び ForUpdate 部。
try 文 (14.19) のcatch 節で宣言した例外ハンドラの仮引数の有効範囲は,catch と関連するブロックの全体とする。これらの規則は,クラス及びインタフェース型の宣言が,型の使用前に出現する必要がないことを示唆している。
package points;
class Point {
int x, y;
PointList list;
Point next;
}
class PointList {
Point first;
}
クラス Point の PointListの使用は正しい。これはクラス型の名前PointListの有効範囲が,パッケージ points の他のコンパイル単位 における他の型宣言でも同様に,クラス Point 及びクラス PointListの両方を含むからとする。名前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
Test。
static) 変数 x。これはクラスTestのメンバとする。
main。これはクラス Testのメンバとする。
main の仮引数 args。
main の局所変数x。
x はメソッド main の本体の全体を通して普通に利用できる。しかし,この例では,局所変数 x の宣言によって,クラス変数 x はメソッド main の本体内でおおい隠される。
局所変数は,宣言(14.4.2)されたブロックの残りの部分を有効範囲とする。この例の場合,これはメソッド main の本体の残りの部分,つまり,初期化子"0" 並びに print 及び println の呼出しの部分とする。
print の呼出しにおける式"x"は局所変数 xの値を参照(表示)する。
println の呼出しは限定名(6.6) Test.xを使用する。これは,クラス型名Test を用いて,クラス変数xにアクセスする。Test.xの宣言はこの時点ではおおい隠され,単純名で参照できないからである。
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.1) とは異なり,かつ,隠ぺい(8.3, 8.4.6.2, 8.5, 9.3, 9.5)とも異なる。6.8の名前規約は,不明瞭さを減少させるのに役立つ。
6.4では,限定名の議論及び名前の意味の決定についての背景として,パッケージ及び参照型のメンバの概要を示す。メンバの完全な説明については,7.1, 8.2, 9.2, 及び 10.7を参照のこと。
パッケージのメンバは,下位パッケージ又はそのパッケージのすべてのコンパイル単位(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 の完全な限定名である。パッケージ vector は Vector という名前のクラスを含むので,Vectorという名前の下位パッケージをもつことはできない。Object は直接的上位クラスをもたない)。
同じ単純名をもつクラス型のフィールド及びメソッドに対する制限は存在しない。同様に,そのクラス型のフィールド又はメソッドとして同じ単純型を持つクラス型のメンバクラス又はメンバインタフェースに対しては何の制限もない。
異なるインタフェースで宣言され継承されるならば,クラスは同じ名前で二つ以上のフィールドをもってよい。そのフィールドを単純名で参照しようとすると,コンパイル時エラーを生じる(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 の宣言によって上書きされているからである。
throws節t を持つ。これは,Objectで宣言されたシグネチャs,返却時の型r,throws節t を持つpublicインスタンスメソッドmに対応する。ただし,同じシグネチャ,同じ返却時の型,適合throws 節を持つメソッドは,インタフェースで明示的に宣言されるとする。
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 ではあいまいとする。
public finalフィールドであるフィールド length。配列の構成要素の数を含む。(lengthは,正又はゼロとする。)
public メソッド clone。これは,クラスObject の同じ名前のメソッドを上書きし,検査例外を投げない。
Objectから継承した全メンバ。clone メソッドが,継承されない唯一のObjectメソッドとなる。
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[]のインスタンスであることを示す。
PackageName: Identifier PackageName . Identifier TypeName: Identifier PackageOrTypeName . Identifier ExpressionName: Identifier AmbiguousName . Identifier MethodName: Identifier AmbiguousName . Identifier PackageOrTypeName: Identifier PackageOrTypeName . Identifier AmbiguousName: Identifier AmbiguousName . Identifier文脈の使用は,異なる種類の実体間の名前の衝突を最小にすることを助ける。6.8 で説明される名前付け規約に従っていれば,このような衝突が発生することはほとんどない。それにもかかわらず,名前の衝突は,違うプログラマ又は違う組織での開発の進展の典型として,故意ではなく発生することがある。たとえば,型,メソッド及びフィールドが同じ名前をもつことがある。使用文脈から,メソッドが意図されているかどうかは明らかになるため,同じ名前をもつメソッドとフィールドの間の識別は,常に可能となる。
."の左側。
extends 節(8.1.3) 内。
implements 節(8.1.4) 内。
extends 節(9.1.2) 内。
try 文の catch 節(14.19) 内の例外仮引数の型。
this 式(15.8.4)の限定型。
super を用いたフィールドアクセスの限定型(15.11.2) 。
super を用いたメソッド呼出しの限定型
(15.12)。
instanceof 関係演算子(15.20.2) に続く型。
("の前。
."及びIdentifier から構成される限定名ならば,"." の左側の名前を最初に再分類する。その理由は,それ自体がAmbiguousNameだからである。このときには,次の選択が存在する。
."の左側の名前をPackageName として再分類したとき,"."の左側の名前のパッケージが存在し,そのパッケ−ジがそのIdentifier と同じ名前の型の宣言を含んでいれば,このAmbiguousNameは,TypeNameとして再分類する。そうでなければ,この AmbiguousNameは,PackageNameとして再分類する。その名前のパッケージが実際に存在するかどうかは,その後の段階で決定する。
."の左側の名前をTypeNameとして再分類したとき,その識別子が,この型名で表記されるクラス又はインタフェースのメソッド又はフィールドの名前ならば,このAmbiguousNameは,ExpressionNameとして再分類する。そうでなければ,もし,その識別子が,その型名で表記されるクラス又はインタフェースのメンバ型の名前ならば,このあいまい名は型名として再分類される。そうでなければ,コンパイル時エラーが生じる。
."の左側の名前をExpressionName として再分類したとき,Tをこの式名で表記される式の型とする。識別子がTで表記されるクラス又はインタフェースのメソッド又はフィールドの名前ならば,このAmbiguousNameは,ExpressionNameとして再分類する。そうでなければ,識別子がTで表記されるクラス又はインタフェースのメンバ型(8.5, 9.5) の名前ならば,このあいまい名は型名として再分類される。そうでなければ,結果はコンパイル時エラーとする。
例として,次のとおり設計された"library code"を考える。
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 として機能するからである。したがって,次の各名前,は,最初は AmbiguousName として分類する。これらはその後再分類する。org.rpgpoet.Music.wizards org.rpgpoet.Music org.rpgpoet org
org という名前の変数又は型が存在しないので)単純名 org は,PackageNameとして再分類する。
org のコンパイル単位で rpgpoet という名前のクラス又はインタフェースがないと仮定すると(パッケージ org は rpgpoet という名前の下位パッケージをもつのでそのようなクラスやインタフェースがないことは判っている),限定名 org.rpgpoet は,PackageNameとして再分類する。
org.rpgpoetは,Music という名前のインタフェース型をもつので,限定名 org.rpgpoet.Music は,TypeNameとして再分類する。
org.rpgpoet.Music は,TypeName なので,限定名org.rpgpoet.Music.wizards は,ExpressionNameとして再分類する。
.Id ならば,Q もパッケージ名でなければならない。パッケージ名 Q.Id は, Q という名前のパッケージ内の,Id という名前のメンバのパッケージに名前付けする。Qが観察可能なパッケージ(7.4.3)を名前付けしないか,又は Id がそのパッケージの観察可能な下位パッケージの単純名でなければ,コンパイル時エラーが発生する。そうでなければ,その PackageOrTypeNameはPackageName として再分類される。その PackageOrTypeNameの意味は,再分類された名前の意味とする。
そうでなければ, PackageNameとして再分類される。 限定PackageOrTypeNameの意味は,再分類名の意味とする。
識別子は,その名前をもつ複数の型の有効範囲内に出現可能とする 。この場合,その名前が表す型は,次のとおり決定する。
.Id ならば,Q は型名又はパッケージ名でなければなら ない。Id が,名前がQ で表される型又はパッケージのメンバである正確に一つの型の名前であるなら,限定型名は,その型を表す。Id がQ 内のメンバ型(8.5, 9.5) の名前でないか,Q内のメンバ型名Id がアクセス可能(6.6)でないか,Id がQ 内の複数のメンバ型の名前ならば ,コンパイル時エラーが発生する。 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 がこのパッケージ内でアクセス可能かどうかを確認する。
final (8.3.1.2)と宣言されていれば,その式名はそのフィールドの値を表す。その式名の型は,そのフィールドの宣言された型とする。そのIdentifierが値でなく変数を要求する文脈に出現すれば,コンパイル時エラーが発生する。
static メソッド(8.4.3.2),静的初期化子(8.7)又は static 変数の初期化子(8.3.1.1, 12.4.2)内に出現すれば,コンパイル時エラーが発生する。
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ではない。その理由は,f がfinal 変数だからとする。)を表す。したがって,最後の代入の左辺が変数で はないために,この例はコンパイル時エラーを生じる。エラーとなる代入を削除すれば,修正したコードはコンパイルでき,次の結果を出力する。
1 2 3
.Idならば,Q は既に,パッケージ名,型名又は式名として分類されている。
staticと宣言されていなければ),コ ンパイル時エラーが発生する。
final宣言されていれば,Q.Idはそのクラス変数の値を表す。式Q.Idの型は,そのクラス変数を宣言した型とする。Q.Idが値ではなく変数を要求する文脈内に出現すれば,コンパイル時エラーが発生する。
.Idはクラス変数を表す。式 Q.Idの型は,クラス変数を宣言した型とする。
.Idは,そのフィールドの値を表す。式 Q.Idの型は,そのフィールドの宣言された型とする。Q.Idが,値ではなく変数を要求する文脈内に出現すれば,コンパイル時エラーが発生する。
final フィールド(クラス変数又はインスタンス変数のいずれであってもよい)。
final フィ−ルドlength。
.Idは,フィールドの値を表す。式 Q.Idの型 はそのフィールドを宣言した型とする。Q.Idが値ではなく変数を要求する文脈内に出現すれば,コンパイル時エラーが発生する。
.Idは,変数,つまり,クラスTのフィールドId を表す。これは,クラス変数又はインスタンス変数のいずれであってもよい。 式 Q.Idの型はそのフィールドを宣言した型とする。
次に例を示す。
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のメソッドでないこと のためである。.Id ならば,Qは,パッケージ名,型名又は式名 として既に分類されている。Qがパッケージ名ならば,コンパイル時 エラーが発生する。そうでなければ,Id はメソッド呼出しのために使用するメソッド名とする。Qが型名ならば,Id は型 Qの staticメソッドを少なくとも一つ名前付けしなければならない。Qが式名ならば,T を式 Qの型とする。Id は型 T のメソッドを少なくとも一つ名前付けしなければならない。メソッド呼出し式における限定メソッド名の解釈の詳細な解説は15.12を参照のこと。
アクセス可能性は,コンパイル時に決定可能な静的特性であることに注意せよ。それは,型及び宣言修飾子にのみ依存する。限定名は,パッケージ及び参照型のメンバへのアクセスの方法とする。関係するアクセスの方法は,フィールドアクセス式(15.11) 及びメソッド呼出し式 (15.12)を含む。三つのすべては,パッケージ,型又は型をもつ式の指示が先行し,"." が出現し,パッケージ又は型のメンバを名前付けするIdentifier が続くという点で構文的に類似する。これらは,まとめて限定アクセス(qualified access) のための構文要素として知られる。
アクセス制御は,限定アクセス並びにクラスインスタンス生成式 (15.9)及び明示的なコンストラクタ呼出し (8.8.5)に適用する。アク セス可能性は,隠ぺい及びメソッド上書き(8.4.6.1)を含めて,クラスメンバの継承(8.2)にも影響する。
public宣言していれば,その宣言のコンパイル単位(7.3)が可視ならば,任意のコードによってアクセス可能とする。最上位クラス又はインタフェース型を public宣言していなければ,それを宣言しているパッケージ内からだけアクセス可能とする。
public宣言していれば,アクセスは許可される。インタフェースのすべてのメンバは,暗黙的に publicとする。
protected宣言していれば,次のいずれか一つが真のときにだけ,アクセスは許可される。
protectedメンバを宣言しているクラスを含むパッケージ内から発生している。
private宣言していれば,アクセス許可の必要十分条件を,メンバの宣言を取り囲む最上位クラス(7.6) の本体内から発生していることとする。
protectedアクセスの詳細protectedメンバ又はコンストラクタは,そのオブジェクトの実装に対して責任があるコードによってだけ,それを宣言したパッケージの外部からアクセスしてよい。protectedメンバへのアクセスprotected メンバmを宣言しているクラスとする。Cの下位クラスS の本体内からのみアクセスが許される。さらに,Id をインスタンスフィールド又はインスタンスメソッドの表記とした場合,次のとおりとする。
.Id,ここで Q は ExpressionNameとする,によってならば,アクセス許可の必要十分条件を,式Q の型が S又は Sの下位クラスの場合とする。
.Id又はメソッド呼出し式 E.Id(. . .)によってならば,アクセス許可の必要十分条件を,Eの型が S 又は S の下位クラスとする。
protectedコンストラクタへの限定アクセスprotected コンストラクタを宣言しているクラスとし,Sをその中の宣言でprotectedコンストラクタが出現する最内クラスとする。この場合に次となる。
super(. . .)の又はEを 基本(Primary) 式とするE.super(. . .)の上位クラスコンストラクタ呼出しによる場合は,アクセスは許可される。
new C(. . .){...}の匿名クラスインスタンス生成式 又はEを基本(Primary)式とするE.new C(. . .){...}の限定クラスインスタンス生成式によってならば,アクセスは許可される。
new C(. . .)の単純クラスインスタンス生成式 又はE を 基本(Primary)式とするE.new C(. . .)の限定クラスインスタンス生成式によってならば,アクセスは許可されない。protectedコンストラクタは,それが定義されているパッケージ内からだけ,(匿名クラスを宣言しない)クラスインスタンス生成式によってアクセス可能とする。
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内では,二つのクラス型を宣言する。
PointVec は public ではなく,パッケージ points のpublic インタフェースの一部でもないが,そのパッケージ内の他のクラスによってだけ使用できる。
Point は public宣言されていて,他のパッケージで使用できる。それは,パッケージ pointsの public インタフェースの一部とする。
Pointの メソッド move, getX及び getY は public 宣言されており,そのため,型Point のオブジェクトを使用するすべてのコードで利用できる。
x 及び y は protected 宣言されていて,パッケージ points の外からは,クラスPointの下位クラス内でだけ,かつ,それらをアクセスするコードによって実装されているオブジェクトのフィールドであるときだけ使用できる。
protected アクセス修飾子がアクセスを制限する方法の例については6.6.7を参照のこと。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の外からはアクセス可能ではないからである。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 内のメソッド moveAlsoは PlusPoint 内のメソッド 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);
}
}
Pointの moveが PlusPoint内の move によって上書きされれば,このプログラムは,StackoverflowErrorが発生するまで無限に再帰するであろう。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及びフィールドmovesをpublicメンバとしてもつ。これらのpublicメンバは,パッケージ pointsにアクセスする他の任意のパッケージに対してアクセス可能とする。フィールドx及びyはpublicではなく,パッケージpoints内からでだけアクセス可能とする。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 への参照が発生するクラス)は,Point(x 及び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の型)の実装に関連しているが,Point3d(zを宣言したクラス)の下位クラスでないからである。
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を参照のこと。
boolean, char,
byte, short, int, long,
float, 又は doubleとする。
."を続け,さらに,その下位パッケージの単純(メンバ)名を続けたものから構成する。
."を続け,さらに,そのクラス又はインタフェースの単純名を続けたものから構成する。
[]"を続けたもので構成する。
longの完全限定名は"long"とする。
java.langの完全限定名は"java.lang"とする 。その理由は,パッケージjavaの下位パッケージlangだからとなる。
java.langで定義したクラスObjectの完全限定名は,"java.lang.Object"とする。
java.utilで定義したインタフェース Enumerationの完全限定名は,"java.util.Enumeration"とする。
doubleの配列"の完全限定名は,"double[]"とする。
Stringの配列の配列の配列の配列"の完全限定名は, "java.lang.String[][][][]"とする。
package points;
class Point { int x, y; }
class PointVec {
Point[] vec;
}
型Pointの完全限定名は"points.Point",型PointVecの 完全限定名は"points.PointVec"及びクラスPointVecのvecフィールドの型の完全限定名は"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だけが正準名となる。
すべてのJavaプログラムで,以下の規約を使用することが望ましい。しかし,長期間にわたり使用してきた,慣用的な使用法が本規約と異なるならば,本規約に,無条件に従う必要はない。例えば,クラス v のメソッド sin 及びメソッド cosは,短く,動詞ではないという理由でJavaの規約を守っていないが,数学の規約に従う。
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が予約している。
式にパッケージ名が出現するときは,次のとおりとする。
import宣言(7.5)を使用することを可能とする。
パッケージ名の最初の構成要素を,型名と間違えることは通常はあまりない。これは型名は,普通1文字の大文字で始まるからである。(Java言語は,実際には,名前がパッケージ 名又は型名を決定するために大文字及び小文字の違いには依存しない。)
同様に,インタフェース型の名前は,各単語の先頭文字を大文字とし,大文字及び小文字を混在させ,短く,記述的で過度に長くないことが望ましい。その名前は,記述的な名詞又は名詞句であってよい。これは,インタフェースClassLoaderSecurityManagerThreadDictionaryBufferedInputStream
java.io.DataInput及びjava.io.DataOutputのように,インタフェースを,抽象上位クラスであるかのように使用するときに適している。名前は,インタフェースRunnable及びCloneableのように,振る舞いを記述する形容詞としてもよい。
クラス及びインタフェース型の名前を不明瞭化することはほとんどない。規約により,フィールド,仮引数及び局所変数の名前は小文字で始まるのに対して,型名は大文字で始まるので,普通は,型名を隠ぺいしない。
get)及び設定する(set)メソッドは,getV及びsetVという名前とすることが望ましい。クラスThreadのメソッドgetPriority及びメソッドsetPriorityをこの例とする。
Stringのように,lengthという名前にすることが望ましい。
boolean条件を検査するメソッドは,isVという名前とすることが望ましい。クラスThreadのメソッド isInterruptedをこの例とする。
toFという名前とすることが望ましい。クラスObjectのメソッド toString,及びクラスjava.util.DateのメソッドtoLocaleString及びtoGMTStringをこの例とする。
メソッド名は,他の名前を不明瞭化したり,他の名前で不明瞭化できない(6.5.7)。
finalでないフィールドの名前は,先頭文字は小文字で始まり,それに続く単語の先頭文字を大文字とすることが望ましい。適切に設計されたJavaクラスは,定数のフィールド(final staticフィールド) (6.8.5)を除くと,public又はprotectedフィールドは非常に少ないことに注意すること。
フィールドは,名詞,名詞句又は名詞の省略形の名前をもつことが望ましい。この規約の例としては,クラスjava.io.ByteArrayInputStreamのフィールドbuf, pos及びcount並びにクラス java.io.InterruptedIOExceptionのフィールドbytesTransferredがある。
フィールド名を含む不明瞭化はほとんどない。
import宣言(7.5)を使用することができる。
_"で区切られた構成要素をもつ,すべて大文字の,一つ以上の単語 ,頭文字又は略語の並びとすることが望ましい。クラス型のfinal変数も,慣例として,同じ並びとしてよい。定数名は,記述的であって,不必要に省略しないことが望ましい。慣例的に,それらは言葉の適切な一部としてよい。 定数名の例には,クラスCharacterのMIN_VALUE, MAX_VALUE,
MIN_RADIX及びMAX_RADIXを含む。集合の選択肢の値,又は,それほど多くはないが,整数値におけるビットマスクを表す定数群は,時々便利なのだが ,次のとおり前置名として共通の頭文字で指示することがある。
interface ProcessStates {
int PS_RUNNING = 0;
int PS_SUSPENDED = 1;
}
定数名を含む不明瞭化は少ない。
ColoredPointへの参照を保持する変数のための cp などとする。
bufferへのポインタを保持するbufなどとする。
一時変数及びループ変数,又は変数が型の特別でない値を保持する場合を除いて,1文字の局所変数名又は仮引数名は避けることが望ましい。 慣例的な1文字の名前は次のとおり
byteに対するb。
charに対するc。
doubleに対するd。
Exceptionに対するe。
floatに対するf。
i, j,k。
longに対するl。
Objectに対するo。
Stringに対するs。
v。
| 目次 | 前 | 次 | 索引 | Java言語規定 第2版 |