該当する結果がありません

一致する検索結果がありませんでした。

お探しのものを見つけるために、以下の項目を試してみてください。

  • キーワード検索のスペルを確認してください。
  • 入力したキーワードの同義語を使用してください。たとえば、「ソフトウェア」の代わりに「アプリケーション」を試してみてください。
  • 下記に示すよく使用される検索語句のいずれかを試してみてください。
  • 新しい検索を開始してください。
急上昇中の質問

 

Java 9 |抜粋

Java 9 Modulesの理解

内容と使用方法

Paul Deitel


Paul Deitel

Paul Deitel

この記事では、Javaの誕生以来、その最も重要な新しいソフトウェア・エンジニアリング・テクノロジーであるJava 9 Platform Module System(JPMS)を紹介します。Project Jigsawの成果であるモジュール性により、あらゆるレベルの開発者が、ソフトウェア・システム、特に大規模システムの構築、保守、変更を行う際に、より生産的な作業ができるようになります。

モジュールの概要

モジュール性により、パッケージより上位レベルの集合体が追加されます。新しい言語の主要な要素は module で、一意に名付けられた再利用可能な関連パッケージのグループと、リソース (イメージや XML ファイルなど)、および、以下を指定する module descriptor です。

  • モジュールの 名前
  • モジュールの依存関係 (つまり、このモジュールが依存する他のモジュール)
  • 他のモジュールに明示的に利用可能にするパッケージ (モジュール内の他のすべてのパッケージは、暗黙的に他のモジュールから利用不可です)
  • 提供するサービス
  • 消費するサービス
  • リフレクションを使用できるその他のモジュール

歴史

Java SEプラットフォームは1995年に誕生しました。現在、およそ1,000万人の開発者が、Internet of Things (IoT)やその他の組込みデバイスなど、リソース制約のあるデバイス用の小規模なアプリケーションから、大規模かつビジネスに必要不可欠であるミッションクリティカルなシステムに至るまで、すべてを構築しています。世の中には膨大な種類のレガシー・コードがありますが、これまでJavaプラットフォームは主にモノリシックなフリー・サイズ型のソリューションでした。長年にわたり、Javaのモジュール化に向けた様々な取り組みが行われてきましたが、どれも広く使われておらず、Javaプラットフォームのモジュール化に使えるようなものはありませんでした。

Java SEプラットフォームのモジュール化は難しく、その取り組みには長い年月を要していました。JSR 277: Java Module Systemは当初、2005年にJava 7用に提案されました。このJSRは、後でJSR 376: Java Platform Module Systemによって置き換えられ、Java 8を対象にしました。Java SEプラットフォームは、Java 9でモジュール化されました。しかしそれは、Java 9が2017年9月まで延期された以降の話です。

ゴール

各モジュールは、その依存関係を明示的に指定する必要があります。

JSR 376によると、Java SEプラットフォームのモジュール化の主な目標は以下の通りです。

  • 信頼性の高い構成- モジュール間の依存関係を、コンパイル時と実行時の両方で認識できる方法で明示的に宣言するためのメカニズムを提供します。システムは、これらの依存関係を調べて、アプリをサポートするために必要なすべてのモジュールのサブセットを決定することができます。
  • 強力なカプセル化- あるモジュールのパッケージは、そのモジュールが明示的にそれらをエクスポートした場合にのみ、他のモジュールからアクセス可能です。その場合でも、他のモジュールは、他のモジュールの機能を必要とすることを明示しない限り、そうしたパッケージを使用することができません。これにより、潜在的な攻撃者がアクセスできるクラスが少なくなるため、プラットフォームの安全性が向上します。モジュール性を考慮することで、よりすっきりとした論理的な設計が可能になるかもしれません。
  • スケーラブルなJavaプラットフォーム- 従来、Javaプラットフォームは多数のパッケージで構成されるモノリスであり、開発やメンテナンスおよび変更が困難でした。また、そのサブセット化は容易ではありませんでした。現在、そうしたプラットフォームは95のモジュールにモジュール化されています(この数はJavaの進化に伴って変わる可能性があります)。アプリやターゲットとするデバイスに必要なモジュールのみで構成されるカスタム・ランタイムを作成することができます。例えば、GUIをサポートしないデバイスの場合、GUIモジュールを含まないランタイムを作成することで、ランタイムのサイズを大幅に縮小することができます。
  • プラットフォームの整合性の向上-Java 9以前は、アプリケーションのクラスが使用することを意図していない多くのクラスをプラットフォームで使用することが可能でした。強力なカプセル化により、これらの内部APIは真にカプセル化され、プラットフォームを使用するアプリケーションから隠されています。このため、コードが内部APIに依存している場合、レガシー・コードをモジュール化されたJava 9に移行することが問題になることがあります。
  • パフォーマンスの向上-JVMは、アプリケーションのパフォーマンスを向上させるために、様々な最適化手法を用いています。JSR376では、必要な型が特定のモジュールにしかないことが事前に分かっている場合、これらの手法がより効果的であることを示しています。

