Javaをゼロから学ぶ

それで、あなたはJavaでプログラムしたいですか?それは素晴らしいことです、そしてあなたは正しい場所に来ました。Javaの101シリーズは、基本から始まり、あなたが生産性のJava開発者になるために知っておく必要があるすべてのコアな概念をカバーし、Javaプログラミングへのセルフガイド紹介しています。このシリーズは技術的なものであり、概念を理解するのに役立つコード例がたくさんあります。Javaだけでなく、プログラミングの経験があることを前提としています。

この最初の記事では、Javaプラットフォームを紹介し、Java SE、Java EE、およびJavaMEの3つのエディションの違いについて説明します。また、JavaアプリケーションのデプロイにおけるJava仮想マシン(JVM)の役割についても学習します。Javaプログラムを開発して実行できるように、システムにJava Development Kit(JDK)をセットアップするのを手伝って、典型的なJavaアプリケーションのアーキテクチャーを始めましょう。最後に、単純なJavaアプリをコンパイルして実行する方法を学習します。

Java12および新しいJShell用に更新

このシリーズはJava12用に更新されており、Javajshellを学習してJavaコードのプロトタイピングを行うためのインタラクティブなツールである新しいものの簡単な紹介が含まれています。

ダウンロードコードを取得するこのチュートリアルのサンプルアプリケーションのソースコードをダウンロードします。JavaWorld用にJeffFriesenによって作成されました。

Javaとは何ですか?

Javaは、CやC ++によく似た汎用のオブジェクト指向言語と考えることができますが、使いやすく、より堅牢なプログラムを作成できます。残念ながら、この定義ではJavaについての洞察はあまり得られません。2000年、Sun Microsystems(Javaプラットフォームの創始者)はJavaを次のように説明しました。 

Javaは、シンプルで、オブジェクト指向で、ネットワークに精通し、解釈され、堅牢で、安全で、アーキテクチャに中立で、移植性があり、高性能で、マルチスレッドで動的なコンピュータ言語です。

これらの定義を個別に検討してみましょう。

Javaは単純な言語です。 Javaは当初、CおよびC ++をモデルにしていましたが、混乱を招く可能性のある機能はいくつかありませんでした。ポインター、複数の実装の継承、および演算子のオーバーロードは、Javaの一部ではないいくつかのC / C ++機能です。 C / C ++で義務付けられていないが、Javaに不可欠な機能は、オブジェクトと配列を自動的に再利用するガベージコレクション機能です。

Javaはオブジェクト指向言語です。 Javaのオブジェクト指向の焦点により、開発者は、言語の制約を満たすために問題を操作することを強制するのではなく、問題を解決するためにJavaを適応させることに取り組むことができます。これは、Cのような構造化言語とは異なります。例として、Javaでは普通預金口座オブジェクトに焦点を当てることができますが、Cでは、普通預金口座の状態(残高など)と動作(預金や引き出しなど)について別々に考える必要があります。

Javaはネットワークに精通した言語です。 Javaの広範なネットワークライブラリにより、HTTP(ハイパーテキスト転送プロトコル)やFTP(ファイル転送プロトコル)などの伝送制御プロトコル/インターネットプロトコル(TCP / IP)ネットワークプロトコルに簡単に対応でき、ネットワーク接続を確立するタスクが簡素化されます。さらに、Javaプログラムは、URL(Uniform Resource Locator)を介して、TCP / IPネットワークを介してオブジェクトにアクセスできます。これは、ローカルファイルシステムからオブジェクトにアクセスする場合と同じように簡単です。

Javaはインタープリター言語です。実行時に、Javaプログラムは、仮想マシン(仮想プラットフォームのソフトウェア表現)および関連する実行環境を介して、基盤となるプラットフォーム(WindowsやLinuxなど)で間接的に実行されます。仮想マシンは、Javaプログラムのバイトコード(命令および関連データ)を、解釈を通じてプラットフォーム固有の命令に変換します。解釈とは、バイトコード命令の意味を理解し、実行する同等の「既定の」プラットフォーム固有の命令を選択することです。次に、仮想マシンはそれらのプラットフォーム固有の命令を実行します。

実行時に利用できるコンパイル時の情報が増えるため、解釈により、障害のあるJavaプログラムのデバッグが容易になります。解釈により、Javaプログラムの各部分間のリンクステップを実行時まで遅らせることも可能になり、開発がスピードアップします。

Javaは堅牢な言語です。Javaプログラムは、Blu-rayプレーヤーから車両ナビゲーションまたは航空管制システムに至るまで、消費者向けアプリケーションとミッションクリティカルなアプリケーションの両方で使用されるため、信頼性が高い必要があります。Javaを堅牢にするのに役立つ言語機能には、宣言、コンパイル時と実行時の重複型チェック(バージョンの不一致の問題を防ぐため)、自動境界チェックを備えた真の配列、およびポインターの省略が含まれます。(Java言語タイプ、リテラル、変数などの使用を開始するには、「基本的なJava言語機能」を参照してください。)

