このドキュメントでは、Java SE 14のプレビュー機能であるレコードをサポートするためのJava言語仕様の変更点について説明します。 この機能の概要については、「JEP 359」を参照してください。
比較ドキュメントは、レコードをサポートするためにJava仮想マシン仕様に必要な変更点を説明します。
変更は、JLSの既存のセクションについて説明しています。 新しいテキストはこのように示され、削除されたテキストはこのように示されます。 必要に応じて、説明と考察が端の方にグレーのボックスで囲まれて記載されています。
第1章: 概要
1.1 仕様の編成
第2章では、言語の字句および構文文法を表すために使用する文法および表記法について説明します。
第3章では、CおよびC++に基づくJavaプログラミング言語の字句構造について説明します。 この言語は、Unicode文字セットで書かれています。 これは、ASCIIのみをサポートするシステム上のUnicode文字の書込みをサポートしています。
第4章では、型、値および変数について説明します。 型は、プリミティブ型および参照型に細分されます。
プリミティブ型は、すべてのマシン上およびすべての実装内で同じであるよう定義されており、2の補数整数、単精度および倍精度のIEEE 754標準浮動小数点数、boolean
型、およびUnicode文字のchar
型の様々なサイズがあります。 プリミティブ型の値は、状態を共有しません。
参照型には、クラス型、インタフェース型および配列型があります。 参照型は、クラスまたは配列のインスタンスである、動的に作成されたオブジェクトによって実装されます。 各オブジェクトに対する複数の参照が存在する場合があります。 すべてのオブジェクト(配列を含む)が、クラス階層の(単一)ルートであるクラスObject
のメソッドをサポートしています。 事前定義されたString
クラスは、Unicode文字列をサポートしています。 オブジェクト内のプリミティブ値をラップするためのクラスが存在します。 多くの場合、ラップおよびラップ解除は、コンパイラによって自動的に実行されます(この場合、ラップはボックス化と呼ばれ、ラップ解除はボックス化解除と呼ばれます)。 クラスおよびインタフェース宣言は汎用的です。つまり、これらは他の参照型によってパラメータ化される場合があります。 この場合、このような宣言は特定の型引数によって呼び出される場合があります。
変数は、型付きの記憶域の場所です。 プリミティブ型の変数には、そのプリミティブ型の値が格納されます。 クラス型の変数には、null参照、または型がそのクラス型またはそのクラス型のサブクラスであるオブジェクトへの参照を格納できます。 インタフェース型の変数には、null参照、またはそのインタフェースを実装する任意のクラスのインスタンスへの参照を格納できます。 配列型の変数には、null参照、または配列への参照を格納できます。 Object
クラス型の変数には、null参照、または(クラス・インスタンスと配列のどちらであるかとは関係なく)任意のオブジェクトへの参照を格納できます。
第5章では、変換および数値昇格について説明します。 変換により、コンパイル時の型、および場合によっては式の値が変更されます。 これらの変換には、プリミティブ型と参照型の間のボックス化およびボックス化解除変換が含まれます。 数値昇格を使用して、数値演算子のオペランドを、演算が実行可能な共通型に変換します。 この言語にはループホールがありません。参照型でのキャストは、型の安全性を確保するために実行時にチェックされます。
第6章では、宣言および名前について説明するとともに、名前が意味するもの(つまり、名前がどの宣言を表しているか)を確認する方法について説明します。 Javaプログラミング言語では、クラス、インタフェースまたはメンバーを使用する前にこれらを宣言する必要はありません。 宣言順序が重要なのは、ローカル変数、ローカル・クラスの場合、およびクラスまたはインタフェース内のフィールド・イニシャライザの順序の場合のみです。 ここでは、読みやすいプログラムの作成に役立つ、推奨される命名規則について説明します。
第7章では、パッケージに組み込まれるプログラムの構造について説明します。 パッケージのメンバーは、クラス、インタフェースおよびサブパッケージです。 パッケージ(およびその結果としてメンバー)は、階層ネームスペース内に名前があります。通常、パッケージ名はインターネット・ドメイン名システムを使用して一意に構成できます。 コンパイル・ユニットは、特定のパッケージのメンバーであるクラスおよびインタフェースの宣言を含み、他のパッケージからクラスおよびインタフェースをインポートしてそれらに短い名前を付けることができます。
パッケージは、非常に大規模なプログラムの構築時にビルディング・ブロックとして機能するモジュールにグループ化できます。 モジュールの宣言により、独自のパッケージ内でコードをコンパイルおよび実行するために必要な他のモジュール(およびその結果としてのパッケージと、その結果としてのクラスおよびインタフェース)を指定します。
Javaプログラミング言語は、パッケージのメンバー、クラスおよびインタフェースに対する外部アクセスに関する制限をサポートしています。 パッケージのメンバーは、同じパッケージ内の他のメンバー、同じモジュール内の他のパッケージのメンバー、または異なるモジュール内のパッケージのメンバーからのみアクセスできます。 クラスおよびインタフェースのメンバーにも同様の制約が適用されます。
第8章では、クラスについて説明します。 クラスのメンバーは、クラス、インタフェース、フィールド(変数)およびメソッドです。 クラス変数はクラスごとに1つ存在します。 クラス・メソッドは、特定のオブジェクトを参照せずに動作します。 インスタンス変数は、クラスのインスタンスであるオブジェクト内に動的に作成されます。 インスタンス・メソッドは、クラスのインスタンス上で呼び出されます。このようなインスタンスは、実行時に現在のオブジェクトthis
になり、オブジェクト指向のプログラミング・スタイルをサポートします。
クラスは単一継承をサポートしており、この場合、各クラスが単一のスーパークラスを持ちます。 各クラスは、スーパークラスからメンバーを継承し、最終的にはクラスObject
から継承します。 クラス型の変数は、そのクラスまたはそのクラスのサブクラスのインスタンスを参照できるため、多相的に既存のメソッドとともに新しい型を使用できます。
クラスは、synchronized
メソッドを使用した同時プログラミングをサポートします。 メソッドは、実行によって発生する可能性があるチェック済例外を宣言します。これにより、コンパイル時のチェックが可能になり、例外条件を確実に処理できるようになります。 オブジェクトは、オブジェクトがガベージ・コレクタによって破棄される前に呼び出されるfinalize
メソッドを宣言します。これにより、オブジェクトが状態をクリーン・アップできるようになります。
簡潔にするために、この言語には、クラスの実装とは別個の宣言「ヘッダー」や、別個の型およびクラス階層はありません。
enumは、小規模な値セットの定義をサポートする特殊なクラスで、型安全な方法で使用できます。 特別なクラスのフォームであるenumは、小規模な値セットの定義およびその操作を型安全な方法でサポートします。 他の言語の列挙とは異なり、enumはオブジェクトであり、独自のメソッドを持つ場合があります。
レコードは、値の集計として機能する単純なオブジェクトの簡略式をサポートするもう1つの特別な種類のクラスです。
第9章では、インタフェースについて説明します。 インタフェースのメンバーは、クラス、インタフェース、定数フィールドおよびメソッドです。 それ以外には無関係なクラスも、同じインタフェースを実装できます。 インタフェース型の変数には、そのインタフェースを実装する任意のオブジェクトへの参照を含めることができます。
クラスおよびインタフェースは、インタフェースからの複数の継承をサポートします。 1つ以上のインタフェースを実装するクラスは、スーパークラスとスーパーインタフェースの両方からインスタンス・メソッドを継承できます。
注釈型は、宣言に注釈を付けるために使用される特別なインタフェースです。 このような注釈は、いかなる方法であれJavaプログラミング言語内のプログラムのセマンティクスに影響を及ぼすことが許可されません。 ただし、これらは、様々なツールに対して有用な入力を提供します。
第10章では、配列について説明します。 配列アクセスには、境界のチェックが含まれます。 配列は、動的に作成されたオブジェクトであり、Object
型の変数に割り当てることができます。 この言語は、多次元の配列ではなく、配列の配列をサポートします。
第11章では、例外について説明します。例外は再開されるものではなく、言語のセマンティクスおよび同時メカニズムと完全に統合されます。 例外には、チェック例外、ランタイム例外およびエラーの3種類があります。 コンパイラでは、メソッドまたはコンストラクタの結果としてチェック例外が発生するのはメソッドまたはコンストラクタがチェック例外を宣言する場合のみとするよう求めることにより、チェック例外が適切に処理されるよう徹底します。 これにより、例外ハンドラが存在するかどうかをコンパイル時にチェックできるようにし、大規模なプログラミングを支援します。 ほとんどのユーザー定義の例外はチェック例外にする必要があります。 Java仮想マシンによってプログラム内で無効な例外が検出されると、NullPointerException
などのランタイム例外が発生します。 Java仮想マシンによって失敗が検出されると、OutOfMemoryError
などのエラーが発生します。 ほとんどの単純なプログラムでは、エラー処理が試行されません。
第12章では、プログラムの実行時に発生するアクティビティについて説明します。 プログラムは通常、コンパイルされたクラスおよびインタフェースを表すバイナリ・ファイルとして格納されます。 これらのバイナリ・ファイルをJava仮想マシンにロードし、他のクラスおよびインタフェースとリンクし、初期化できます。
初期化後は、クラス・メソッドおよびクラス変数を使用できます。 一部のクラスはインスタンス化し、クラス型の新しいオブジェクトを作成できます。 クラス・インスタンスであるオブジェクトには、クラスの各スーパークラスのインスタンスも含まれます。オブジェクトの作成には、これらのスーパークラス・インスタンスの再帰的な作成が含まれます。
オブジェクトが作成されなくなると、ガベージ・コレクタによって回収される場合があります。 オブジェクトがファイナライザを宣言すると、このファイナライザがオブジェクトの再利用前に実行され、ファイナライザがなければリリースされなかったはずのリソースをクリーン・アップする機会がオブジェクトに与えられます。 クラスが必要なくなると、クラスはアンロードされる場合があります。
第13章では、バイナリの互換性について説明します。ここでは、型を変更すると、変更された型を使用しても再コンパイルはされていない他の型にどのような影響が及ぶのかを明確に示します。 これらの考慮事項は、たいていはインターネットを介して連続的なバージョンのシリーズとして広範に配布する型の開発者に関連するものです。 優れたプログラム開発環境では、型が変更されるたびに依存コードが自動的に再コンパイルされるため、ほとんどのプログラマはこれらの詳細を意識する必要はありません。
第14章では、CおよびC++に基づくブロックおよび文について説明します。 この言語にはgoto
文はありませんが、ラベル付きのbreak
およびcontinue
文が含まれます。 Cとは異なり、Javaプログラミング言語では、制御フロー文にboolean
(またはBoolean
)式が必要であり、コンパイル時により多くのエラーを捕捉することを期待して、(ボックス化解除を介す場合を除き)型を暗黙的にboolean
には変換しません。 synchronized
文は、基本的なオブジェクトレベルのモニター・ロックを提供します。 try
には、ローカルでない制御の転送を防ぐためにcatch
およびfinally
句を含めることができます。
第15章では、式について説明します。 このドキュメントでは、決定論と移植性を高めるために、式の評価の(明白な)順序を完全に規定します。 オーバーロードのメソッドおよびコンストラクタは、適用可能なものの中から最も的確なメソッドまたはコンストラクタを選択することにより、コンパイル時に解決されます。
第16章では、この言語でローカル変数が使用される前に確実に定義されるようにする明確な方法について説明します。 他のすべての変数は自動的にデフォルト値に初期化されますが、Javaプログラミング言語では、プログラミング・エラーのマスキングを回避するためにローカル変数は自動的には初期化されません。
第17章では、スレッドおよびロックのセマンティクスについて説明します。これらは、当初はMesaプログラミング言語に導入されたモニターベースの同時実行性に基づいています。 Javaプログラミング言語では、高パフォーマンスの実装をサポートする共有メモリーのマルチプロセッサのメモリー・モデルを規定します。
第18章では、汎用メソッドの適用性をテストし、汎用メソッドの呼出し時に型を推測するために使用される様々な型インタフェース・アルゴリズムについて説明します。
第19章では、この言語の構文文法を示します。
1.5 プレビュー機能
プレビュー機能の説明には、「レコード型」というテキストが追加されます。
レコード型に関連付けられた重要なAPI要素は、次のとおりです。
- クラス
java.lang.Record
。 java.lang.annotation.ElementType
内のenum定数RECORD_COMPONENT
。
第3章: 字句構造
3.8 識別子
識別子は、Javaの文字およびJavaの数字からなる無限長のシーケンスで、先頭はJavaの文字です。
- Identifier:
- Keyword、BooleanLiteral、NullLiteralのいずれでもないIdentifierChars
- IdentifierChars:
- JavaLetter {JavaLetterOrDigit}
- JavaLetter:
- 「Javaの文字」である任意のUnicode文字
- JavaLetterOrDigit:
- 「Javaの文字または数字」である任意のUnicode文字
「Javaの文字」は、メソッドCharacter.isJavaIdentifierStart(int)
がtrueを返す文字です。
「Javaの文字または数字」は、メソッドCharacter.isJavaIdentifierPart(int)
がtrueを返す文字です。
「Javaの文字」には、大文字および小文字のASCIIのラテン文字
A-Z
(\u0041-\u005a
)、a-z
(\u0061-\u007a
)、および歴史的理由によってASCIIのドル記号($
または\u0024
)とアンダースコア(_
または\u005f
)が含まれます。 ドル記号は、機械的に生成されたソース・コードで使用するか、まれに、レガシー・システムで既存の名前にアクセスする場合のみ使用する必要があります。 アンダースコアは、2つ以上の文字で構成された識別子には使用できますが、キーワードであるために1文字の識別子として使用することはできません。
「Javaの数字」には、ASCII数字
0-9
(\u0030-\u0039
)が含まれます。
文字および数字は、Unicode文字セット全体から取得できます。Unicode文字セットは、世界中で現在使用されているほとんどの作成スクリプトをサポートしています。これには、中国語、日本語および韓国語の大規模なセットが含まれます。 これによりプログラマは、ネイティブ言語で作成されるプログラムで識別子を使用できるようになります。
識別子には、キーワード(3.9)、ブール・リテラル(3.10.3)またはnullリテラル(3.10.7)と同じスペル(Unicode文字列)を使用することはできません。使用すると、コンパイル時にエラーが発生します。
2つの識別子が同一であるのは、無視できるモジュールを無視した後に、識別子が文字または数字ごとに同じUnicode文字を持つ場合のみです。 無視できる文字は、メソッドCharacter.isIdentifierIgnorable(int)
がtrueを返す文字です。 外観が同じである識別子でも、依然として異なる場合があります。
たとえば、単一文字LATIN CAPITAL LETTER A (
A
、\u0041
)、LATIN SMALL LETTER A (a
、\u0061
)、GREEK CAPITAL LETTER ALPHA (A
、\u0391
)、CYRILLIC SMALL LETTER A (a
、\u0430
)およびMATHEMATICAL BOLD ITALIC SMALL A (a
、\ud835\udc82
)で構成された識別子はすべて異なります。Unicodeの複合文字は、正規の同等の分解文字とは異なります。 たとえば、LATIN CAPITAL LETTER A ACUTE (
Á
、\u00c1
)は、識別子内でLATIN CAPITAL LETTER A (A
,\u0041
)の直後にNON-SPACING ACUTE (´
、\u0301
)が付いたものとは異なります。 『The Unicode Standard』のセクション3.11「Normalization Forms」を参照してください。
識別子の例は、次のとおりです。
String
i3
- αρετη
MAX_VALUE
isLetterOrDigit
識別子var
およびrecord
は、一部のコンテキストでは許可されていないため、制限付き識別子です。
JDK14を対象とした別のJEP (JEP 361: switch文)では、補足的に、識別子yield
を制限付き識別子にすることが提案されています。
型識別子は、文字列var
でもなく文字列record
でもない識別子です。ではありません
- TypeIdentifier:
var
またはrecord
ではない識別子
型識別子は、型の宣言または使用が含まれる特定のコンテキストで使用されます。 たとえば、クラスの名前はTypeIdentifierである必要があるため、
var
またはrecord
という名前のクラスを宣言することは不正です(8.1)。
3.9 キーワード
ASCII文字で構成された51文字の列は、キーワードとして使用するために予約されており、識別子として使用することはできません(3.8)。
- キーワード:
- (次のうちの1つ)
abstract continue for new switch
assert default if package synchronized
boolean do goto private this
break double implements protected throw
byte else import public throws
case enum instanceof return transient
catch extends int short try
char final interface static void
class finally long strictfp volatile
const float native super while
_
(アンダースコア)
キーワード
const
およびgoto
は、現在使用されていませんが、予約されています。 これにより、これらのC++のキーワードがプログラムで誤って出現した場合にJavaコンパイラがより適切なエラー・メッセージを作成できるようになります。
場合によっては、様々な文字列が誤ってキーワードであるとみなされます。
これ以外の文字列として、open
、module
、requires
、transitive
、exports
、opens
、to
、uses
、provides
およびwith
の10種類の制限付きキーワードがあります。 これらの文字列は、ModuleDeclaration、ModuleDirectiveおよびRequiresModifierプロダクションの端末として表示される場合のみ、キーワードとしてトークン化されます(7.7)。 これらは、それ以外のすべての場所で識別子としてトークン化されます。これにより、制限付きキーワードの導入前に作成されたプログラムとの互換性を確保します。 例外が1つあります。文字列transitive
は、ModuleDirectiveプロダクション内の文字列requires
のすぐ右側で、後ろにセパレータが続かないかぎり、キーワードとしてトークン化されます。この場合、これは識別子としてトークン化されます。
第4章: 型、値および変数
4.11 型の使用場所
型は、ほとんどの種類の宣言内および特定の種類の式内で使用されます。 特に、型を使用する1617の型コンテキストがあります。
宣言内:
式内:
明示的なコンストラクタ呼出し文、クラス・インスタンス作成式またはメソッド呼出し式の明示的な型引数リスト内の型(8.8.7.1、15.9、15.12)
インスタンス化対象のクラス型として(15.9)またはインスタンス化対象の無名クラスの直接スーパークラスまたは直接スーパーインタフェースとしての非修飾クラス・インスタンス作成式内(15.9.5)
配列作成式内の要素型(15.10.1)
キャスト式のキャスト演算子内の型(15.16)
instanceof
関係演算子に続く型(15.20.2)メンバー・メソッドを検索するための参照型として、またはコンストラクトに対するクラス型または配列型としてのメソッド参照式内(15.13)。
また、型は次としても使用されます。
前述の任意のコンテキスト内の配列型の要素型
前述の任意のコンテキスト内でパラメータ化された型の非ワイルドカード型引数またはワイルドカード型引数の境界。
最後に、Javaプログラミング言語には、型の使用方法を示す3つの特別な語句があります。
型コンテキストの型の意味は、次によって与えられます。
4.2: プリミティブ型の場合
4.4: 型パラメータの場合
4.5: パラメータ化されたクラスおよびインタフェース型、またはパラメータ化された型内の型引数として、またはパラメータ化された型内のワイルドカード型引数の境界として表示されるクラスおよびインタフェース型の場合
4.8: RAWであるクラスおよびインタフェース型の場合
4.9: 型パラメータの境界内の交差型の場合
10.1: 配列型の場合
一部の型コンテキストは、参照型をパラメータ化する方法を制限します。
次の型コンテキストでは、型がパラメータ化された参照型である場合、ワイルドカード型引数がないことが必須となります。
インタフェース宣言の
extends
句内(9.1.3)インスタンス化対象のクラス型として(15.9)またはインスタンス化対象の無名クラスの直接スーパークラスまたは直接スーパーインタフェースとしての非修飾クラス・インスタンス作成式内(15.9.5)
メンバー・メソッドを検索するための参照型として、またはコンストラクトに対するクラス型または配列型としてのメソッド参照式内(15.13)。
また、明示的なコンストラクタ呼出し文、クラス・インスタンス作成式、メソッド呼出し式、またはメソッド参照式に対する明示的な型引数リストでは、ワイルドカード型引数は許可されません(8.8.7.1、15.9、15.12、15.13)。
次の型コンテキストでは、型がパラメータ化された参照型である場合、制限のないワイルドカード型引数のみがある(つまり、具象化可能型である)ことが必須となります。
次の型コンテキストでは、パラメータ化された参照型には例外が含まれ、例外の型が非汎用であるため、これを一緒に使用することは許可されません(6.1)。
型が使用される任意の型コンテキストで、プリミティブ型を表すキーワード、または参照型の単純名を表すIdentifierに注釈を付けることができます。 また、配列型内のネストの目的のレベルで
[
の左側に注釈を付けることにより、配列型に注釈を付けることもできます。 これらの場所にある注釈は型注釈と呼ばれ、9.7.4に規定されています。 いくつか例を挙げます。
@Foo int[] f;
は、プリミティブ型int
に注釈を付けます
int @Foo [] f;
は、配列型int[]
に注釈を付けます
int @Foo [][] f;
は、配列型int[][]
に注釈を付けます
int[] @Foo [] f;
は、配列型int[][]
のコンポーネント型である配列型int[]
に注釈を付けます
宣言内に現れる
5つ6つの型コンテキストは、宣言コンテキストと同じ数の構文上の場所を占有します(9.6.4.1)。
メソッドの戻り型(注釈型の要素の型を含む)
クラスまたはインタフェースのフィールド宣言内の型(enum定数を含む)
レコード型のレコード・コンポーネント宣言の型
メソッド、コンストラクタまたはラムダ式の仮パラメータ宣言内の型
ローカル変数制限内の型
例外パラメータ宣言内の型
1つのプログラム内で同じ構文の場所が型コンテキストと宣言コンテキストの両方になる場合がありますが、これは、宣言の修飾子が宣言済エンティティの型の直前にくるためです。9.7.4では、このような場所内の注釈がどのように型コンテキストまたは宣言コンテキストあるいはその両方に現れると考えられるかについて説明します。
例4.11-1. 型の使用方法
import java.util.Random;
import java.util.Collection;
import java.util.ArrayList;
class MiscMath<T extends Number> {
int divisor;
MiscMath(int divisor) { this.divisor = divisor; }
float ratio(long l) {
try {
l /= divisor;
} catch (Exception e) {
if (e instanceof ArithmeticException)
l = Long.MAX_VALUE;
else
l = 0;
}
return (float)l;
}
double gausser() {
Random r = new Random();
double[] val = new double[2];
val[0] = r.nextGaussian();
val[1] = r.nextGaussian();
return (val[0] + val[1]) / 2;
}
Collection<Number> fromArray(Number[] na) {
Collection<Number> cn = new ArrayList<Number>();
for (Number n : na) cn.add(n);
return cn;
}
<S> void loop(S s) { this.<S>loop(s); }
}
この例では、型は次の宣言に使用されています。
インポートされた型(7.5): ここでは、パッケージ
java.util
の型java.util.Random
からインポートされた型Random
が宣言されていますクラスのクラス変数およびインスタンス変数(8.3)、およびインタフェースの定数(9.3)であるフィールド: ここでは、クラス
MiscMath
のフィールドdivisor
が型int
であると宣言されていますメソッド・パラメータ(8.4.1): ここでは、メソッド
ratio
のパラメータl
が型long
であると宣言されていますメソッド結果(8.4): ここでは、メソッド
ratio
の結果が型float
であると宣言され、メソッドgausser
の結果が型double
であると宣言されていますコンストラクタ・パラメータ(8.8.1): ここでは、
MiscMath
のコンストラクタのパラメータが型int
であると宣言されていますローカル変数(14.4、14.14): メソッド
gausser
のローカル変数r
およびval
が型Random
およびdouble[]
(double
の配列)であると宣言されています例外パラメータ(14.20): ここでは、
catch
句の例外パラメータe
が型Exception
であると宣言されています型パラメータ(4.4): ここでは、
MiscMath
の型パラメータが、宣言された境界として型Number
を持つ型変数T
であると宣言されていますパラメータ化された型を使用する宣言内: ここでは、パラメータ化された型
Collection<Number>
内の型引数(4.5.1)として型Number
が使用されています。
および次の種類の式内:
クラス・インスタンス作成(15.9): ここでは、型
Random
を使用するクラス・インスタンス作成式により、メソッドgausser
のローカル変数r
が初期化されています汎用クラス(8.1.2)インスタンス作成(15.9): ここでは、式
new ArrayList<Number>()
内の型引数としてNumber
が使用されています配列作成(15.10.1): ここでは、
double
の配列をサイズ2で作成する配列作成式により、メソッドgausser
のローカル変数val
が初期化されています汎用メソッド(8.4.4)またはコンストラクタ(8.8.4)の呼出し(15.12): ここでは、メソッド
loop
が明示的な型引数S
を使用してそれ自体を呼び出していますキャスト(15.16): ここでは、メソッド
ratio
のreturn
文がキャスト内でfloat
型を使用していますinstanceof
演算子(15.20.2): ここでは、instanceof
演算子により、e
が型ArithmeticException
と割当て互換しているかどうかがテストされています
4.12 変数
4.12.3 変数の種類
次の8つの種類の変数があります。
クラス変数は、クラス宣言内でキーワード
static
を使用して宣言されたフィールド(8.3.1.1)、またはインタフェース宣言内でキーワードstatic
ありまたはなしで宣言されたフィールド(9.3)です。クラス変数は、そのクラスまたはインタフェースが準備され(12.3.2)、デフォルト値に初期化された(4.12.5)ときに作成されます。 クラス変数は、そのクラスまたはインタフェースがアンロード(12.7)されたときに実質的に存在しなくなります。
インスタンス変数は、キーワード
static
を使用せずにクラス宣言内で明示的または暗黙的に宣言されたフィールドです(8.3.1.1)。インスタンス変数であるフィールド
a
がクラスTに含まれる場合、クラスTまたはTのサブクラス(8.1.4)である任意のクラスの、新しい作成されたオブジェクトの一部として、新しいインスタンス変数a
が作成されてデフォルト値(4.12.5)に初期化されます。 インスタンス変数は、オブジェクトに必要なファイナライズ(12.6)が完了した後、この変数がフィールドであるオブジェクトが参照されなくなったときに実質的に存在しなくなります。配列コンポーネントは、配列である新しいオブジェクトが作成されるたびに作成されてデフォルト値(4.12.5)に初期化される名前のない変数です(10、15.10.2)。 配列コンポーネントは、配列が参照されなくなったときに実質的に存在しなくなります。
メソッドに渡されるメソッド・パラメータ (8.4.1)の名前引数値。
メソッド宣言で宣言されるすべてのパラメータについて、そのメソッドが呼び出されるたびに新しいパラメータ変数が作成されます(15.12)。 新しい変数は、メソッド呼出し内の対応する引数値を使用して初期化されます。 メソッド・パラメータは、メソッドの本体の実行が完了したときに実質的に存在しなくなります。
コンストラクタに渡されるコンストラクタ・パラメータ (8.8.1)の名前引数値。
コンストラクタ宣言で宣言されるすべてのパラメータについて、クラス・インスタンス作成式(15.9)または明示的なコンストラクタ呼出し(8.8.7)がそのコンストラクタを呼び出すたびに新しいパラメータ変数が作成されます。 新しい変数は、作成式、コンストラクタまたは呼出し内の対応する引数値を使用して初期化されます。 コンストラクタ・パラメータは、コンストラクタの本体の実行が完了したときに実質的に存在しなくなります。
ラムダ式の本体(15.27.2)に渡されるラムダ・パラメータ (15.27.1)の名前引数値。
ラムダ式で宣言されるすべてのパラメータについて、ラムダの本体によって実装されたメソッドが呼び出されるたびに新しいパラメータ変数が作成されます(15.12)。 新しい変数は、メソッド呼出し内の対応する引数値を使用して初期化されます。 ラムダ・パラメータは、ラムダ式の本体の実行が完了したときに実質的に存在しなくなります。
例外パラメータは、
try
文のcatch
句によって例外が捕捉されるたびに作成されます(14.20)。新しい変数は、例外に関連付けられた実際のオブジェクトを使用して初期化されます(11.3、14.18)。 例外パラメータは、
catch
句に関連付けられたブロックの実行が完了したときに実質的に存在しなくなります。ローカル変数は、ローカル変数宣言文によって宣言されます(14.4)。
制御のフローがブロック(14.2)または
for
文に入るたびに(14.14)、そのブロックまたはfor
文内に直接含まれるローカル変数宣言文によって宣言されたローカル変数ごとに新しい変数が作成されます。ローカル変数宣言文には、その変数を初期化する式が含まれる場合があります。 ただし、初期化する式を持つローカル変数は、それを宣言するローカル変数宣言文が実行されるまでは初期化されません。 (明確な割当てのルール(16)により、ローカル変数が初期化されるか、それ以外の場合は値が割り当てられる前にローカル変数の値が使用されないようにします。) ローカル変数は、ブロックまたはfor文の実行が完了したときに実質的に存在しなくなります。
1つの例外的な状況を除けば、ローカル変数は常に、ローカル変数宣言文が実行されるときに作成されるとみなすことができます。 この例外的状況には、
switch
文(14.11)が含まれます。この場合、制御はブロックに入ることが可能になりますがローカル変数宣言文の実行をバイパスします。 ただし、明確な割当て(16)のルールによって課される制約のため、このようにバイパスされたローカル変数宣言文で宣言されたローカル変数は、割当て式(15.26)によって明確に値が割り当てられる前には使用できません。
例4.12.3-1. 様々な変数の種類
class Point {
static int numPoints; // numPoints is a class variable
int x, y; // x and y are instance variables
int[] w = new int[10]; // w[0] is an array component
int setX(int x) { // x is a method parameter
int oldx = this.x; // oldx is a local variable
this.x = x;
return oldx;
}
}
4.12.4 final
変数
変数はfinal
として宣言できます。 final
変数は1回のみ割り当てることができます。 final
変数が割当て(16)の直前に明確に割当て解除されないかぎり、この変数を割り当てると、コンパイル時にエラーが発生します。
final
変数はいったん割り当てられると、常に同じ値をとります。 オブジェクトへの参照がfinal
変数内に保持されている場合、オブジェクトの状態はオブジェクトの演算子によって変更される可能性がありますが、この変数は常に同じオブジェクトを参照します。 これはオブジェクトである配列にも当てはまります。配列への参照がfinal
変数内に保持されている場合、配列のコンポーネントは配列の演算子によって変更される可能性がありますが、この変数は常に同じ配列を参照します。
空のfinal
は、宣言にイニシャライザが欠落しているfinal
変数です。
定数変数は、定数式を使用して初期化される型String
またはプリミティブ型のfinal
変数です(15.28)。 変数が定数変数であるかどうかは、クラス初期化(12.4.1)、バイナリ互換性(13.1)、到達可能性(14.21)および明確な割当て(16.1.1)と密接な関係を持つ場合があります。
インタフェースのフィールド(9.3)、try
-with-resources文のリソースとして宣言されたローカル変数(14.20.3)、およびmulti-catch
句の例外パラメータ(14.20)、およびレコード・コンポーネントに対応するフィールド(8.10.1)の34種類の変数が暗黙的にfinal
であると宣言されています uni-catch
句の例外パラメータは、final
と暗黙的に宣言されることはありませんが、実質的にfinalである場合があります。
例4.12.4-1. final変数
変数final
を宣言すると、値が変更されないことを示す有用な記述として機能し、プログラミングのエラーを回避するのに役立ちます。 次のプログラムでは、
class Point {
int x, y;
int useCount;
Point(int x, int y) { this.x = x; this.y = y; }
static final Point origin = new Point(0, 0);
}
クラスPoint
は、final
クラスの変数origin
を宣言します。 origin
変数には、座標が(0, 0)であるクラスPoint
のインスタンスであるオブジェクトへの参照が保持されています。 変数Point.origin
の値は変更できないため、常に、イニシャライザによって作成されたオブジェクトである同じPoint
オブジェクトを参照します。 ただし、このPoint
オブジェクトに対する操作によってその状態が変更される可能性があります。たとえば、useCount
を変更したり、さらには誤ってx
またはy
座標を変更する場合などです。
final
として宣言されていない特定の変数は、かわりに実質的にfinalであるとみなされます。
次がすべて当てはまる場合、宣言子がイニシャライザを持つローカル変数(14.4.2)は実質的にfinalです。
次がすべて当てはまる場合、宣言子にイニシャライザが欠落しているローカル変数は実質的にfinalです。
final
としては宣言されません。割当て式の左側として出現する場合は常に、明確に未割当てであり、その割当ての前では明確に割り当てられていません。つまり、明確に未割当てであり、割当て式の右側の後では明確に割り当てられていません(16)。
接頭辞または接尾辞の増加または減少演算子のオペランドとして使用されることはありません。
宣言子がイニシャライザであるローカル変数として、実質的にfinalであるかどうかを確認することを目的として、メソッド、コンストラクタ、ラムダまたは例外パラメータ(8.4.1、8.8.1、9.4、15.27.1、14.20)が処理されます。
変数が実質的にfinalである場合、final
修飾子を宣言に追加しても、コンパイル時にエラーは発生しません。 反対に、有効なプログラム内でfinal
として宣言されているローカル変数またはパラメータは、final
修飾子が削除されていても、実質的にfinalになります。
第6章: 名前
名前を使用して、プログラム内で宣言されるエンティティを参照します。
宣言されたエンティティ(6.1)は、パッケージ、クラス型(標準、またはenum、またはレコード)、インタフェース型(標準または注釈型)、参照型のメンバー(クラス、インタフェース、フィールドまたはメソッド)、(クラス、インタフェース、メソッドまたはコンストラクタの)型パラメータ、(メソッド、コンストラクタまたは例外ハンドラの)パラメータ、またはローカル変数です。
プログラム内の名前は、単一の識別子で構成された単純名、または「.
」トークンによって区切られた識別子のシーケンスで構成された修飾名のどちらかです(6.2)。
名前を取り入れるすべての宣言にはscope (6.3)があります。これは、プログラム・テキストの一部であり、その中で、宣言されたエンティティを単純名によって参照できます。
修飾名N.xを使用して、パッケージまたは参照型のメンバーを参照できます。この場合、Nは単純名または修飾名で、xは識別子です。 Nがパッケージを示す場合、xはそのパッケージのメンバーです。これは、クラスまたはインタフェース型またはサブパッケージです。 Nが参照型または参照型の変数を示す場合、xはその型のメンバーを示します。これは、クラス、インタフェース、フィールドまたはメソッドです。
名前の意味を確認する場合(6.5)、発生のコンテキストを使用して、同じ名前を持つパッケージ、型、変数およびメソッド間で区別します。
アクセス制御(6.6)をクラス、インタフェース、メソッドまたはフィールド宣言内で指定して、メンバーへのアクセスを許可するタイミングを制御します。 アクセスはスコープとは異なる概念です。 アクセスにより、プログラム・テキストの一部を指定し、その中で、宣言されたエンティティを修飾名によって参照できます。 宣言されたエンティティへのアクセスは、フィールド・アクセス式(15.11)、メソッドが単純名では指定されないメソッド呼出し式(15.12)、メソッド参照式(15.13)、または修飾クラス・インスタンス作成式(15.9)にも関連します。 アクセス修飾子がない場合、ほとんどの宣言はパッケージ・アクセス権を持つため、その宣言が含まれていれば、パッケージ内のどの場所でもアクセスできます。その他の選択肢は、public
、protected
およびprivate
です。
この章では、完全修飾名および正規名(6.7)についても説明します。
6.1 宣言
宣言により、エンティティがプログラムに導入され、このエンティティを参照するために名前内で使用できる識別子(3.8)が組み込まれます。 この識別子には、導入されるエンティティがクラス、インタフェースまたは型パラメータである場合は型識別子であるという制約があります。
宣言されたエンティティは、次のいずれかです。
module
宣言で宣言されたモジュール(7.7)package
宣言で宣言されたパッケージ(7.4)単一静的インポート宣言またはオンデマンド静的インポート宣言で宣言された、インポートされた
static
メンバー(7.5.3、7.5.4)クラス型宣言で宣言されたクラス(8.1)
インタフェース型宣言で宣言されたインタフェース(9.1)
汎用クラス、インタフェース、メソッドまたはコンストラクタの宣言の一部として宣言された型パラメータ(8.1.2、9.1.2、8.4.4、8.8.4)
参照型のメンバー(8.2、9.2、8.9.3、9.6、10.7)で、次のいずれか:
enum定数(8.9)
フィールドで、次のいずれか:
メソッドで、次のいずれか:
パラメータで、次のいずれか:
ローカル変数で、次のいずれか:
コンストラクタ(8.8)も宣言によって導入されますが、新しい名前が導入されるのではなく、そのコンストラクタが宣言されたクラスの名前が使用されます。
汎用ではない型の宣言(class C ...
)では、1つのエンティティ(非汎用型(C
))が宣言されます。 非汎用型は、構文上の類似点を除いてRAW型ではありません。 対照的に、汎用型(class C<T> ...
またはinterface C<T> ...
)の宣言では、汎用型(C<T>
)および対応する非汎用型(C
)の2つのエンティティが宣言されます。 この場合、用語C
の意味は、この用語が出現するコンテキストによって異なります。
汎用性が重要ではない場合、次の非汎用コンテキストに示すように、識別子
C
は非汎用型C
を示します。汎用性が重要である場合、非汎用コンテキストを除く6.5のすべてのコンテキストの場合のように、識別子
C
は次のどちらかを示します。
14種類の非汎用コンテキストは、次のとおりです。
モジュール宣言内の
uses
またはprovides
ディレクティブ内(7.7.1)単一型インポート宣言内(7.5.1)
単一静的インポート宣言内の
.
の左側(7.5.3)オンデマンド静的インポート宣言内の
.
の左側(7.5.4)コンストラクタ宣言内の
(
の左側(8.8)注釈内の
@
記号の後(9.7)クラス・リテラル内の
.class
の左側(15.8.2)修飾された
this
式の.this
の左側(15.8.4)修飾されたスーパークラス・フィールド・アクセス式の
.super
の左側(15.11.2)修飾されたメソッド呼出し式内の
.
Identifierまたは.super.
Identifierの左側(15.12)メソッド参照式内の
.super::
の左側(15.13)例外パラメータ宣言内(14.20)
最初の11の非汎用コンテキストは、6.5.1内のTypeNameの最初の11の構文的コンテキストに対応しています。 12番目の非汎用コンテキストは、修飾されたExpressionName (C.x
など)に、静的メンバー・アクセスを示すためのTypeName C
が含まれる可能性がある場所です。 これらの12のコンテキスト内でTypeNameが共通して使用されていることが重要です。これは、これらのコンテキストには、型のファーストクラス未満の使用方法が含まれることを示します。 対照的に、13番目と14番目の非汎用コンテキストではClassTypeが採用されています。これは、throws
およびcatch
句には、型がファーストクラスの方法でフィールド宣言などにあわせて使用されていることを示します。 これら2つのコンテキストに非汎用としての特性が与えられるのは、例外型をパラメータ化できないという事実のためです。
ClassTypeプロダクションでは注釈が許可されるため、
throws
またはcatch
句内で型の使用に注釈を付けることができます。一方、TypeNameプロダクションでは注釈が許可されないため、単一型インポート宣言などの型の名前に注釈を付けることはできません。
命名規則
Java SEプラットフォームのクラス・ライブラリは、可能なかぎり、次の命名規則に従って選択された名前を使用しようとします。 これらの命名規則は、コードをより読みやすくし、ある種の命名規則の競合を回避する上で役に立ちます。
Javaプログラミング言語で書かれたすべてのプログラムで、これらの命名規則を使用することをお薦めします。 ただし、以前から使用されてきた慣例的な使用方法とは異なる場合、これらの命名規則に無条件に従う必要はありません。 このため、たとえば、クラス
java.lang.Math
のsin
およびcos
メソッドには、ここで提案されている命名規則をこれらのメソッド名が無視する形になるとしても、これらは短く、動詞ではないため、数学的に慣例的な名前が使用されます。
パッケージ名およびモジュール名
開発者は、広範に配布するパッケージに一意のパッケージ名を選択することにより、公開される2つのパッケージが同じ名前を持つ可能性を避けるべく策を講じる必要があります。 これにより、パッケージを簡単かつ自動的にインストールおよびカタログ化できるようになります。 このセクションでは、このような一意のパッケージ名を生成するために提案されている命名規則を規定します。 一連のパッケージをローカルかつ日常的なパッケージ名から、ここで説明する一意の名前形式に変換する処理を自動的にサポートするために、Java SEプラットフォームを実装することをお薦めします。
一意のパッケージ名を使用しない場合、競合するパッケージの作成とはまったく異なる点でパッケージ名の競合が発生する可能性があります。 この結果、ユーザーやプログラマでは解決が困難または不可能になる状況が生じるおそれがあります。 クラス
ClassLoader
およびModuleLayer
を使用して、同じ名前を持つパッケージを相互に隔離できますが、その場合、パッケージのインタラクションが制限されても、単純なプログラムには透過的な方法では制限されません。
一意のパッケージ名を形成するには、最初に
oracle.com
などのインターネット・ドメイン名を用意します(またはこのようなドメイン名を持つ組織に属します)。 その後、この名前をコンポーネント別に反転させて、この例ではcom.oracle
を取得します。次に、組織内でパッケージ名をより詳細に管理するために策定した命名規則を使用して、この名前をパッケージ名の接頭辞として使用します。 このような命名規則では、特定のパッケージ名コンポーネントを部署、部門、プロジェクト、マシンまたはログイン名として指定する場合があります。
例6.1-1. 一意のパッケージ名
com.nighthacks.scrabble.dictionary
org.openjdk.compiler.source.tree
net.jcip.annotations
edu.cmu.cs.bovik.cheese
gov.whitehouse.socks.mousefinder
一意のパッケージ名の最初のコンポーネントは常に、すべて小文字のASCII文字で書かれます。これは、
com
、edu
、gov
、mil
、net
またはorg
などの最上位のドメイン名の1つ、またはISO標準3166に規定されている国を示す英語2文字のコードの1つにする必要があります。
場合によっては、インターネットのドメイン名が有効なパッケージ名ではないことがあります。 次に、これらの状況に対処する上で提案される命名規則を示します。
モジュールの名前は、エクスポートされたプリンシパル・パッケージの名前に対応している必要があります。 モジュールにこのようなパッケージがない場合、または慣習的な理由により、モジュール名をエクスポートされたパッケージの1つに対応していない名前にする必要がある場合、その名前は依然として、その作者が関連するインターネットのドメインを反転させた形から始まる必要があります。
例6.1-2. 一意のモジュール名
com.nighthacks.scrabble
org.openjdk.compiler
net.jcip.annotations
パッケージまたはモジュール名の最初のコンポーネントは、識別子
java
にしないでください。 識別子java
から始まるパッケージまたはモジュール名は、Java SEプラットフォームのパッケージまたはモジュール用として予約されています。
パッケージまたはモジュールの名前は、パッケージまたはモジュールがインターネット上のどこに格納されているかを示すことを意図していません。 たとえば、
edu.cmu.cs.bovik.cheese
という名前のパッケージは必ずしも、ホストcmu.edu
またはcs.cmu.edu
またはbovik.cs.cmu.edu
から取得できるわけではありません。 一意のパッケージまたはモジュール名を生成するために提案される命名規則は、パッケージまたはモジュール名用として別のレジストリを作成するかわりに、広く知られる既存の一意の名前レジストリにパッケージおよびモジュールの命名規則を単に便乗させる方法です。
クラスおよびインタフェース型の名前
クラス型の名前は、過度に長くない説明的な名詞または名詞句にし、大文字と小文字を混在させ、各単語の先頭を大文字にする必要があります。
例6.1-3. 説明的なクラス名
`ClassLoader`
SecurityManager
`Thread`
Dictionary
BufferedInputStream
同様に、インタフェース型の名前は、過度に長くない短い説明的な名前にし、大文字と小文字を混在させ、各単語の先頭を大文字にする必要があります。 この名前は、説明的な名詞または名詞句である場合があります。これは、インタフェースが抽象的なスーパークラスであるかのように使用される場合(
java.io.DataInput
やjava.io.DataOutput
など)、またはインタフェースが動作を示す形容詞である場合(インタフェースRunnable
やCloneable
など)である場合に適しています。
型変数名
型変数名は、簡潔(可能であれば1文字)でありながら示唆に富む名前にする必要があります。また、小文字は含めないでください。 これにより、型パラメータを一般的なクラスやインタフェースと区別しやすくなります。
コンテナ型には、要素型として名前
E
を使用する必要があります。 マップには、キーの型としてK
、および値の型としてV
を使用する必要があります。 任意の例外型には、名前X
を使用する必要があります。 Oracleでは、型を区別するためにより具体的な名前がない場合は、型にT
を使用しています。 (これはたいてい、汎用メソッドの場合です。)
任意の型を示す型パラメータが複数存在する場合、アルファベットで
T
の隣にある文字(S
など)を使用する必要があります。 また、異なる型変数を区別するために下付き数字(T1
、T2
など)を使用することも許容されます。 このような場合、同じ接頭辞を持つすべての変数に添字を付ける必要があります。
汎用クラス内に汎用メソッドが出現する場合、混乱を避けるために、メソッドおよびクラスの型パラメータに同じ名前を使用しないようにすることをお薦めします。 同じことが、ネストした汎用クラスにも当てはまります。
例6.1-4. 従来の型変数名
public class HashSet<E> extends AbstractSet<E> { ... }
public class HashMap<K,V> extends AbstractMap<K,V> { ... }
public class ThreadLocal<T> { ... }
public interface Functor<T, X extends Throwable> {
T eval() throws X;
}
型パラメータが前述のカテゴリの1つに都合よく該当しない場合、名前はできるだけ1文字の範囲内で意味のあるものとして選択する必要があります。 前述の名前(
E
、K
、V
、X
、T
)は、指定したカテゴリに該当しない型パラメータには使用しないでください。
メソッド名
メソッド名は、動詞または動詞句にし、大文字と小文字を混在させ、先頭の文字を小文字にし、後続の任意の単語の先頭を大文字にする必要があります。 次に、メソッド名に関する追加の特定の命名規則を示します。
変数Vであるとみなされる可能性がある属性を取得および設定するメソッドには、
get*V*
およびset*V*
という名前を付ける必要があります。 例として、クラスThread
のメソッドgetPriority
およびsetPriority
があります。何かの長さを返すメソッドには、クラス
String
内の場合のように、length
という名前を付ける必要があります。オブジェクトに関するブール条件Vをテストするメソッドには、
is*V*
という名前を付ける必要があります。 例として、クラスThread
のメソッドisInterrupted
があります。オブジェクトを特定のフォーマットFに変換するメソッドには、
to*F*
という名前を付ける必要があります。 例として、クラスObject
のメソッドtoString
、クラスjava.util.Date
のメソッドtoLocaleString
およびtoGMTString
があります。
可能かつ適切であるかぎり、新しいクラス内のメソッドの名前を同様の既存のクラス(特にJava SEプラットフォームAPIのクラス)に基づいて付けると、使用しやすくなります。
フィールド名
final
ではないフィールドの名前は、大文字と小文字を混在させ、先頭の文字を小文字にし、後続の単語の先頭を大文字にする必要があります。 適切に設計されたクラスの場合、定数(static
またはfinal
フィールド)であるフィールドは除き、public
またはprotected
フィールドが使用されることはほとんどありません。
フィールドには、名詞、名詞句または名詞の短縮形である名前が含まれる必要があります。
この命名規則の例として、クラス
java.io.ByteArrayInputStream
のフィールドbuf
、pos
およびcount
、およびクラスjava.io.InterruptedIOException
のフィールドbytesTransferred
があります。
定数名
インタフェース型内の定数の名前は、1つ以上の単語、頭字語または短縮形のシーケンスにし、すべて大文字にし、コンポーネントをアンダースコア「
_
」文字で区切る必要があります。また、クラス型の変数final
の場合も、慣習的にこのようにする場合があります。 定数名は説明的なものにし、不必要に省略しないでください。 これらは慣習的に、妥当な話し言葉の一部である場合があります。
定数名の例として、クラス
Character
のMIN_VALUE
、MAX_VALUE
、MIN_RADIX
およびMAX_RADIX
があります。
セットの代替値、またはそれほど頻繁ではありませんが整数値のマスキング・ビットを表す定数のグループは、場合によっては名前の接頭辞として共通の頭字語を使用して指定すると役に立ちます。
次に例を示します。
interface ProcessStates { int PS_RUNNING = 0; int PS_SUSPENDED = 1; }
ローカル変数およびパラメータ名
ローカル変数およびパラメータ名は短いながら意味のあるものにする必要があります。 これらは多くの場合、次のような単語ではない小文字の短いシーケンスです。
頭字語:
ColoredPoint
への参照が格納された変数のcp
の場合のように、一連の単語の先頭文字です短縮形: ある種のバッファへのポインタが格納された変数の
buf
などですニーモニック用語: 通常は広く使用されているクラスのパラメータ名の後ろでパターン化された慣例的な名前を持つ一連のローカル変数を使用して、記憶しやすく、わかりやすい方法で編成されています。 次に例を示します。
in
およびout
: ある種の入力および出力が関わる場合は常に、System
のフィールドの後ろでパターン化されます
off
およびlen
: オフセットおよび長さが関わる場合は常に、java.io
のインタフェースDataInput
およびDataOutput
のメソッドread
およびwrite
のパラメータの後ろでパターン化されます
1文字のローカル変数またはパラメータ名は回避する必要があります。ただし、一時またはループ変数の場合、あるいは変数に特徴のない型の値が格納されている場合は除きます。 慣例的な1文字の名前は、次のとおりです。
byte
を表すb
char
を表すc
double
を表すd
Exception
を表すe
float
を表すf
int
を表すi
、j
およびk
long
を表すl
Object
を表すo
String
を表すs
- ある型の任意の値を表す
v
2、3の小文字のみで構成されたローカル変数またはパラメータ名は、一意のパッケージ名の最初のコンポーネントである最初の国コードおよびドメイン名と競合しないようにする必要があります。
6.5 名前の意味の確認
6.5.1 コンテキストに応じた名前の構文的分類
次のコンテキストでは、名前が構文的にModuleNameとして分類されます。
次のコンテキストでは、名前が構文的にPackageNameとして分類されます。
モジュール宣言内の
exports
またはopens
の右側修飾されたPackageName内の「
.
」の左側
次のコンテキストでは、名前が構文的にTypeNameとして分類されます。
最初の11の非汎用コンテキスト(6.1):
モジュール宣言内の
uses
またはprovides
ディレクティブ内(7.7.1)単一型インポート宣言内(7.5.1)
単一静的インポート宣言内の
.
の左側(7.5.3)オンデマンド静的インポート宣言内の
.
の左側(7.5.4)コンストラクタ宣言内の
(
の左側(8.8)注釈内の
@
記号の後(9.7)クラス・リテラル内の
.class
の左側(15.8.2)修飾された
this
式の.this
の左側(15.8.4)修飾されたスーパークラス・フィールド・アクセス式の
.super
の左側(15.11.2)修飾されたメソッド呼出し式内の
.
Identifierまたは.super.
Identifierの左側(15.12)メソッド参照式内の
.super::
の左側(15.13)
型が使用されている
1617のコンテキスト内のReferenceType (配列型内のカッコの左側にあるReferenceType、パラメータ化された型内の<の左側、パラメータ化された型の非ワイルドカード型引数内、またはパラメータ化された型のワイルドカード型引数のextends
またはsuper
句内を含む)を構成する識別子または点線付きの識別子シーケンスとして(4.11):インタフェース宣言の
extends
句内(9.1.3)汎用クラス、インタフェース、メソッドまたはコンストラクタの型パラメータ宣言の
extends
句内(8.1.2、9.1.2、8.4.4、8.8.4)メソッドのレシーバ・パラメータの型(8.4)
例外パラメータ宣言内の型(14.20)
レコードのレコード・コンポーネントの型(8.10.1)
11.12. 明示的なコンストラクタ呼出し文、クラス・インスタンス作成式、またはメソッド呼出し式に対する明示的な型引数リスト内(8.8.7.1、15.9、15.12)12.13. 非修飾クラス・インスタンス作成式内で、インスタンス化するクラス型として(15.9)、またはインスタンス化する無名クラスの直接スーパークラスまたは直接スーパーインタフェースとして(15.9.5)13.14. 配列作成式内の要素型(15.10.1)14.15. キャスト式のキャスト演算子内の型(15.16)15.16.instanceof
関係演算子に続く型(15.20.2)16.17. メンバー・メソッドを検索するための参照型として、またはコンストラクトに対するクラス型または配列型としてのメソッド参照式内(15.13)。
前述の16のコンテキスト内のReferenceTypeの識別子からのTypeNameの抽出は、要素型や型引数などのReferenceTypeのサブ用語すべてに繰り返し適用することを意図しています。
たとえば、フィールド宣言に型
p.q.Foo[]
が使用されるとします。 配列型のカッコは無視され、用語p.q.Foo
が識別子の点線シーケンスとして配列型内のカッコの左側に抽出され、TypeNameとして分類されます。 後のステップで、p
、q
およびFoo
のどれが型名またはパッケージ名であるかが確認されます。別の例として、キャスト演算子に型
p.q.Foo<? extends String>
が使用されるとします。 用語p.q.Foo
が識別子用語の点線シーケンスとして再度、今回はパラメータ化された型内の<
の左側に抽出され、TypeNameとして分類されます。 用語String
が、パラメータ化された型のワイルドカード型引数のextends
句内の識別子として抽出され、TypeNameとして分類されます。
次のコンテキストでは名前がExpressionNameとして構文的に分類されています。
修飾されたスーパークラス・コンストラクタ呼び出し内で修飾する式として(8.8.7.1)
修飾されたクラス・インスタンス作成式内で修飾する式として(15.9)
配列アクセス式内で配列参照式として(15.10.3)
PostfixExpressionとして(15.14)
割当て演算子の左側のオペランドとして(15.26)
try
-with-resources文内のVariableAccessとして(14.20.3)
次のコンテキストでは、名前が構文的にMethodNameとして分類されます。
- メソッド呼出し式内の「
(
」の前(15.12)
次のコンテキストでは、名前が構文的にPackageOrTypeNameとして分類されます。
修飾されたTypeName内の「
.
」の左側オンデマンド型インポート宣言内(7.5.2)
次のコンテキストでは、名前が構文的にAmbiguousNameとして分類されます。
修飾されたExpressionName内の「
.
」の左側メソッド呼出し式内の「
(
」の前にある右端の.
の左側修飾されたAmbiguousName内の「
.
」の左側注釈型要素宣言のデフォルト値句内(9.6.2)
要素と値のペア内の「
=
」の右側(9.7.1)メソッド参照式内の
::
の左側(15.13)
構文的分類の結果、特定の種類のエンティティを式の特定の部分に制限できるようになります。
フィールド、パラメータまたはローカル変数の名前を式として使用できます(15.14.1)。
メソッドの名前は、式内にメソッド呼出し式の一部としてのみ表示される場合があります(15.12)。
クラスまたはインタフェース型の名前は式内に、クラス・リテラルの一部(15.8.2)、修飾された
this
式(15.8.4)、クラス・インスタンス作成式(15.9)、配列作成式(15.10.1)、キャスト式(15.16)、instanceof
式(15.20.2)、enum定数(8.9)、あるいはフィールドまたはメソッドの修飾名の一部としてのみ出現する場合があります。パッケージの名前は、式内にクラスまたはインタフェース型の修飾名の一部としてのみ表示される場合があります。
第7章: パッケージおよびモジュール
7.5 インポート宣言
7.5.1 単一型インポート宣言
単一型インポート宣言では、単一型に正規名を付け、単一の型インポート宣言が出現するコンパイル・ユニットのモジュール、クラスおよびインタフェース宣言内で単一名で使用可能にすることにより、単一型をインポートします。
- SingleTypeImportDeclaration:
import
TypeName;
TypeNameは、クラス型、インタフェース型、enum型、レコード型または注釈型の正規名である必要があります(6.7)。
型は、名前付きパッケージのメンバーであるか、最も外側にあり字句的に囲んでいる型宣言(8.1.3)が名前付きパッケージのメンバーである型のメンバーである必要があります。そうでない場合、コンパイル時にエラーが発生します。
名前付き型がアクセス不可能である場合、コンパイル時にエラーが発生します(6.6)。
同じコンパイル・ユニット内の2つの単一型インポート宣言が、同じ単純名を持つ型をインポートしようとすると、コンパイル時にエラーが発生します。ただし、2つの型が同じ型である場合は除きます。この場合、重複する宣言は無視されます。
単一型インポート宣言によってインポートされた型が、import
宣言を含むコンパイル・ユニット内で宣言される場合、import
宣言は無視されます。
単純名がnである型が単一型インポート宣言によってインポートされ、コンパイル・ユニットによって単純名がnである最上位の型(7.6)も宣言される場合、コンパイル時にエラーが発生します。
コンパイル・ユニットに、単純名がnである型をインポートする単一型インポート宣言と、単純名がnである型をインポートする単一静的インポート宣言(7.5.3)の両方が含まれる場合、コンパイル時にエラーが発生します。ただし、2つの型が同じ型である場合は除きます。この場合、重複する宣言は無視されます。
例7.5.1-1. 単一型インポート
import java.util.Vector;
これにより、単純名Vector
がコンパイル・ユニット内のクラスおよびインタフェース宣言内で使用可能になります。 このため、単純名Vector
は、フィールド、パラメータ、ローカル変数の宣言、または同じ名前を持つネストした型宣言によってシャドウ化(6.4.1)または不明瞭化(6.4.2)されていないあらゆる場所で、パッケージjava.util
内の型宣言Vector
を参照します。
java.util.Vector
の実際の宣言は汎用です(8.1.2)。 インポートされた後、名前Vector
は、Vector<String>
などのパラメータ化された型内の修飾なしで、またはRAW型Vector
として使用できます。 import
宣言に関連する制限として、汎用型宣言内で宣言されたネストした型はインポートできますが、外側の型は常に消去されます。
例7.5.1-2. 重複型宣言
次のプログラムを実行すると、
import java.util.Vector;
class Vector { Object[] vec; }
次の場合と同様に、Vector
の宣言が重複するため、コンパイル時にエラーが発生します。
import java.util.Vector;
import myVector.Vector;
この場合、myVector
は、コンパイル・ユニットが含まれるパッケージです。
package myVector;
public class Vector { Object[] vec; }
例7.5.1-3. サブパッケージのインポートなし
import
宣言では、サブパッケージをインポートすることはできません。型のみがインポートされます。
たとえば、java.util
をインポートし、名前util.Random
を使用して型java.util.Random
を参照しようとしても動作しません。
import java.util;
class Test { util.Random generator; }
// incorrect: compile-time error
例7.5.1-4. パッケージ名でもある型名のインポート
パッケージ名および型名は通常、6.1で説明されている命名規則では異なるものです。 ただし、人為的な例として次を想定します。ここで使用されるのは、Mosquito
という名前のパブリック・クラスを宣言する、慣例に従わない名前が付けられたパッケージVector
:
package Vector;
public class Mosquito { int capacity; }
および次のコンパイル・ユニットです。
package strange;
import java.util.Vector;
import Vector.Mosquito;
class Test {
public static void main(String[] args) {
System.out.println(new Vector().getClass());
System.out.println(new Mosquito().getClass());
}
}
クラスVector
をパッケージjava.util
からインポートする単一型インポート宣言では、パッケージ名Vector
が後続のimport
宣言に出現して適切に認識されることが阻止されることはありません。 この例では、次の出力をコンパイルして生成しています。
class java.util.Vector
class Vector.Mosquito
7.5.2 オンデマンド型インポート宣言
オンデマンド型インポート宣言では、名前付きパッケージまたは型のアクセス可能な型をすべて必要に応じてインポートできます。
- TypeImportOnDemandDeclaration:
import
PackageOrTypeName.
*
;
PackageOrTypeNameは、パッケージ、クラス型、インタフェース型、enum型、レコード型または注釈型の正規名(6.7)である必要があります。
PackageOrTypeNameが型を示す場合(6.5.4)、この型は、名前付きパッケージのメンバーであるか、最も外側にあり字句的に囲んでいる型宣言(8.1.3)が名前付きパッケージのメンバーである型のメンバーである必要があります。そうでない場合、コンパイル時にエラーが発生します。
名前付きパッケージが現在のモジュールから一意に見えない場合(7.4.3)、または名前付き型にアクセスできない場合(6.6)は、コンパイル時にエラーが発生します。
オンデマンド型インポート宣言で現在のコンパイル・ユニットの名前付きパッケージまたはjava.lang
のいずれかに名前を付ける場合、コンパイル時エラーにはなりません。 このような場合、オンデマンド型インポート宣言は無視されます。
同じコンパイル・ユニット内に複数のオンデマンド型インポート宣言がある場合、同じ名前またはパッケージの名前が付けられる場合があります。 これらの宣言の1つを除いてすべてが重複しているとみなされます。この結果、その型は1回のみインポートされたものとして扱われます。
コンパイル・ユニットにオンデマンド型インポート宣言とオンデマンド静的インポート宣言(7.5.4)の両方が含まれる場合、同じ型の名前が付けられる場合があります。この結果、その型のstatic
メンバー(8.5、9.5)が1回のみインポートされたものとして扱われます。
例7.5.2-1. オンデマンド型インポート
import java.util.*;
これにより、パッケージjava.util
内で宣言されたすべてのpublic
型の単純名がコンパイル・ユニットのクラスおよびインタフェース宣言内で使用可能になります。 このため、単純名Vector
は、型Vector
がシャドウ化(6.4.1)または不明瞭化(6.4.2)されていないコンパイル・ユニット内のあらゆる場所でパッケージjava.util
内のその型宣言を参照します。
この宣言は、単純名がVector
である単一型インポート宣言によって、コンパイル・ユニットが属するパッケージ内でVector
という名前が付けられて宣言された型によって、またはネストしたクラスまたはインタフェースによってシャドウ化される場合があります。
この宣言は、フィールド、パラメータ、またはVector
という名前のローカル変数の宣言によって不明瞭化される場合があります。
(これらのいずれかの状況が発生するのは異常です。)
7.5.3 単一静的インポート宣言
単一静的インポート宣言では、特定の単純名を持つアクセス可能なすべてのstatic
メンバーを型からインポートします。 これにより、単一静的インポート宣言が出現するコンパイル・ユニットのモジュール、クラスおよびインタフェース宣言内でstatic
メンバーを単一名で使用できるようになります。
- SingleStaticImportDeclaration:
import
static
TypeName.
Identifier;
TypeNameは、クラス型、インタフェース型、enum型、レコード型または注釈型の正規名(6.7)である必要があります。
型は、名前付きパッケージのメンバーであるか、最も外側にあり字句的に囲んでいる型宣言(8.1.3)が名前付きパッケージのメンバーである型のメンバーである必要があります。そうでない場合、コンパイル時にエラーが発生します。
名前付き型がアクセス不可能である場合、コンパイル時にエラーが発生します(6.6)。
この識別子は、名前付き型の少なくとも1つのstatic
メンバーに名前を付ける必要があります。 その名前を持つstatic
メンバーがないか、名前付きメンバーがすべてアクセス不可能である場合は、コンパイル時にエラーが発生します。
1回の単一静的インポート宣言で、同じ名前を持つ複数のフィールドまたは型、あるいは同じ名前またはシグネチャを持つ複数のメソッドをインポートできます。 このようになるのは、すべて同じ名前を持つ複数のフィールド、メンバー型またはメソッドを名前付き型が独自のスーパー・タイプから継承する場合です。
同じコンパイル・ユニット内の2つの単一静的インポート宣言が、同じ単純名を持つ型をインポートしようとすると、コンパイル時にエラーが発生します。ただし、2つの型が同じ型である場合は除きます。この場合、重複する宣言は無視されます。
単一静的インポート宣言によって単純名がnである型がインポートされ、コンパイル・ユニットによって単純名がnである最上位の型(7.6)も宣言される場合、コンパイル時にエラーが発生します。
コンパイル・ユニットに、単純名がnである型をインポートする単一静的インポート宣言と、単純名がnである型をインポートする単一型インポート宣言(7.5.1)の両方が含まれる場合、コンパイル時にエラーが発生します。ただし、2つの型が同じ型である場合は除きます。この場合、重複する宣言は無視されます。
7.5.4 オンデマンド静的インポート宣言
オンデマンド静的インポート宣言では、名前付き型のアクセス可能なstatic
メンバーをすべて必要に応じてインポートできます。
- StaticImportOnDemandDeclaration:
import
static
TypeName.
*
;
TypeNameは、クラス型、インタフェース型、enum型、レコード型または注釈型の正規名(6.7)である必要があります。
型は、名前付きパッケージのメンバーであるか、最も外側にあり字句的に囲んでいる型宣言(8.1.3)が名前付きパッケージのメンバーである型のメンバーである必要があります。そうでない場合、コンパイル時にエラーが発生します。
名前付き型がアクセス不可能である場合、コンパイル時にエラーが発生します(6.6)。
同じコンパイル・ユニット内に複数のオンデマンド静的インポート宣言がある場合、同じ型の名前が付けられる場合があります。この結果、このような宣言が正確に1つ存在するものとして扱われます。
同じコンパイル・ユニット内に複数のオンデマンド静的インポート宣言がある場合、同じメンバーの名前が付けられる場合があります。この結果、メンバーが正確に1回インポートされたものとして扱われます。
1回のオンデマンド静的インポート宣言で、同じ名前を持つ複数のフィールドまたは型、または同じ名前とシグネチャを持つ複数のメソッドをインポートできます。 このようになるのは、すべて同じ名前を持つ複数のフィールド、メンバー型またはメソッドを名前付き型が独自のスーパー・タイプから継承する場合です。
コンパイル・ユニットにオンデマンド静的インポート宣言とオンデマンド型インポート宣言(7.5.2)の両方が含まれる場合、同じ型の名前が付けられる場合があります。この結果、その型のstatic
メンバー(8.5、9.5)が1回のみインポートされたものとして扱われます。
第8章: クラス
クラス宣言では、新しい参照型を定義し、これらの実装方法について記述します(8.1)。
最上位クラスは、ネストしたクラスではないクラスです。
ネストしたクラスは、宣言が別のクラスまたはインタフェースの本体内で行われるクラスです。
この章では、すべてのクラスの共通セマンティクスについて説明します。具体的には、最上位クラス(7.6)およびネストしたクラス(メンバー・クラス(8.5、9.5)、ローカル・クラスおよびローカル・レコード(14.3)および無名クラス(15.9.5)を含む)です。 特定の種類のクラスに固有の詳細は、これらのコンストラクトに特化したセクションで説明します。
名前付きクラスはabstract
(8.1.1.1)として宣言でき、これが不完全に実装されている場合は抽象であると宣言する必要があります。このようなクラスはインスタンス化できませんが、サブクラスによって拡張できます。 クラスはfinal
(8.1.1.2)として宣言される場合があります。この場合、このクラスはサブクラスを持つことができません。 クラスがpublic
として宣言されている場合、そのモジュールの任意のパッケージ内のコードから、および場合によっては他のモジュール内のコードから参照できます。 Object
を除く各クラスは、既存の単一のクラスの拡張(つまり、サブクラス) (8.1.4)であり、インタフェースを実装する場合があります(8.1.5)。 クラスは汎用(8.1.2)である場合があります。つまり、クラスは、クラスの様々なインスタンス間でバインディングが異なる可能性のある型変数を宣言できます。
クラスは、他の種類の宣言と同じように、注釈(9.7)を使用して修飾できます。
クラスの本体は、メンバー(フィールド、メソッド、ネストしたクラスおよびインタフェース)、インスタンスと静的イニシャライザ、およびコンストラクタ(8.1.6)を宣言します。 メンバー(8.2)のスコープ(6.3)は、メンバーが属するクラスの宣言の本体全体です。 フィールド、メソッド、メンバー・クラス、メンバー・インタフェースおよびコンストラクタ宣言には、アクセス修飾子(6.6) public
、protected
またはprivate
が含まれる場合があります。 クラスのメンバーには、宣言されたメンバーと継承されたメンバーの両方が含まれます(8.2)。 新しく宣言されたフィールドは、スーパークラスまたはスーパーインタフェース内で宣言されたフィールドを隠すことができます。 新しく宣言されたクラス・メンバーおよびインタフェース・メンバーは、スーパークラスおよびスーパーインタフェース内で宣言されたクラス・メンバーまたはインタフェース・メンバーを隠すことができます。 新しく宣言されたメソッドは、スーパークラスまたはスーパーインタフェース内で宣言されたメソッドを隠す、実装する、またはオーバーライドすることができます。
フィールド宣言(8.3)では、1回インカネーションされるクラス変数、およびクラスのインスタンスごとに新しくインカネーションされるインスタンス変数を記述します。 フィールドはfinal
(8.3.1.2)として宣言できます。この場合、このフィールドは1回のみ割り当てることができます。 任意のフィールド宣言にイニシャライザを含めることができます。
メンバー・クラス宣言(8.5)では、前後のクラスのメンバーであるネストしたクラスを記述します。 メンバー・クラスはstatic
である場合があります。この場合、メンバー・クラスは前後のクラスのインスタンス変数にアクセスできません。または、内部クラス(8.1.3)である場合があります。
メンバー・インタフェース宣言(8.5)では、前後のクラスのメンバーであるネストしたインタフェースを記述します。
メソッド宣言(8.4)では、メソッド呼出し式(15.12)によって呼び出すことのできるコードを記述します。 クラス・メソッドは、クラス型に関連して呼び出されます。インスタンス・メソッドは、クラス型のインスタンスである特定のオブジェクトに関連して呼び出されます。 宣言が実装方法を示していないメソッドは、abstract
として宣言する必要があります。 メソッドはfinal
(8.4.3.3)として宣言される場合があります。この場合、このメソッドは隠したりオーバーライドすることができません。 メソッドは、プラットフォーム依存のnative
コード(8.4.3.4)によって実装される場合があります。 synchronized
メソッド(8.4.3.6)は、synchronized
文(14.19)で使用されるように、本体を実行する前にオブジェクトを自動的にロックし、戻り時にオブジェクトを自動的にロック解除します。これにより、そのアクティビティを他のスレッド(17)のアクティビティと同期できるようになります。
メソッド名はオーバーロードする場合があります(8.4.9)。
インスタンス・イニシャライザ(8.6)は、作成時にインスタンスの初期化をサポートするために使用できる実行可能コードのブロックです(15.9)。
静的イニシャライザ(8.7)は、クラスの初期化をサポートするために使用できる実行可能コードのブロックです。
コンストラクタ(8.8)はメソッドと似ていますが、メソッド呼出しによって直接呼び出すことはできません。コンストラクタは、新しいクラス・インスタンスを初期化するために使用されます。 メソッドと同様、これはオーバーロードする場合があります(8.8.8)。
8.1 クラス宣言
クラス宣言では、新しい名前付き参照型を指定します。
クラス宣言には、標準クラス宣言、およびenum宣言およびレコード宣言の23種類があります。
- ClassDeclaration:
- NormalClassDeclaration
- EnumDeclaration
- RecordDeclaration
- NormalClassDeclaration:
- {ClassModifier}
class
TypeIdentifier [TypeParameters]
[Superclass] [Superinterfaces] ClassBody
このセクションのルールは、enum宣言およびレコード宣言を含むすべてのクラス宣言に適用されます。 ただし、クラス修飾子、内部クラスおよびスーパークラスに関してはenum宣言およびレコード宣言に特別なルールが適用されます。これらのルールについては、8.9および8.10を参照してください。
クラス宣言内のTypeIdentifierは、クラスの名前を指定します。
クラスの単純名が前後のクラスまたはインタフェースの単純名と同じである場合は、コンパイル時にエラーが発生します。
クラス宣言のスコープおよびシャドウ化については、6.3および6.4に規定されています。
8.1.4 スーパークラスおよびサブクラス
標準クラス宣言内のオプションのextends
句は、現在のクラスの直接スーパークラスを指定します。
- スーパークラス:
extends
ClassType
extends
句は最初のクラスであり、直接スーパークラスを持たないため、クラスObject
の定義内に出現しないようにする必要があります。出現すると、コンパイル時にエラーが発生します。
ClassTypeは、アクセス可能なクラス型(6.6)に名前を付ける必要があります。そうでない場合、コンパイル時にエラーが発生します。
クラスfinal
はサブクラスを持つことが許可されていないため、final
であるクラスにClassTypeが名前を付けた場合はコンパイル時にエラーが発生します(8.1.1.2)。
ClassTypeがクラスEnum
またはEnum
の呼出しに名前を付けた場合は、コンパイル時にエラーが発生します(8.9)。
ClassTypeがクラスRecord
の名前を付けた場合は、コンパイル時にエラーが発生します(8.10)。
ClassTypeには型引数があります。これは、整形式のパラメータ化された型(4.5)を表し、いずれの型引数もワイルドカード型引数にすることはできません。ワイルドカード型引数にすると、コンパイル時にエラーが発生します。
(場合によっては汎用の)クラス宣言C<
F1,...,Fn>
(n ≥ 0, C ≠ Object
)が与えられたときに、extends
句が存在する場合、クラス型C<
F1,...,Fn>
の直接スーパークラスは、Cの宣言のextends
句で与えられた型です。そうでない場合はObject
です。
汎用クラス宣言C<
F1,...,Fn>
(n > 0)が与えられた場合、パラメータ化されたクラス型C<
T1,...,Tn>
(この場合、Ti (1 ≤ i ≤ n)は型)の直接スーパークラスは、D<
U1 θ,...,Uk θ>
(この場合、D<
U1,...,Uk>
はC<
F1,...,Fn>
の直接スーパークラス、およびθは[*F~1~*:=*T~1~*,...,*F~n~*:=*T~n~*]
の代替)です。
クラスは、直接スーパークラスの直接サブクラスであると言うことができます。 直接スーパークラスは、その実装が現在のクラスの実装の導出元であるクラスです。
サブクラス関係は、直接サブクラス関係の推移閉包です。 クラスAがクラスCのサブクラスであるのは、次のいずれかの条件が満たされる場合です。
AがCの直接サブクラスである
クラスBが存在し、AがBのサブクラスであり、BがCのサブクラスであり、この定義が再帰的に適用される。
クラスCがクラスAのスーパークラスであると言えるのは、Aが常にCのサブクラスである場合です。
例8.1.4-1. 直接スーパークラスおよびサブクラス
class Point { int x, y; }
final class ColoredPoint extends Point { int color; }
class Colored3DPoint extends ColoredPoint { int z; } // error
この場合、これらの関係は次のとおりです。
クラス
Point
は、Object
の直接サブクラスである。クラス
Object
は、クラスPoint
の直接スーパークラスである。クラス
ColoredPoint
は、クラスPoint
の直接サブクラスである。クラス
Point
は、クラスColoredPoint
の直接スーパークラスである。
クラスColored3dPoint
の宣言では、finalクラスColoredPoint
を拡張しようとするため、コンパイル時にエラーが発生します。
例8.1.4-2. スーパークラスおよびサブクラス
class Point { int x, y; }
class ColoredPoint extends Point { int color; }
final class Colored3dPoint extends ColoredPoint { int z; }
この場合、これらの関係は次のとおりです。
クラス
Point
は、クラスColoredPoint
のスーパークラスである。クラス
Point
は、クラスColored3dPoint
のスーパークラスである。クラス
ColoredPoint
は、クラスPoint
のサブクラスである。クラス
ColoredPoint
は、クラスColored3dPoint
のスーパークラスである。クラス
Colored3dPoint
は、クラスColoredPoint
のサブクラスである。クラス
Colored3dPoint
は、クラスPoint
のサブクラスである。
クラスCが型Tに直接依存するのは、TがCのextends
またはimplements
句内で、スーパークラスまたはスーパーインタフェースとして、またはスーパークラスまたはスーパーインタフェース名の完全修飾形式の修飾子として指定されている場合です。
クラスCが参照型Tに依存するのは、次のいずれかの条件が満たされる場合です。
CがTに直接依存する。
Cが、Tに依存(9.1.3)するインタフェースIに直接依存する。
Cが、Tに依存するクラスDに直接依存する(この定義を再帰的に使用します)。
クラスがそれ自体に依存する場合は、コンパイル時にエラーが発生します。
クラスがロードされるときに、循環的に宣言されたクラスが実行時に検出された場合、ClassCircularityError
がスローされます(12.2.1)。
例8.1.4-3. それ自体に依存するクラス
class Point extends ColoredPoint { int x, y; }
class ColoredPoint extends Point { int color; }
このプログラムを実行すると、クラスPoint
がそれ自体に依存しているため、コンパイル時にエラーが発生します。
8.5 メンバー型宣言
8.5.1 静的メンバー型宣言
キーワードstatic
は、非内部クラスまたはインタフェースTの本体内のメンバー型Cの宣言を変更する場合があります。 この結果、Cが内部クラスではないことを宣言します。 Tのstatic
メソッドの本体内にTの現在のインスタンスがないように、CにもTの現在のインスタンスはなく、字句的に囲むインスタンスもありません。
static
クラスに包含クラスの非static
メンバーの使用が含まれる場合、コンパイル時にエラーが発生します。
メンバー・インタフェースは暗黙的にstatic
です(9.1.1)。 メンバー・インタフェースの宣言でstatic
修飾子の重複指定が許可されています。
メンバー・レコードは暗黙的にstatic
です(8.10)。 メンバー・レコードの宣言でstatic
修飾子の重複指定が許可されています。
8.8 コンストラクタ宣言
コンストラクタは、クラスのインスタンスであるオブジェクトの作成時に使用されます(12.5、15.9)。
- ConstructorDeclaration:
- {ConstructorModifier} ConstructorDeclarator [Throws] ConstructorBody
- ConstructorDeclarator:
- [TypeParameters] SimpleTypeName
(
[ReceiverParameter,
] [FormalParameterList])
- SimpleTypeName:
- TypeIdentifier
このセクションのルールは、enum宣言およびレコード宣言を含むすべてのクラス宣言内のコンストラクタに適用されます。 ただし、コンストラクタ修飾子、コンストラクタ本体およびデフォルト・コンストラクタに関してはenum宣言に特別なルールが適用されます。これらのルールについては、8.9.2を参照してください。 特別なルールは、特別なコンパクト宣言形式を含め、コンストラクタに関するレコード宣言にも適用されます。詳細は、8.10.4を参照してください。
ConstructorDeclarator内のSimpleTypeNameは、コンストラクタ宣言を含むクラスの単純名である必要があります。そうでない場合、コンパイル時にエラーが発生します。
その他すべての点において、コンストラクタ宣言は、結果を持たないメソッド宣言に似ています(8.4.5)。
コンストラクタ宣言はメンバーではありません。 これは決して継承されないため、隠されたりオーバーライドされたりすることはありません。
コンストラクタは、クラス・インスタンス作成式によって(15.9)、文字列連結演算子+
を使用した変換および連結によって(15.18.1)、および他のコンストラクタからの明示的なコンストラクタ呼出しによって(8.8.7)呼び出されます。 コンストラクタへのアクセスはアクセス修飾子によって制御されるため(6.6)、アクセス不可能なコンストラクタを宣言することによってクラスのインスタンス化を阻止できます(8.8.10)。
コンストラクタがメソッド呼出し式(15.12)によって呼び出されることはありません。
例8.8-1. コンストラクタ宣言
class Point {
int x, y;
Point(int x, int y) { this.x = x; this.y = y; }
}
8.10 レコード型
これは、新しい項です。
レコード宣言では、特別な種類のクラス型である新しいレコード型を指定します。
- RecordDeclaration:
- {ClassModifier}
record
TypeIdentifier [TypeParameters] RecordHeader [SuperInterfaces] RecordBody
レコード宣言に修飾子abstract
が含まれる場合は、コンパイル時にエラーが発生します。
レコード宣言は暗黙的にfinal
です。 レコード型の宣言でfinal
修飾子の重複指定が許可されています。
ネストしたレコード型は暗黙的にstatic
です。 ネストしたレコード型の宣言でstatic
修飾子の重複指定が許可されています。
これが意味するのは、内部クラスの本体内でレコード型を宣言できないということです(8.1.3)。これは、内部クラスには定数変数以外の
static
メンバーを指定できないためです。
レコード宣言に対して同じキーワードが修飾子として複数回出現する場合、またはレコード宣言にアクセス修飾子public
、protected
およびprivate
が複数含まれる場合(6.6)は、コンパイル時にエラーが発生します。
レコード型Rの直接スーパークラスはjava.lang.Record
です。
レコード宣言ではスーパークラスを明示的に指定できないため、レコード型の直接スーパークラスが
java.lang.Record
であることを明示的に宣言することはできません。
直列化メカニズムでは、レコード型のインスタンスは通常の直列化可能なオブジェクトまたは外部化可能なオブジェクトとは異なる方法で扱われます。 特に、レコード・オブジェクトは標準コンストラクタを使用して直列化復元されます(8.10.4)。
8.10.1 レコード・コンポーネント
レコード型のレコード・コンポーネント(存在する場合)は、レコード宣言のヘッダー内でカンマ区切りのパラメータ指定子のリストで指定されます。 各レコード・コンポーネントは、(必要に応じてfinal
修飾子および/または1つ以上の注釈が前に付いた)型、レコード・コンポーネントの名前を指定する(必要に応じて後ろにカッコが付いた)識別子で構成されます。 レコード型にレコード・コンポーネントがない場合、レコード・ヘッダーは空のカッコのペアで構成されます。
各レコード・コンポーネントは、レコード型の、暗黙的に宣言されたフィールドおよび(明示的または暗黙的に宣言された)アクセサ・メソッドに対応します(8.10.3)。
- RecordHeader:
(
[ RecordComponentList ])
- RecordComponentList:
- RecordComponent {
,
RecordComponent } - RecordComponent:
- { VariableModifier } UnannType VariableDeclaratorId
- VariableArityRecordComponent
- VariableArityRecordComponent:
- { VariableModifier } UnannType { Annotation }
...
Identifier
RecordComponentのプロダクションがFormalParameterのプロダクションのコンテンツと同一である場合があります(8.4.1)。
便宜上、ここでは8.4.1、8.3および4.3の次のプロダクションを示します。
- FormalParameter:
- { VariableModifier } UnannType VariableDeclaratorId
- VariableArityParameter
- VariableArityParameter:
- { VariableModifier } UnannType { Annotation }
...
Identifier- VariableModifier:
- Annotation
final
- VariableDeclaratorId:
- Identifier [ Dims ]
- Dims:
- { Annotation }
[ ]
{ { Annotation }[ ]
}
レコード・コンポーネントでfinal
修飾子の重複指定が許可されています。 final
がレコード・コンポーネントの修飾子として複数回出現する場合は、コンパイル時にエラーが発生します。
レコード・コンポーネントは、型に続く省略記号が示す可変個引数レコード・コンポーネントである場合があります。 1つのレコード型に対して最大で1つの可変個引数レコード・コンポーネントが許可されています。 可変個引数レコード・コンポーネントがレコード・コンポーネントのリスト内で最後の位置以外の場所に出現する場合は、コンパイル時にエラーが発生します。
レコード宣言で同じ名前を持つ2つのレコード・コンポーネントを宣言する場合は、コンパイル時にエラーが発生します。
レコード宣言で名前clone
、finalize
、getClass
、hashCode
、notify
、notifyAll
、toString
またはwait
を持つレコード・コンポーネントを宣言する場合は、コンパイル時にエラーが発生します。
すべてのレコード・コンポーネント内に対応するアクセサ・メソッドがある場合(8.10.3)、この制限により、クラス
Object
から不正にオーバーロードされた可能性があるメソッドを含むレコード型が阻止されます。
レコード・コンポーネントに対する注釈修飾子のルールは、9.7.4に規定されています。
宣言されるレコード・コンポーネントの型は、それが可変個引数レコード・コンポーネントであるかどうかによって異なります。
レコード・コンポーネントが可変個引数レコード・コンポーネントでないときに、カッコのペアがUnannTypeおよびVariableDeclaratorId内に出現しない場合、およびそれ以外の場合に10.2に規定されている場合、宣言される型はUnannTypeによって示されます。
レコード・コンポーネントが可変個引数レコード・コンポーネントである場合、宣言される型は10.2に規定されている配列型です。
宣言される可変個引数レコード・コンポーネントの型に非具象化可能な要素型(4.7)がある場合、コンパイル時に可変個引数レコード・コンポーネントの宣言に対して未チェック警告エラーが発生します。ただし、@SafeVarargs
(9.6.4.7)によってレコード型に注釈が付けられている場合は除きます。そうでない場合、警告は@SuppressWarnings
(9.6.4.5)によって抑制されます。
8.10.2 レコード本体
レコード宣言の本体には、コンストラクタおよびメンバー宣言の他に、静的イニシャライザが含まれる場合があります。
- RecordBody:
{
{RecordBodyDeclaration}}
- RecordBodyDeclaration:
- ClassBodyDeclaration
- CompactConstructorDeclaration
便宜上、ここでは8.1.6の次のプロダクションを示します。
- ClassBodyDeclaration:
- ClassMemberDeclaration
- InstanceInitializer
- StaticInitializer
- ConstructorDeclaration
- ClassMemberDeclaration:
- FieldDeclaration
- MethodDeclaration
- ClassDeclaration
- InterfaceDeclaration
;
レコード宣言の本体に非静的フィールド宣言(8.3.1.1)が含まれる場合は、コンパイル時にエラーが発生します。
レコード宣言の本体にnative
メソッド宣言(8.4.3.4)が含まれる場合は、コンパイル時にエラーが発生します。
レコード宣言の本体にインスタンス・イニシャライザ(8.6)が含まれる場合は、コンパイル時にエラーが発生します。
8.10.3 レコード・メンバー
レコード型R内では、レコード・コンポーネントのアクセサ・メソッドは、名前がRのレコード・コンポーネントの名前と同じであり、仮パラメータ・リストが空であるメソッドです。
レコード型Rには、次のメンバーがあります。
レコード・コンポーネント・リスト内にあるレコード・コンポーネントごとに:
レコード・コンポーネントと同じ名前を持ち、レコード・コンポーネントの宣言された型と同じ型の、暗黙的に宣言された
private
final
フィールド。 このフィールドに付けられるのは、対応するレコード・コンポーネント内に出現し、注釈型がフィールド宣言コンテキストまたは型コンテキスト、あるいはこれら両方に適用される注釈です。レコード・コンポーネントのアクセサ・メソッド。
レコード・コンポーネントのアクセサ・メソッドが明示的に宣言されない場合、次の特性を持つアクセサ・メソッドが暗黙的に宣言されます。
名前がレコード・コンポーネントの名前と同じである
戻り型が、宣言されたレコード・コンポーネントの型と同じである
汎用ではない
空の仮パラメータ・リストがある
public
として宣言されているこれに付けられるのが、対応するレコード・コンポーネント内に出現し、注釈型がメソッド宣言コンテキストまたは型コンテキスト、あるいはこれら両方に適用される注釈である。
暗黙的に宣言されたアクセサ・メソッドの本体がそのまま、対応するフィールドの値を返す。
コンポーネント名に対する制限(8.10.1)とは、暗黙的に宣言されたアクセサ・メソッドのいずれも、クラス
Object
の非private
メソッドとオーバーライド等価であるシグネチャを持たないことを意味します。
すべてのメンバーが
java.lang.Record
から継承されます。 レコード本体内で明示的にオーバーライドされないかぎり、Rは、java.lang.Record
のメソッドequals
、hashCode
およびtoString
をオーバーライドする、暗黙的に宣言されたメソッドを持ちます。java.lang.Record
のこれらのメソッドのいずれかをレコード本体内で明示的に宣言する必要がある場合、実装により、java.lang.Record
に規定されているとおりに予想されるセマンティクスを満たす必要があります。Rの宣言の本体で明示的に宣言された他のすべてのメンバー。
アクセサ・メソッドが明示的に宣言される場合、次のルールも別途満たす必要があります。そうでない場合、コンパイル時にエラーが発生します。
アクセサ・メソッドの戻り型が、宣言された対応するレコード・コンポーネントの型と同じである
アクセサ・メソッドが汎用でない(8.4.4)
アクセサ・メソッドが、宣言された
public
であるアクセサ・メソッドが、宣言された
static
ではないアクセサ・メソッドが
throws
句を持たない標準クラス宣言内のメソッドの他のすべてのルールが満たされている(8.4)
レコード・コンポーネントに出現する注釈は、そのレコード・コンポーネントに対して明示的に宣言されたアクセサ・メソッドには引き継がれません。 これは、レコード・コンポーネントから適用可能な注釈を使用して注釈が付けられた、暗黙的に宣言されたアクセサ・メソッドとは対照的です。
8.10.4 レコード・コンストラクタ宣言
レコード・コンポーネントの適切な初期化をサポートするために、レコード型はデフォルトのコンストラクタを暗黙的に宣言しません(8.8.9)。 かわりに、レコード型には、レコード・コンポーネントに対応するすべてのフィールドを初期化する、明示的または暗黙的に宣言された標準コンストラクタがあります。
レコード型Rには、導出されたコンストラクタ・シグネチャがあります。これは、名前Rを持ち、型パラメータを持たず、次のようにRのレコード・コンポーネント・リストから導出される仮パラメータ・リストを持ちます。
- レコード・コンポーネント・リスト内の各レコード・コンポーネントごとに、同じ名前および宣言された型を持つ仮パラメータが導出されます。 この仮パラメータに付けるのは、対応するレコード・コンポーネント内に出現し、注釈型が仮パラメータ・コンテキストまたは型コンテキスト、あるいはこれら両方に適用される注釈です。
レコード型R内で宣言されたコンストラクタは、導出されたRのコンストラクタ・シグネチャとシグネチャがオーバーライド等価(8.4.2)である場合、標準コンストラクタであると言えます。
標準コンストラクタは、導出されたレコード型のコンストラクタ・シグネチャとオーバーライド等価であるシグネチャを持つため、存在できる明示的に宣言された標準コンストラクタは1つのみです。
標準コンストラクタが明示的に宣言される場合、次の条件も別途満たす必要があります。そうでない場合、コンパイル時にエラーが発生します。
標準コンストラクタの仮パラメータ・リスト内の仮パラメータの型は、対応するレコード・コンポーネントの宣言された型と同じである。
標準コンストラクタが汎用でない(8.8.4)。
標準コンストラクタが、宣言された
public
である。標準コンストラクタが
throws
句を持たない。標準コンストラクタの本体に、明示的なコンストラクタ呼出し文が含まれない(8.8.7.1)。
標準クラス宣言内のコンストラクタの他のすべてのルールが満たされている(8.8)。
明示的に宣言された標準コンストラクタのシグネチャが、導出されたコンストラクタ・シグネチャとオーバーライド等価である必要があることは、レコード・コンポーネントの注釈が、対応する仮パラメータの注釈とは異なる可能性があることを意味します。 たとえば、次が有効です。
標準コンストラクタが明示的に宣言されない場合、次の特性を持つ標準コンストラクタが暗黙的に宣言されます。
暗黙的に宣言された標準コンストラクタのシグネチャが、レコード型に対して導出されたコンストラクタ・シグネチャによって与えられる。
暗黙的に宣言された標準コンストラクタが、
public
であるとして宣言される。暗黙的に宣言された標準コンストラクタが
throws
句を持たない。暗黙的に宣言された標準コンストラクタの本体が、レコード・コンポーネントがレコード・コンポーネント・リスト内に表示される順序で、対応する仮パラメータを使用してレコード・コンポーネントに対応する各フィールドを初期化する。
レコード型Rが、そのシグネチャがRのコンストラクタ・シグネチャとオーバーライド等価でないコンストラクタを宣言する場合、各コンストラクタ(存在する場合)が、次の条件をすべて満たす必要があります。満たさない場合、コンパイル時にエラーが発生します。
コンストラクタ本体が、レコード型Rの別のコンストラクタ(標準コンストラクタである可能性があるものを含む)の明示的なコンストラクタ呼出しで開始される。
標準クラス宣言内のコンストラクタ宣言の他のすべてのルールが満たされている(8.8)。
これらの要件により、レコード型Rの標準コンストラクタについて触れられるようになります。 つまり、すべてのレコード型Rが、明示的または暗黙的に宣言された単一の標準コンストラクタを持ちます。 この標準コンストラクタには、次の特性があります。
public
として宣言されている。throws
句を持たない。- 汎用ではない。
- そのシグネチャが、導出されたRのコンストラクタ・シグネチャと等価である(任意の注釈を除く)。
- コンストラクタ本体が、Rのレコード・コンポーネント・リスト内のレコード・コンポーネントに対応するすべてのフィールドを初期化する。
8.10.5 コンパクト・レコード・コンストラクタ宣言
コンパクト・コンストラクタ宣言は、レコード型に対して標準コンストラクタを宣言する簡潔な代替方法を提供します。
- CompactConstructorDeclaration:
- { Annotation } { ConstructorModifier } SimpleTypeName ConstructorBody
レコード型R内では、コンパクト・コンストラクタ宣言のシグネチャは、導出されたRのコンストラクタ・シグネチャです(8.10.4)。
レコード内のコンストラクタや実際に一般的なクラス内のコンストラクタとは異なり、コンパクト・コンストラクタに対して明示的な仮パラメータ・リストは提供されず、仮パラメータ・リストはレコード・コンポーネント・リストから導出されます。
1つのレコード型に対して複数のコンパクト・コンストラクタ宣言を宣言すると、コンパイル時にエラーが発生します。
クラス宣言内のコンストラクタのシグネチャ(8.8.2)に関するルールでは、レコード宣言内にコンパクト・コンストラクタ宣言および標準コンストラクタ宣言が含まれる場合も、コンパイル時にエラーが発生します。 コンパクト・コンストラクタは標準コンストラクタです。
コンパクト・コンストラクタ宣言は、次の条件をすべて満たす必要があります。そうでない場合、コンパイル時にエラーが発生します。
コンパクト・コンストラクタが、宣言された
public
である。コンパクト・コンストラクタの本体に、
return
文が含まれない(14.17)。コンパクト・コンストラクタの本体に、明示的なコンストラクタ呼出し文が含まれない(8.8.7.1)。
標準クラス宣言内のコンストラクタの他のすべてのルールが満たされている(8.8)。ただし、Rのレコード・コンポーネントに対応するフィールドを確定的に割り当てる必要がある要件、さらにコンパクト・コンストラクタの末尾に明確に割り当ててはならない要件は除きます(8.3.1.2)。
また、コンパクト・コンストラクタの本体の末尾では、明確に割り当てられない(16 (明確な割当て)) Rのレコード・コンポーネントに対応するすべてのフィールドは、対応する仮パラメータの値に暗黙的に初期化されます。 これらのフィールドは、レコード・コンポーネント・リスト内で宣言される順序で暗黙的に初期化されます。
コンパクト・コンストラクタ宣言は、検証および/または正規化コードのみをコンストラクタ本体に提供することを意図しています。残りの初期化コードはコンパイラによって提供されます。 ここでは、2つの簡単な例を示します。
record NonNegativePoint(int i, int j) { public NonNegativePoint { // Validates that both components are non-negative if ( i < 0 || j < 0 ) throw new IllegalArgumentException(); } } record NonNullString(int i, String s) { public NonNullString { // Normalizes the String component to be non-null if ( s == null) this.s = ""; else this.s = s; } }
これらの宣言は次と等価です。
record NonNegativePoint(int i, int j) { public NonNegativePoint { // Validates that both components are non-negative if ( i < 0 || j < 0 ) throw new IllegalArgumentException(); this.i = i; this.j = j; } } record NonNullString(int i, String s) { public NonNullString { // Normalizes the String component to be non-null if ( s == null) this.s = ""; else this.s = s; this.i = i; } }
第9章 インタフェース
9.6 注釈型
9.6.4 事前定義済注釈型
9.6.4.1 @Target
型java.lang.annotation.Target
の注釈を注釈型Tの宣言で使用して、Tが適用可能であるコンテキストを指定します。java.lang.annotation.Target
には、コンテキストを指定するために型java.lang.annotation.ElementType[]
を持つ単一要素value
が用意されています。
注釈型は、注釈が宣言に適用される宣言コンテキスト内、または宣言および式で使用される型に注釈が適用される型コンテキスト内に適用可能である場合があります。
9つ10の宣言コンテキストがあり、各コンテキストがjava.lang.annotation.ElementType
のenum定数に対応しています。
モジュール宣言(7.7)
java.lang.annotation.ElementType.MODULE
に対応していますパッケージ宣言(7.4.1)
java.lang.annotation.ElementType.PACKAGE
に対応しています型宣言: クラス、インタフェース、enum、レコード、および注釈型宣言(8.1.1、9.1.1、8.5、9.5、8.9、8.10、9.6)
java.lang.annotation.ElementType.TYPE
に対応していますまた、注釈型宣言は
java.lang.annotation.ElementType.ANNOTATION_TYPE
に対応していますメソッド宣言(注釈型の要素を含む) (8.4.3、9.4、9.6.1)
java.lang.annotation.ElementType.METHOD
に対応していますコンストラクタ宣言(8.8.3)
java.lang.annotation.ElementType.CONSTRUCTOR
に対応しています汎用クラス、インタフェース、メソッドおよびコンストラクタの型パラメータ宣言(8.1.2、9.1.2、8.4.4、8.8.4)
java.lang.annotation.ElementType.TYPE_PARAMETER
に対応していますフィールド宣言(enum定数を含む) (8.3.1、9.3、8.9.1)
java.lang.annotation.ElementType.FIELD
に対応しています仮パラメータおよび例外パラメータ宣言(8.4.1、9.4、14.20)
java.lang.annotation.ElementType.PARAMETER
に対応していますローカル変数宣言(
for
文のループ変数およびtry
-with-resources文のリソース変数を含む) (14.4、14.14.1、14.14.2、14.20.3)java.lang.annotation.ElementType.LOCAL_VARIABLE
に対応していますレコード・コンポーネント宣言(8.10.1)
java.lang.annotation.ElementType.RECORD_COMPONENT
に対応しています
1617の型コンテキスト(4.11)があり、これらはすべて、java.lang.annotation.ElementType
のenum定数TYPE_USE
によって表されます。
型java.lang.annotation.Target
の注釈のvalue
要素内に同じenum定数が複数回出現すると、コンパイル時にエラーが発生します。
型java.lang.annotation.Target
の注釈が注釈型Tの宣言内に存在しない場合、Tは、型パラメータ宣言を除くすべての宣言コンテキスト内に適用されますが、型コンテキストには適用されません。
これらのコンテキストは、Java SE 7で注釈が許可されていた構文的な場所です。
9.7 注釈
9.7.4 注釈が出現する可能性がある場所
宣言注釈は、宣言に適用され、その宣言によって表される宣言コンテキスト(9.6.4.1)に独自の型を適用できる注釈、またはクラス、インタフェース、enum、レコード、注釈型または型パラメータ宣言に適用され、型コンテキスト(4.11)に独自の型を適用できる注釈です。
型注釈は、型(または型の任意の部分)に適用され、型コンテキストに独自の型を適用できる注釈です。
たとえば、次のフィールド宣言が与えられた場合、
@Foo int f;
@Foo
は、Foo
に@Target(ElementType.FIELD)
によってメタ注釈が付けられた場合はf
に対する宣言注釈であり、Foo
に@Target(ElementType.TYPE_USE)
によってメタ注釈が付けられた場合はint
に対する型注釈です。@Foo
は同時に宣言注釈と型注釈の両方にすることができます。型注釈は、配列型またはそのコンポーネント型(10.1)に適用できます。 たとえば、
A
、B
およびC
が@Target(ElementType.TYPE_USE)
によってメタ注釈が付けられた注釈型であるとするときに、次のフィールド宣言が与えられた場合、@C int @A [] @B [] f;
@A
は配列型int[][]
に適用され、@B
はコンポーネント型int[]
に適用され、@C
は要素型int
に適用されます。 その他の例については、次の情報を参照してください 10.2この構文の重要な特性は、2つの宣言においては配列レベルの数のみが異なり、型の左側注釈が同じ型を参照している点です。 たとえば、
@C
は、次のすべての宣言内の型int
に適用されます。@C int f; @C int[] f; @C int[][] f;
宣言注釈を他のすべての修飾子の前に書き、型注釈をそれが適用される型の直前に書くことは慣例ですが、必須ではありません。
プログラム構文で、一見すると宣言または型、あるいはその両方に適用されるような場所に注釈が出現する場合があります。 これは、宣言されたエンティティの型の直前に修飾子がある次の5つ6つの宣言コンテキストのいずれかで考えられます。
メソッド宣言(注釈型の要素を含む)
コンストラクタ宣言
フィールド宣言(enum定数を含む)
仮パラメータ宣言および例外パラメータ宣言
ローカル変数宣言(
for
文のループ変数およびtry
-with-resources文のリソース変数を含む)レコード・コンポーネント宣言
Javaプログラミング言語の文法では、これらの場所にある注釈が宣言(8.3)の修飾子として明確に取り扱われますが、これは純粋に構文上だけのものです。 注釈が宣言または宣言されたエンティティの型のどちらに適用されるか、つまり、注釈が宣言注釈または型注釈のどちらであるかは、注釈の型の適用性によって決まります。
注釈の型が、宣言に対応する宣言コンテキストに適用可能であり、型コンテキストには適用可能でない場合、注釈は宣言のみに適用されるとみなされます。
注釈の型が、型コンテキストに適用可能であり、宣言に対応する宣言コンテキストには適用可能でない場合、注釈は、その注釈に最も近い型のみに適用されるとみなされます。
注釈の型が、宣言に対応する宣言コンテキストに適用可能であると同時に型コンテキストに適用可能である場合、注釈は、宣言とその注釈に最も近い型の両方に適用されるとみなされます。
前述の2番目のと3番目のケースでは、注釈に最も近い型は、次のように決定されます。
注釈が
void
メソッド宣言、またはvar
を使用するローカル変数宣言(14.4、14.14.2、14.20.3)の前にある場合、最も近い型は存在しません。 注釈の型が、その注釈に最も近い型のみに適用されるとみなされる場合、コンパイル時にエラーが発生します。注釈がコンストラクタ宣言の前にある場合、最も近い型は、新しく構築されたオブジェクトの型です。 新しく構築されたオブジェクトの型は、コンストラクタ宣言の直前と直後にある型の完全修飾名です。 この完全修飾名内で、注釈は、コンストラクタ宣言が示す単純な型名に適用されます。
その他すべてのケースでは、最も近い型は、宣言されたエンティティのソース・コード内に書かれた型です。その型が配列型である場合、その要素型が注釈に最も近いとみなされます。
たとえば、フィールド宣言
@Foo public static String f;
の場合、@Foo
に最も近い型はString
です。 (フィールド宣言の型がjava.lang.String
として作成されていた場合、java.lang.String
が、@Foo
に最も近い型になり、後のルールにより、型注釈をパッケージ名java
に適用することが禁止されます。) 汎用メソッド宣言@Foo <T> int[] m() {...}
の場合、宣言されたエンティティ用として作成された型はint[]
であるため、@Foo
は要素型int
に適用されます。var
を使用しないローカル変数宣言と、ラムダ式の仮パラメータ宣言は、両方とも、ソース・コードで宣言注釈と型注釈を使用可能であるが、型注釈のみをclass
ファイルに格納できるという点が似ています。
型Tの注釈が次の構文上の修飾子である場合、コンパイル時にエラーが発生します。
モジュール宣言: ただし、Tはモジュール宣言には適用できません。
パッケージ宣言: ただし、Tはパッケージ宣言には適用できません。
クラス、インタフェース、
またはenum、またはレコード宣言: ただし、Tは型宣言、型コンテキストまたは注釈型宣言に適用できません。メソッド宣言(注釈型の要素を含む): ただし、Tはメソッド宣言または型コンテキストに適用できません。
コンストラクタ宣言: ただし、Tはコンストラクタ宣言または型コンテキストに適用できません。
汎用クラス、インタフェース、メソッドまたはコンストラクタの型パラメータ宣言: ただし、Tは型パラメータ宣言または型コンテキストに適用できません。
フィールド宣言(enum定数を含む): ただし、Tはフィールド宣言または型コンテキストに適用できません。
仮パラメータ宣言または例外パラメータ宣言: ただし、Tは仮パラメータ宣言および例外パラメータ宣言または型コンテキストに適用できません。
レシーバ・パラメータ: ただし、Tは型コンテキストに適用できません。
ローカル変数宣言(
for
文のループ変数またはtry
-with-resources文のリソース変数を含む): ただし、Tはローカル変数宣言または型コンテキストに適用できません。レコード・コンポーネント: ただし、Tはレコード・コンポーネント宣言、フィールド宣言、メソッド宣言、仮パラメータ宣言および例外パラメータ宣言、または型コンテキストに適用できません。
これら
9つ11の条項のうち5つ6つの条項で「~または型コンテキスト」と記載されているのは、これらが、注釈を宣言または宣言されたエンティティの型に適用できるように見える5つ6つの構文上の場所を特徴付けているからです。 また、クラス、インタフェース、enum、レコードおよび注釈型宣言、さらに型パラメータ宣言に関するこれら9つ11の条項のうち2つの条項で「~または型コンテキスト」と記載されているのは、型に@Target(ElementType.TYPE_USE)
がメタ注釈として付けられている(ため、型コンテキストに適用可能である)注釈を型宣言に適用する方が便利である可能性があるからです。
次の両方が当てはまる場合、型注釈は許容されます。
注釈が最も近い単純名がPackageNameではなくTypeNameとして分類されている。
注釈が最も近い単純名の後ろに「
.
」および別のTypeNameがある。つまり、注釈が@Foo T.U
として出現し、U
がT
の内部クラスを示している。
2番目の条項では、
Outer
に囲まれたネストしたクラス内でOuter.this
が正当である場合、Outer
は、実行時に一部のオブジェクトの型を表すため、注釈が付けられる可能性があると考えられます。 その一方で、Outer.this
が正当ではない場合(これが出現するクラスには実行時にOuter
の包含インスタンスがないため)、Outer
は、論理的に単なる名前(完全修飾された型名のパッケージ名のコンポーネントと同種)であるため、注釈が付けられない可能性があります。
たとえば、次のプログラムの場合、
B
には語彙的な包含インスタンスがないため(8.5.1)、B
の本体内にA.this
を作成することはできません。 したがって、A
は論理的に型ではなく単なる名前であるため、@Foo
を型A.B
内のA
に適用することはできません。@Target(ElementType.TYPE_USE) @interface Foo {} class Test { class A { static class B {} } @Foo A.B x; // Illegal }
その一方で、次のプログラムの場合、
D
の本体内にC.this
を作成できます。 したがって、C
は実行時の一部のオブジェクトの型を表すため、@Foo
を型C.D
内のC
に適用できます。@Target(ElementType.TYPE_USE) @interface Foo {} class Test { static class C { class D {} } @Foo C.D x; // Legal }
最後に、2番目の条項は、修飾された型内で1レベル深く見えます。 これは、
static
クラスが最上位クラスまたは別のネストしたstatic
クラス内でのみネストされる可能性があるからです。 次のようなネストを作成することはできません。@Target(ElementType.TYPE_USE) @interface Foo {} class Test { class E { class F { static class G {} } } @Foo E.F.G x; }
ここでしばらくの間、このネストが正当ではなかったと仮定します。 フィールド
x
の型で、G
の本体ではE.F.this
が不正であるため、E
およびF
は論理的にG
を修飾する名前です。 この場合、@Foo
はE
の隣では正当になりません。 ただし、技術的には、@Foo
は次の深さにある語句F
が内部クラスを示すため、E
の隣にあることが許容されます。しかし、本来クラスのネストは不正であるため、これには議論の余地があります。
型Tの注釈が型コンテキスト内の型の最も外側のレベルに適用されるときに、型コンテキスト、または同じ構文上の場所を占有する宣言コンテキスト(存在する場合)にTを適用できない場合、コンパイル時にエラーが発生します。
型Tの注釈が型コンテキスト内の型の一部(つまり、最も外側のレベルではない)に適用されるときに、型コンテキストにTを適用できない場合、コンパイル時にエラーが発生します。
型Tの注釈が型コンテキスト内の型(または型の一部)に適用されるときに、型コンテキストにTを適用でき、注釈が許容されない場合、コンパイル時にエラーが発生します。
たとえば、
@Target(ElementType.TYPE_USE)
によってのみメタ注釈が付けられた注釈型TA
があるとします。@TA
が最も近い単純名がパッケージ名として分類されているため、語句@TA java.lang.Object
およびjava.@TA lang.Object
は不正です。 一方、java.lang.@TA Object
は不正です。
不正な語句は「どこでも」不正です。 注釈パッケージ名に対する禁止事項は広範に適用されます。具体的には、単なる型コンテキストである場所(
class ... extends @TA java.lang.Object {...}
など)、および宣言コンテキストと型コンテキストの両方である場所(@TA java.lang.Object f;
など)に適用されます。 (クラス、パッケージおよび型パラメータ宣言では単純名のみが使用されるため、パッケージ名に注釈を付けられる単なる宣言コンテキストである場所は存在しません。)
TA
に追加的に@Target(ElementType.FIELD)
のメタ注釈が付けられた場合、語句@TA java.lang.Object
は、宣言コンテキストと型コンテキストの両方である場所(フィールド宣言@TA java.lang.Object f;
など)で正当になります。 ここでは、TA
はフィールド宣言コンテキストに適用できるため、@TA
は(型java.lang.Object
に対してではなく)f
の宣言に対して適用されるとみなされます。
第10章: 配列
10.2 配列変数
配列型の変数には、オブジェクトへの参照が格納されます。 配列型の変数を宣言しても、配列オブジェクトが作成されたり、配列コンポーネントにスペースが割り当てられることはありません。 配列への参照を含めることのできる変数自体のみが作成されます。 ただし、宣言子のイニシャライザ部分(8.3、9.3、14.4.1)によって配列が作成され、この配列に対する参照が変数の初期値になる場合があります。
例10.2-1. 配列変数の宣言
int[] ai; // array of int
short[][] as; // array of array of short
short s, // scalar short
aas[][]; // array of array of short
Object[] ao, // array of Object
otherAo; // array of Object
Collection<?>[] ca; // array of Collection of unknown type
前述の宣言では配列オブジェクトは作成されません。 配列オブジェクトを作成する配列変数の宣言の例を次に示します。
Exception ae[] = new Exception[3];
Object aao[][] = new Exception[2][3];
int[] factorial = { 1, 1, 2, 6, 24, 120, 720, 5040 };
char ac[] = { 'n', 'o', 't', ' ', 'a', ' ',
'S', 't', 'r', 'i', 'n', 'g' };
String[] aas = { "array", "of", "String", };
変数の配列型は、変数宣言の先頭にある型の一部として、または変数の宣言子の一部として、あるいはその両方として出現する可能性があるカッコのペアによって異なります。 特に、フィールド、仮パラメータ、またはローカル変数またはレコード・コンポーネント (8.3、8.4.1、9.3、9.4、14.4.1、14.14.2、15.27.1、8.10.1)の宣言では、変数の配列型は次によって示されます。
宣言の先頭に出現する要素型
宣言子内の変数の識別子の後ろにあるカッコのペア(可変個引数パラメータには適用不可)
宣言の先頭にある型内に出現するカッコのペア(可変個引数パラメータの省略記号はカッコのペアとして扱われます)。
メソッドの戻り型(8.4.5)は配列型である場合があります。 正確な配列型は、メソッド宣言の先頭にある型の一部として、またはメソッドの仮パラメータ・リストの後ろに、あるいはその両方として出現する可能性があるカッコのペアによって異なります。 配列型は次によって示されます。
結果に出現する要素型
仮パラメータ・リストの後ろにあるカッコのペア
結果に出現するカッコのペア。
カッコのペアが型と宣言子の両方に出現する配列変数宣言内、またはカッコのペアが仮パラメータ・リストの前と後ろの両方に出現するメソッド宣言内には「複合表記」を使用しないことをお薦めします。
例10.2-2. 配列変数および配列型
次のローカル変数宣言文
byte[] rowvector, colvector, matrix[];
は次と同等です。
byte rowvector[], colvector[], matrix[][];
これは、各ローカル変数の配列型が変更されないためです。 同様に、次のローカル変数宣言文
int a, b[], c[][];
は次の一連の宣言文と同等です。
int a;
int[] b;
int[][] c;
カッコはCおよびC++の慣例に同意し、宣言内でカッコを使用することが許可されています。 ただし、変数宣言の一般的なルールでは、型と宣言の両方にカッコを使用することが許可されているため、次のローカル変数宣言文
float[][] f[][], g[][][], h[]; // Yechh!
は次の一連の宣言と同等です。
float[][][][] f;
float[][][][][] g;
float[][][] h;
配列型の形成方法のため、次のパラメータ宣言は同じ配列型を持ちます。
void m(int @A [] @B [] x) {}
void n(int @A [] @B ... y) {}
また、想定外ですが、次のフィールド宣言は同じ配列型を持ちます。
int @A [] f @B [];
int @B [] @A [] g;
配列オブジェクトがいったん作成されると、その長さは一切変更されません。 配列変数が異なる長さの配列を参照できるようにするには、異なる配列に対する参照を変数に割り当てる必要があります。
配列の長さはその型の一部ではないため、配列型の単一の変数に、異なる長さの配列への参照を含めることができます。
配列変数vに型A[]
があり、Aが参照型である場合、vには、任意の配列型B[]
のインスタンスへの参照を格納できますが、これはBのAへの割当てが可能であることが前提です(5.2)。 この結果、後の割当てで実行時例外が発生する可能性があります。詳細は、10.5を参照してください。
第13章: バイナリ互換性
比較ドキュメントは、レコードをサポートするためにJava仮想マシン仕様に必要な変更点を説明します。
13.1 バイナリの形式
プログラムは、Java仮想マシン仕様、Java SE 13 Editionによって規定されているclass
ファイル形式に、またはJavaプログラミング言語で作成されたクラス・ローダーによってこの形式にマップできる表現にコンパイルする必要があります。
クラスまたはインタフェース宣言に対応するclass
ファイルには、特定の特性が必要です。 これらの特性の多くは、バイナリの互換性を確保するソース・コードの変換をサポートするように明確に選択されています。 必須特性は次のとおりです。
クラスまたはインタフェースはバイナリ名によって名前を付ける必要があり、これは次の制約を満たす必要があります。
メンバー型のバイナリ名(8.5、9.5)は、直前と直後の型のバイナリ名、その後ろに順に続く
$
、メンバーの単純名で構成されます。ローカル・クラスのバイナリ名(14.3)は、直前と直後の型のバイナリ名、その後ろに順に続く
$
、空でない数字のシーケンス、ローカル・クラスの単純名で構成されます。無名クラスのバイナリ名(15.9.5)は、直前と直後の型のバイナリ名、その後ろに順に続く
$
、空でない数字のシーケンスがで構成されます。汎用クラスまたはインタフェースによって宣言される型変数のバイナリ名(8.1.2、9.1.2)は、直前と直後の型のバイナリ名、その後ろに順に続く
$
、型変数の単純名で構成されます。汎用メソッドによって宣言される型変数のバイナリ名(8.4.4)は、メソッドを宣言する型のバイナリ名、その後ろに順に続く
$
、メソッドの記述子(JVMS §4.3.3)、$
、型変数の単純名で構成されます。汎用コンストラクタによって宣言される型変数のバイナリ名(8.8.4)は、コンストラクタを宣言する型のバイナリ名、その後ろに順に続く
$
、コンストラクタの記述子(JVMS §4.3.3)、$
、型変数の単純名で構成されます。
別のクラスまたはインタフェース型への参照は、型のバイナリ名を使用するシンボリックである必要があります。
定数変数(4.12.4)であるフィールドへの参照は、コンパイル時に定数変数のイニシャライザが示す値Vに解決される必要があります。
このようなフィールドが
static
である場合、バイナリ・ファイルのコード内にフィールドへの参照が存在しない必要があります。これには、このフィールドを宣言したクラスまたはインタフェースも含まれます。 このようなフィールドは常に、初期化(12.4.2)されているものとして示される必要があり、このフィールドのデフォルトの初期値は(Vとは異なる場合)、表示されないようにします。このようなフィールドが非
static
である場合、バイナリ・ファイルのコード内にフィールドへの参照が存在しない必要があります。ただし、このフィールドが含まれるクラス内は除きます。 (インタフェースにはstatic
フィールドしかないため、これはインタフェースではなくクラスです。) このクラスには、インスタンス作成時(12.5)にフィールドの値をVに設定するためのコードが必要です。クラスC内でのフィールド・アクセスを示す正当な式が与えられ、定数値ではなく、(場合によっては別個の)クラスまたはインタフェースD内で宣言されているfという名前のフィールドを参照している場合、Oracleではフィールド参照の修飾型を次のように定義します。
式が単純名によって参照されているときに、fが現在のクラスまたはインタフェースCのメンバーである場合、TをCにします。 そうでない場合、Tは、fがメンバーである、最も内側にあり字句的に囲んでいる型宣言にします。 どちらの場合も、Tが参照の修飾型です。
参照の形式がTypeName
.
fであり、TypeNameがクラスまたはインタフェースを示している場合、TypeNameが示すクラスまたはインタフェースが参照の修飾型です。式の形式がExpressionName
.
fまたはPrimary.
fである場合は次のようになります。ExpressionNameまたはPrimaryのコンパイル時の型が交差型V1
&
...&
Vn (4.9)である場合、参照の修飾型はV1です。そうでない場合、ExpressionNameまたはPrimaryのコンパイル時の型が参照の修飾型です。
式の形式が
super.
fである場合、Cのスーパークラスが参照の修飾型です。式の形式がTypeName
.super.
fである場合、TypeNameが示すクラスのスーパークラスが参照の修飾型です。
fへの参照は、参照の修飾型のイレイジャ(4.6)およびフィールドの単純名fへのシンボリック参照にコンパイルする必要があります。 また、型が想定どおりであるかどうかを検証者がチェックできるように、この参照には、宣言されたフィールドの型のイレイジャへのシンボリック参照も含まれている必要があります。
クラスまたはインタフェースC内のメソッド呼出し式またはメソッド参照式が与えられ、(場合によっては別個の)クラスまたはインタフェースD内で宣言されている(または暗黙的な宣言されている(9.2)) mという名前のメソッドを参照している場合、Oracleではメソッド呼出しの修飾型を次のように定義します。
Dが
Object
である場合、式の修飾型はObject
です。そうでない場合は、次のようになります。
メソッドが単純名によって参照されているときに、mが現在のクラスまたはインタフェースCのメンバーである場合、TをCにします。そうでない場合、Tは、mがメンバーである、最も内側にあり字句的に囲んでいる型宣言にします。 どちらの場合も、Tがメソッド呼出しの修飾型です。
式の形式がTypeName
.
mまたはReferenceType::
mである場合、TypeNameまたはReferenceTypeが示す型がメソッド呼出しの修飾型です。式の形式がExpressionName
.
m、Primary.
m、ExpressionName::
mまたはPrimary::
mである場合、次のようになります。ExpressionNameまたはPrimaryのコンパイル時の型が交差型V1
&
...&
Vn (4.9)である場合、メソッド呼出しの修飾型はV1です。そうでない場合、ExpressionNameまたはPrimaryのコンパイル時の型がメソッド呼出しの修飾型です。
式の形式が
super.
mまたはsuper::
mである場合、Cのスーパークラスがメソッド呼出しの修飾型です。式の形式がTypeName
.super.
mまたはTypeName.super::
mであり、TypeNameがクラスXを示している場合、Xがメソッド呼出しの修飾型です。また、TypeNameがインタフェースXを示している場合、Xがメソッド呼出しの修飾型です。
メソッドへの参照はコンパイル時に、呼出しの修飾型のイレイジャ(4.6)およびメソッドのシグネチャ(8.4.2)のイレイジャへのシンボリック参照に解決する必要があります。 メソッドのシグネチャには、15.12.3で確認されたとおりに次のすべてが含まれている必要があります。
メソッドの単純名
メソッドに対するパラメータ数
各パラメータの型へのシンボリック参照
また、メソッドへの参照には、示されるメソッドの戻り型のイレイジャへのシンボリック参照が含まれているか、示されるメソッドが
void
を宣言され、値を戻さないことを示すものが含まれている必要があります。クラス・インスタンス作成式(15.9)、明示的なコンストラクタ呼出し文(8.8.7.1)、またはクラスまたはインタフェースC内のClassType
::
new
(15.13)形式のメソッド参照式が与えられ、(場合によっては別個の)クラスまたはインタフェースD内で宣言されているコンストラクタmを参照している場合、Oracleでは、コンストラクタ呼出しの修飾型を次のように定義します。式の形式が
new
D(...)
、ExpressionName.new
D(...)
、Primary.new
D(...)
またはD::
new
である場合、呼出しの修飾型はDです。式の形式が
new
D(...){...}
、ExpressionName.new
D(...){...}
またはPrimary.new
D(...){...}
である場合、式の修飾型は式のコンパイル時の型です。式の形式が
super(...)
、ExpressionName.super(...)
またはPrimary.super(...)
である場合、式の修飾型はCの直接スーパークラスです。式の形式が
this(...)
である場合、式の修飾型はCです。
コンストラクタへの参照はコンパイル時に、呼出しの修飾型のイレイジャ(4.6)およびコンストラクタのシグネチャ(8.8.2)へのシンボリック参照に解決する必要があります。 コンストラクタのシグネチャには、次の両方が含まれている必要があります。
コンストラクタのパラメータ数
各仮パラメータの型へのシンボリック参照
クラスまたはインタフェースのバイナリ表現には、次もすべて含まれる必要があります。
これがクラスであり、
Object
ではない場合、このクラスの直接スーパークラスのイレイジャへのシンボリック参照。それぞれの直接スーパーインタフェースのイレイジャへのシンボリック参照(存在する場合)。
フィールドの単純名およびフィールドの型のイレイジャへのシンボリック参照として与えられた、クラスまたはインタフェース内で宣言された各フィールドの仕様。
これがクラスである場合、各コンストラクタの消去されたシグネチャ(前述を参照)。
クラスまたはインタフェース内で宣言された各メソッド(インタフェースについては、暗黙的に宣言されたメソッドを除く(9.2))ごとに、消去されたシグネチャおよび戻り型(前述を参照)。
クラスまたはインタフェースを実装するために必要なコード。
すべての型に、正規名をリカバリするために十分な情報が含まれている必要があります(6.7)。
すべてのメンバー型に、ソースレベルのアクセス修飾子をリカバリするために十分な情報が含まれている必要があります。
すべてのネストしたクラスおよびネストしたインタフェースに、直前と直後の型へのシンボリック参照が必要です(8.1.3)。
すべてのクラスに、すべてのメンバー型(8.5)へのシンボリック参照、およびメソッド、コンストラクタ、静的イニシャライザ、インスタンス・イニシャライザ、フィールド・イニシャライザ内に出現するローカル・クラスと無名クラスへのシンボリック参照が含まれている必要があります。
すべてのインタフェースに、すべてのメンバー型(9.5)へのシンボリック参照、およびデフォルトのメソッドとフィールド・イニシャライザ内に出現するローカル・クラスと無名クラスへのシンボリック参照が含まれている必要があります。
Javaコンパイラによって発行されたコンストラクトは、発行されたコンストラクトがクラス初期化メソッドでないかぎり、ソース・コードで明示的または暗黙的に宣言されたコンストラクトに対応していない場合、合成としてマークする必要があります(JVMS §2.9)。
Javaコンパイラによって発行されたコンストラクトは、ソース・コードで暗黙的に宣言された仮パラメータに対応している場合、必須としてマークする必要があります(8.8.1、8.8.9、8.9.3、15.9.5.1)。
次の仮パラメータは、ソース・コードで暗黙的に宣言されます。
参考までに、次のコンストラクタは、ソース・コードでは暗黙的に宣言されますが、
class
ファイル内で必須としてマークできるのは仮パラメータのみであるため、必須としてはマークされません(JVMS §4.7.24)。
モジュール宣言に対応するclass
ファイルには、バイナリ名がmodule-info
であり、スーパークラス、スーパーインタフェース、フィールドおよびメソッドを持たないクラスのclass
ファイルのプロパティが必要です。 また、このモジュールのバイナリ表現には次のものがすべて含まれている必要があります。
module
の後ろに示す名前へのシンボリック参照として与えられたモジュールの名前の仕様。 また、仕様では、モジュールが標準とオープンのどちらであるかも示す必要があります(7.7)。requires
ディレクティブが示すモジュールの名前へのシンボリック参照として与えられ、このディレクティブによって示される各依存の仕様(7.7.1)。 また、仕様では、依存がtransitive
であるかどうか、および依存がstatic
であるかどうかも示す必要があります。exports
またはopens
ディレクティブが示すパッケージの名前へのシンボリック参照として与えられ、これらのディレクティブが示す各パッケージの仕様(7.7.2)。 また、ディレクティブが修飾されていた場合、仕様では、ディレクティブのto
句が示すモジュールの名前へのシンボリック参照を与える必要があります。uses
ディレクティブが示す型の名前へのシンボリック参照として与えられ、このディレクティブが示す各サービスの仕様(7.7.3)。provides
ディレクティブのwith
句が示す型の名前へのシンボリック参照として与えられ、このディレクティブが示すサービス・プロバイダの仕様(7.7.4)。 また、仕様では、ディレクティブがサービスとして示す型の名前へのシンボリック参照を与える必要があります。
次の各セクションでは、既存のバイナリとの互換性を損なわずにクラスおよびインタフェース型宣言に対して加えられる可能性のある変更点について説明します。 前述の翻訳要件に基づき、Java仮想マシンおよびそのclass
ファイル形式はこれらの変更をサポートしています。 前述の要件に基づくクラス・ローダーによってclass
ファイルにマップし戻される圧縮または暗号化された表現など、他の有効なバイナリ形式もすべて、これらの変更を必然的にサポートします。
13.4 クラスの展開
13.4.27 レコードの展開
これは新しいサブセクションです
レコード宣言内のレコード・コンポーネントを追加、削除、変更または順序変更すると、既存のバイナリとの互換性が損なわれ、リンク時間のエラー、すなわちIncompatibleClassChangeError
が発生する可能性があります。
存在しなくなったレコード・コンポーネントに既存のバイナリがアクセスしようとすると、実行時にクライアントに障害が発生し、NoSuchFieldError
が返されます。 したがって、広範に配布されるレコードについては、このような変更をすることはお薦めしません。
その他すべての点において、レコードのバイナリの互換性に関するルールは、クラスのルールと同じです。
第14章: ブロックおよび文
14.2 ブロック
ブロックは、中カッコで囲まれた文、ローカル・クラス宣言およびローカル変数宣言文のシーケンスです。
ブロックは、中カッコで囲まれた文および宣言のシーケンスです。 ローカル変数宣言文は、名前をスコープに取り込むために重要な種類の文です。 ブロック内に出現する宣言はクラスおよびレコード(ただし、enumではありません)である場合があります。これらの宣言は、ローカル・クラスおよびローカル・レコードと呼ばれています。
- ブロック:
{
[BlockStatements]}
- BlockStatements:
- BlockStatement {BlockStatement}
- BlockStatement:
- LocalVariableDeclarationStatement
ClassDeclarationNormalClassDeclaration- RecordDeclaration
- Statement
ブロックは、ローカル変数宣言文および他の文のそれぞれを最初から最後(左から右)の順に実行することによって実行されます。 これらすべてのブロック文が正常に完了すると、ブロックは正常に完了します。 これらすべてのブロック文がなんらかの理由により突如完了すると、同じ理由でブロックも突如完了します。
14.3 ローカル・クラス宣言
ローカル・クラス宣言は、ローカル・クラスまたはローカル・レコード(ただし、enumではありません)の宣言です。
ローカル・クラスは、クラスのメンバーではなく、名前を持つネストしたクラス(8)です(6.2、6.7)。
ローカル・クラスはすべて内部クラスです(8.1.3)。
ローカル・レコードは、クラスのメンバーではないレコード型宣言です(8.10)。 ローカル・レコードは暗黙的にstatic
です。 ローカル・レコードはローカル・クラスではありません。
ローカル・レコードに、包含ブロックで宣言された変数の使用が含まれる場合、コンパイル時にエラーが発生します。
ローカル・レコードには、ローカル・レコードがアクセスできる変数に関する制約があります。 ローカル・レコードが暗黙的に
static
であることは、ローカル・レコードで包含クラスの非static
メンバーを使用するとコンパイル時にエラーが発生することを意味します。 包含クラスのstatic
メンバーの使用は許可されています。 この制約を示す例を次に示します。
ローカル・クラス宣言文はすべて、ただちにブロックに含まれます(14.2)。 ローカル・クラス宣言文は、ブロック内の他の種類の文と自由に混在できます。
ローカル・クラス宣言にアクセス修飾子public
、protected
またはprivate
(6.6)が含まれるか、ローカル・クラス宣言がローカル・レコード、修飾子static
(8.1.1)ではない場合、コンパイル時にエラーが発生します。
ローカル・クラス宣言のスコープおよびシャドウ化については、6.3および6.4に規定されています。
例14.3-1. ローカル・クラス宣言
ローカル・クラスに関する前述のルールの複数の側面を示す例を次に示します。
class Global {
class Cyclic {}
void foo() {
new Cyclic(); // create a Global.Cyclic
class Cyclic extends Cyclic {} // circular definition
{
class Local {}
{
class Local {} // compile-time error
}
class Local {} // compile-time error
class AnotherLocal {
void bar() {
class Local {} // ok
}
}
}
class Local {} // ok, not in scope of prior Local
}
}
メソッドfoo
の最初の文は、ローカル・クラス宣言のスコープの前に出現しているため、ローカル・クラスCyclic
のインスタンスではなく、メンバー・クラスGlobal.Cyclic
のインスタンスを作成しています。
ローカル・クラス宣言のスコープが(本体のみではなく)宣言全体を含んでいることは、ローカル・クラスCyclic
の定義がGlobal.Cyclic
ではなくそれ自体を拡張しているため、真に周期的であることを意味します。 その結果、ローカル・クラスCyclic
の宣言はコンパイル時に拒否されます。
ローカル・クラス名は同じメソッド(または場合によってはコンストラクタまたはイニシャライザ)内で再宣言することはできないため、Local
の2回目と3回目の宣言の結果、コンパイル時にエラーが発生します。 ただし、Local
は、AnotherLocal
など、より深くネストした別のクラス内のコンテキスト内で再宣言できます。
Local
の最後の宣言は、Local
の前の宣言のスコープ外で行われているため正当です。