JAVAでの、clone() 参照渡し?について

このQ&Aのポイント
  • ArrayListで文字列の配列(String[ ])の配列を作りました。
  • list.add(item)だと上手くいかず、list.add(item.clone())で上手くいく理由を知りたいです。
  • item.clone()は参照渡しを行うため、異なる値が保存されます。
回答を見る
  • ベストアンサー

JAVAでの、clone() 参照渡し?について

ArrayListで文字列の配列(String[ ])の配列を作りました。 そして、listにaddするときに *・・・ list.add(item)だと上手くいきません。      繰り返して異なる値のはずなのですが、      例えば、listget(0)[0] , list.get(1)[0] , list.get(2)[0]が全て同じ値になってしまいます。     しかし、     list.add(item.clone())だと上手くいきます、よくわかりませんが参照渡しというのでしょうか? 前者で何故上手くいかないのかがわからないのです。 この二つの違いは何なのでしょうか。 【プログラム】 ArrayList<String[]> list = new ArrayList<String[]>(); String[] item = new String[6]; //このwhileは数回繰り返されますが、下記の値は毎度異なります。 while(rs.next()) { item[0] = rs.getString("Field"); item[1] = rs.getString("Type"); item[2] = rs.getString("Null"); item[3] = rs.getString("Key"); item[4] = rs.getString("Default"); item[5] = rs.getString("Extra"); list.add(item); ・・・・・・・・・・・・・・・・・・・・*       }

  • Java
  • 回答数5
  • ありがとう数2

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

  • ベストアンサー
  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.4

「参照」について、より詳しく勉強するのがよいでしょう。 また、「浅いコピー」「深いコピー」の話も読んでみましょう 理解していないと、今後も悩まされることになります String[] item = new String[6]; これで、itemにあるString[6] への参照値が代入されました。 この値を 500 としましょう。 tem[0] = rs.getString("Field"); item[1] = rs.getString("Type"); item[2] = rs.getString("Null"); item[3] = rs.getString("Key"); item[4] = rs.getString("Default"); item[5] = rs.getString("Extra"); これらの item[i]は「変数itemに納められている『参照値500』のところにあるString[]のi番目の要素」です。 変数itermの「参照値500」が変化するわけではありません。 list.add(item); ここで、listにaddされるのは「参照値500」です。その内容ではありません。 つまりlistは  参照値500,参照値500,参照値500,参照値500,... となります。 list(i)が同じ参照なのですから、そのj番目も同じになります list.add(item.clone()); cloneにより、同じ内容の新しいオブジェクトができます。新しいオブジェクトなので、参照も既存のもととは別になります。 よって、listは  参照値510,参照値511,参照値512,参照値513,... 等と、全てが別の参照となり、別々の値を保存できます。 // 例として連番にしましたが、実際にはそのような続き番号になる保証はありません // 参照値そのものを意識することは通常ありません whileの内側に String[] item = new String[6]; を入れる、というのも、毎回新しいString[6]を作ってlistに追加する、ということで、上記cloneと同様のlistができます。

その他の回答 (4)

  • Ogre7077
  • ベストアンサー率65% (170/258)
回答No.5

