Javaプログラムにおける名前は,単一の識別子で構成される単純名又は"."トークンで区切られる識別子の並びから構成される限定名
(6.2)のいずれかとする。
宣言によって導入したすべての名前は, 有効範囲(scope) (6.3)をもつ。有効範囲とは,その中から,宣言した実体が単純名によって参照できるJavaプログラムテキストの一部分とする。
パッケージ及び参照型(つまり,クラス型,インタフェース型及び配列型)は,メンバ(6.4)をもつ。メンバは,限定名
N.x を使用して参照可能とする。 ここで N
は単純名又は限定名とし, x は識別子とする。N
がパッケージに名前付けをしていれば,x
はそのパッケージのメンバ,つまり,クラス型,インタフェース型又はサブパッケージのいずれかとする。
N が参照型又は参照型の変数に名前付けしていれば,x
はその型のメンバ,フィールド又はメソッドに名前を付ける。
名前の意味の決定(6.5)において,Javaは同じ名前をもったパッケージ,型,変数及びメソッドの間のあいまいさを解消するために,名前が出現する文脈を使用する。
アクセス制御(6.6)は,メンバへのアクセス(access)が許可されるときを制御するために,クラス,インタフェース,メソッド又はフィールドの宣言で指定できる。アクセスは,有効範囲とは異なる概念とする。アクセスは,宣言した実体が,限定名,フィールドアクセス式(15.10)又はメソッドを単純名で指定しない場合のメソッド呼出し式(15.11)
によって参照できる,Javaプログラムテキストの部分を指定する。
デフォルトアクセスは,メンバ宣言を含んでいるパッケージ内のどこからでも,そのメンバにアクセス可能とする。その他の可能性は,public,protected
及び private とする。
完全限定名(6.7)及び名前付け規約(6.8)についてもこの章で述べる。
フィールド,仮引数又は局所変数の名前は,式(15.13.1)として使用できる。
メソッドの名前は,メソッド呼出し式(15.11)の一部としてだけ式に出現してよい。
クラス又はインタフェース型の名前は,クラスインスタンス生成式(15.8),配列生成式(15.9),キャスト式(15.15),若しくは instanceof 式(15.19.2)の一部分,又はフィールド若しくはメソッドに対する限定名の一部としてだけ式に出現してよい。
パッケージの名前は,クラス型又はインタフェース型の限定名の一部としてだけ式に出現してよい。
package 宣言(7.4)で宣言したパッケージ。
abstract なメソッドの仮引数。
try 文(14.18)の
catch 節で宣言した例外ハンドラの仮引数。
名前には二つの形式が存在する。単純名及び限定名とする。単純名(simple
name) は,単一の識別子とする。限定名(qualified name)
は,名前,"." トークン及び識別子から構成する。
名前の意味の決定 (6.5)において,Java言語は,名前が出現する文脈を考慮する。Java言語は,文脈の中のどこで,名前が,パッケージ(6.5.3),型(6.5.4),式における変数若しくは値 (6.5.5),又はメソッド(6.5.6)を表示(参照)しなければならないかを識別する。
Javaプログラムにおけるすべての識別子が,名前の一部とは限らない。識別子は,次の状況においても使用する。
."トークンの前に出現するキーワードsuper
の値とするオブジェクトのメンバを示すために,"."トークンの後に識別子が出現してもよい。
."トークンの前に出現するキーワード
super
の値とするオブジェクトに対して呼び出されたメソッドを示すために,"."トークンの後及び
"("トークンの前に識別子が出現してもよい。
break (14.13) 及び
continue (14.14)
文の中のラベル。
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.11)で出現する識別子とする。二番目に出現する
length も名前とはしない。 メソッド呼出し式(15.11)で出現する識別子とする。
ラベル付き文,並びにそれに関連のある 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(20.12.26)のある版からもって来た。元の版では,ラベルは
test と呼ばれていた。 ラベルを,局所変数 i
と同じ名前をもつように変更しても,i
の宣言の有効範囲においてそのラベルを隠ぺいすることはない。 識別子
max
も,文ラベルとして使用できた。つまり,ラベルは,ラベル付き文内の局所変数
max を隠ぺいしない。
package
宣言によって導入するパッケージの有効範囲は,ホストシステム(7.4.3)によって決定する。すべてのJavaコードは
,java
と名前付けされた標準パッケージの有効範囲内にある。したがって,パッケージ
java は常にJavaコードによって参照可能とする。
class Test {
int i = j; // compile-time error: incorrect forward reference
int j = 1;
}
class Test {
Test() { k = 2; }
int j = 1;
int i = j;
int k;
}
Test のコンストラクタ(8.6)が,3行後ろで宣言したフィールド
k を参照しているにもかかわらず,エラーなくコンパイルできる。
for 文 (14.12)の
ForInit 部において宣言した局所変数の有効範囲は,次のすべてを含む。
for 文の ForInit
部内の,それ自体の右側に続くすべての宣言子。
for 文の 式(Expression) 及び ForUpdate 部。
try 文(14.18)の
catch
節で宣言した例外ハンドラの仮引数の有効範囲は,catch
と関連するブロックの全体とする。
package points;
class Point {
int x, y;
PointList list;
Point next;
}
class PointList {
Point first;
}
クラス Point の PointList の使用は正しい。
これはクラス型の名前 PointList の有効範囲が,パッケージ
points
の他のコンパイル単位における他の型宣言でも同様に,クラス Point
及びクラス PointList の両方を含むからとする。
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.3.2)されたブロックの残りの部分を有効範囲とする。
この例の場合,これはメソッド main
の本体の残りの部分,つまり,初期化子"0" 並びに
print 及び println の呼出しの部分とする。
print の呼出しにおける式"x"は局所変数
x の値を参照(表示)する。
println の呼出しは限定名(6.6)
Test.x を使用する。Test.x
の宣言はこの点では隠ぺいされ,単純名では参照できないからである。
class Point { int x, y; }
class Test {
static Point Point(int x, int y) {
Point p = new Point();
p.x = x; p.y = y;
return p;
}
public static void main(String[] args) {
int Point;
Point[] pa = new Point[2];
for (Point = 0; Point < 2; Point++) {
pa[Point] = new Point();
pa[Point].x = Point;
pa[Point].y = Point;
}
System.out.println(pa[0].x + "," + pa[0].y);
System.out.println(pa[1].x + "," + pa[1].y);
Point p = Point(3, 4);
System.out.println(p.x + "," + p.y);
}
}
これはエラー無しにコンパイルされ,実行すると次を出力する。
0,0 1,1
3,4
main の本体内では,Point
の参照ごとに,それを使用する文脈に依存した別々の宣言を見つけることとなる。
new
Point[2]",クラスインスタンス生成式"new
Point()"
の二つの出現,及び三つの異なる局所変数の宣言式の始まりにおいて,Point
は 型名(TypeName) (6.5.4)であって,それぞれ,クラス型
Point を表す。
Point(3,
4)"では,Point の出現は メソッド名(MethodName)
(6.5.6)であって,クラス(static)メソッド
Point を表す。
Point
を参照する。
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.4では,限定名の議論及び名前の意味の決定についての背景として,パッケージ及び参照型のメンバの概要を示す。メンバの完全な説明については,7.1,8.2,9.2 及び 10.7を参照のこと。
一般に,あるパッケージのサブパッケージは,ホストシステム(7.2)によって決定される。しかし,標準パッケージ
java は,常に
サブパッケージlang,util,io及びnet
を含み,さらに,その他のサブパッケージを含んでもよい。同じパッケージの二つの異なるメンバは,同じ単純名(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.6.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.11で与えられたオーバロード解決手順によってコンパイル時に決定される。
この例では,クラス Point のメンバは,Point
で宣言された float インスタンス変数 x 及び
y,二つの宣言されたメソッド
move,宣言されたメソッド toString,並びにメソッド
hashCode (20.1.4)のような
Point がその暗黙の直接的ス−パクラス Object
から継承するメンバ,とする。Point はクラス Object
のメソッド toString(20.1.2)を継承していないことに注意すること。これは,そのメソッドがクラス
Point 内のメソッド toString
の宣言によって上書きされているからである。
インタフェースは,異なるインタフェースで宣言及び継承されるならば,同じ単純名をもつ二つ以上のフィールドをもってよい。ただし,そのようなフィールドを単純名で参照しようとするとコンパイル時エラーが発生する(6.5.5.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 ではあいまいとする。
Object (4.3.2,20.1)から継承したメンバ。
final)フィールドであるフィールド
length。その型はint
とし,配列の構成要素の数を含む。
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:Javaにおける文脈の使用は,異なる種類の実体間の名前の衝突を最小にすることを助ける。6.8で説明される名前付け規約に従っていれば,このような衝突が発生することはほとんどない。それにもかかわらず,名前の衝突は,違うプログラマ又は違う組織での開発の進展の典型として,故意ではなく発生することがある。たとえば,型,メソッド及びフィールドが同じ名前をもつことがある。Javaでは,名前を使用する文脈が,必ず,名前がメソッドか又はフィールドであるかを明らかにするため,同じ名前をもつメソッドとフィールドの間の識別には問題が生じない。
Identifier
PackageName.Identifier TypeName:
Identifier
PackageName.Identifier ExpressionName:
Identifier
AmbiguousName.Identifier MethodName:
Identifier
AmbiguousName.Identifier AmbiguousName:
Identifier
AmbiguousName.Identifier
次の文脈では,名前を構文上, 型名(TypeName) として分類する。
extends
節内。
implements 節内。
extends 節内。
次の文脈では,名前を構文上,メソッド名(MethodName) として分類する。
("の前。
."及び識別子(Identifier)から構成される限定名ならば,"."
の左側の名前を最初に再分類する。その理由は,それ自体があいまい名(AmbiguousName)だからである。このときには,次の選択が存在する。
."の左側の名前をパッケージ名(PackageName)
として再分類したとき,さらに次の選択肢が存在する。
."の左側の名前のパッケージが存在し,そのパッケ−ジがその識別子(Identifier)
と同じ名前の型の宣言を含んでいれば,このあいまい名(AmbiguousName)は,型名(TypeName)として再分類する。
."の左側の名前を型名(TypeName)として再分類したとき,このあいまい名(AmbiguousName)は,式名(ExpressionName)として再分類する。
."の左側の名前を式名(ExpressionName)
として再分類したとき,このあいまい名(AmbiguousName)は,式名(ExpressionName)として再分類する。
さらに,他のパッケージ内での次の例を考える。
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)
として分類する。その理由は,それはPostfix式(PostfixExpression)
として機能するからである。従って,次の各名前,
ORG.rpgpoet.Music.wizards ORG.rpgpoet.Music ORG.rpgpoet ORGは,最初は あいまい名(AmbiguousName) として分類する。これらはその後再分類する。
bazola の他のコンパイル単位で ORG
という名前のクラス又はインタフェースが存在しないと仮定すると,単純名
ORG は,パッケージ名(PackageName)として再分類する。
ORG のコンパイル単位で
rpgpoet
という名前のクラス又はインタフェースがないと仮定すると(パッケージ
ORG は rpgpoet
という名前のサブパッケージをもつのでそのようなクラスやインタフェースがないことは判っている),限定名
ORG.rpgpoetは,パッケージ名(PackageName)として再分類する。
ORG.rpgpoet は,Music
という名前のインタフェース型をもつので,限定名
ORG.rpgpoet.Music は,型名(TypeName)として再分類する。
ORG.rpgpoet.Music は,型名(TypeName)
なので,限定名 ORG.rpgpoet.Music
は,式名(ExpressionName)として再分類する。
.Id ならば,Q
もパッケージ名でなければならない。パッケージ名
Q.Id は, Q
という名前のパッケージ内の,Id
という名前のメンバのパッケージに名前付けする。Q
がアクセス可能なパッケージに名前付けするか,又は Id
がそのパッケージのアクセス可能なサブパッケージに名前付けしなければ,コンパイル時エラーが発生する。
.Id ならば, Q
はパッケージ名でなければならない。型名 Q.Id
は,名前がQ のパッケージ内の,名前がId
というメンバの型に名前を与える。Q
がアクセス可能なパッケージ名でないか,Id
がそのパッケージ内の型名でないか,又はそのパッケージ内の Id
という名前の型がアクセス可能(6.6)でなければ,コンパイル時エラーが発生する。
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この例では,
wnj.test
は,そのホストシステム上のパッケージ名でなければならない。この場合は,まず最初に,6.5.3.1で記述した手順を使用してパッケージ
wnj を探し,次に,このパッケージの
サブパッケージtest
がアクセス可能なことを確認することで,解決される。
java.util.Date (21.3)は,型を表していなければならない。そこでまず最初に,java.util
がアクセス可能なパッケージであるかどうかを決めるために,その手順を再帰的に使用し,実際アクセス可能なので,次に,型Date
がこのパッケージ内でアクセス可能かどうかを確認する。
staticメソッド(8.4.3.2),静的初期化子(8.5)又は 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
が,値ではなく変数を要求する文脈内に出現すれば,コンパイル時エラーが発生する。
.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.11を参照のこと。
."
が出現する,という点で構文的に類似する。これらは,まとめて限定アクセス(qualified
access) のための構文要素として知られる。
Javaは,パッケージ又はクラスのユーザが,そのパッケージ又はクラスの実装の不必要な詳細に依存することを防止するために,アクセス制御(access
control)
の機構を提供する。アクセス制御は,限定アクセス並びにクラスインスタンス生成式(15.8),明示的なコンストラクタ呼出し (8.6.5)及びクラス Class のメソッド
newInstance(20.3.6)によるコンストラクタの呼出しに適用する。
アクセスが許可されるならば,アクセスされる実体はアクセス可能(accessible) という。
public
宣言していれば,それを宣言しているパッケージにアクセス可能な任意のJavaコードによってアクセス可能とする。クラス又はインタフェース型を
public
宣言していなければ,それを宣言しているパッケージ内からだけアクセス可能とする。
public
宣言していれば,アクセスは許可される。インタフェースのすべてのメンバは,暗黙的に
public とする。
protected
宣言していれば,次のいずれか一つが真のときにだけ,アクセスは許可される。
protected
メンバを宣言しているクラスを含むパッケージ内から発生している。
protected
メンバを宣言したクラスのサブクラス内で発生し,そのアクセスが6.6.2で記述されているように正しい。
private
宣言していれば,それを宣言しているクラス内からアクセスが発生しているときにだけアクセスは許可される。
protected アクセスの詳細protected
メンバ又はコンストラクタは,そのオブジェクトの実装に対して責任があるコードによってだけ,それを宣言したパッケージの外部からアクセスしてよい。C
を protected
メンバ又はコンストラクタを宣言しているクラスとし,S を
protected メンバ又はコンストラクタの使用が発生する C
のサブクラスとする。
protected
メンバ(フィールド又はメソッド)に対する場合,Id
をその名前とする。その際の,限定アクセスの方法を検討する。
super.Id
のフィールドアクセス式によってならば,アクセスは許可される。
.Id,ここでQ は型名
TypeNameとする,によってならば,Q が S 又は S
のサブクラスのときに限り,アクセスは許可される。
.Id,ここで Q は
式名(ExpressionName)とする,によってならば,式 Q の型が
S 又は S のサブクラスのときに限り,アクセスは許可される。
.Id,ここでEは 基本(Primary)
式とする,又はメソッド呼出し式
E.Id(. .
.),ここでE は基本(Primary)
式とする,によってならば,E の型が S 又は S
のサブクラスのときに限り,アクセスは許可される。
protected
コンストラクタに対する場合,次のとおりとする。
super(. .
.) によってならば,アクセスは許可される。
new
T(. . .)
によってならば,アクセスは許可されない。(protected
コンストラクタは,それが定義されているパッケージ内からだけ,クラスインスタンス生成式によってアクセス可能とする。)
Class (20.3.6)のメソッド
newInstance の呼出しによってならば,アクセスは許可されない。
及び
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; }
}
パッケージ Point 内では,二つのクラス型を宣言する。
PointVec は public
ではなく,パッケージ points のpublic
インタフェースの一部でもないが,そのパッケージ内の他のクラスによってだけ使用できる。
Point は public
宣言されていて,他のパッケージで使用できる。それは,パッケージ
points の public インタフェースの一部とする。
Point の メソッド
move,getX,及び getY は
public 宣言されており,そのため,型Point
のオブジェクトを使用するすべてのJavaコードで利用できる。
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.4.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.4)。例えば,次のコンパイル単位を考える。
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
フィールド,メソッド及びコンストラクタの例point を宣言する次の例を考える。
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.4,15.15)を試みることはできるが,実行時の
p のクラスが Point3d
でなければ,このキャストは失敗し,例外を発生する。
メソッド warp でもコンパイル時エラーが発生する。仮引数
a の protected メンバ z
にアクセスできない。その理由は,クラス Point(フィールド
z への参照が発生するクラス)は,Point(仮引数
a の型)の実装に関連しているが,Point( 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.6.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[]"とする。
すべてのJavaプログラムで,以下の規約を使用することが望ましい。しかし,長期間にわたり使用してきた,慣用的な使用法が本規約と異なるならば,本規約に,無条件に従う必要は無い。例えば,クラス
java.lang.Math のメソッド sin 及びメソッド
cos
は,短く,動詞ではないという理由でJavaの規約を守っていないが,数学的な慣用名をもつ。
COM,EDU,GOV,MIL,NET若しくは
ORG のようなインターネットドメイン又は UK
若しくは JP
のような2文字のISO国コードを示す,最初の識別子を2文字又は3文字の大文字で構成する限定名とする。この規約に従って作成した架空の一意な名前の例を次に示す。
COM.JavaSoft.jag.Oak ORG.NPR.pledge.driver UK.ac.city.rugby.game局所使用だけを意図したパッケージの名前は,小文字で始まる識別子をもつことが望ましい。しかし,その最初の識別子を
java とするのは望ましくない。識別子 java
で始まるパッケージ名は,標準Javaパッケージを名前付けするためにJavaSoftが予約している。
import
宣言(7.5)を使用することを可能とする。
次に例を示す。
同様に,インタフェース型の名前は,各単語の先頭文字を大文字とし,大文字及び小文字を混在させ,短く,記述的で過度に長くないことが望ましい。その名前は,記述的な名詞又は名詞句であってよい。これは,インタフェースClassLoaderSecurityManagerThreadDictionaryBufferedInputStream
java.io.DataInput 及び java.io.DataOutput
のように,インタフェースを,抽象スーパクラスであるかのように使用するときに適している。名前は,インタフェースjava.lang.Runnable
及び java.lang.Cloneable
のように,振舞いを記述する形容詞としてもよい。
クラス及びインタフェース型の名前を隠ぺいすることはほとんどない。規約により,フィールド,仮引数及び局所変数の名前は小文字で始まるのに対して,型名は大文字で始まるので,普通は,型名を隠ぺいしない。
(get)及び設定する(set)メソッドは,
getV 及び setV
という名前とすることが望ましい。クラス java.lang.Thread
のメソッド getPriority (20.20.22)
及びメソッドsetPriority (20.20.23)をこの例とする。
java.lang.String (20.12.11)
内に存在するように,length という名前にすることが望ましい。
boolean
条件を検査するメソッドは,isV
という名前とすることが望ましい。クラス java.lang.Thread (20.20.32)のメソッド
isInterrupted をこの例とする。
toF という名前とすることが望ましい。クラス
java.lang.Object (20.1.2)のメソッド
toString,クラス java.util.Date のメソッド
toLocaleString (21.3.27)
及びメソッド toGMTString (21.3.28)をこの例とする。
メソッド名は,他の名前を隠ぺいしたり,他の名前で隠ぺいされたりできない(6.5.6)。
final
でないフィールドの名前は,先頭文字は小文字で始まり,それに続く単語の先頭文字を大文字とした,大文字及び小文字を混在したものとすることが望ましい。適切に設計されたJavaクラスは,定数のフィールド(final
static フィールド) (6.8.5)を除くと,public 又は
protected フィールドは非常に少ないことに注意すること。
フィールドは,名詞,名詞句又は名詞の省略形の名前をもつことが望ましい。この規約の例としては,クラス
java.io.ByteArrayInputStream (22.6)のフィールド
buf,pos 及び count 並びにクラス
java.io.InterruptedIOException (22.30.1)のフィールド
bytesTransferred がある。
import
宣言(7.5)を使用することができる。
_"で区切られた構成要素をもつ,すべて大文字の,一つ以上の単語,頭文字又は略語の並びとすることが望ましい。クラス型の
final
変数も,慣例として,同じ並びとしてよい。定数名は,記述的であって,不必要に省略しないことが望ましい。慣例的に,それらは言葉の適切な一部としてよい。定数名の例には,クラス
java.lang.Character の
MIN_VALUE,MAX_VALUE,MIN_RADIX 及び
MAX_RADIX を含む。
集合の選択肢の値,又は,それほど多くはないが,整数値におけるビットマスクを表す定数群は,時々便利なのだが,次のとおり前置名として共通の頭文字で指示することがある。
interface ProcessStates {
int PS_RUNNING = 0;
int PS_SUSPENDED = 1;
}
定数名を含む隠ぺいは少ない。
次に例を示す。
ColoredPoint
への参照を保持する変数のための cp などとする。
buffer へのポインタを保持する
buf などとする。
次に例を示す。
慣例的な1文字の名前は次のとおり。
byte に対する b。
char に対する c。
double に対する d。
Exception に対する e。
float に対する f。
i,j,k。
long に対する l。
Object に対する o。
String に対する s。
v。