JDKのモジュールのリスト

Java9の重要な点は、JDKをモジュールに分割し、さまざまな構成に対応できるようにしたことです。(「JEP 200: The Modular JDK」を参照。」すべての JavaモジュラリティーJEPおよびJSRを 表1に示します。)JDKのbinフォルダからjavaコマンドで、--list-modulesオプションをつけて、以下のように使用します。

java --list-modules

には、JDKのモジュール群がリストアップされており、Java言語SE仕様を実装した標準モジュール(javaで始まる名前)、JavaFXモジュール(javafxで始まる名前)、JDK固有のモジュール(jdkで始まる名前)、Oracle固有のモジュール(oracleで始まる名前)などが含まれています。各モジュール名のあとのバージョン文字列- @9は、モジュールが Java 9に属していることを示します。

モジュール宣言

前述の通り、モジュールはモジュール記述子(モジュールの依存関係、モジュールが他のモジュールに提供するパッケージなどを指定するメタデータ)を提供する必要がありますモジュール記述子は、module-info.javaというファイルに定義されているモジュール宣言をコンパイルしたものです。各モジュール宣言は、次に示すように、キーワードmoduleで始まり、その後に一意のモジュール名と中カッコで囲まれたモジュール本体が続きます。

モジュールシステムの主な目的は、強力なカプセル化にあります。

module modulename {
}

モジュール宣言の本文は空にすることも、requiresexportsprovides...withusesおよびopensなど、様々なモジュール・ディレクティブを含めることもできます(それぞれで説明します)。後で確認するように、モジュール宣言をコンパイルすると、モジュール記述子が作成されます。モジュール記述子は、モジュールのルート・フォルダ内のmodule-info.classという名前のファイルに格納されます。ここでは、各モジュール・ディレクティブについて簡単に説明します。その後、実際のモジュール宣言を示します。

キーワードexportsmoduleopenopensprovidesrequiresuseswith、および後で紹介するtoおよびtransitiveは制限付きキーワードです。これらはモジュール宣言でのみキーワードであり、コード内のどこでも識別子として使用できます。

requires.requiresモジュール・ディレクティブは、このモジュールが別のモジュールに依存することを指定します。この関係はモジュール依存性と呼ばれます。各モジュールは、その依存関係を明示的に指定する必要があります。モジュールAがモジュールBをrequiresした場合、モジュールAはモジュールBを読み取り、モジュールBはモジュールAによって読み取られます。別のモジュールへの依存性を指定するには、次のようにrequiresを使用します。

requires modulename;

また、コンパイル時には必要だが、実行時には任意であることを示すrequires static指示文もあります。これは optional dependency として知られており、この紹介では説明しません。

requires transitive(暗黙の可読性).他のモジュールへの依存関係を指定し、自分のモジュールを読んでいる他のモジュールもその依存関係を読むようにするには、implied readability として知られている requires transitive を以下のように使用します。

requires transitive modulename;

java.desktopモジュール宣言から、次のディレクティブを考えます。

requires transitive java.xml;

この場合、java.desktopを読み取るいかなるモジュールも、暗黙的にjava.xmlを読み取ります。たとえば、java.desktopモジュールのメソッドがjava.xmlモジュールからタイプを返す場合、java.desktopを読み取るモジュール内のコードはjava.xmlに依存します。java.desktopのモジュール宣言にrequires transitiveディレクティブがない場合、java.xml明示的に読み取らないかぎり、このような依存モジュールは構成されません。

