
Javaの構文とは、 Javaプログラムの記述方法と解釈方法を定義する一連の規則のことです。
構文は主にCとC++から派生しています。C++とは異なり、Javaにはグローバル関数やグローバル変数はありませんが、グローバル変数とみなされるデータメンバがあります。すべてのコードはクラスに属し、すべての値はオブジェクトです。唯一の例外はプリミティブデータ型で、パフォーマンス上の理由からオブジェクトとはみなされません(ただし、オートボクシングによってオブジェクトに自動的に変換したり、その逆を行ったりすることは可能です)。演算子オーバーロードや符号なし整数型などの一部の機能は、言語を簡素化し、プログラミング上のミスを防ぐために省略されています。
Javaの構文は、数々のメジャーJDKリリースを経て徐々に拡張され、現在ではジェネリックプログラミングや匿名関数(Javaではラムダ式と呼ばれる関数リテラル)などの機能をサポートしています。2017年以降、新しいJDKバージョンは年に2回リリースされています。
Javaの「Hello, World!」プログラムは以下のとおりです。
public class HelloWorld { public static void main ( String [] args ) { System . out . println ( "Hello World!" ); } }Java 25以降では、明示的なクラスを使用しない簡略化されたHello Worldプログラムを作成できます。
void main () { IO.println ( " Hello World!" ) ; }識別子とは、コード内の要素の名前のことです。要素の名前を選択する際には、従うべき一定の標準的な命名規則があります。Java の識別子は、大文字と小文字を区別します。
識別子には以下を含めることができます。
識別子には以下のことはできません。
以下の単語はキーワードであり、いかなる状況下でも識別子として使用することはできません。キーワードは47個あります。
abstractassertbooleanbreakbytecasecatchcharclasscontinuedefaultdodoubleelseenumextendsfinalfinallyfloatforifimplementsimportinstanceofintinterfacelongnativenewpackageprivateprotectedpublicreturnshortstaticsuperswitchsynchronizedthisthrowthrowstransienttryvoidvolatilewhile以下の単語は文脈キーワードであり、特定の文脈でのみ制限されます。そのような文脈は 16 種類あります。
exportsmodulenon-sealedopenopenspermitsprovidesrecordrequiressealedtotransitivevarwhenwithyield以下の単語は、その言語で使用される文字通りの値を指し、3つあります。
truefalsenull以下の単語はキーワードとして予約されていますが、現在使用目的はありません。4つあります。
_constgotostrictfp整数リテラルは、intデフォルトでは型になりますが、リテラルにまたは接尾辞longを追加して型を指定することもできます (例: )。Java SE 7 以降では、読みやすさを向上させるために、数値の桁の間にアンダースコアを含めることができます。たとえば、数値145608987は145_608_987と記述できます。Ll367L
変数は、値に関連付けられた識別子です。変数は、型と名前を記述することで宣言され、必要に応じて同じステートメント内で値を代入することで初期化されます。
int count ; // 型 'int' の 'count' という名前の初期化されていない変数を宣言しますcount = 35 ; // 変数を初期化しますint count = 35 ; // 変数を宣言し、同時に初期化します同じ型の複数の変数は、カンマを区切り文字として使用することで、1つのステートメントで宣言および初期化できます。
int a , b ; // 同じ型の複数の変数を宣言int a = 2 , b = 3 ; // 同じ型の複数の変数を宣言および初期化Java 10以降、 . を使用することで変数の型を自動的に推論することが可能になりましたvar。
import java.io.FileOutputStream ;// ストリームは初期化子から推測されるように FileOutputStream 型になりますvar stream = new FileOutputStream ( "file.txt" );// 明示的な型を指定した同等の宣言FileOutputStream stream = new FileOutputStream ( "file.txt" );区切り記号{と}は、コードブロックと新しいスコープを示します。クラスメンバーやメソッド本体などは、さまざまな状況においてこれらの括弧内に記述できる内容の例です。
メソッド本体内では、以下のように波括弧を使用して新しいスコープを作成できます。
void doSomething () { int a ;{ int b ; a = 1 ; }a = 2 ; b = 3 ; // 変数 b が内部スコープで宣言されているため、不正です。}Javaには、従来のコメント、行末コメント、ドキュメントコメントの3種類のコメントがあります。
従来のコメント(ブロックコメントとも呼ばれる)は、`<code><img></code>`で始まり、 /*`<code><img></code>`で終わります*/。複数行にわたる場合もあります。このタイプのコメントはC言語とC++から派生したものです。
/* これは複数行にわたるコメントです。複数行になる場合があります。 */行末コメントは、//現在の行の末尾から始まり、その行の末尾まで続きます。このタイプのコメントは、C++ や現代の C 言語にも存在します。
// これは行末コメントですソースファイル内のドキュメントコメントは、Javadocツールによって処理され、ドキュメントが生成されます。このタイプのコメントは、/**Javadocツールで定義された規則に従って開始される点を除けば、従来のコメントと全く同じです。技術的には、これらのコメントは特殊な種類の従来のコメントであり、言語仕様では具体的に定義されていません。
/** * これはドキュメントコメントです。* * @author John Doe */パッケージ内のクラスjava.lang(サブパッケージ内のクラスは除く)は、明示的にインポートされた型に同じ名前がない限り、すべてのプログラムに暗黙的にインポートされます。重要なクラスには以下が含まれます。
java.lang.Systemjava.lang.SystemJavaで最も基本的なクラスの1つです。システムとのやり取りを行うためのユーティリティクラスであり、標準入力、出力、エラー ストリーム、システム プロパティと環境変数、時間などを含んでいます。
java.lang.Objectjava.lang.Objectは Java の最上位型です。これは、親クラスを宣言していないすべてのクラスの暗黙のスーパークラスです (したがって、Java のすべてのクラスは を継承しますObject)。すべての値をこの型に変換できますが、プリミティブ値の場合はオートボクシングが発生します。
java.lang.Recordすべてのレコードは暗黙的に を拡張しますjava.lang.Record。したがって、recordは として扱われますがclass、他のクラスを拡張することはできません。
java.lang.Enum<E>Java のすべての列挙型java.lang.Enum<E>(enum) は暗黙的に を継承します。したがって、enumは として扱われますがclass、他のクラスを継承することはできません。型パラメータEは として制約されます。Enum<EextendsEnum<E>>
java.lang.Class<T>java.lang.Class<T>は、実行時にアプリケーション内のclassまたはを表すクラスです。直接インスタンス化して構築することはできませんが、ファイルのバイトからクラスが派生するときに JVM によって作成されます。クラス リテラルは、そのようなクラス に対してを介して取得できます。たとえば、は を返します。モデル化されている未知のクラスは、 として表すことができます( はワイルドカードを表します)。interface.classX.classXString.classClass<String>Class<?>?
は「 classX.class 」という名前のフィールドにアクセスしているように見えますが、実際には「 class 」という名前のフィールドは存在しません。実際には、クラスの実行時定数プールから定数をオペランドスタックにプッシュする命令を実行しています。[ 1 ]ldc
java.lang.Stringjava.lang.Stringは Java の基本文字列型です。不変です。 を実装していないIterable<Character>ため、for-each ループで反復処理することはできませんが、 に変換できます。一部のメソッドでは、各UTF-16コード単位を としてchar[]扱いますが、実質的にUTF-32 であるに変換するメソッドも利用できます。は を実装しているため、内の はメソッド でアクセスできます。charint[]Stringjava.lang.CharSequencecharStringcharAt()
java.lang.Throwablejava.lang.Throwableは、Java のおよびステートメントでスローまたはキャッチできるすべてのもののスーパークラスです。その直接の既知のサブクラスは、(深刻な回復不能なエラー用)と(プログラムの実行中に自然に発生する可能性のある例外用)です。throwcatchjava.lang.Errorjava.lang.Exception
java.lang.Errorjava.lang.Errorはすべてのエラー クラスのスーパータイプであり、 を継承しますThrowable。これは、妥当なアプリケーションでは検出すべきでない条件を示すために使用されます。
java.lang.Exceptionjava.lang.Exceptionは、すべての例外クラスのスーパータイプであり、 を継承しますThrowable。これは、妥当なアプリケーションが捕捉する可能性がある条件を示すために使用されます。
java.lang.Mathjava.lang.MathMath.sin()は、数学関数と数学定数( 、、、Math.pow()など)を含むユーティリティクラスですMath.PI。
java.lang.IOjava.lang.IOは Java 25 で導入されたクラスです (以前は にありましたjava.io) 。とjava.io.IOを介して標準入力および出力ストリームに簡単にアクセスできるようになります。System.inSystem.out
各プリミティブ型には、関連付けられたラッパークラスがあります(プリミティブ型を参照)。
Javaアプリケーションは、クラスの集合体で構成されます。クラスはパッケージ内に存在しますが、他のクラスの中にネストすることも可能です。
main方法すべての Java アプリケーションにはエントリ ポイントが必要です。これは、グラフィカル インターフェイス アプリケーションとコンソール アプリケーションの両方に当てはまります。エントリ ポイントはメソッドですmain。メソッドを持つクラスは複数存在できますmainが、メイン クラスは常に外部で定義されます (たとえば、マニフェスト ファイル内)。mainメソッドはメイン クラスとともに宣言する必要がありますpublic。メソッドは でなければならずstatic、コマンドライン引数は文字列の配列として渡されます。C ++やC#とは異なり、値を返さず、 を返す必要がありますvoid。ただし、 を呼び出すことで、オペレーティングシステムにリターン コードを指定できますSystem.exit()。
public static void main ( String [] args ) { // ... }パッケージはクラス名の一部であり、名前付きエンティティをグループ化したり、他のエンティティと区別したりするために使用されます。パッケージのもう1つの目的は、アクセス修飾子とともにコードへのアクセスを制御することです。たとえば、 は、パッケージ にあるjava.io.InputStreamクラスの完全修飾クラス名です。InputStreamjava.io
パッケージは基本的に名前空間です。パッケージには階層構造はありませんが、ピリオドが付いているため階層構造のように見える場合があります。パッケージはモジュールを使用して、プロジェクト内外からのアクセス可否を制御できます。
パッケージはファイルの先頭で次のpackage宣言によって宣言されます。
パッケージorg.wikipedia.examples ;public class Foo { // ... }修飾子付きのクラスは、同じ名前で拡張子が.java のpublicファイルに配置し、パッケージ名に対応するネストされたフォルダに入れる必要があります。上記のクラスのパスは次のようになります。org.wikipedia.examples.Fooorg/wikipedia/examples/Foo.java
モジュールプログラミング(モジュール)は、パッケージをグループ化し、どのパッケージがパブリック API に属するかを厳密に制御するために使用されます。JARファイルとは異なり、モジュールは依存するモジュールとエクスポートするパッケージを明示的に宣言します。[ 2 ]明示的な依存関係の宣言により、大規模なアプリケーションやソフトウェア コンポーネント間の依存関係について推論しやすくなり、コードの整合性が向上します。
モジュール宣言は、モジュールのソースファイル階層のルートにあるmodule-info.javaというファイルに配置されます。JDK は、コンパイル時と実行時の両方で、モジュール間の依存関係と相互作用を検証します。
例えば、次のモジュール宣言は、モジュールがorg.wikipedia.bar別のモジュールに依存していることを宣言しorg.wikipedia.baz、次のパッケージをエクスポートしorg.wikipedia.bar.alphaますorg.wikipedia.bar.beta。
モジュール組織。ウィキペディア。bar { orgが必要です。ウィキペディア。バズ;exports org.wikipedia.bar.alpha ; exports org.wikipedia.bar.beta ; }org.wikipedia.bar.alphaパッケージのパブリックメンバーは、依存モジュールからアクセスできます。プライベートメンバーは、リフレクションプログラミングorg.wikipedia.bar.betaなどの手段でもアクセスできません。Javaバージョン9 から 16 では、このような「不正アクセス」が事実上許可されるかどうかは、コマンドライン設定に依存します。[ 3 ]
Java 9では JDK がモジュール化されました。[ 4 ]例えば、Java 標準ライブラリの大部分はモジュールによってエクスポートされますjava.base。
import文は、別のパッケージ(名前空間)に属する型を解決するために使用されます。これはusingC++の`import`に似ていると考えることができます。
型インポート宣言を使用すると、パッケージを含む完全な名前ではなく、単純な名前で名前付き型を参照できます。インポート宣言には、単一型インポート宣言とオンデマンドインポート宣言があります。インポート宣言は、パッケージ宣言の後に、コードファイルの先頭に配置する必要があります。
パッケージorg.wikipedia.examples ;import java.util.Random ; // 単一型の宣言public class ImportsTest { public static void main ( String [] args ) { /* 次の行は、 * java.util.Random random = new java.util.Random(); * と同等です。 * インポートがないと正しくありませんでした。 */ Random random = new Random (); } }コード内には、オンデマンドインポートの宣言が記述されています。「ワイルドカードインポート」(または「グロブインポート」)は、パッケージ内のすべての型をインポートします。「静的インポート」は、パッケージのメンバーをインポートします。
/** * この形式のクラスインポートにより、パッケージ java.util 内のすべてのクラスが名前で使用可能になります。 * 前の例のインポート宣言の代わりに使用できます。 */ import java.util.* ;ワイルドカードインポートは、そのパッケージ内にシンボルが存在しない場合、何もインポートしない可能性があります。たとえば、のようなステートメントは有効ですが、何も実行されません。なぜなら、すべてのクラスはパッケージ内のパッケージに存在するため、このようなインポートではパッケージ内のすべてのクラスが再帰的にインポートされないからです。importjava.*;java
このタイプの宣言は、 J2SE 5.0以降で利用可能です。静的インポート宣言を使用すると、クラス名を指定せずに、別のクラス、インターフェース、アノテーション、または列挙型で定義された静的メンバーにアクセスできます。
import static java.lang.System.out ; // 'out' は java.lang.System の静的フィールドですpublic class HelloWorld { public static void main ( String [] args ) { /* 次の行は System.out.println("Hi World!");と同等で あり、import 宣言がないと誤りになります。 */ out . println ( "Hello World!" ); } }オンデマンドインポート宣言を使用すると、次のタイプのすべてのフィールドをインポートできます。
/** * この形式の宣言により、java.lang.System クラスのすべてのフィールドを名前で使用できるようになります。 * 前の例の import 宣言の代わりに使用できます。*/ import static java.lang.System.* ;列挙定数は静的インポートでも使用できます。たとえば、この列挙型は、次のパッケージに含まれていますscreen。
public enum Colors { RED , BLUE , GREEN };別のクラスで静的インポート宣言を使用して列挙定数を取得することが可能です。
import org.wikipedia.screen.ColorName ; import static org.wikipedia.screen.ColorName.* ;public class Dots { /* 次の行は 'ColorName foo = ColorName.RED' と同等であり、 静的インポートがないと誤りになります。 */ ColorName foo = RED ;void shift () { /* 次の行は if (foo == ColorName.RED) foo = ColorName.BLUE; と同等です */ if ( foo == RED ) { foo = BLUE ; } } }Java 25以降、モジュールはimport文で使用して、モジュールがエクスポートするすべてのパッケージを自動的にインポートできます。[ 5 ]これは、を使用して行いますimport module。たとえば、は、と同等です。importmodulejava.sql;
import java.sql.* ; import javax.sql.* ; // java.logging、java.transaction.xa、java.xml からの残りの間接エクスポート同様に、同様に、はに属する 54 個のパッケージすべてをインポートします。importmodulejava.base;java.base
import module java.base ;/** * java.base モジュールをインポートすることで、ほとんどのクラスを手動でインポートする必要がなくなります。 * 以下のクラス (java.lang 以外) が使用されます。* java.text.MessageFormat * java.util.Date * java.util.List * java.util.concurrent.ThreadLocalRandom */ public class Example { public static void main ( String [] args ) { List < String > colours = List . of ( "Red" , "Orange" , " Yellow" , "Green" , "Blue" , " Indigo" , "Violet" ); IO . println ( MessageFormat . format ( "My favourite colour is {0} and today is {1,date,long}" , colours . get ( ThreadLocalRandom . current (). nextInt ( colours . size ())), new Date () )); } }Java の演算子はC++の演算子と似ています。ただし、Java のガベージコレクションdelete機構のため、演算子はありません。また、 Java はポインタをサポートしていないため、ポインタに対する操作はありません。もう 1 つの違いは、Java には符号なし右シフト演算子 ( ) があるのに対し、C の右シフト演算子の符号の有無は型に依存することです。Java の演算子はオーバーロードできません。オーバーロードできる唯一の演算子は文字列連結です。>>>operator+
if声明Javaのif文はC言語のif文と似ており、同じ構文を使用します。
if ( i == 3 ) { doSomething (); }if文にはオプションのブロックを含めることができelse、その場合はif-then-else文になります。
if ( i == 3 ) { doSomething (); } else { doSomethingElse (); }C言語と同様に、else-if構文には特別なキーワードは含まれず、個別のif-then-else文のシーケンスとして構成されます。
if ( i == 3 ) { doSomething (); } else if ( i == 2 ) { doSomethingElse (); } else { doSomethingDifferent (); }また、単純な if 文の代わりに?:演算子を使用することもできます。例:
int a = 1 ; int b = 2 ; int minVal = ( a < b ) ? a : b ;switch声明Java のswitch 文byteでは、、、、shortおよび(は不可)charのプリミティブデータ型、またはそれらに対応するラッパー型を使用できます。J2SE 5.0 以降では、列挙型を使用できます。Java SE 7 以降では、文字列を使用できます。[ 7 ]その他の参照型は、文では使用できません。intlongswitch
可能な値はcaseラベルを使用して一覧表示されます。Java のこれらのラベルには定数 (列挙型定数および文字列定数を含む) のみを含めることができます。実行は、括弧内の式に対応するラベルの後に開始されます。オプションのdefaultラベルを指定することで、式に対応するケースラベルが存在しない場合に、その後のコードを実行することができます。
各ラベルのコードはbreakキーワードで終わります。キーワードを省略すると、実行は次のラベルに進みますが、通常はコンパイル時に警告が表示されます。
switch ( ch ) { case 'A' : doSomething (); // ch == 'A' の場合にトリガーされるbreak ; case 'B' : case 'C' : doSomethingElse (); // ch == 'B' または ch == 'C' の場合にトリガーされるbreak ; default : doSomethingDifferent (); // その他の場合にトリガーされるbreak ; }switch表現Java 14以降、新しい矢印構文を使用するswitch式が使えるようになりました。
enum Result { GREAT , FINE , // その他の列挙値}Result result = switch ( ch ) { case 'A' -> Result . GREAT ; case 'B' , 'C' -> Result . FINE ; default -> throw new Exception (); };あるいは、同じことをステートメントで表現することも可能ですyieldが、意図しないフォールスルーの問題を回避できるため、矢印構文を使用することをお勧めします。
Result result = switch ( ch ) { case 'A' : yield Result . GREAT ; case 'B' : case 'C' : yield Result . FINE ; default : throw new Exception (); };反復文は、特定の条件が真と評価されたときに繰り返し実行される文です。J2SE 5.0以降、Java にはこのような文が 4 つの形式で用意されています。条件の型はboolean、またはである必要がありますjava.lang.Boolean。Java は、整数型やクラス型を暗黙的にブール値に変換しません。
例えば、以下のコードはC言語では有効ですが、Javaではコンパイルエラーになります。
while ( 1 ) { doSomething (); }whileループループ内ではwhile、各反復処理の前にテストが実行されます。
while ( i < 10 ) { doSomething (); }do-whileループdo-ループではwhile、各イテレーションの後にテストが実行されます。したがって、コードは常に少なくとも1回は実行されます。
// doSomething() は少なくとも 1 回呼び出されますdo { doSomething (); } while ( i < 10 );forループforJavaのループは、初期化子、条件式、およびカウンタ式で構成されます。条件式を除き、カンマを区切り文字として使用することで、同じ種類の式を複数含めることができます。ただし、C言語とは異なり、カンマは単なる区切り文字であり、演算子ではありません。
for ( int i = 0 ; i < 10 ; i ++ ) { doSomething (); } // 2 つの変数を使用したより複雑なループfor ( int i = 0 , j = 9 ; i < 10 ; i ++ , j -= 3 ) { doSomething (); }C言語と同様に、3つの式はすべて省略可能です。以下のループは決して終了しません。
for (;;) { doSomething (); }foreach ループはJ2SE 5.0以降で利用可能になりました。このタイプのループは、配列やコレクションに対する組み込みのイテレータを使用して、指定されたコレクションの各項目を返します。すべての要素が返され、コードブロックのコンテキストでアクセス可能です。ブロックが実行されると、残りの項目がなくなるまで次の項目が返されます。このJava のfor ループは、後にC++11に追加されました。C #とは異なり、このタイプのループには特別なキーワードは使用されず、代わりに異なる表記スタイルが使用されます。
for ( int i : intArray ) { doSomething ( i ); }breakラベルは、およびステートメントで使用されるコード内のポイントに付けられますcontinue。gotoはJavaの予約語ですが、コード内の特定のポイントにジャンプするために使用することはできません(実際には、まったく使用できません)。
開始: someMethod ();break声明このbreakステートメントは、最も近いループまたはステートメントから抜け出しますswitch。終了したステートメントの次のステートメントが存在する場合は、そのステートメントの実行が継続されます。
for ( int i = 0 ; i < 10 ; i ++ ) { while ( true ) { break ; } // この時点でループを抜ける}ラベルを使用することで、外側のループから抜け出すことが可能です。
outer : for ( int i = 0 ; i < 10 ; i ++ ) { while ( true ) { break outer ; } } // この時点でブレークしますcontinue声明このcontinueステートメントは、現在の制御ステートメントの現在のイテレーションを終了し、次のイテレーションを開始します。while以下のコードのループは、 を呼び出して文字を読み取りgetChar()、文字がスペースの場合はループ本体のステートメントをスキップします。
int ch ; while ( ch == getChar ()) { if ( ch == ' ' ) { continue ; // whileループの残りの部分をスキップ}// whileループの残りの部分。ch == ' ' の場合は到達しない。doSomething (); }continueラベルはステートメントとステートメントで指定できますbreak。
outer : for ( String str : stringsArr ) { char [] strChars = str . toCharArray (); for ( char ch : strChars ) { if ( ch == ' ' ) { /* 外側のサイクルを続行し、次の 文字列を stringsArr から取得します */ continue outer ; } doSomething ( ch ); } }return声明このreturnステートメントは、メソッドの実行を終了し、値を返すために使用されます。メソッドによって返される値は、returnキーワードの後に記述されます。メソッドが以外の値を返す場合はvoid、ステートメントを使用して何らかの値を返す必要がありますreturn。
void doSomething ( boolean streamClosed ) { // streamClosedがtrueの場合、実行は停止しますif ( streamClosed ) { return ; } readFromStream (); }int calculateSum ( int a , int b ) { int result = a + b ; return result ; }returnステートメントは、例外を除いて、直ちに実行を終了します。例外は、ステートメントがブロック内で見つかりtry、が補完されている場合です。この場合finally、制御はブロックに渡されますfinally。
void doSomething ( boolean streamClosed ) { try { if ( streamClosed ) { return ; } readFromStream (); } finally { // readFromStream() が呼び出されなかった場合でも最後に呼び出されますfreeResources (); } }try- catch-finallyステートメント例外はブロック内で処理されtryますcatch。
try { // 例外をスローする可能性のあるステートメントmethodThrowingExceptions (); } catch ( Exception e ) { // 例外をキャッチしてここで処理するreportException ( e ); } finally { // try/catch ブロックの後に必ず実行されるステートメントfreeResources (); }ブロック内のステートメントtryが実行され、いずれかのステートメントで例外が発生した場合、ブロックの実行は中断され、例外はcatchブロックによって処理されます。複数のブロックが存在するcatch場合、例外変数の型がスローされた例外の型と一致する最初のブロックが実行されます。
Java SE 7 では、uni-catch 句に加えて、multi-catch 句も導入されました。このタイプの catch 句を使用すると、Java は、互いにサブクラスではない異なるタイプの例外を単一のブロックで処理できます。これは共用型に似ているように見えますが、実際には、代替案の中で最も具体的な共通スーパータイプです。
import java.net.HttpRetryException ; import java.net.http.HttpTimeoutException ;void makeRequest () throws HttpRetryException , HttpTimeoutException { // ... }void main ( String [] args ) { try { methodThrowingExceptions (); } catch ( HttpRetryException | HttpTimeoutException e ) { // HttpRetryException と HttpTimeoutException の両方がここでキャッチされ、処理されます// 実際には、java.io.IOException. reportException ( e );に簡略化されます} }catchスローされた例外の型に一致するブロックがない場合、 try-catchステートメントを含む外側のブロック(またはメソッド)の実行は中断され、例外は包含ブロック(またはメソッド)の外に渡されます。例外は、現在アクティブなメソッドのいずれかに一致するブロックが見つかるまで、呼び出しスタックcatchを上方向に伝播されます。例外が最上位のmainメソッドまで伝播しても一致するcatchブロックが見つからない場合、例外のテキストによる説明が標準出力ストリームに書き込まれます。
ブロック内のステートメントは、例外がスローされたかどうか、またステートメントに到達したかどうかに関わらず、常にandブロックfinallyの後に実行されます。このようなブロックは、必ず実行されるクリーンアップコードを提供するのに役立ちます。trycatchreturn
とブロックcatchはfinally省略可能ですが、ブロックの後に少なくともどちらか一方が必要ですtry。
try-with-resourcesステートメントtry-with-resources ステートメントは、Java SE 7 でdispose パターンの実装として導入された特殊なタイプのtry- catch-ステートメントです。 -with-resources ステートメントでは、キーワードの後に 1 つ以上のリソースの初期化が続きます。これらのリソースは、ブロックの実行が終了すると自動的に解放されます。リソースは を実装する必要があります。 -with-resources ステートメントは、通常の- -ステートメントとは異なり、またはブロックを持つ必要はありません。finallytrytrytryjava.lang.AutoCloseabletrycatchfinallytrycatchfinally
import java.beans.XMLEncoder ; import java.io.FileOutputStream ; import java.io.IOException ; import java.util.logging.Level ; import java.util.logging.Logger ;try ( FileOutputStream fos = new FileOutputStream ( " filename " ) ; XMLEncoder xEnc = new XMLEncoder ( fos ) ) { xEnc.writeObject ( object ) ; } catch ( IOException e ) { Logger.getLogger ( Serializer.class.getName ( ) ) . log ( Level.SEVERE , null , e ) ; }Java 9以降では、既に宣言済みの変数を使用することが可能です。
import java.beans.XMLEncoder ; import java.io.FileOutputStream ; import java.io.IOException ; import java.util.logging.Level ; import java.util.logging.Logger ;FileOutputStream fos = new FileOutputStream ( " filename " ) ; XMLEncoder xEnc = new XMLEncoder ( fos ) ; try ( fos ; xEnc ) { xEnc.writeObject ( object ) ; } catch ( IOException e ) { Logger.getLogger ( Serializer.class.getName ( ) ) . log ( Level.SEVERE , null , e ) ; }throw声明このthrowステートメントは、例外をスローしてブロックまたはメソッドの実行を終了するために使用されます。スローされた例外インスタンスは、このthrowステートメントの後に記述されます。
void methodThrowingExceptions ( Object obj ) { if ( obj == null ) { // NullPointerException 型の例外をスローするthrow new NullPointerException (); } // オブジェクトが null の場合は呼び出されないdoSomethingWithObject ( obj ); }assert声明assertステートメントはJ2SE 1.4以降で使用可能です。これらのステートメントは、ソースコード内でアサーションassertを行うために使用され、特定のクラスまたはパッケージに対して実行中に有効/無効を切り替えることができます。アサーションを宣言するには、キーワードの後に条件式を記述します。ステートメントの実行時に条件式が真と評価されるとfalse、エラーが発生しますjava.lang.AssertionError。このステートメントには、コロンの後に別の式を記述することができ、これがエラーの詳細メッセージとして機能します。
// n が 0 の場合、java.lang.AssertionError がスローされますassert n != 0 ; /* n が 0 の場合、コロンの後のメッセージとともにjava.lang.AssertionError がスローされます*/ assert n != 0 : "n はゼロに等しかった" ;Java では、クラス を通じて実行スレッドが提供されます。このクラスは(ラムダ式など)java.lang.Threadを受け取り、メソッドを使用して開始され、を使用して一時停止/ブロックされます。他のスレッドに通知するには、オブジェクト ロックを解放し、別のスレッドが またはを呼び出すまでスレッドを一時停止します。java.lang.Runnablestart()sleep()wait()notify()notifyAll()
Thread t = new Thread (() - > { System.out.println ( " Running " ); } );t.start ( ) ;デーモンスレッドとは、ガベージコレクタや監視スレッドなど、バックグラウンドで実行されるスレッドのことです。JVMは、デーモンスレッドのみが残った時点で終了します。
現在のスレッドには、このcurrentThread()メソッドでアクセスできます。
従来、スレッドで呼び出すとエラーjava.lang.ThreadDeathがスローされていましたが、Java 20 [ 8 ]以降削除され、このエラーはスローされなくなりました。[ 9 ]現在、スレッドを停止する慣用的な方法はメソッドを使用することです。このメソッドでは、スレッドはクリーンアップなしで即座に停止されるのではなく、正常に終了することができます。stop()stop()interrupt()
Javaにはマルチスレッドプログラミングのための組み込みツールがあります。スレッド同期のために、Java言語には`sread`文synchronizedが含まれています。
コードブロックを同期化するには、synchronizedキーワードの後に括弧内にロックオブジェクトを記述します。実行中のスレッドが同期化されたブロックに到達すると、相互排他ロックを取得し、ブロックを実行してからロックを解放します。ロックが解放されるまで、他のスレッドはこのブロックに入ることができません。ロックには、null以外の任意の参照型を使用できます。
/* someObject のロックを取得します。参照型であり、null であってはなりません。*/ synchronized ( someObject ) { // 同期ステートメント}Javaはライブラリを提供するjava.util.concurrentとともに、アトミック性機能(java.util.concurrent.atomic)とロック機能(java.util.concurrent.locks)も提供する。
の代わりに、非同期計算java.lang.Thread用の別のクラスjava.util.concurrent.CompletableFuture<T>が提供されています[ 10 ] 。これはC#のに似ていると見なすことができますが、JavaにはC#のような明示的なコルーチンはありません。System.Threading.Tasks.Task<T>
Java 21 のProject Loomの一部として仮想スレッドが導入され、数百万のタスクにスケーリングしながら、通常のブロッキング同期コードを実行できるようになりました。[ 11 ] [ 12 ]従来の Java スレッドは「プラットフォーム スレッド」と呼ばれ、おおよそ OS スレッドに相当しますが、Java 仮想スレッドは軽量で、JVM によって管理され、実際の OS スレッドの小さなプールにスケジュールされます。仮想スレッドは依然として同期ですjava.lang.Threadが、などのファクトリ メソッドを使用して作成されますofVirtual()。コードは依然として同期でブロッキングですが、物理的な OS スレッドは非同期です。待機のために停止すると、JVM はコードを物理スレッドから切り離し、OS が非同期イベント通知を送信して中断したコードを引き継いで完了するまで、他のタスクを実行します。
Java のプリミティブ型には、整数型、浮動小数点数、UTF-16コード単位、ブール型があります。C++ や C# とは異なり、Java にはcharUTF-16 コード単位を表すために使用される型を除いて、符号なし型はありません。符号なし型がないことは>>>、C++ には存在しない符号なし右シフト演算 ( ) や、 などのメソッドを導入することで補われています.toUnsignedInt()。しかしながら、これによって C や C++ との互換性が失われるという批判も出ています。[ 13 ]
null型がなく、プリミティブ型でもクラス型でもありません。任意のオブジェクト型が格納できますnull。
このクラスは、キーワードを表すオブジェクトVoidへの参照を保持するために使用されます。 はオブジェクトの型にはなり得ないため、インスタンス化することはできません。たとえば、 は、が値を返さないタスクを実行することを示します。ClassvoidvoidCompletableFuture<Void>java.util.concurrent.CompletableFuture<T>
このクラスは、、、、、、に変換java.lang.Numberできるすべての数値を表します。bytedoublefloatintlongshort
char必ずしも単一の文字に対応するとは限りません。サロゲートペアの一部を表す場合もあり、その場合はUnicodeコードポイントは2つの値のシーケンスで表されますchar。
ラッパークラスには、プリミティブ型に対する操作のための追加の静的メソッド(例:)Integer.parseInt()と、型の情報を記述する静的定数が含まれています。ラッパークラスjava.lang.Character自体には、さらにネストされた型が含まれています。
java.lang.Character.SubsetUnicode文字セットのサブセットを表すjava.lang.Character.UnicodeBlockUnicodeブロックを表す定数を含むjava.lang.Character.UnicodeScriptUnicodeにおけるスクリプトの列挙型この言語機能はJ2SE 5.0で導入されました。ボックス化とは、プリミティブ型の値を対応する参照型の値に変換する操作です。参照型は、そのプリミティブ型のラッパーとして機能します。ボックス化解除とは、ボックス化された参照型の値を対応するプリミティブ型の値に変換する逆の操作です。どちらの操作も明示的な型変換を必要としません。
例:
int foo = 42 ; // プリミティブ型Integer bar = foo ; /* foo は bar にボックス化され、bar は int のラッパーとして機能するInteger 型です*/ int foo2 = bar ; // プリミティブ型にアンボックス化参照型には、クラス型、インターフェース型、配列型などがあります。コンストラクタが呼び出されると、ヒープ上にオブジェクトが作成され、変数に参照が割り当てられます。オブジェクトの変数がスコープ外になると、参照は破棄され、参照がなくなると、オブジェクトはガベージとしてマークされます。その後、ガベージコレクタがオブジェクトを収集して破棄します。
参照変数とは、nullどのオブジェクトも参照しない変数のことです。
Javaにおける配列は、クラスインスタンスと同様に、実行時に作成されます。配列の長さは作成時に定義され、変更することはできません。
int [] numbers = new int [ 5 ] ; numbers [ 0 ] = 2 ; numbers [ 1 ] = 5 ; int x = numbers [ 0 ] ; int len = numbers.length ; // len = 5JavaではC言語スタイルの配列宣言も受け入れられますが、一般的には使用されていません。
int arr [] = new int [ 10 ] ;JVMでは、配列は各次元ごとに左角括弧で表され、以下の文字で示されます。
bytechardoublefloatintlongshortboolean例えば、int[][]は になり[[I、String[]は になります[Ljava.lang.String;。
voidメモリ上には型として存在しませんが、内部的には文字Vで表現されます。
配列は最大255次元に制限されています。配列の理論上の最大長は(2,147,483,647、に相当Integer.MAX_VALUE)配列は32ビットのインデックスでしかアドレス指定できないため、この制限は通常、システムと仮想マシンに依存します。
クラスjava.util.Arraysと は、それぞれjava.lang.reflect.Array配列の操作と配列に対する反射操作のために提供されています。[ 14 ] [ 15 ]
配列にはフィールドがあるように見えますが、それは実際のフィールドではなく、バイトコード命令lengthによってネイティブに評価される組み込みプロパティです。[ 1 ]配列には宣言されたメンバー、メソッド、コンストラクタはありません(から継承されたものを除く)。arraylengthjava.lang.Object
配列はクラスを継承しjava.lang.Object、インターフェースjava.lang.Cloneableとを実装しますjava.io.Serializable。配列は暗黙的にであり、から継承することはできません。配列はクラスであるにもかかわらず、実行時にメモリ内に直接作成され、物理的なバイトコード表現がなく、クラスローダーによってロードされないため、配列用の.classファイルはfinalありません。
配列は参照型であるため、汎用型パラメータ内で直接使用できます。
import java.util.ArrayList ; import java.util.List ;List < int []> frequencies = new ArrayList <> ();// 長い構文int [] numbers = new int [] { 20 , 1 , 42 , 15 , 34 }; // 短い構文int [] numbers2 = { 20 , 1 , 42 , 15 , 34 };Javaでは、多次元配列は配列の配列として表現されます。厳密に言えば、他の配列への参照の配列として表現されます。
int [][] numbers = new int [ 3 ][ 3 ] ; numbers [ 1 ][ 2 ] = 2 ;int [][] numbers2 = {{ 2 , 3 , 2 }, { 1 , 2 , 6 }, { 2 , 4 , 5 }};多次元配列の性質上、部分配列の長さは変化する可能性があるため、多次元配列はC言語とは異なり、長方形である必要はありません。
int [][] numbers = new int [ 2 ][] ; // 最初の次元のみを初期化numbers [ 0 ] = new int [ 3 ] ; numbers [ 1 ] = new int [ 2 ] ;クラスは、Javaのようなオブジェクト指向言語の基本要素です。クラスには、データを格納および操作するメンバが含まれています。クラスは、トップレベルクラスとネストされたクラスに分けられます。ネストされたクラスは、別のクラスの中に配置され、外側のクラスのプライベートメンバにアクセスできるクラスです。ネストされたクラスには、メンバクラス(単純なネストの場合はstatic修飾子を使用して定義され、内部クラスの場合は使用せずに定義されます)、ローカルクラス、および匿名クラスが含まれます。
クラスの非静的メンバは、そのクラスから作成されるオブジェクトに関連するインスタンス変数とメソッドの型を定義します。これらのオブジェクトを作成するには、演算子を使用してクラスをインスタンス化しnew、クラスコンストラクタを呼び出す必要があります。
Foo foo = new Foo ();インスタンスと静的クラスの両方のメンバには、.ドット演算子を使用してアクセスします。
インスタンスメンバーへのアクセス インスタンスメンバーには、変数名を通してアクセスできます。
String foo = "Hello" ; String bar = foo . toUpperCase ();静的クラスメンバーへのアクセス 静的メンバーには、クラス名またはその他の型を使用してアクセスできます。これには、クラスインスタンスの作成は必要ありません。静的メンバーは、static修飾子を使用して宣言されます。
public class Foo { public static void doSomething () { // ... } }// 静的メソッドFoo.doSomething ( )を呼び出す修飾子は、型や型メンバーの宣言を変更するために使用されるキーワードです。特に、アクセス修飾子を含むサブグループが存在します。
abstract- クラスが基底クラスとしてのみ機能し、インスタンス化できないことを指定します。static- メンバークラスにのみ使用され、メンバークラスが包含クラスの特定のインスタンスに属していないことを指定します。final- としてマークされたクラスは、final継承することも、サブクラスを持つこともできません。strictfp- すべての浮動小数点演算はIEEE 754に準拠して実行されなければならず、中間結果を格納するために拡張精度を使用することを禁止する。デフォルトでは、abstract キーワードを使用しない限り、すべてのクラスのすべてのメソッドは具象メソッドです。抽象クラスには、実装を持たない抽象メソッドを含めることができます。デフォルトでは、default キーワードを使用しない限り、すべてのインターフェースのすべてのメソッドは抽象メソッドです。default キーワードは、インターフェースに具象メソッドを指定するために使用できます。
// デフォルトでは、abstract キーワードが使用されない限り、すべてのクラスのすべてのメソッドは具象です。abstract class Demo { // 抽象クラスには、実装を持たない抽象メソッドを含めることができます。public abstract int sum ( int x , int y );// 抽象クラスには具体的なメソッドも含まれる場合があります。public int product ( int x , int y ) { return x * y ; } }// デフォルトでは、default キーワードを使用しない限り、すべてのインターフェースのすべてのメソッドは抽象メソッドです。interface DemoInterface { int getLength (); // ここでは abstract キーワードを使用できますが、完全に無意味です// このコンテキストでは、default キーワードを使用してインターフェースの具体的なメソッドを指定できますdefault int product ( int x , int y ) { return x * y ; } }![]()
finalクラスはサブクラス化できません。サブクラス化することでセキュリティと効率性が向上する可能性があるため、Java 標準ライブラリの多くのクラスは finaljava.lang.Systemですjava.lang.String。
例:
final class Final { // ... }// 禁止されているクラスDerived extends Final { // ... }アクセス修飾子(または継承修飾子)は、クラス、メソッド、およびその他のメンバーのアクセス可能性を設定します。 とマークされたメンバーは、publicどこからでもアクセスできます。クラスまたはそのメンバーに修飾子がない場合は、デフォルトのアクセスが想定されます。
public class Foo { int baz () { return 0 ; }private class Bar {} }次の表は、アクセス元のクラスの場所と、アクセス対象のクラスまたはクラスメンバーの修飾子に応じて、クラス内のコードがそのクラスまたはメソッドにアクセスできるかどうかを示しています。

コンストラクタは、オブジェクトが初期化されるときに呼び出される特別なメソッドのようなブロックです。その目的は、オブジェクトのメンバーを初期化することです。コンストラクタと通常のメソッドの主な違いは、コンストラクタはクラスのインスタンスが作成されるときにのみ呼び出され、何も返さないことです。コンストラクタはメソッドに似た方法で宣言されますが、クラス名が付けられ、戻り値の型は指定されません。クラスの場合X、コンストラクタは ですX(...)。特に、デフォルトコンストラクタにはパラメーターがありませんX()。
class Foo { String str ;// 引数なしのコンストラクタFoo () {}// 引数1つのコンストラクタFoo ( String str ) { this . str = str ; } }コンストラクタはメソッドに似ているように見えるが、実際にはインスタンス初期化ブロックであり、メソッド呼び出しによって直接呼び出すことはできない(C++ではコンストラクタは特別なメンバ関数とみなされる)。[ 16 ]それにもかかわらず、JVM バイトコードでは、コンストラクタは という名前で現れ<init>、「インスタンス初期化メソッド」と呼ばれ、 とマークされているvoid(そのため、実行完了時に結果オブジェクトを JVM のオペランドスタックにプッシュしない)。[ 17 ]
初期化子とは、クラスまたはクラスのインスタンスが作成されるときに実行されるコードブロックのことです。初期化子には、静的初期化子とインスタンス初期化子の2種類があります。
静的初期化子は、クラスが作成されるときに静的フィールドを初期化します。これらは、static次のキーワードを使用して宣言されます。
class Foo { static { // 初期化} }クラスは一度だけ作成されます。したがって、静的初期化子は複数回呼び出されることはありません。一方、インスタンス初期化子は、クラスのインスタンスが作成されるたびに、コンストラクタの呼び出し前に自動的に呼び出されます。コンストラクタとは異なり、インスタンス初期化子は引数を取ることができず、一般的にチェック例外をスローすることもできません(いくつかの特殊な場合を除く)。インスタンス初期化子は、キーワードを含まないブロックで宣言されます。
class Foo { { // 初期化} }Java はガベージ コレクション機構に依存しているため、デストラクタ~X()や演算子はありませんdelete。ただし、すべてのオブジェクトにはfinalize()ガベージ コレクションの前に呼び出されるメソッドがあり、これをオーバーライドしてファイナライゼーションを実装できます。ただし、どのスレッドが特定のオブジェクトのメソッドを呼び出すか、あるいはそもそも呼び出されるかどうかは保証されませんfinalize()。ファイナライザは非決定論的であり (C++ のデストラクタとは異なり)、呼び出しで重要なリソースを解放すると、finalize()予測不可能な動作につながる可能性があります。[ 18 ] Java 9 で導入された別のクラスは、java.lang.ref.Cleanerネイティブ ポインタ、ファイル ディスクリプタ、ソケットなどの非メモリ リソースを解放するための低レベルの安全ネットとして追加されています。[ 19 ]
Java のすべてのステートメントはメソッド内に記述する必要があります。メソッドは関数に似ていますが、クラスに属します。メソッドには戻り値、名前、そして通常は引数とともに呼び出されたときに初期化されるいくつかのパラメーターがあります。C++ と同様に、何も返さないメソッドの戻り値の型は として宣言されます。C++ とは異なり、Java のメソッドはデフォルトの引数void値を持つことはできず、代わりにメソッドは通常オーバーロードされます。
class Foo { int bar ( int a , int b ) { return ( a * 2 ) + b ; }// 同じ名前だが引数が異なるオーバーロードされたメソッドint bar ( int a ) { return a * 2 ; } }メソッドは.、オブジェクトに対する表記法を用いて呼び出されます。静的メソッドの場合は、クラス名も使用されます。
Foo foo = new Foo ( ); int result = foo.bar ( 7 , 2 ) ; // foo に対して非静的メソッドが呼び出されますint finalResult = Math.abs ( result ) ; //静的メソッド呼び出しこのthrowsキーワードは、メソッドが例外をスローすることを示します。チェック例外はすべて、カンマ区切りのリストで指定する必要があります。
import java.io.File ; import java.io.IOException ; import java.util.zip.DataFormatException ;// IOException と DataFormatException がスローされる可能性があることを示しますvoid operateOnFile ( File f ) throws IOException , DataFormatException { // ... }abstract抽象メソッドは抽象クラスにのみ存在でき、そのようなメソッドは本体を持たず、サブクラス自体が抽象クラスでない限り、サブクラスでオーバーライドする必要があります。static- メソッドを静的にして、クラスインスタンスを作成せずにアクセスできるようにします。ただし、静的メソッドは同じクラス内の非静的メンバーにアクセスすることはできません。final- サブクラスではメソッドをオーバーライドできないことを宣言します。native- このメソッドは、プラットフォーム依存のコード内でJNIを介して実装されていることを示します。実際の実装は Java コードの外部で行われ、このようなメソッドには本体がありません。strictfp浮動小数点演算の実行において、IEEE 754規格に厳密に準拠することを宣言していました。現在は廃止されています。synchronized- このメソッドを実行するスレッドはモニターを取得する必要があることを宣言します。synchronizedメソッドの場合、モニターはクラスインスタンス、またはjava.lang.Classメソッドが静的である場合です。finalメソッドはサブクラスによってオーバーライドまたは隠蔽することはできません。 [ 20 ]これは、クラスの機能や一貫性にとって重要なメソッドをサブクラスが変更することによる予期しない動作を防ぐために使用されます。[ 21 ]
例:
public class Base { public void foo () { // ... }public final void bar () { // ... }public static void baz () { // ... }public static final void qux () { // ... } }public class Derived extends Base { // OK、Base::foo() をオーバーライドします@Override public void foo () { // ... }// 禁止@Override public void bar () { // ... }// OK、Base::baz() をオーバーライドします@Override public static void baz () { // ... }// 禁止@Override public static void qux () { // ... } }よくある誤解として、メソッドをfinalとして宣言すると、コンパイラがメソッドが呼び出された場所に直接挿入できるfinalようになるため、効率が向上するというものがある(インライン展開を参照)。メソッドは実行時にロードされるため、コンパイラはこれを行うことができない。どのクラスがロードされたかを正確に知っているのは実行環境とJITコンパイラだけであり、メソッドがfinalかどうか、いつインライン化するかについての決定を下せるのはそれらだけである。[ 22 ]
直接実行可能なプラットフォーム固有のマシンコードを生成するマシンコードコンパイラは例外です。静的リンクを使用する場合、コンパイラはコンパイル時に計算可能なメソッドと変数がインライン化される可能性があると安全に想定できます。
この言語機能はJ2SE 5.0で導入されました。メソッドの最後の引数を可変引数として宣言すると、メソッドは可変引数メソッド(固定引数メソッドとは対照的に)または単に可変引数メソッドになります。これにより、宣言された型の値を(場合によってはゼロ個)可変個、引数としてメソッドに渡すことができます。これらの値は、メソッド内で配列として使用できます。
// numbers は可変長引数を表しますvoid printReport ( String header , int ... numbers ) { // numbers は int[] として表示されますSystem . out . println ( header ); for ( int num : numbers ) { System . out . println ( num ); } }// 可変引数メソッドprintReport ( "レポートデータ" , 74 , 83 , 25 , 96 )を呼び出すデータを格納するために、クラス本体内でフィールド、つまりクラス変数を宣言することができます。
class Foo {ダブルバー; }フィールドは宣言時に直接初期化できます。
class Foo { double bar = 2.3 ; }static- フィールドを静的メンバーにします。final- フィールドは、コンストラクタ内、初期化ブロック内、または宣言時のいずれか早い方で一度だけ初期化できます。transient- このフィールドはシリアル化時に保存されないことを示します。volatile- フィールドが宣言されている場合volatile、すべてのスレッドが変数に対して一貫した値を参照することが保証されます。Java のクラスは、1 つのクラスからのみ継承できます。クラスは、としてマークされていない任意のクラスから派生できます。継承はキーワードを使用して宣言されます。クラスは、キーワードを使用して自身を参照でき、キーワードを使用して直接のスーパークラスを参照できます。finalextendsthissuper
クラスFoo {}class Foobar extends Foo {}クラスがスーパークラスを指定しない場合、暗黙的にjava.lang.Objectクラスから継承します。したがって、Java のすべてのクラスはObjectクラスのサブクラスです。
スーパークラスにパラメータなしのコンストラクタがない場合、サブクラスはコンストラクタ内でスーパークラスのどのコンストラクタを使用するかを指定する必要があります。例:
class Foo { public Foo ( int n ) { // n を使って何か処理を行う} }class Foobar extends Foo { private int number ; // スーパークラスにはパラメータなしのコンストラクタがないため、スーパークラスのどのコンストラクタを使用するか、またどのように使用するかを指定する必要がありますpublic Foobar ( int number ) { super ( number ) ; this.number = number ; } }C++とは異なり、finalJavaの非メソッドはすべて仮想メソッドであり、継承クラスによってオーバーライドできます。
class Operation { public int doSomething () { return 0 ; } }class NewOperation extends Operation { @Override public int doSomething () { return 1 ; } }抽象クラスとは、不完全なクラス、または不完全とみなされるべきクラスであり、(直接)インスタンス化することはできません。[ 23 ]
クラスがX抽象メソッドを持つとは、以下のいずれかに該当する場合をいう。
X抽象メソッドの宣言を明示的に含んでいます。X継承チェーン内の のスーパークラスのいずれも抽象メソッドを持ち、Xそれを実装するメソッドを宣言も継承もしていません。Xメソッド(したがって必然的に抽象メソッド)を宣言または継承しますが、Xそれを実装するメソッドは宣言も継承もしません。パッケージorg.wikipedia.examples ;public class MyAbstractClass { private static final String hello ;static { System.out.printf ( " % s : static block runtime%n" , MyAbstractClass.class.getName ( ) ) ; hello = String.format ( " hello from % s " , MyAbstractClass.class.getName ( ) ) ; }{ System.out.printf ( " % s : インスタンスブロック実行時% n " , MyAbstractClass.class.getName ( ) ) ; }public AbstractClass ( ) { System.out.printf ( "%s: コンストラクタ実行時% n " , MyAbstractClass.class.getName ( ) ) ; }public static void hello ( ) { System.out.println ( hello ) ; } }パッケージorg.wikipedia.examples ;public class MyCustomClass extends MyAbstractClass {static { System.out.printf ( " % s : static block runtime % n " , MyCustomClass.class.getName ( ) ) ; }{ System.out.printf ( " % s : インスタンスブロック実行時% n " , MyCustomClass.class.getName ( ) ) ; }public CustomClass ( ) { System.out.printf ( "%s: コンストラクタ実行時% n " , MyCustomClass.class.getName ( ) ) ; }public static void main ( String [] args ) { MyCustomClass nc = new MyCustomClass (); hello (); MyAbstractClass . hello (); // これも有効} }出力:
org.wikipedia.examples.MyAbstractClass: 静的ブロックランタイム org.wikipedia.examples.MyCustomClass: 静的ブロックランタイム org.wikipedia.examples.MyAbstractClass: インスタンスブロックランタイム org.wikipedia.examples.MyAbstractClass: コンストラクタ実行時 org.wikipedia.examples.MyCustomClass: インスタンスブロックランタイム org.wikipedia.examples.MyCustomClass: コンストラクタ実行時 org.wikipedia.examples.MyAbstractClass からこんにちは この言語機能はJ2SE 5.0で導入されました。厳密には、列挙型は本体に列挙定数を含むクラスの一種です。各列挙定数は、列挙型のインスタンスを定義します。列挙型クラスは、列挙型クラス自体以外ではインスタンス化できません。
enum Season { WINTER , SPRING , SUMMER , AUTUMN , }列挙定数にはコンストラクタを持たせることができ、コンストラクタはクラスがロードされるときに呼び出されます。
public enum Season { WINTER ( "寒い" ), SPRING ( "暖かい" ), SUMMER ( "暑い" ), AUTUMN ( "涼しい" );Season ( String description ) { this.description = description ; }private final String description ;public String getDescription () { return description ; } }列挙型はクラス本体を持つことができ、その場合、列挙型は列挙型クラスを継承する匿名クラスとして扱われます。
public enum Season { WINTER { @Override String getDescription () { return "cold" } }, SPRING { @Override String getDescription () { return "warmer" ; } }, SUMMER { @Override String getDescription () { return "hot" ; } }, FALL { @Override String getDescription () { return "cooler" ; } };abstract String getDescription (); }インターフェースは、フィールドを含まず、通常は実際の実装なしに多数のメソッドを定義する型です。インターフェースは、任意の数の異なる実装との契約を定義するのに役立ちます。すべてのインターフェースは暗黙的に抽象です。インターフェースのメソッドは、言語バージョンに応じて、strictfpクラスと同じ効果を持つアクセス修飾子のサブセットを持つことができ、staticJava SE 8 以降では、も同様の効果があります。
interface ActionListener { int ACTION_ADD = 0 ; int ACTION_REMOVE = 1 ; void actionSelected ( int action ); }インターフェースは、implementsキーワードを使用してクラスによって実装されます。複数のインターフェースを実装することも可能で、その場合はimplementsキーワードの後にカンマ区切りのリストで記述します。インターフェースを実装するクラスは、そのすべてのメソッドをオーバーライドする必要があります。そうでない場合は、抽象クラスとして宣言する必要があります。
interface RequestListener { int requestReceived (); }class ActionHandler implements ActionListener , RequestListener { public void actionSelected ( int action ) { // ... }public int requestReceived () { // ... } }// インターフェースで定義されたメソッドの呼び出し// ActionHandler は RequestListener として表現できます... RequestListener listener = new ActionHandler (); // ...したがって、requestReceived() メソッドを実装することがわかっていますlistener . requestReceived ();これらの機能は、Java SE 8 のリリースとともに導入されました。インターフェースが定義するメソッドが 1 つだけの場合 ( から継承されたメソッドを除くjava.lang.Object)、そのインターフェースは自動的に関数型インターフェースになります。この場合、実装は新しいクラスで実装する代わりにラムダ式として表現できるため、関数型スタイルのコードの記述が大幅に簡素化されます。関数型インターフェースには、オプションで 注釈を付けることができます。このjava.lang.FunctionalInterface注釈は、コンパイラにインターフェースが実際に関数型インターフェースの定義に準拠しているかどうかをチェックするように指示します。
// 関数型インターフェース@FunctionalInterface interface Calculation { int calculate ( int someNumber , int someOtherNumber ); }// このインターフェースをパラメータとして受け取るメソッドint runCalculation ( Calculation calculation ) { return calculation . calculate ( 1 , 2 ); }// ラムダ式を使用してメソッドrunCalculation を呼び出します(( number , otherNumber ) -> number + otherNumber );// 匿名クラスを使用した同等のコードrunCalculation ( new Calculation () { @Override public int calculate ( int someNumber , int someOtherNumber ) { return someNumber + someOtherNumber ; } })ラムダ式のパラメータ型は完全に指定する必要はなく、実装するインターフェースから推論できますが、ラムダ式の戻り値の型を明示的に指定する場所はありません(戻り値の型は推論されます)。ラムダ式の本体がreturn式のみの場合は、本体ブロックやステートメントなしで記述できます。また、メソッドにパラメータが1つしかないインターフェースの場合は、丸括弧を省略できます。[ 24 ]
// 上記と同じ呼び出しだが、型が完全に指定され、本体ブロックが含まれているrunCalculation (( int number , int otherNumber ) -> { return number + otherNumber ; });// 単一のパラメータのみを持つメソッドを持つ関数型インターフェース interface StringExtender { String extendString ( String input ) ; }// ラムダ式を使用してこの型の変数を初期化しますStringExtender extender = input -> input + " Extended" ;ラムダ式は句を指定できませんthrows。ラムダ式は、何らかのターゲット関数インターフェース(などjava.lang.Runnable)を実装します。ラムダ式自体は具体的な型の完全な式ではなく、むしろ多項式であり、その型は自身の内容のみではなく、周囲のターゲット型によって影響を受けます。[ 25 ]
import java.util.function.Function ;// 無効です。ラムダ式自体には独立した型がありません。var f = ( int x ) -> x + 1 ; // 代わりに次のようになります: Function < Integer , Integer > f = x -> x + 1 ;ラムダが を拡張する関数インターフェースを実装する場合java.lang.Serializable、ラムダがシリアライズされると、ラムダ自体に関する情報をキャプチャするjava.lang.invoke.SerializedLambda[ 26 ]となり、その「シリアライズ形式」と呼ばれる[ 27 ]になります。これは、ラムダ実装クラスが合成的で JVM に固有であるため、別の JVM 呼び出しで正確に再構築する必要があるためです。C++ と同様に、ラムダ型名は合成的でコンパイラによって生成され、実装の詳細は指定されていません。
Runnable r = ( ) - > System.out.println ( " Hello" ) ;//次のような出力が考えられます。// class org.wikipedia.examples.Main$$Lambda$1/0x0000000800b00440 System.out.println ( r.getClass ( ) );ラムダ式はクラスファイルを生成せず、invokedynamicJVMに対して命令を出力します。ランタイムはこの命令を使用して、適切な実装クラスを作成します。
キャプチャラムダは、キャプチャされた状態を保存する必要があるため、通常は別々のオブジェクトですが、キャプチャしないラムダはシングルトンになる可能性があります。
Runnable r1 = () -> {}; Runnable r2 = () -> {};System.out.println ( r1 == r2 ) ; //真偽値はJVMによって決定されますしかし、C++とは異なり、ラムダ型は言語モデルの一部ではありません。その実行時クラスについては何も依存できませんが、C++ではラムダ型を抽出してdecltype真の一意のクロージャ型を取得できます。ラムダはjava.lang.Class<?>コード内で参照できません。
Javaでは、演算子を使用してメソッド参照を行うことができます::(これはC++の名前空間修飾演算子とは関係ありません::)。インターフェースと互換性のある名前付きメソッドが既に存在する場合は、ラムダ式を使用する必要はありません。このメソッドは、メソッド参照を使用してラムダ式の代わりに渡すことができます。メソッド参照にはいくつかの種類があります。
上記の呼び出しコードは、runCalculationメソッド参照を使用して以下のように置き換えることができます。
runCalculation ( Integer :: sum );Javaでは、コンストラクタはメソッドとはみなされないため、X::X存在しません。コンストラクタ参照はで取得しますX::new。
インターフェースは、クラスと同様に他のインターフェースを継承できます。クラスとは異なり、複数のインターフェースを継承することが可能です。ただし、複数のインターフェースに同じ名前のフィールドが存在する可能性があり、その場合は単一のあいまいなメンバーとなり、アクセスできなくなります。
/* このインターフェースを実装するクラスは、ActionListener と RequestListener の両方のメソッドを実装する必要があります */ interface EventListener extends ActionListener , RequestListener { }Java SE 8では、インターフェースにデフォルトメソッドが導入されました。これにより、開発者は既存のインターフェースに新しいメソッドを追加しても、既にそのインターフェースを実装しているクラスとの互換性を損なうことなく済みます。通常のインターフェースメソッドとは異なり、デフォルトメソッドには本体があり、実装クラスがオーバーライドしていない場合に呼び出されます。
interface StringManipulator { String extendString ( String input ); // 実装が任意であるメソッドdefault String shortenString ( String input ) { return input . substring ( 1 ); } }// すべてのメソッドを実装していなくても、これは有効なクラスですclass PartialStringManipulator implements StringManipulator { @Override public String extendString ( String input ) { return String . format ( "%s Extended" , input ); } }静的メソッドは、Java SE 8で導入されたもう一つの言語機能です。クラスと全く同じように動作します。
interface StringUtils { static String shortenByOneSymbol ( String input ) { return input . substring ( 1 ); } }StringUtils.shortenByOneSymbol ( "Test " ) ;Java 9 リリースでプライベート メソッドが追加されました。インターフェースには、本体がプライベートとしてマークされたメソッドを持たせることができ、その場合、継承クラスからはアクセスできません。コードの再利用を目的として、デフォルト メソッドから呼び出すことができます。
interface Logger { default void logError () { log ( Level . ERROR ); }default void logInfo ( ) { log ( Level.INFO ) ; }private void log ( Level level ) { SystemLogger.log ( level.id ) ; } }Javaにおけるアノテーションは、コードにメタデータを埋め込むための手段です。この言語機能はJ2SE 5.0で導入されました。
Javaには定義済みの注釈型がいくつかありますが、新しい注釈型を定義することもできます。注釈型の宣言は、インターフェース宣言の特殊な型です。宣言方法はインターフェースと同じですが、interfaceキーワードの前に記号が付きます@。Javaの注釈はインターフェースであり、暗黙的にから拡張されjava.lang.annotation.Annotation、他のものから拡張することはできません。任意のオブジェクトになり得るC++の注釈とは異なり、Javaの注釈は実際の実行時オブジェクトとしてインスタンス化することはできません。
@interface BlockingOperations {}アノテーションは、共通インターフェースと同じ宣言を本体に含めることができます。さらに、列挙型やアノテーションを含めることもできます。主な違いは、抽象メソッド宣言にはパラメーターがなく、例外もスローできないことです。また、defaultメソッド名の後にキーワードを使用して宣言するデフォルト値を持つことができます。
@interface BlockingOperations { boolean fileSystemOperations (); boolean networkOperations () default false ; }アノテーションは、パッケージ、クラス(列挙型を含む)、インターフェース(アノテーションを含む)、フィールド、メソッド、パラメータ、コンストラクタ、ローカル変数など、あらゆる種類の宣言で使用できます。また、列挙定数にも使用できます。アノテーションは、@アノテーション型名の前に記号を付け、その後に括弧で囲んだ要素と値のペアを記述して宣言します。デフォルト値のないすべての要素には、値を割り当てる必要があります。
@BlockingOperations ( fileSystemOperations , // 必須networkOperations = true // オプション) void openOutputStream () { // アノテーション付きメソッド}一般的な形式の他に、注釈を宣言するための省略形が2つあります。マーカー注釈は省略形であり、要素に値が割り当てられていない場合に使用されます。
@Unused // @Unused() の省略形void travelToJupiter () {}もう1つの短縮形は「単一要素注釈」と呼ばれます。これは、要素が1つだけ含まれる注釈タイプ、または複数の要素が存在するものの、デフォルト値が欠落している要素が1つだけの場合に使用されます。単一要素注釈形式では、要素名は省略され、代わりに値のみが記述されます。
/* @BlockingOperations(fileSystemOperations = true) と同等です。networkOperations にはデフォルト値があり、値を割り当てる必要はありません。*/@BlockingOperations(true)voidopenOutputStream(){}Generic programming (generics), or parameterized types, or parametric polymorphism, is one of the major features introduced in J2SE 5.0. Before generics were introduced, it was required to declare all the types explicitly. With generics, it became possible to work in a similar manner with different types without declaring the exact types. The main purpose of generics is to ensure type safety and to detect runtime errors during compilation. Unlike C++ templates, generics do not instantiate a specialization for each type, and unlike C#, generics are not reified, and information on the used parameters is not available at runtime due to type erasure[28] (while Kotlin, another JVM language, offers reified generics, it achieves this by inlining the type at the call site[29]). This is because historically, Java lacked generics entirely; thus generics are erased at runtime to allow a generic class X<T> to be compatible with X.
For instance, before generics were introduced, the Java collections framework stored everything as java.lang.Object.
importjava.util.ArrayList;importjava.util.List;Listnames=newArrayList();names.add("Alice");names.add("Bob");Stringfirst=(String)names.get(0);// first = "Alice"names.add(1);// AllowedAt runtime, generics appear as the lower bound of the type parameter (if no lower bound is specified, this is implicitly java.lang.Object). Because generics are erased, it is not possible to construct a generic type (such as newT()) or check types against a specialization (such as if(namesinstanceofList<String>)).
Also, generic classes may not extend java.lang.Throwable.[30] This is because a generic exception FooException<T> would erase FooException<String> and FooException<Integer> to the same type at runtime, making the two indistinguishable at runtime. However, a generic type may be thrown (as long as it is bounded below by java.lang.Throwable). For example, the following pattern, sometimes known as the generic rethrow or sneaky throw, is used to bypass checked exceptions entirely, such as in the Project Lombok@SneakyThrows attribute.[31]
static<TextendsThrowable>voidsneakyThrow(Throwablet)throwsT{throw(T)t;}This erases T down to java.lang.Throwable, bypassing the checked exception mechanism (which enforces only on types which do not descend from java.lang.Error or java.lang.RuntimeException) entirely.
Classes can be parameterized by adding a type variable inside angle brackets (< and >) following the class name. It makes possible the use of this type variable in class members instead of actual types. There can be more than one type variable, in which case they are declared in a comma-separated list.
It is possible to limit a type variable to a subtype of some specific class or declare an interface that must be implemented by the type. In this case the type variable is appended by the extends keyword followed by a name of the class or the interface. If the variable is constrained by both class and interface or if there are several interfaces, the class name is written first, followed by interface names with & sign used as the delimiter (in a way which resembles an intersection type).
/* This class has two type variables, T and V. T must be a subtype of ArrayList and implement Formattable interface */publicclassMapper<TextendsArrayList&Formattable,V>{publicvoidadd(Tarray,Vitem){// array has add method because it is an ArrayList subclassarray.add(item);}}When a variable of a parameterized type is declared or an instance is created, its type is written exactly in the same format as in the class header, except the actual type is written in the place of the type variable declaration.
/* Mapper is created with CustomList as T and Integer as V.CustomList must be a subclass of ArrayList and implement Formattable */Mapper<CustomList,Integer>mapper=newMapper<CustomList,Integer>();Since Java SE 7, it is possible to use a diamond (<>) in place of type arguments, in which case the latter will be inferred. This is sometimes called the "diamond operator", even though it is not actually an operator, but rather an empty type list. The following code in Java SE 7 is equivalent to the code in the previous example:
Mapper<CustomList,Integer>mapper=newMapper<>();When declaring a variable for a parameterized type, it is possible to use wildcards instead of explicit type names. Wildcards are expressed by writing ? sign instead of the actual type. It is possible to limit possible types to the subclasses or superclasses of some specific class by writing the extends keyword or the super keyword correspondingly followed by the class name.
/* Any Mapper instance with CustomList as the first parametermay be used regardless of the second one.*/Mapper<CustomList,?>mapper;mapper=newMapper<CustomList,Boolean>();mapper=newMapper<CustomList,Integer>();/* Will not accept types that use anything buta subclass of Number as the second parameter */voidaddMapper(Mapper<?,?extendsNumber>mapper){}Usage of generics may be limited to some particular methods, this concept applies to constructors as well. To declare a parameterized method, type variables are written before the return type of the method in the same format as for the generic classes. In the case of constructor, type variables are declared before the constructor name.
classMapper{// The class is not generic, the constructor is<T,V>Mapper(Tarray,Vitem){}}/* This method will accept only arrays of the same type asthe searched item type or its subtype */static<T,VextendsT>booleancontains(Titem,V[]arr){for(TcurrentItem:arr){if(item.equals(currentItem)){returntrue;}}returnfalse;}Interfaces can be parameterized in the similar manner as the classes.
interfaceExpandable<TextendsNumber>{voidaddItem(Titem);}// This class is parameterizedclassMyArray<TextendsNumber>implementsExpandable<T>{voidaddItem(Titem){}}// And this is not and uses an explicit type insteadclassIntegerArrayimplementsExpandable<Integer>{voidaddItem(Integeritem){}}Object[] becomes [Ljava/lang/Object;