• ベストアンサー

クラスでnew宣言

いつも御世話になっています。 クラス作成時に、 オブジェクト型(クラス型)を変数として宣言している時がある気がするのですが、ClassB classB = new ClassB(); この場合の利点は何かあるのでしょうか? 普通に考えれば、この記述を宣言することで、この宣言がされているクラス自身が、ClassBの実体を持つことになり、このクラスだけで多数のクラスの実体を利用できるようになる。 と思ったのですが。 クラスとしては、 ClassA { private ClassB classB = new ClassB(); } という場合です。 ここで、private ClassB classB;でない理由: むやみに、上記の書き方をすると、外部から書き換えられてしまう恐れがあるから、、なるべくその可能性を回避するため 宜しくお願いします。

  • Java
  • 回答数7
  • ありがとう数7

質問者が選んだベストアンサー

  • ベストアンサー
  • sh_hirose
  • ベストアンサー率66% (56/84)
回答No.5

>ClassBの実体を持つことになり、このクラスだけで多数のクラスの実体を利用できるようになる。 「ClassBの実体を持つことにより、このクラスでClassBそのものを利用できるようになる。」です。 >この場合の利点は何かあるのでしょうか? これは class ClassA { private ClassB classB; public ClassA() { classB = new ClassB(); } } と同等です。 >ここで、private ClassB classB;でない理由: >むやみに、上記の書き方をすると、外部から書き換えられてしまう恐れがあるから、、なるべくその可能性を回避するため たとえば以下の場合なら正しいです。 class ClassA { private ClassB classB = new ClassB(); public void add(String value) { classB.add(value); } public String getString() { return classB.getValue(); } } (ClassBにはadd、getStringというメソッドがあるとします。) この場合ならclassBのインスタンスは変更できません。 メリットとしてはインスタンスを変更せずに内部の値(ClassBのフィールドの値)を特定の処理を行ってから設定、取得を行うことが出来るようになります。 privateでかつインスタンスを変更させたくない場合は private ClassB classB = new ClassB(); を private final ClassB classB = new ClassB(); に変えてしまった方がいいと思います。

kannitiha
質問者

お礼

遅くなり申し訳ありません。 皆さんの回答を読んで、大体理解できました。 ありがとうございました。

kannitiha
質問者

補足

回答ありがとうございます。 遅くなりました。 丁寧な回答ありがとうございます。 インスタンス変数をnewしてしまったほうが見栄え上も良さそうですね。 だいたいの処理、がわかりました。 また、わからなければ質問させて頂きます。 宜しくお願いします。

その他の回答 (6)

  • salsberry
  • ベストアンサー率69% (495/711)
回答No.7

他の方への返答を見ていると、どのように理解されたのか少し不安になります。 Javaでは、フィールドxを明示的に初期化せずに ClassA { private ClassB x; } と書いたら ClassA { private ClassB x = null; } と同じ意味になります。 xの値がnullのままではxに対してメソッドを呼び出したりすることができませんから、ClassAのインスタンスを生成した後に適切なタイミングでClassBのインスタンスへの参照をxに代入する必要があります。xに対して何も操作をしない場合であればnullのままでも構いませんが。 xに代入する値としては、new ClassB()以外にも ・ClassB型の他の変数やフィールドから値をコピーする ・ClassB型を返すメソッドの結果を代入する などがあります。 ClassAのインスタンス生成ごとに毎回必ず新しいClassBのインスタンスを使うのであれば ClassA { private ClassB x = new ClassB(); } の書き方でいいですが、逆に、new ClassB()以外の値を使うのであれば "= new ClassB()" の部分は不要というか、単に実行時間とメモリの無駄です。

kannitiha
質問者

お礼

遅くなり申し訳ありません。 何とか、みなさんの回答を読んで、大体の意味は理解できました。 ありがとうございました。

kannitiha
質問者

補足

