web-dev-qa-db-ja.com

なぜオブジェクトを変数に保存せずにインスタンス化して初期化するのですか?

タイトルの表現が間違っていると申し訳ありませんが、JavaFXで例を提供するのが最も簡単です。

primaryStage.setScene(new Scene(grid, 300, 275));

今私が理解していることから、このコードはSceneオブジェクトをインスタンス化して初期化していますが、宣言していません。これが事実である場合、それはメモリに格納されていないと言うのは正しいでしょうか?なぜこれをしたいのでしょうか?このSceneオブジェクトをsetSceneメソッドに正常に渡すことができても、Sceneオブジェクトを保存できないのはなぜですか。

4
Pat Nak

これが事実である場合、それはメモリに格納されていないと言うのは正しいでしょうか?

あんまり。 Sceneオブジェクトがインスタンス化されています 定義により はメモリが割り当てられていることを意味します。

なぜこれをしたいのでしょうか?

ser232967 が指摘したように、ソースコードを整理するのに便利な方法です。 1行が同じように読みやすいのに、なぜ5行のコードを記述(そして他の人に強制的に読み込む)のでしょうか。

このSceneオブジェクトをsetSceneメソッドに正常に渡すことができても、Sceneオブジェクトを保存できないのはなぜですか。

weはもはやそのSceneオブジェクトを必要としないからです。 setSceneメソッドはそれを使用しました(そしておそらくそれへの参照を保存しました)が、それは私たちの問題ではないので、それについて心配する必要はありません。

9
Dan Pichelman

これがそのシーンが使用される唯一の場所である場合、変数を宣言し、値を割り当てて、それを渡すことはあまり意味がありません。

同様に、次のことを行うことができます。

int x = 300;
int y = 275;
primaryStage.setScene(new Scene(grid, x, y));

例のように、1つのステートメントで合理的にカプセル化できる場合は、それを行う方が理にかなっています。上記のように使い捨て変数を宣言すると、コードが乱雑になる可能性があります。

5
Evan Trimboli

これが事実である場合、それはメモリに格納されていないと言うのは正しいでしょうか?

いいえ。オブジェクトはまだメモリに確実に保存されています。宣言がない場合でも、別のオブジェクト内からの参照を参照できます。これは、オブジェクトprimaryStageのセッターメソッド内でオブジェクトを初期化したためです。

それをまったく参照せずにインスタンス化して、次のように書いた場合:

new Scene(grid, 300, 275);

それはまだメモリに保存されますが、到達不可能であり、参照(参照)がないため、最終的にはガベージコレクションされる可能性が高くなります。

オブジェクトをインスタンス化すると、宣言があるかどうかに関係なく、heapメモリ空間に保存されます。ヒープメモリは、オブジェクトを格納するために割り当てられるメモリ領域です。 Stackメモリは、ローカル変数を格納するために割り当てられたメモリ内の領域です。

あなたの例では、Sceneセッターメソッド内でprimaryStageを初期化しました。つまり、primaryStageSceneを指す参照を持っているため、クリーンアップできません。ガベージコレクターによって。したがって、Sceneは、少なくともprimaryStageが存在する限りメモリに残ります。

オブジェクトにはライフサイクルがあります。つまり、JVMがオブジェクトに到達できる限り、オブジェクトはメモリ内に存在します。オブジェクトの存続期間を継続するには、それを指す参照変数が必要です。そのオブジェクトを指す参照変数がない場合、そのオブジェクトはガベージコレクションの対象になります。これは、JVMがこのオブジェクトを決定したプロセスです。新しいオブジェクトを格納するためのスペースを空けるために、メモリはもはや有用ではなく、そのオブジェクトを削除する可能性があります。

メモリ管理の詳細については、この件に関するOracleのドキュメントを確認してください。スタックとヒープの違いを理解できます。メモリだけでなく、JVMに組み込まれたガベージコレクションのさまざまなタイプのいくつか。 https://docs.Oracle.com/cd/E13150_01/jrockit_jvm/jrockit/geninfo/diagnos/garbage_collect.html

なぜこれをしたいのでしょうか?

一般的なケースは、まだ持っていないオブジェクト参照を必要とするメソッドを呼び出すことです。非静的メソッドを呼び出したいが、それを呼び出すための既存のインスタンスがない場合があります。以下に例を示します。

_class Orange {
  void printOrange(){
    System.out.print("Oranges are my favorite fruit.");
  }
}
class OrangeJuice extends Orange {
  public static void main(String[] args) {

  // some other useful code for OrangeJuice

    new Orange().printOrange();
  }
}
_

この例では、出力は次のようになります。

_Oranges are my favorite fruit.
_

単にprintメソッドを呼び出すために参照変数を作成する必要はなかったので、これがOrangeクラスを使用する唯一の方法であるなら、なぜ時間とメモリを無駄にするのでしょうか。この場合、次の間にprintOrange()を呼び出すことができます。

  • 参照変数を作成するためにスタックメモリのスペースを使用しない
  • printOrange()を呼び出すだけで初期化したOrangeオブジェクトの存続期間を短縮することにより、ヒープ領域を効率的に使用する
  • 無関係な宣言を作成しないことにより、コードを単純化しました。できる限り簡略化しているため、組織、理解しやすさ、構築時間に役立ちます。

宣言なしでインスタンス化するもう1つの理由は、大量のデータを処理するプログラムの場合が一般的ですが、スタックオーバーフローを防ぐためです。スタックスペースでローカル変数が上限に達したために、スタックスペースがストレージスペースの過剰使用によりクラッシュした場合です。

オブジェクトは実行時にのみ宣言/作成できます。コンパイルして例外エラーなしで実行できるからといって、最終的にクラッシュできないわけではありません。オブジェクトを大規模に宣言し、ガベージコレクションを許可しない場合、メモリの過剰使用によりプログラムがクラッシュする可能性があります。

参照変数はスタックメモリに格納されるため、宣言をできるだけ少なく(プログラムの機能に影響を与えずに)することで、これが発生する可能性を減らします。もちろん、これは通常、大規模なプログラムや、大量のデータストリームを処理するプログラムに関連する問題です。

このSceneオブジェクトをsetSceneメソッドに正常に渡すことができても、Sceneオブジェクトを保存できないのはなぜですか?

コンパイラは、メモリ管理の必要性を理解するように設計されています。オブジェクトを利用するために明示的な宣言を行う必要はありません。宣言はメモリとビルド時間を要します。

この場合、Youdidオブジェクトを「保存」します。オブジェクトSceneのセッターメソッドsetScene内でprimaryStageを初期化することにより、メモリ内のそのSceneのスペースへのポインターを作成しました。現在はそこにあり、primaryStageオブジェクトを通じて参照できます。

オブジェクト指向の結果を控えた出力を生成するための非静的メソッドを呼び出す場合、コンパイラーはその結果を生成するための足がかりとしてオブジェクトを必要とします。これにより、コードをより効率的に使用できるようにするために、メソッドを呼び出すために参照変数が通常使用される場所の代わりにインスタンス化を配置できます。

宣言なしでオブジェクトをインスタンス化することにより、特定のケースでは、基本的に「setSceneメソッドを呼び出したいのですが、Sceneオブジェクトを構築するには、そのためにSceneオブジェクトを厳密にインスタンス化し、コードをより単純にします。」

1