
Javaのインスタンスとは?Javaのインスタンス生成方法や注意点を解説!
- SE
- Javaのインスタンスとはどのようなものなのでしょうか。
- PM
- インスタンスとは簡単に言えば「クラスをnewするとできるもの」です。
目次
Javaのインスタンスとは?
インスタンスとは何なのでしょうか。インスタンスとは簡単に言えば「クラスをnewするとできるもの」です。インスタンスはJavaに限らず、C#などの他のオブジェクト指向言語でも共通する概念ですが、最初のうちは使い方を覚えるだけで問題はありません。
以下のクラスを例に説明をしましょう。
class TestClass {
public int value;
static int s_value;
public void dispValue() {
System.out.println(value);
}
public static void dispValue_s() {
System.out.println(s_value);
}
};
静的と動的
上のTestClassは以下のように利用できます。
TestClass.s_value = 3;
TestClass.dispValue_s();
実行すると「3」と表示されます。TestClass内のs_valueやdispValue_s()にはstaticというキーワードが付いていますが、これを付けると「静的」になります。staticがないvalueやdispValue()は「動的」と言います。
動的なフィールドやメソッドは普通には呼び出せない
動的なvalueやdispValue()は以下のように呼び出そうとしてもエラーになってしまいます。
TestClass.value = 3;
TestClass.dispValue();
また以下のようにdispValue_s()内でvalueを呼び出そうとしても、やはりエラーになります。
public static void dispValue_s() {
System.out.println(value); // s_valueでないとエラー
}
動的なフィールドやメソッドは直接呼び出せません。どうすれば良いのでしょうか。
動的なフィールドやメソッドはインスタンスとして呼び出す
動的なフィールドやメソッドは、クラスをインスタンスにしないと呼び出せないのです。以下のようにnewをしてインスタンスを生成すれば、呼び出すことができます。
TestClass c = new TestClass();
c.value = 3;
c.dispValue();
newしてインスタンス化するというのは、コンピュータの仕組み的に言えば、動的なメモリを確保するということです。valueというフィールドはnewしないとメモリが確保されないので使えないのです。s_valueは静的で、これは最初からメモリが確保されているのですぐに使えます。
むやみにnewしない方が良いのも事実
「いちいちnewしてインスタンスを生成するより、全てstaticにすればよいのでは?」と思う人もいるかもしれません。それで作れればそれで問題ありません。静的の方がパフォーマンスが良いため、動作も速くなります。Javaでは「むやみにnewしない」が鉄則です。
「それではインスタンスは何の役に立つの?」と思いますよね。しかし動的なクラスは静的なクラスよりメリットがあるのです。インスタンスは以下のように同じクラスを元に複数生成し、データを別個に持つことが出来ます。
TestClass c1 = new TestClass();
c1.value = 3;
TestClass c2 = new TestClass();
c2.value = 4;
インスタンスには静的データにはないメリットがある
静的なstaticフィールドは最初からメモリが確保されているのでnewせずにすぐ使えますが、最初から使える数が決まっているという問題があります。例えば以下のようにTestClassのs_valueを、5つの要素を入れられる配列に拡張するとします。
static int[] s_value = { 0, 0, 0, 0, 0 };
しかし6つ以上の値を入れたい場合、Javaプログラムの実行中に配列を拡張して追加することはできません。newでいくらでも増やせるインスタンスであれば、メモリの余裕さえあれば実行中でも際限なく追加できるのです。
膨大なデータを扱う場合はインスタンスが必要
Javaを使用したWebシステムにはサーブレットがあります。Webサイトにはユーザーから多くのアクセスが発生し、マルチスレッドで動的に処理する必要があります。上限が見えない程の膨大な量のアクセスがあるため、newで作られるインスタンスを使う必要があるのです。
なおインスタンスは常にnewで生成されるわけではありません。例えばString型の文字列のインスタンスは以下のように宣言してもnewされています。
String str = “”あいうえお””;
ただし以下のようにnewすることもできます。
String str = new String(“”あいうえお””);
newが非推奨のクラスもある
int型の数値を中に保持するInteger型のインスタンスは、newを使用せず以下のように生成します。
Integer i = Integer.valueOf(100);
以下のようにnewで生成することもできますが、非推奨となっています。理由はvalueOfで生成すると内部でインスタンスが再利用されて、パフォーマンスが良くなるようにJavaが設計されているからです。この点からもnewはむやみに利用すべきでないことがわかります。
Integer i = new Integer(100); // 取り消し線が引かれてワーニングが出る
インスタンスの再利用の落とし穴
上で述べたように、Javaは内部処理的に同じインスタンスで済めば再利用するようにしています。これに関連して、String型文字列を扱う時に注意すべき点があります。以下のJavaサンプルを実行してみてください。
String str1 = “”abc””;
String str2 = “”abc””;
if (str1==str2) {
System.out.println(“”同じインスタンスです””);
}
if (str1.equals(str2)) {
System.out.println(“”同じ内容の文字列です””);
}
==の比較が一見矛盾した結果になる
上のJavaサンプルを実行すると以下のように表示されます。
同じインスタンスです
同じ内容の文字列です
これはおかしな結果です。equalsは文字列の内容比較なので正しいですが、==で比較した場合は同じインスタンスかどうかの比較になります。同じ内容でも別のインスタンスなのに、なぜ同じになってしまうのでしょうか。
実はJavaの内部処理では、内容が同じ文字列はメモリを節約するために1つのインスタンスにまとめられてしまっているのです。
インスタンスを==で比較するのは避ける
今度はstr1とstr2の宣言を以下のように修正して実行してみてください。
String str1 = “”abc””;
str1 += “”a””;
String str2 = “”abc””;
str2 += “”a””;
これで実行すると、「同じ内容の文字列です」のみ表示されます。str2を宣言する時に、str1がabcaになっていて、abcではないので別のインスタンスになったということです。
このようなことがあるので、==で同じインスタンスかどうかを判定するのは避けた方が良いと言えます。
インスタンス生成を抑止する方法
staticなフィールドとメソッドだけしかないため、インスタンスの生成が不要な場合クラスは、newを抑止することが可能です。
class TestClass {
private TestClass() { // コンストラクタ
}
static int s_value;
public static void dispValue_s() {
System.out.println(s_value);
}
};
このクラスをnewしようとするとエラーになります。コンストラクタがprivateであるため外部から呼び出せないのです。インスタンスを生成することはコンストラクタを呼び出すことと同義です。コンストラクタが無いクラスでも、実は見えないコンストラクタが存在しています。
- SE
- Javaのインスタンスについてよく理解できました。
- PM
- Javaのインスタンスは使い分けが必要です。しっかりと理解して使用しましょう。
Javaのインスタンス生成はオブジェクト指向の基本
Javaのインスタンスについて解説しましたが、ご理解頂けたでしょうか。
インスタンスを生成しない方がパフォーマンスの良いプログラムを作れるのですが、必要な時はインスタンスを効果的に利用するのがオブジェクト指向らしいプログラミングと言えます。