回答ありがとうございます。 今、思っているのはnew演算子を使用する場合は、 複数のメソッドで、毎回新しいインスタンスを作るなら、 一つにまとめて宣言してしまえば、忘れないし、実行時間とメモリを省略できる ex) public class ClassB { public void setName() { } } public class ClassA { public void delete() { private ClassB classB = new ClassB(); classB.setName(); } public void update() { private ClassB classB = new ClassB(); classB.setName(); } public void add() { private ClassB classB = new ClassB(); classB.setName(); } } ↓ public class ClassA { private ClassB classB = new ClassB(); //複数箇所で利用されているので一つにまとめて宣言 public void delete() { classB.setName(); } public void update() { classB.setName(); } public void add() { classB.setName(); } } といった感じで理解しています。 単に private ClassB classB; これは単なる「カタ」=容器のようなものなので、使用時にはインスタンス化する必要がある。 もし、使用する可能性があるかわからないときに、宣言する、といった感じなのですが。 =毎回、使用するのでないなら、使用時にインスタンス化した方がいい気はします。 宜しくお願いします。

  • salsberry
  • ベストアンサー率69% (495/711)
回答No.6

ClassAのコンストラクタが2つ以上ある場合を考えてみましょう。 ClassA { private ClassB classB = new ClassB(); private int x; public ClassA() { x = 10; } public ClassA(int i) { x = i; } } は ClassA { private ClassB classB; private int x; public ClassA() { classB = new ClassB(); x = 10; } public ClassA(int i) { classB = new ClassB(); x = i; } } と同じ意味になります。 つまり、共通するフィールドclassBの初期化を1カ所にまとめることができて、書き忘れの防止になります。

kannitiha
質問者

お礼

遅くなり申し訳ありません。 皆さんの回答を読んで大体理解できました。 ありがとうございました。

kannitiha
質問者

補足

回答ありがとうございます。 遅くなりました。 丁寧な内容ありがとうございます。 見ている限り、一つにした方が、見栄えがよさそうですね。 「書き忘れの防止」ですか。その通りですね。 わかりました。 またわからなければ、質問させて頂きます。 宜しくお願いします。

回答No.4

#2の一部修正 >publicなgetterがある、コンストラクタで設定する、とかいう話なら別ですが。 ↓ >publicなsetterがある、コンストラクタで設定する、とかいう話なら別ですが。 sとg間違え、意味がまったく逆になっちゃう。

kannitiha
質問者

お礼

回答ありがとうございます。 皆さんの回答を読んで、大体理解できました。 ありがとうございました。

kannitiha
質問者

補足

回答ありがとうございます。 遅くなりました。 >ここで、private ClassB classB;でない理由: >むやみに、上記の書き方をすると、外部から書き換えられてしまう恐れがあるから、、なるべくその可能性を回避するため ???どういう意味でしょ? ClassB classB = new ClassB();とClassB classB;の利用は、違うと思うのですが、 初期化するか、変数宣言するかで、どう違うのかがよくわかっていません。 手持ちのjavaの本を見ると、クラス型変数は、実体ではなく、参照するために使用される変数=ClassBにアクセスしてデータ代入等を行うなら 初期化してインスタンスを生成して代入すべき、と感じたのですが。 一応、コンストラクタもsetterも使用しない場合で考えています。 以上宜しくお願いします。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.3

そもそも「new 宣言」ってなんだ. new は宣言じゃないぞ. たぶん, このようについでに new する理由は次の 1点でしょう: 確実に「ClassB のオブジェクト」として確保する. 言い換えると「確保し忘れるのを防ぐ」ということだ. #2 でも言われるように, 「private にする」こと自体が「むやみに外部から書き換えられるのを防ぐ」ためです. 基本的に, private なメンバを外部から直接アクセスすることはできません (リフレクションは「基本的」じゃない). で, 「むやみ」じゃない変更 (設定) 手段がコンストラクタだったり public な setter だったりします.

参考URL:
http://javafaq.jp/S010.html
kannitiha
質問者

お礼

遅くなり申し訳ありません。 皆さんの回答を読んで、大体理解できました。 ありがとうございました。

kannitiha
質問者

補足

回答ありがとうございます。 遅くなりました。 なるほど、 ClassB classB = new ClassB();と、ClassB classB;では、 前は「ClassB」のオブジェクトを確保し忘れないためで、 後は、ClassB型の変数、という感じなのでしょうか? 一般に、ClassB classB; クラス型変数は、参照する場合のみに使用する感じなのでしょうか? むやみやたらに、外部書き換えを防ぐなら、「private」を使用すればいいんですね。 勉強になりました。 URL参考にさせて頂きます。 宜しくお願いします。

回答No.2

>ここで、private ClassB classB;でない理由: >むやみに、上記の書き方をすると、外部から書き換えられてしまう恐れがあるから、、なるべくその可能性を回避するため ???どういう意味でしょ? privateのフィールドの中身を外部(他のクラス?)からどうやって書き換えるんでしょうか?(リフレクションは除くとして) publicなgetterがある、コンストラクタで設定する、とかいう話なら別ですが。

  • x_jouet_x
  • ベストアンサー率68% (162/236)
回答No.1

> オブジェクト型(クラス型)を変数として宣言している時がある気がするのですが、ClassB classB = new ClassB(); これは「オブジェクト型の変数をあるクラス(例: ClassA)のインスタンス変数として宣言をして、かつそこでインスタンス化している」ということでしょうか? > ClassBの実体を持つことになり、このクラスだけで多数のクラスの実体を利用できるようになる。 このように考えられる理由が今ひとつ分かりません。

kannitiha
質問者

お礼

遅くなり申し訳ありません。 みなさんの回答を読んで、大体理解できました。 ありがとうございました。

kannitiha
質問者

補足

回答ありがとうございます。 遅くなりました。 質問の件ですが、 >これは「オブジェクト型の変数をあるクラス(例: ClassA)のインスタンス変数として宣言をして、かつそこでインスタンス化している」ということで>しょうか? >>大体、そのような感じ、です。 > ClassBの実体を持つことになり、このクラスだけで多数のクラスの実体を利用できるようになる。 >>クラスのインスタンスを複数宣言した場合に、そのインスタンスを使用してクラスにアクセスができるようになる、といった意味です。 宜しくお願いします。

関連するQ&A

  • 参照メンバを持つクラス

    ClassAとClassBにCMyDataオブジェクトを渡したいのですが、メモリ上に同じデータのコピーを作りたくないので、コンストラクタがCMyDataの参照を受け取る設計にしました。こうすることで、CMyDataの実体はメモリ上に1つしか存在しないことになります。 ただ、クラスが、自身が管理していない外部領域にあるデータへの参照を使って仕事をするというのに違和感を感じます。 完全コンストラクタというデザインパターンがあって、クラスのインスタンスを生成する時に必要な全てのデータを渡すのが正しい流儀だそうです。 しかしこのClassA(B)の設計では、ClassA(B)の寿命が終わるまで参照先のデータが生きているとは限りません。もっといい設計はないでしょうか?ちなみにCMyDataは実際にはかなり大きなデータで、一時的であってもコピーを複数持ちたくないのです。ClassAとClassBは、実際は他のデータも参照するため1つのクラスにはしたくないのです。 class CMyData { // 色々なデータ }; class CMain { CMyData* myData; // ファイルからデータを読み込んで生成 ClassA* objA; ClassB* objB; void ReadFile() { myData = new CMyData(); // ファイルからデータを読み込みCMyData構築 } void Init() { ReadFile(); objA = new ClassA(*myData); // 自身のメンバ変数の参照でClassAを構築 objB = new ClassB(*myData); } void DoProcess() { Init(); // 実行は一度だけ objA->hoge(); // ClassAに仕事をさせる objB->foo(); // ClassBに仕事をさせる } } class ClassA { CMyData& m_data; public: ClassA(CMyData& data) m_data=data; // CMyDataオブジェクトを参照で受け取る void hoge(); } class ClassB { CMyData& m_data; public: ClassB(CMyData& data) m_data=data; // CMyDataオブジェクトを参照で受け取る void foo(); }

  • 親クラスのフリをした子クラスの使い方を教えて下さい

    以前、QNo.3479089でお世話になった者です。類似というか、続きの質問です。 ClassAを継承するClassBがあり、条件によって、ClassAまたはClassBをインスタンス化して使います。 (ClassBは、ClassAのメソッドの一部をオーバーライドして、ClassB固有のメソッドも追加しています) ClassA* pObj = NULL; if( ある条件 ) {   pObj = new ClassA(); } else( その他の条件 ) {   pObj = new ClassB(); } pObj->common_method(); これが常套手段と伺ったのですが、ClassBがインスタンス化された場合、ClassB固有のメソッドmethodBを呼び出そうとすると、「ClassAにはmethodBが存在しない」といったようなコンパイルエラーが出ます。 pObj->methodB(); // ここで、エラー それで、エラーを解消するために、「その他の条件」の時に、dynamic_castを使ってみました。 if( その他の条件 ) {   ClassB* pObj2 = dynamic_cast<ClassB*>( pObj );   pObj2->methodB(); } 上記でコンパイルエラーは解消したのですが、なにか、非常にめんどくさいです。 また、ClassAのフリをした実体ClassBを使っているのだから、オーバーライドしているメソッドもdynamic_castをしないと呼び出されないような気がします。 結局、親のフリした子クラスを作成する場合、こんなにめんどくさいことをしないといけないのでしょうか? それともこのやり方はおかしいですか? この場合、どういうふうにするものなのか、教えて下さい。よろしくお願いします。

  • 無名パッケージのクラス

    パッケージ化されたクラス(pacA.ClassA)から、無名パッケージ(ClassB)のクラスを参照できるのでしょうか。 状況を詳しく書きますと、 ClassB はコンパイル済みで、pacA.ClassA の中で ClassB を new しています。 pacA.ClassA をコンパイルしたいのですが、ClassB を import できません(コンパイルエラー)。 それとも、ClassB は import する必要がなく、単に私のコンパイルの仕方(classpathの通し方等)が悪かったのでしょうか。 どなたか教えて頂けませんか。

    • ベストアンサー
    • Java
  • 「new 式」 で、変数を 式 として指定することはできますか?

    「new 式」 で、変数を 式 として指定することはできますか? 例えば次のような感じで、変数clの内容によりclassAあるいはclassBをnew するようなことがしたいです。 class base [ ... }; class classA : public base { .... }; class classB : public base { .... }; classA* ca; classB* cb; base* cl; cl = classA; ca = new cl; cl = classB; ca = new cl; これにより、多種のclassをnewする際にいちいち pa = new classA; pb = new classB; pc = new classC; pd = new classD; ............ としないで、 for (n=0; n<xxx; n++) p[n] = new cl[n]; …みたいに簡潔に書けないかなと考えてます。 よろしくお願いします。

  • メンバ変数宣言時にfinal修飾子

    いつも御世話になっています。 final修飾子を使用する際で、メンバ変数宣言時で、 オブジェクト型変数にfinalをつけた際、値を変更できると思うのですが。 インターフェースで考えた時はどうなるのでしょうか? クラス型だと, final ClassA object1 = new ClassA(); classA.value = 10; //valueはint型 と記述されると思うのですが、 また、配列だと, final String[] hairetu = {"one","two"}; classA.strValue = hairetu; とするのがいいのでしょうか? 宜しくお願いします。

    • ベストアンサー
    • Java
  • 継承元クラスのプロパティを参照する手段

    お世話になります。 ActionScrip3に関する質問です。 現在、カスタムクラスを勉強しております。 外部クラスでClassA、ClassBを作成し、 ClassAにある処理の途中でClassBを実行し、ClassBの中からClassAのプロパティを参照しにいく 処理を行いたいと思い、ClassBのコンストラクタからClassAのプロパティをtraceしました。 プロパティppt2は「かきくけこ」が出力されましたが、ppt1は「null」になってしまいました。 恐らく、タイムラインからClassAに対して設定したプロパティの値は見にいけていないようですが、 タイムラインから設定したプロパティの値を継承したClassBから参照しにいく方法はありますでしょうか? 下記ソースと同じ方法でなくても結構ですので、タイムラインから設定した スーパークラスのプロパティ値をサブクラスから参照・変更できる方法を ご教授いただければと存じます。 お手数ではありますが、宜しくご教授ください。 宜しくお願いいたします。 /* タイムライン側の処理 -----------------------*/ var test:ClassA = new ClassA(); test.ppt1 = "あいうえお"; test.goNext(); /* ClassAの処理 -----------------------*/ package {  // インポート記述は省略  public class ClassA {   var ppt1:String;   var ppt2:String = "かきくけこ";   // コンストラクタ   public function ClassA() { }   public function goNext():void {    var classb:ClassB = new classB();   }  } } /* ClassBの処理 -----------------------*/ package {  // インポート記述は省略  public class ClassB extends ClassA {   // コンストラクタ   private function ClassB() {    trace(ppt1);    trace(ppt2); }  } }

    • ベストアンサー
    • Flash
  • (クラス名.this.メソッド)って・・・?

    次のようなクラスで public class ClassA {   public static void main(String[]args)   {     new ClassA(); /* 構築A */   }   public ClassA()   {     new ClassI();   }   public class ClassI()   {     ClassA.this.MethodA(); /* 命令A */   }   public void MethodA()   {     System.out.println("HELLO");   } } この命令Aの部分の (クラス名.this.メソッド)というアクセス方法がよくわかりません とりあえす(ClassA.this)が構築Aの部分で生成された インスタンスではないかとおもうのですがそれで正しいのでしょうか? また インナークラスはインナークラスの定義されているクラス以外から インスタンスを生成できないのでしょうか? つまり次のクラスを追加して public class ClassB {   public ClassB()   {     new ClassA.ClassI(); /* 構築B */   } } ここの構築Bのように(この場合はダメの様ですが)他のクラスから 構築することです もし仮にできるとしたら そのときの命令Aの(ClassA.this)は一体なんの インスタンスを指すのでしょうか 急ぎのプログラムを作っているので たいへん不躾ですが、なるべく早くお答えをお願いします

    • ベストアンサー
    • Java
  • 条件によって別のクラスのインスタンスを作成する場合

    大きな条件分岐があって、その条件によって別のクラスを同じ名前でインスタンス化し、以降で使いたいのですが、うまくコンパイルが通りません。考えてみればifブロックの中だけで有効なインスタンスになってしまうので、当たり前かも知れません。どのようにすれば、使えるようになるのでしょうか。 以下にコードを載せます。正しい書き方を教えて下さい。 よろしくお願いします。 if(条件A){ classA object; // objectという名前でclassAをインスタンス化 }else{ classB object; // objectという名前でclassAとは別のclassBをインスタンス化 } object.methodA(); // objectのmethodA関数を使用したい

  • クラスがメンバーとしてクラスを持つ時の宣言について

    自作クラスMainClassがMyClassというクラスをメンバー変数として持つ場合、宣言時に引数をいくつか持つコンストラクタを呼び出そうとすると構文エラーとなります。 class MyClass { public: MyClass(int, int); } class MainClass { private: MyClass myclass(10,10); } このような宣言はできないのでしょうか。 引数なしのコンストラクタは呼び出せているようです。

  • クラスの宣言でのメモリ使用サイズの違い

    お世話になります。 現在、Visual Studio 2005にてMFCのC++のプログラムを作成しているのですが、そこでメモリの使用容量について疑問に感じた点があったのでこちらで、質問させて頂きました。 お聞きしたい内容は あるクラス1内で別のクラス2を宣言する際に、メンバ変数としてそのクラス2を宣言し、クラス1のコンストラクタでnewでメモリを確保し、デスクリタでdeleteする方法と、その都度クラス2の変数または関数が必要なときにnewでメモリを確保して、deleteで開放する方法とでは、メモリの確保等で違いがなにかありますでしょうか? また、クラス2をクラス1,クラス3で使用する場合には、クラス1,クラス3でそれぞれクラス2のオブジェクトを宣言するのと、クラス1でクラス2のオブジェクトを宣言し、そのオブジェクトをクラス3でexternするのではどちらの方がメモリの使用等からよい方法なのでしょうか? 今までほとんどメモリを気にせずにプログラムを作っていた為、メモリの使用の点ではほとんど無知な為、変な質問なのかもしれませんが、ご存知の方がいらっしゃいましたら、ご回答をお願い致します。 開発環境は Widows CE 6.0 Visual Studio 2005 です。

専門家に質問してみよう