Javaの堅牢性のもう1つの側面は、0が偽で、ゼロ以外の値が真である整数式ではなく、ブール式によってループを制御する必要があることです。たとえば、Javaはwhile (x) x++;、ループが期待どおりに終了しない可能性があるなどの理由で、Cスタイルのループを許可しません。代わりに、次のようなブール式を明示的に指定する必要がありますwhile (x != 10) x++;(つまり、ループxは10に等しくなるまで実行されます)。

Javaは安全な言語です。Javaプログラムは、ネットワーク化された/分散された環境で使用されます。Javaプログラムはネットワークのさまざまなプラットフォームに移行して実行できるため、ウイルスの拡散、クレジットカード情報の盗用、またはその他の悪意のある行為を実行する可能性のある悪意のあるコードからこれらのプラットフォームを保護することが重要です。堅牢性をサポートするJava言語機能(ポインターの省略など)は、Javaサンドボックスセキュリティモデルや公開鍵暗号化などのセキュリティ機能と連携します。これらの機能を組み合わせることで、ウイルスやその他の危険なコードが疑うことを知らないプラットフォームで大混乱を引き起こすのを防ぎます。

理論的には、Javaは安全です。実際には、さまざまなセキュリティの脆弱性が検出され、悪用されています。その結果、SunMicrosystemsとOracleは現在もセキュリティアップデートをリリースし続けています。

Javaはアーキテクチャに依存しない言語です。ネットワークは、さまざまなマイクロプロセッサとオペレーティングシステムに基づいたさまざまなアーキテクチャのプラットフォームを接続します。 Javaがプラットフォーム固有の命令を生成し、これらの命令をネットワークの一部であるすべての種類のプラットフォームに「理解」させることは期待できません。代わりに、Javaは、各プラットフォームが(JVMの実装を介して)解釈しやすい、プラットフォームに依存しないバイトコード命令を生成します。

Javaは移植可能な言語です。アーキテクチャの中立性は移植性に貢献します。ただし、Javaの移植性には、プラットフォームに依存しないバイトコード命令以上のものがあります。整数型のサイズは変化してはならないことに注意してください。たとえば、32ビット整数型は、32ビット整数が処理される場所(たとえば、16ビットレジスタを備えたプラットフォーム、32ビットレジスタを備えたプラットフォーム、またはプラットフォーム)に関係なく、常に署名され、32ビットを占める必要があります。 64ビットレジスタを使用)。 Javaのライブラリも移植性に貢献しています。必要に応じて、Javaコードをプラットフォーム固有の機能に可能な限り移植可能な方法で接続するタイプを提供します。

Javaは高性能言語です。解釈により、通常は十分すぎるレベルのパフォーマンスが得られます。非常に高性能なアプリケーションシナリオの場合、Javaはジャストインタイムコンパイルを使用します。これは、解釈されたバイトコード命令シーケンスを分析し、頻繁に解釈される命令シーケンスをプラットフォーム固有の命令にコンパイルします。その後、これらのバイトコード命令シーケンスを解釈しようとすると、同等のプラットフォーム固有の命令が実行され、パフォーマンスが向上します。

Javaはマルチスレッド言語です。一度に複数のタスクを実行する必要があるプログラムのパフォーマンスを向上させるために、Javaはスレッド実行の概念をサポートしています。たとえば、ネットワーク接続からの入力を待機している間にグラフィカルユーザーインターフェイス(GUI)を管理するプログラムは、両方のタスクにデフォルトのGUIスレッドを使用する代わりに、別のスレッドを使用して待機を実行します。これにより、GUIの応答性が維持されます。 Javaの同期プリミティブを使用すると、スレッドはデータを破損することなく、スレッド間でデータを安全に通信できます。 (Java 101シリーズの他の場所で説明されているJavaのスレッドプログラミングを参照してください。)

Javaは動的言語です。プログラムコードとライブラリ間の相互接続は実行時に動的に行われるため、それらを明示的にリンクする必要はありません。その結果、プログラムまたはそのライブラリの1つが進化した場合(たとえば、バグ修正やパフォーマンスの向上のため)、開発者は更新されたプログラムまたはライブラリを配布するだけで済みます。動的な動作により、バージョン変更が発生したときに配布するコードが少なくなりますが、この配布ポリシーによってバージョンの競合が発生する可能性もあります。たとえば、開発者はライブラリからクラスタイプを削除したり、名前を変更したりします。会社が更新されたライブラリを配布すると、クラスタイプに依存する既存のプログラムは失敗します。この問題を大幅に減らすために、Javaはインターフェースタイプをサポートしています、これは2者間の契約のようなものです。(Java 101シリーズの他の場所で説明されているインターフェース、タイプ、およびその他のオブジェクト指向言語機能を参照してください。)

