Java パッケージ
出典:
Usemynotes この投稿は、Java のパッケージをより深く理解し、その目的と実装方法を理解するのに役立ちます。
Javaのパッケージとは何ですか
Java のパッケージは、クラス、インターフェイス、サブパッケージのグループをグループ化する方法です。パッケージは、関連するクラス、インターフェイス、列挙などのグループを作成するために使用されます。
サブパッケージは、別のパッケージ内にあるパッケージです。これらはデフォルトではインポートされませんが、必要に応じて手動でインポートできます。アクセス仕様はサブパッケージの個々のメンバーには提供されず、別個のパッケージとして扱われます。
Java のいくつかのタイプのパッケージ:
- java.lang - デフォルトで Java にバンドルされています。
- java.io - 入出力に関連するクラス、メソッド、その他の要素が含まれています。
なぜパッケージが必要なのでしょうか?
- 名前の競合を避けるため。
- 制御されたアクセスを提供するため。
- データのカプセル化を実現します。
Javaでパッケージを作成するにはどうすればよいですか?
Computerというパッケージを作成しましょう。通常、パッケージ名は小文字で書かれます。これは、クラス名との名前の競合を避けるためにのみ行われます。
また、 Pluggableというインターフェイスも作成します。これは、
コンピュータパッケージ内に配置されます。
package computer;
interface Pluggable {
public void pluggedIn();
public void pluggedOut();
}
次に、上記のインターフェイスを実装する
PenDrive というクラスを作成します。
package computer;
public class PenDrive implements Pluggable {
int storage = 64;
public void pluggedIn () {
System.out.println("Pen Drive is connected");
}
public void pluggedOut () {
System.out.println("Pen Drive is removed");
}
public int storage() {
return storage;
}
public static void main(String args[]) {
PenDrive p = new PenDrive ();
p.pluggedIn();
System.out.println("Pen Drive Storage: " + p.storage());
p.pluggedOut();
}
}
Javaでパッケージ階層を作成するにはどうすればよいですか?
階層を形成する場合、Java のパッケージには逆の順序で名前が付けられます。これにより、それらはディレクトリまたはフォルダーに非常に似たものになります。1 つのフォルダーに 1 つ以上のサブフォルダーを含めることができるパーソナル コンピューターと同様に、Java のパッケージにも同じことが当てはまります。
Asia.India.Kolkataという名前のパッケージを見てみましょう。これらはすべて既存のフォルダーですが、地理を考慮すると、カルカッタがインドにあり、インドがアジアにあることは明らかです。階層の主な目的は、クラスを見つけやすくすることです。
Java のパッケージの種類
組み込みパッケージ
組み込みパッケージは、Java API の一部である多数の組み込みクラスで構成されるパッケージです。これらのパッケージには次のものが含まれます。
- java.util - このパッケージには、リンク リスト、セットなどのデータ構造を実装するために使用される有限数のユーティリティ クラスが含まれています。また、日付と時刻の操作などもサポートしています。
- java.net - ネットワーク操作に使用されるクラスが含まれています。
ユーザー定義パッケージ
ユーザーが定義したパッケージをユーザーパッケージと呼びます。ユーザーは手動でパッケージを作成し、その中に必要な数のクラスを含めることができます。
別のパッケージからパッケージにアクセスするにはどうすればよいですか?
次の 3 つの簡単な方法で、別のパッケージからパッケージにアクセスできます。
- import ステートメントでのアスタリスクの使用
アスタリスク (
* ) 文字は、Java では「すべてのもの」を表すために使用されます。これを使用すると、パッケージのサブパッケージ内にあるすべてのものをインポートできます。
例: tools という名前のパッケージを考えてみましょう。このパッケージ内にあるものをすべてインポートしたい場合は、次のような import ステートメントを使用する必要があります。
import tools.*;
- import package.ClassName を使用します。
パッケージ内でクラス名を記述することは、必要なクラスのみをプログラムにインポートし、不必要なクラスのインポートを回避する効果的な方法です。
例: Books という名前のパッケージについて考えてみましょう。
そこから特定のクラスまたはインターフェイスのみをインポートしたい場合 (ここではPagesクラスを見ていきます)、以下を使用してそれのみをインポートできます。
import book.Pages;
完全修飾名を使用して、Java パッケージまたはそのクラスを直接使用する方法があります。この方法では、パッケージをインポートする必要がなく、プログラム内で直接使用できます。
例:
java.awt.List aSimpleList = new java.awt.List();
Java のデフォルトのバッチ サイズ
デフォルトでは、Java は
java.langパッケージをインポートします。
String、
Integerなど、単純な Java プログラムで一般的に使用されるクラスが多数あります。最も重要なクラスの 1 つは
Objectクラスで、これも
java.langパッケージに含まれています。このパッケージのサイズは、そのコンポーネント (インターフェイス 8 個、クラス 37 個、列挙型 3 個、例外 27 個、エラー タイプ 23 個、および注釈タイプ 5 個) に基づいています。
初心者向けのスレッドセーフな Java メソッド
出典:
Medium この記事を使用すると、Java のスレッド セーフなメソッドの動作について学ぶことができます。 多くのジュニア/ミドル Java 開発者が、スレッドセーフなメソッドが実際のプロジェクトでどのように機能するべきかを誤解していることがわかりました。また、通常はマルチスレッド環境で作業するため、それらを正しく使用することが非常に重要です。スレッドセーフなメソッドは、互いのデータ状態に影響を与えることなく、複数のスレッドから同時に呼び出すことができるメソッドです。この概念の理解が不十分だと、発見して修正することが困難なバグが発生します。このような間違いを避けるために、例を見てみましょう。
例 #1:
public static int countLetters(String input) {
int counter = 0;
for (Character c : input.toCharArray()) {
if (Character.isAlphabetic(c)) {
counter++;
}
}
return counter;
}
- countLettersメソッドは静的で、 int値を返し、文字列パラメータを入力として受け入れます。
- メソッド内でプリミティブ変数カウンターが作成され、ループは入力文字列の文字をループし、文字が出現するたびに変数カウンターをインクリメントします。
このメソッドはスレッドセーフですか? 多くの開発者は「ノー」と答えます。この場合、スレッドセーフではないインクリメント操作があるからです。それを理解しましょう。Java メモリ モデルにはスタックとヒープがあります。各スレッドには独自のスタックがあり、すべてのスレッドが同じヒープを共有します。この点において、スタック データは常にスレッド セーフですが、ヒープ データはそうではありません。スタックにはプリミティブとオブジェクト参照が格納されます。ヒープにはオブジェクト自体が含まれます。これは、このコード例では、各スレッドが
独自の変数カウンターをスタックに保存し、他のスレッドのデータに影響を与えないため、メソッドが
スレッド セーフであることを意味します。
入力String値もオブジェクトですが、Stringおよびプリミティブ ラッパー ( Integer、Long、Double、Booleanなど) は不変であるため、スレッド セーフであることに注意してください。
例2:
public static int countLetters2(String input) {
List<Character> listCounter = new ArrayList<>();
for (Character c : input.toCharArray()) {
if (Character.isAlphabetic(c)) {
listCounter.add(c);
}
}
return listCounter.size();
}
このコードは最初の例と同じロジックを使用しましたが、プリミティブ
int変数の代わりにListオブジェクトを使用しました。
前の部分から、Java のオブジェクトはヒープに格納され、 List はオブジェクトであることがわかりました。また、スタックがオブジェクトへの参照をヒープに保存していることもわかります。例 #2 では、各スレッドが新しい
ArrayListオブジェクトを作成し、
listCounter変数がそのオブジェクトへの参照をヒープに保存するため、他のスレッドはそのオブジェクトを変更できません。
List<Character> listCounter = new ArrayList<>();
これは、このメソッドがスレッドセーフであることを意味します。
例 #3:
public class CounterUtil {
List<Character> listCounter = new ArrayList<>();
public int countLetters3(String input) {
for (Character c : input.toCharArray()) {
if (Character.isAlphabetic(c)) {
listCounter.add(c);
}
}
return listCounter.size();
}
}
この例では、グローバル変数
listCounterを 持つシングルトン (これは重要です) クラス
CounterUtilがあります。この変数はシングルトン インスタンスと同時に作成されます。
複数のスレッドがcountChars3メソッドを呼び出す場合、それらはすべて同じグローバル変数
listCounterを使用し、ヒープ上の同じオブジェクトへの参照を保存し、そこにあるスレッドは相互に影響を与えます。したがって、このメソッドはスレッドセーフではないと結論付けることができます。また、
List<Character> listCounter をプリミティブ変数
int counterに変更したとしても、すべてのスレッドが同じプリミティブ変数を使用するため、スレッド セーフではありません。
最後の例:
public static int countLetters4(List<Character> inputList) {
List<Character> listCounter = new ArrayList<>();
for (Character c : inputList) {
if (Character.isAlphabetic(c)) {
listCounter.add(c);
}
}
return listCounter.size();
}
countLetters4 メソッドは、
Stringパラメータの代わりに文字のリストを受け入れます。ここでは、このメソッドがスレッドセーフであることを
保証できません。なぜ?開発者がこのメソッドをどのように使用するかわからないからです。
外部の別のスレッドがcounterLetters4メソッドと同時に
inputListのデータを変更すると、最終結果に影響を与える可能性があります。
結論
ここでは 4 つの例しか見ていませんし、Java プロジェクトのスレッド セーフのすべての側面をカバーしているわけではありませんが、始めるには適しています。次回コード内でメソッドを見つけたら、「このメソッドはスレッド安全ですか?」と自問してください。そしてすぐに、あなたはその答えを明確に理解するでしょう。
GO TO FULL VERSION