JSR 379 によると、Java SEの標準モジュールは、ここで説明したようなすべてのケースで暗黙の可読性を付与する必要があります。また、Java SE標準モジュールは非標準モジュールに依存することがありますが、暗黙の可読性を与えてはいけません。これにより、Java SE標準モジュールにのみ依存するコードは、Java SE実装間で移植可能であることが保証されます。

exports and exports…to.exports モジュール指示文は、他のすべてのモジュールのコードから public 型 (とその入れ子の publicprotected 型) にアクセスできるようにするモジュールのパッケージの一つを指定します。exports...to ディレクティブは、エクスポートされたパッケージにアクセスできるモジュールのコードをカンマ区切りで指定することができ、これは qualified エクスポートとして知られています。

uses.usesモジュール・ディレクティブは、このモジュールによって使用されるサービスを指定し、モジュールをサービス・コンシューマーにします。serviceは、インタフェースを実装したクラス、またはusesディレクティブで指定されたabstractクラスを拡張するクラスのオブジェクトです。

provides…with.provides…withモジュール・ディレクティブは、モジュールがサービス実装を提供することを指定し、モジュールをサービス・プロバイダーにします。provides の部分は、モジュールの uses ディレクティブにリストされているインタフェースまたは abstract クラスを指定し、 with の部分は、implementsインタフェースまたは extends abstract クラスのサービス・プロバイダ・クラスの名前を指定します。

open, opens, and opens…to.Java 9以前では、リフレクションを使用して、パッケージ内のすべてのタイプと、この機能を許可するかどうかに関係なく、タイプのすべてのメンバー( private メンバーも含む)について学習できました。したがって、真にカプセル化されているとは言えませんでした。

ジュールシステムの主な目的は、強力なカプセル化にあります。デフォルトでは、モジュールのタイプが、パブリックタイプかつそのパッケージをエクスポートしない限り、他のモジュールからアクセスできません。公開するパッケージのみを公開します。Java 9において、これはリフレクションにも適用されます。

パッケージへの実行時のみアクセスを許可します。フォームのオープン・モジュール・ディレクティブ

opens package

特定のパッケージpublicタイプ(およびそのネストされたpublicおよびprotectedタイプ)が実行時にのみ他のモジュールのコードにアクセスできることを示します。また、指定したパッケージ内のすべてのタイプ(およびすべてのタイプのメンバー)には、リフレクションを介してアクセスできます。

特定のモジュールによるパッケージへの実行時のみアクセスを許可します。フォームのopens...toモジュール・ディレクティブ

opens package to comma-separated-list-of-modules

特定のパッケージpublicタイプ(およびそのネストされたpublicおよびprotectedタイプ)が実行時にのみリストされているモジュールのコードにアクセスできることを示します。指定したパッケージのすべてのタイプ(およびすべてのタイプのメンバー)は、指定されたモジュールのコードに対するリフレクションを介してアクセスできます。

モジュール内のすべてのパッケージへのアクセスを実行時のみ許可します。もし、与えられたモジュール内のすべてのパッケージが、実行時に、他のすべてのモジュールにリフレクションを介してアクセス可能であるべきなら、次のように、モジュール全体をopenすることができます。

open module modulename {
// module directives
}

リフレクションのデフォルト

デフォルトでは、パッケージへの実行時リフレクト・アクセス権を持つモジュールは、パッケージのpublicタイプ(およびそのネストされたpublicおよびprotectedタイプ)を表示できます。しかし、他のモジュールのコードは、以前のJavaバージョンと同様に、setAccessibleによって、privateメンバーを含む、公開されたパッケージ内のすべてのタイプとそれらのタイプ内のすべてのメンバーにアクセスすることが可能です。

setAccessibleおよびリフレクションの詳細は、オラクルのドキュメントを参照してください。


Paul Deitel氏は、Deitel & AssociatesのCEO兼最高技術責任者で、MITを卒業し、35年にわたるコンピュータ業界での経験を有しています。Javaチャンピオンで、22年以上Javaでプログラミングを行っています。Deitel氏と共著者のHarvey M博士Deitel氏は、世界で最も売れているプログラミング言語に関する執筆者です。同氏は、は、Java、Android、iOS、C#、C++、C、インターネット・プログラミング・コースを、産業界、政府、学術界の顧客に国際的に提供してきました。


注:この記事はJava Magazine 2017年9月/10月号から抜粋したものです。

お問い合わせ

エキスパートがお手伝いいたします