Java では new しない限り、新しいオブジェクト(を格納したメモリ領域)は生成されません。 ご提示のプログラムの場合なら 1個目: new ArrayList<String[]>() 2個目: new String[6] の二つのみです (rs.getString が内部的に new String() を行っている可能性は無視します) オブジェクトの生成は大変重い処理とされています。 ゆえに引数や変数でオブジェクトを扱う場合は オブジェクトを一意に識別できる番号だけを受け渡して、 メモリ領域には直接触れないでやり取りします。 つまり「参照渡し」と呼ばれる処理形態ですね。 list.add(item) も変数代入と同じ処理なので、 処理完了時の1個目のオブジェクトの中身は 0: 2個目のオブジェクト(を一意に識別できる番号) 1: 2個目のオブジェクト(を一意に識別できる番号) 2: 2個目のオブジェクト(を一意に識別できる番号) 3: 2個目のオブジェクト(を一意に識別できる番号) ... となり、まったく同じオブジェト(を一意に識別できる番号)が 複数個入ったリストになります。 list.add(item.clone()) ならば、clone の内部で new された オブジェクト(を一意に識別できる番号)を追加するので、 0: 3個目のオブジェクト(を一意に識別できる番号) // ループ1回目の2個目のオブジェクトと同値 1: 4個目のオブジェクト(を一意に識別できる番号) // ループ2回目の2個目のオブジェクトと同値 2: 5個目のオブジェクト(を一意に識別できる番号) // ループ3回目の2個目のオブジェクトと同値 3: 6個目のオブジェクト(を一意に識別できる番号) // ループ4回目の2個目のオブジェクトと同値 ... となります。

  • teketon
  • ベストアンサー率65% (141/215)
回答No.3

A.String型配列への参照を保持する変数item B.String型の参照を保持する配列の変数item[0]~item[5] でitemは構成されています。 list.add(item)の場合、 上記Bを書き換えていますが、上記Aの書き換えは行っていません。 そのため、すべてのlistは最後の要素と同じ内容になります。 例  1周め.list(0)[0]=A,list(0)[1]=B,list(0)[2]=C  2周め.list(0)[0]=D,list(0)[1]=E,list(0)[2]=F,list(1)[0]=D,list(1)[1]=E,list(1)[2]=F  3週め.list(0)[0]=G,list(0)[1]=H,list(0)[2]=I,list(1)[0]=G,list(1)[1]=H,list(1)[2]=I,list(2)[0]=G,list(2)[1]=H,list(2)[2]=I list.add(item.clone())の場合、 配列をclone()すると上記Aをもとに、新しいString型配列への参照を作成します(つまり新しいAを作っている)。 そのため、すべてのlistは別の値を保持します。 例  1周め.list(0)[0]=A,list(0)[1]=B,list(0)[2]=C  2周め.list(0)[0]=A,list(0)[1]=B,list(0)[2]=C,list(1)[0]=D,list(1)[1]=E,list(1)[2]=F  3週め.list(0)[0]=A,list(0)[1]=B,list(0)[2]=C,list(1)[0]=D,list(1)[1]=E,list(1)[2]=F,list(2)[0]=G,list(2)[1]=H,list(2)[2]=I これらの動作は誤解を招きやすいので、下記のようにすることをオススメします。 ArrayList<String[]> list = new ArrayList<String[]>(); //このwhileは数回繰り返されますが、下記の値は毎度異なります。 while(rs.next()) { //ループの中で配列を作成する String[] item = new String[6]; item[0] = rs.getString("Field"); item[1] = rs.getString("Type"); item[2] = rs.getString("Null"); item[3] = rs.getString("Key"); item[4] = rs.getString("Default"); item[5] = rs.getString("Extra"); list.add(item); }

  • wormhole
  • ベストアンサー率28% (1619/5653)
回答No.2

>listにaddするときには、itemの値は毎回上書きされていて、 >つまり毎回異なるitemを渡しているはずだと思うのですが、 どこでitemが上書きされてるのか教えてください。 少なくとも質問に書かれてるコード上にはそのようなヶ所はありません。

  • wormhole
  • ベストアンサー率28% (1619/5653)
回答No.1

itemのインスタンスそのものはずっと同じになってますが(new String[6]は1回しかされない)。 ArrayList<String[]> list = new ArrayList<String[]>(); while (rs.next()) { String[] item = new String[6]; item[0] = ... ... list.add(item); } 違いわかりますか?

-Sawyer-
質問者

お礼

回答ありがとうございます。 String[] item = new String[6]; をwhileの外側で作っても、 listにaddするときには、itemの値は毎回上書きされていて、 つまり毎回異なるitemを渡しているはずだと思うのですが、 外側で作ると、どんな不都合がおこるのでしょう。