この定義を解凍すると、Javaについて多くのことがわかります。最も重要なことは、Javaが言語であると同時にプラットフォームでもあることを明らかにすることです。このチュートリアルの後半で、Javaプラットフォームコンポーネント(つまり、Java仮想マシンとJava実行環境)について詳しく学習します。

Javaの3つのエディション:Java SE、Java EE、およびJava ME

SunMicrosystemsは1995年5月にJava1.0ソフトウェア開発キット(JDK)をリリースしました。最初のJDKはデスクトップアプリケーションとアプリレットの開発に使用され、その後Javaはエンタープライズサーバーとモバイルデバイスのプログラミングを含むように進化しました。必要なすべてのライブラリを単一のJDKに格納すると、JDKが大きくなりすぎて配布できなくなります。特に、1990年代の配布は、小さいサイズのCDと遅いネットワーク速度によって制限されていたためです。ほとんどの開発者は最後のすべてのAPIを必要としなかったため(デスクトップアプリケーション開発者はエンタープライズJava APIにアクセスする必要はほとんどありません)、SunはJavaを3つの主要なエディションに分解しました。これらは最終的にJavaSE、Java EE、およびJavaMEとして知られるようになりました。

  • Java Platform、Standard Edition(Java SE)は、クライアント側アプリケーション(デスクトップで実行)およびアプレット(Webブラウザーで実行)を開発するためのJavaプラットフォームです。セキュリティ上の理由から、アプレットは正式にサポートされなくなったことに注意してください。
  • Java Platform、Enterprise Edition(Java EE)は、Java SE上に構築されたJavaプラットフォームであり、エンタープライズ指向のサーバーアプリケーションの開発にのみ使用されます。サーバー側アプリケーションには、Javaサーブレットが含まれます。これは、アプレットに似ていますが、クライアントではなくサーバー上で実行されるJavaプログラムです。サーブレットは、JavaサーブレットAPIに準拠しています。
  • Java Platform、Micro Edition(Java ME)、JavaSEの上に構築されています。これは、モバイル情報デバイスで実行されるJavaプログラムであるMIDletと、組み込みデバイスで実行されるJavaプログラムであるXletを開発するためのJavaプラットフォームです。

Java SEは、Javaの基盤プラットフォームであり、Java101シリーズの焦点です。コード例は、執筆時点でのJavaの最新バージョンであるJava12に基づいています。

JavaプラットフォームとJVM

Javaは、コンパイルされたJavaコードを実行するためのプログラミング言語であると同時にプラットフォームでもあります。このプラットフォームは主にJVMで構成されていますが、基盤となる(ネイティブ)プラットフォームでのJVMの実行をサポートする実行環境も含まれています。JVMには、Javaコードをロード、検証、および実行するためのいくつかのコンポーネントが含まれています。図1は、このプラットフォームでJavaプログラムがどのように実行されるかを示しています。 

ジェフ・フリーゼン

図の上部には一連のプログラムクラスファイルがあり、そのうちの1つがメインクラスファイルとして示されています。Javaプログラムは、少なくともメインクラスファイルで構成されます。メインクラスファイルは、ロード、検証、および実行される最初のクラスファイルです。

JVMは、クラスのロードをクラスローダーコンポーネントに委任します。クラスローダーは、ファイルシステム、ネットワーク、アーカイブファイルなどのさまざまなソースからクラスファイルをロードします。これらは、JVMをクラスのロードの複雑さから隔離します。

ロードされたクラスファイルはメモリに保存され、Classクラスから作成されたオブジェクトとして表されます。ロードされると、バイトコードベリファイアはさまざまなバイトコード命令を検証して、それらが有効であり、セキュリティを危険にさらさないことを確認します。

クラスファイルのバイトコードが有効でない場合、JVMは終了します。それ以外の場合、そのインタプリタコンポーネントは、一度に1命令ずつバイトコードを解釈します。解釈はバイトコード命令を識別し、同等のネイティブ命令を実行します。

一部のバイトコード命令シーケンスは、他のシーケンスよりも頻繁に実行されます。インタプリタがこの状況を検出すると、JVMのジャストインタイム(JIT)コンパイラは、バイトコードシーケンスをネイティブコードにコンパイルして、実行を高速化します。

実行中に、インタプリタは通常、別のクラスファイルのバイトコード(プログラムまたはライブラリに属する​​)を実行する要求に遭遇します。これが発生すると、クラスローダーはクラスファイルをロードし、バイトコードベリファイアはロードされたクラスファイルのバイトコードを実行前に検証します。また、実行中に、バイトコード命令は、JVMがファイルを開く、画面に何かを表示する、音を出す、またはネイティブプラットフォームとの連携を必要とする別のタスクを実行するように要求する場合があります。JVMは、Java Native Interface(JNI)ブリッジ・テクノロジーを使用して応答し、ネイティブ・プラットフォームと対話してタスクを実行します。