序#
《On Java》は読む価値のある良書です。Java の基礎はあるものの、この本を読むと基礎部分でも新たな理解を得ることができます。著者は《Thinking in Java》の著者でもあり、使用法を説明するだけでなく、その知識の由来やなぜそれを使うのか、その価値はどこに現れるのか、それが一体何なのかを普及することが得意です。一度読んだだけでは忘れてしまうことを望まないので、各章ごとに感想を書き、後でこの記事を読み直すこともできます。何か中二病の計画を忘れてしまったのではないでしょうか?
第 1 章 オブジェクトとは何か#
この章では、Java の核心的な特徴を読者にまとめています。Java の基礎を持っていない読者は、Java の概要を理解することができます。基礎を持っている読者は、さらに深い理解を得ることができ、著者の独自の見解を読むことができます。
チューリング公式のガイドでは、「理解するだけで十分」とされています。個人的には、この章の主な知識ポイントは以下のとおりです:
抽象の歴程#
すべてのプログラミング言語は抽象の一種です。実際、解決できる問題の複雑さは、抽象の種類と品質に直接依存します。
アセンブリ言語は、機械語の抽象です。手続き型プログラミング言語である C 言語は、アセンブリ言語の抽象です。手続き型プログラミング時代には、プログラマは自分自身をコンピュータの視点に置き、問題を解決する方法を考える必要がありました。このような抽象タイプでは、問題自体の構造ではなく、コンピュータの構造を頻繁に考慮する必要があります。
オブジェクト指向プログラミングの登場により、以前の手続き型プログラミングの問題点がうまく解決されました。この本によれば、以前のプログラマはマシンモデル(ソリューションスペース、つまりコンピュータ)と実際の問題を解決するための問題モデル(問題が実際に存在するスペース、つまりビジネス)の関連付けを確立する必要がありました。しかし、手続き型プログラミングによって確立された関連付けの抽象度は高くなく、プログラマはまだコンピュータを考慮する必要があり、この関連付けを維持するために労力を費やす必要がありました。一方、オブジェクト指向プログラミングでは、マシンモデルの要素と問題モデルの要素をオブジェクトというキャリアを介して 1 対 1 にマッピングし、プログラマはオブジェクト指向思考の強力な抽象能力を使って問題モデルを直接マシンモデルに記述し、関連付けの問題を解決することができます。あなたが読んでいるのは、マシンモデルが提供するソリューションであり、ビジネスモデルの実際のビジネスを記述しています。明らかに、この抽象タイプはより一般的で効率的です。
オブジェクト指向プログラミングの目的#
オブジェクト指向プログラミングの目的は、問題を解決するためにオブジェクトが提供する特定のサービスを作成または使用することです。プログラムもユーザーにサービスを提供し、そのためには特定のオブジェクトのサービスを使用する必要があります。
隠蔽の実現#
良いクラスを設計するためのテクニックの 1 つは、詳細を隠蔽することです。使用者に細部を露出しないでください。なぜなら、使用者がクラスをどのように使用するかわからないからです。これにより、クラスの変更が将来的に問題を引き起こす可能性がなくなります。したがって、私たちはサービスだけを提供し、他のすべての不要な情報を隠蔽します。使用者は私たちのサービスが更新されても無効にならないことを信頼し、私たちは自由に修正やリファクタリングを行うことができます。
再利用、継承、多態性#
ここでは、Java の重要な特徴について説明しています。継承と多態性の目的は、できるだけコードを再利用することです。たとえば、既存のクラスと非常に似ているクラスを作成する必要がある場合、コードを再度書く必要はありません。代わりに、継承を使用するだけです。ただし、継承を使用する場合は注意が必要です。継承の原則は、「置き換えの原則」を満たすことです。つまり、「A は B である」という関係を満たす必要があります。継承を使用する必要があるかどうかを判断するための明確な基準は、「上位クラスにキャストする必要がありますか?」です。
実際のコーディングでは、メソッドが具体的なクラスに依存しないようにする必要があります。メソッドは基本クラスを受け取るだけで十分であり、渡される具体的なサブクラスについては気にする必要はありません。冗長な条件コードを書く必要がなくなり、実行時に具体的なサブクラスのメソッドを実行するように処理を委任することができます。これが多態性です。
第 2 章 Java のインストールと本書のサンプル#
注目すべきは、この章では環境変数や
classpath
などについての説明はありません。インストール手順は、Win
プラットフォームのChocolateyやMac OS
のHomeBrewなどのパッケージ管理ツールを使用して解決されています。これらのツールは環境変数を自動的に処理します。もちろん、環境変数を設定する目的は、コンソールで Java プログラムをコンパイルおよび実行するための便宜ですが、現在の IDE やスクリプトはますますスマートになっており、環境変数を自動的に設定できるようになっています。
第 3 章 オブジェクトはどこにでもある#
言わずと知れた「万物はオブジェクトである」。この章では、Java で最も重要なオブジェクトと、Java プログラムの実行に関与するさまざまな「勢力」について説明しています。チューリングガイドのアドバイスは「理解するだけで十分」とされているため、この章では以下のポイントに重点を置いてまとめます:
オブジェクトと参照#
このセクションでは、Java では実際にオブジェクトと対話していないという事実について触れています。私たちは、プログラミング言語がデータを処理するために最終的にはメモリを使用することを知っています。では、メモリを安全に処理する方法は何でしょうか?メモリを直接操作するのでしょうか?それとも間接的な方法を使用するのでしょうか?Java は、理想的な答えを提供しています:参照を使用します。参照は、オブジェクトを制御し、オブジェクトの動作を呼び出し、オブジェクトの状態を変更するためのものです。
データはどこに保存されているのか?#
このセクションでは、Java のデータ保存方法について説明しています:
- 1. レジスタ。コンピュータアーキテクチャの授業で学んだように、レジスタは最も高速なデータ保存方法です。なぜなら、それが中央処理装置、つまりCPUに直接保存されているからです。ただし、レジスタは貴重なリソースなので、Java ではレジスタの割り当てを手動で制御することは許されていません。
- 2. スタック。RAM 内にあり、プロセッサはスタックポインタを使用してデータを操作します。ただし、データ構造の知識に基づくと、スタックは追加と削除の面で柔軟性に欠けるため、一部のデータ(たとえばオブジェクト参照)はスタックに保存され、オブジェクト自体はそうではありません。
- 3. ヒープ。RAM 内にあり、ヒープはすべての Java オブジェクトを格納するための汎用メモリプールです。コンパイラはヒープ上のオブジェクトのライフサイクルについては関知しません。割り当てとクリーンアップの方法がありますし、時代の進歩に伴い、Java のヒープメモリ割り当てメカニズムは非常に効率的になりました。
- 4. 定数プール。定数はプログラムコードまたは ROM に直接保存されます。たとえば、すべての文字列と文字列定数は文字列リソースプールに保存されます。
- 5.RAM 以外の保存方法。通常、メモリ以外のデータを指します。たとえば、シリアライズオブジェクトは、他のマシンに送信できるオブジェクトです。また、永続オブジェクトは、ディスクに保存されるオブジェクトです。これらのデータ保存タイプは、オブジェクトを他のメディアに保存し、必要に応じてオブジェクトに変換することができます。最も典型的な例は、データベースの保存です。
第 4 章 & 第 5 章 演算子 & 制御フロー#
これらの 2 つの章では、Java の演算子と制御フローの構文について詳しく説明しています。チューリングガイドのアドバイスは「両方をマスターし、困難はありません」とされています。C 言語と基本的に同じですので、興味深い点だけを記録します。
オブジェクトの代入には注意が必要#
前述したように、実際にはオブジェクト自体を操作しているわけではありません。オブジェクトの参照を操作しているだけです。したがって、オブジェクトの代入を行うと、参照が別の参照にコピーされ、2 つの参照が同じオブジェクトを指すことになります。代入された参照に対応するオブジェクトは参照されなくなります。オブジェクトの代入には注意が必要であり、予期しない結果が生じる可能性があります。
Java == C++ -- --#
これは Java の創始者であるジェームズ・ゴスリンの見解であり、彼は Java は C++ から不要で難しい要素を取り除いた、よりシンプルな言語であると考えています。もちろん、完全な減算ではありません 2333
== と!=#
異なる方法で作成された同じ内容のラッパークラスは、メモリ上の異なる場所に保存されることがあります。しかし、演算子==
と!=
はオブジェクトの参照を比較するため、オブジェクトを比較する場合はequals()
を使用することが最善です。
boolean-exp ? value0 :value1
三項演算子#
これは、2 つの値から変数に値を割り当てる場合に使用されます。if-else
と同じ結果をより短く書くために使用されます。
for-in
#
float[] f = new float[10];
for(int i=0; i<10; i++)
f[i] = rand.nextFloat();
for(float x : f)
System.out.println(x);
残念ながら、for-in
はイテレーションにのみ使用できます。f の要素を変更することはできません。
for(;;)
#
コンパイラは
while(true)
とfor(;;)
を同等に扱い、Java のソースコードでもほぼ同じように使用されます。
Math.random()
の範囲#
実際の例は文字列を使用するswitch
です。Math.random()
の厳密な範囲は[0,1)
です。