関連するQ&A

  • JSPでのArrayListの表示について困っています

    以下のようにしてスレッドNoが同じものだけ表示したいと考えております。 servletの「text」という変数にはすべての値が格納されているところまでは確認できました。 それをJSPにて表示したいのですが、どのようにすれば出力されるのかわかりません。 どなたかお教えいただければと思います。 宜しく御願い致します。 --------------------------------------------------------- java /** * *TEXTテーブルからスレッドNoが同じものを返すメソッド * * */ public ArrayList selecttext(int no)throws SQLException{ ArrayList<Textbeen> list = new ArrayList<Textbeen>(); TextDAO kei =new TextDAO(); Connection db=kei.createConnection(); Statement sttSql=db.createStatement(); ResultSet rs=sttSql.executeQuery("SELECT * FROM TEXT WHERE KB_TH_NO='"+no+"' "); while(rs.next()){ String name=rs.getString("KB_NAME"); String tino =rs.getString("KB_TITLE_NO"); String title = rs.getString("KB_TITLE"); String mail = rs.getString("KB_MAIL"); String text = rs.getString("KB_TEXT"); String pass = rs.getString("KB_TITLE_PASS"); String date = rs.getString("KB_TIME"); int th_no = rs.getInt("KB_TH_NO"); Textbeen thread = new Textbeen(name, title, tino, mail, text, pass, date, th_no); //TO(Threadオブジェクト)を、保持するリストに追加 list.add(thread); } kei.closeConnection(db); return list; } ---------------------------------------------------------- servlet ArrayList text = new ArrayList(); try{ text = list.selecttext(TH_no); } catch(Exception e){ e.getStackTrace(); } request.setAttribute("test", text); String nextPage = "/view/user/ThreadTop.jsp"; ----------------------------------------------------------

  • JSPとJavaBeansについて

    JSPとJavaBeansを用いて情報を共有したいと考えています。 値を取得した後に配列に入れています。 ArrayList list = new ArrayList(); while(rs.next()){ int op = rs.getInt("op"); list.add(new Integer(op)); } int[] in = new int[list.size()]; for (int i = 0; i < list.size(); i++) { in[i] = ((Integer)list.get(i)).intValue(); この後に、in[i]の要素をBeansに送り、別のJSPでその値を使いたいと考えています。 ただ、Beansで配列のデータを扱う場合にはどのようにすれば宜しいのでしょうか? アドバイスを頂けると助かります。 宜しくお願いします。

  • while文の表示

    こんにちは 今DB接続し DBからデータを表示するのを勉強しています public String[][] selectExec(String sql) throws SQLException{ Statement smt = con.createStatement(); //ステートメントオブジェクト作成 SQL文を送るために作成 ResultSet aa=smt.executeQuery(sql); //SQLから要素取得 ArrayList<String> TESTNO = new ArrayList<String>(); //TESTNO用ののArrayList作成 ArrayList<String> NAME = new ArrayList<String>(); //KAME用 ArrayList<String> KANA = new ArrayList<String>(); //KANA用 while(aa.next()){ //Resultsetが最終行になるまで実行 TESTNO.add(aa.getString("TESTNO")); NAME.add(aa.getString("NAME")); KANA.add(aa.getString("KANA")); } aa.close(); //使い終わったリザルトクローズ smt.close(); //ステートメントクローズ      //オブジェクトの解放 return hairetu(TESTNO,NAME,KANA); public String[][] selectExec(String sql, int fromIdx,int toIdx) throws SQLException{ String[][]all=selectExec(sql); ArrayList list = new ArrayList(Arrays.asList(all[0])); ArrayList list1 = new ArrayList(Arrays.asList(all[1])); ArrayList list2 = new ArrayList(Arrays.asList(all[2])); int i=1; while(i<fromIdx){ //指定された前のリスト削除 list.remove(0); list1.remove(0); list2.remove(0); i++; } while(toIdx<list .size()){ //指定されたあとのリスト削除 list .remove(toIdx); list1.remove(toIdx); list2.remove(toIdx); toIdx++; } return hairetu(list ,list1,list2); public String[][] hairetu(ArrayList T,List N ,List K){ String[][]all=new String[3][T.size()]; all[0] = (String[])T.toArray(new String[0]);//配列TSETNOに収納 all[1] = (String[])N.toArray(new String[0]);//配列NAMEに収納 all[2] = (String[])K.toArray(new String[0]);//配列KANAに収納 return all; selectExec(String sql)で全表示 selectExec(String sql, int fromIdx,int toIdx) で列を何行~何行を指定 でリストに変換、リスト削除して 二次元配列にもどしているのですが たとえば 1~5を指定すると 0 0 0 1 1 1 2 2 2 3 3 3 4 4 4 6 6 6 8 8 8 ↑のように 5ひとつとばしで表示されます while文の書き方がわるいのでしょうか・・・・ アドバイスお願いします

    • ベストアンサー
    • Java
  • メソッド オーバーロード ete

    こんにちは 今オーバーロードやメソッドについて学習中です 今回作成したのはDB接続の 処理をするほうのクラスなのですが 同じソースはひとつにまとめろといわれました 自分なりに メソッドを作ってまとめてみたのですが まだだめなようです あとどのようにまとめれば 良いとおもいますか? 例文なども出していただけると助かります 一部ソースのせます public String[][] selectExec(String sql, int fromIdx) throws SQLException{ Statement smt = con.createStatement(); //ステートメントオブジェクト作成 SQL文を送るために作成 ResultSet aa=smt.executeQuery(sql); //SQLから要素取得 ArrayList<String> TESTNO = new ArrayList<String>(); //TESTNO用のArrayList作成 ArrayList<String> NAME = new ArrayList<String>(); //NAME用 ArrayList<String> KANA = new ArrayList<String>(); //KANA用 aa.relative(fromIdx-1); //カーソルの位置を移動 while(aa.next()){ TESTNO.add(aa.getString("TESTNO")); NAME.add(aa.getString("NAME")); KANA.add(aa.getString("KANA")); } aa.close(); //使い終わったリザルトクローズ smt.close(); //ステートメントクローズ      //オブジェクトの解放 hairetu(TESTNO,NAME,KANA); //配列に収納するメソッド呼び出し return hairetu(TESTNO,NAME,KANA); } /* * すべての行を取得 */ public String[][] selectExec(String sql) throws SQLException{ Statement smt = con.createStatement(); //ステートメントオブジェクト作成 SQL文を送るために作成 ResultSet aa=smt.executeQuery(sql); //SQLから要素取得 ArrayList<String> TESTNO = new ArrayList<String>(); //TESTNO用ののArrayList作成 ArrayList<String> NAME = new ArrayList<String>(); //KAME用 ArrayList<String> KANA = new ArrayList<String>(); //KANA用 while(aa.next()){ //Resultsetが最終行になるまで実行 TESTNO.add(aa.getString("TESTNO")); NAME.add(aa.getString("NAME")); KANA.add(aa.getString("KANA")); } aa.close(); //使い終わったリザルトクローズ smt.close(); //ステートメントクローズ      //オブジェクトの解放 return hairetu(TESTNO,NAME,KANA); } /* * 指定された行から行を取得 */ public String[][] selectExec(String sql, int fromIdx,int toIdx) throws SQLException{ Statement smt = con.createStatement(); //ステートメントオブジェクト作成 SQL文を送るために作成 ResultSet aa=smt.executeQuery(sql); //SQLから要素取得 ArrayList<String> TESTNO = new ArrayList<String>(); //TESTNO用ののArrayList作成 ArrayList<String> NAME = new ArrayList<String>(); //NAME用 ArrayList<String> KANA = new ArrayList<String>(); //KANA用 aa.relative(fromIdx); while(fromIdx<=toIdx){ TESTNO.add(aa.getString("TESTNO")); NAME.add(aa.getString("NAME")); KANA.add(aa.getString("KANA")); aa.next(); fromIdx++; } aa.close(); //使い終わったリザルトクローズ smt.close(); //ステートメントクローズ      //オブジェクトの解放 return hairetu(TESTNO,NAME,KANA); } public String[][] hairetu(ArrayList T,ArrayList N ,ArrayList K){ String[][]all=new String[3][T.size()]; all[0] = (String[])T.toArray(new String[0]);//配列TSETNOに収納 all[1] = (String[])N.toArray(new String[0]);//配列NAMEに収納 all[2] = (String[])K.toArray(new String[0]);//配列KANAに収納 return all; }/* リストから配列に収納するメソッド。 配列でリターンします */ 下のhairetuメソッドはあとから作成しました。 もうひとつ作ったのですが TEST(TESTNO,aa,"TESTNO"); TEST(NAME,aa,"NAME"); TEST(KANA,aa,"KANA"); 呼び出し↑ メソッド public ArrayList TEST(ArrayList T,ResultSet a ,String s) throws SQLException{ T.add(a.getString(s)); // リストにSQL文を収納 return T; } これは却下されました 見づらいとは思いますが いろいろアドバイスください

    • ベストアンサー
    • Java
  • JAVA 配列のリストの作り方

    ArrayList<String[]> stl = new ArrayList<String[]>(); このように、配列をリスト構造で作ることはできませんか?

  • Itaratorから値を取得するには?

    ArrayList<String> list = new ArrayList<String>(); list.add("その1"); list.add("その2"); list.add("その3"); list.add("その4"); Itarator itar = list.itarator(); while(itar.hasNext()){ System.out.println(itar.toString); itar.Next(); } 上記のように記述するとコンソールには その1 その2 その3 その4 というように出力されることを期待したのですが 結果はitar自身の値が返ってきてしまいました。 Itaratorを使用して、ArrayListの値を出力させるには どうすればよいのでしょうか?

    • ベストアンサー
    • Java
  • java のstruts1.3です。

    java のstruts1.3です。 Cannot invoke newStrutsKadai.EntryWorkForm.setArrayDB on bean class 'class newStrutsKadai.EntryWorkForm' - argument type mismatch - had objects of type "java.lang.String" but expected signature "java.util.ArrayList" と言うエラーがでます。 以下javaのソースです。DB接続は完璧に出来ています。 public final class EntryWorkForm extends ActionForm { private static final long serialVersionUID = 1L; private String cmbOsName; ArrayList<EntryWorkForm> array = new ArrayList<EntryWorkForm>( ) ; public void reset( ActionMapping map, HttpServletRequest req ) { //必要な部分だけ抜粋 //検索された行数文ループ while( rs.next( ) ) {//本マスタテーブル 検索された行数文ループ String stOSName = rs.getString("OSName"); //上記の2行を丁寧に記述した EntryWorkForm obj = new EntryWorkForm( stOSName.toString() ); array.add( obj ) ; } //END while( rs.next( ) ) this.setArrayDB( array );//ここでエラーエラーエラー } /****************************************************************************************/ private ArrayList<EntryWorkForm> arrayDB = new ArrayList<EntryWorkForm>( ); //セット オブジェクト配列 public void setArrayDB( ArrayList<EntryWorkForm> arrayDB ){ this.arrayDB = arrayDB; } //ゲット オブジェクト配列 public ArrayList<EntryWorkForm> getArrayDB ( ) { return this.arrayDB ; } /****************************************************************************************/ public String getCmbOSName ( ) { return this.cmbOsName; } public void setCmbOSName ( String cmbOsName ) { this.cmbOsName = cmbOsName; } public EntryWorkForm( ) { } //コンストラクタ 引数あり EntryWorkForm ( String cmbOSName ) { System.out.println("テスト用で作成したコンストラクタが呼ばれています。 ReturnScreenFormDB.java"); cmbOsName = cmbOSName; } 質問です--- JSPでセレクトボックスに動的に出力しています。 JSP画面でボタンを押して画面遷移をすると上記のエラーが出ます。

    • ベストアンサー
    • Java
  • DB接続 二次元配列 指定表示

    DB接続でデータを取得したいとおもっています 今DBで3×10のデータがはいっており、... DB接続でデータを取得したいとおもっています 今DBで3×10のデータがはいっており、取得、二次元配列に返してあげている状態です この例だと3列(TESTNO、KANA、NAME)だと取得できるのですが TESTNO,KANA の二列取得をしたときにエラーが発生してしまいます どのように改善すればエラーが発生せず、取得できるようになりますか? それともこのロジック自体がまずいのでしょうか? アドバイスお願いします ソース一部 public String[][] selectExec(String sql) throws SQLException{ Statement smt = con.createStatement(); //ステートメントオブジェクト作成 SQL文を送るために作成 ResultSet aa=smt.executeQuery(sql); //SQLから要素取得 ArrayList<String> TESTNO = new ArrayList<String>(); //TESTNO用ののArrayList作成 ArrayList<String> NAME = new ArrayList<String>(); //KAME用 ArrayList<String> KANA = new ArrayList<String>(); //KANA用 while(aa.next()){ //Resultsetが最終行になるまで実行 TESTNO.add(aa.getString("TESTNO")); NAME.add(aa.getString("NAME")); KANA.add(aa.getString("KANA")); } aa.close(); //使い終わったリザルトクローズ smt.close(); //ステートメントクローズ //オブジェクトの解放 return hairetu(TESTNO,NAME,KANA); } public String[][] hairetu(ArrayList T,ArrayList N ,ArrayList K){ String[][]all=new String[3][T.size()]; all[0] = (String[])T.toArray(new String[0]);//配列TSETNOに収納 all[1] = (String[])N.toArray(new String[0]);//配列NAMEに収納 all[2] = (String[])K.toArray(new String[0]);//配列KANAに収納 return all; よろしくお願いします

    • ベストアンサー
    • Java
  • 九九の表の応用

    Java勉強中の超初心者です。 ちょっと前に同じ質問をしたのですが、前回の回答をよく見たら 趣旨とは違った処理をしていたのでもう一度、質問をさせて下さい。 ArrayListを使った九九の表を作成します。 この時に、九九の計算結果を一旦、Stringの配列に格納してから、 ArrayListから値を出力します。 この時にArrayListに格納してから出力するソースは書くことが できたのですが、一旦、格段はString[]s = new String[9];として Stringの配列に格納してから、ArrayListにまとめて出力する方法 をご教授お願いできますか? ----------------------------------------------------------- ArrayList list = new ArrayList(); //ここにString[]s = new String[9];が入ります。 for(int i = 1; i <= 9; i++ ){ for(int j = 1; j <= 9; j++){ list.add(i*j); System.out.print(list.get(list.size() - 1) + " "); if((list.size() - 1) % 9 == 8 && (list.size() - 1) != 0){ System.out.println(""); } } } ---------------------------------------------------------- 上記のソースを元に作成できたらと、思います。

    • ベストアンサー
    • Java
  • ArrayList で配列を扱う場合の記述方法について

    ArrayList で配列を扱う場合の記述方法について、 探しきれないのでご教授お願いします。 ArrayList list = new ArrayList(); list.add("AAA"); list.add("BBB"); list.add("CCC"); for (int i = 0; i < list.size(); i++) { System.out.println(i+"は"+list.get(i)); } という箇所をArrayList<Date>listを使って書き直すのはどのようになるでしょうか。 ArrayList<Date>list= new ArrayList<Date>(); list.add("AAA"); list.add("BBB"); list.add("CCC"); for (int i = 0; i < list.size(); i++) { System.out.println(i+"は"+list.get(i)); } とすると、 型 ArrayList<Date> のメソッド add(Date) は引数 (String) に適用できません。 というエラーになってしまいました。

    • ベストアンサー
    • Java

専門家に質問してみよう