• ベストアンサー

参照渡し

javaでintやStringって参照渡しって可能なのでしょうか? プリミティブタイプ以外は参照渡しとあるサイトに書いてあったのですが Stringは何故、値渡しなのでしょうか。 宜しくお願いします。

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

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

  • ベストアンサー
  • UKY
  • ベストアンサー率50% (604/1207)
回答No.7

> あと補足なんですがインスタンスが確保されているものに > a = null;とかするのは問題あるでしょうか? > なんとなくメモリリークが起きる気がするのですが、、 問題ありません。メモリリークも起きません。 確かに、文字列を連結したりするたびに新しい文字列のインスタンスが生成されていきますが、Javaでは、不要になったインスタンスのメモリは、自動的に「ガーベジコレクタ」によって開放されます。 つまり、不要なインスタンスを破棄・処分するためのコードをいちいちプログラマが書く必要は無いのです。 ある変数に代入されているインスタンスが不要になったら、その変数にnullを代入しておくだけで、あとは適当なタイミングにガーベジコレクタがメモリを開放してくれます。(メモリの開放はnull代入の直後とは限りません)

sha-girl
質問者

お礼

再度にわたるご回答、感謝しております。

その他の回答 (6)

  • Sephy
  • ベストアンサー率35% (7/20)
回答No.6

(1) String a; a = "aaa"; (2) String a = new String(); a = "aaa";  (1)と(2)の動作の違いについて。 (1)  String型の参照を格納する変数aを宣言。(つまりStringオブジェクトはまだ生成されていない。)  aに"aaa"というStringオブジェクトの参照を代入する。  メモリでいうならば「参照用のa」「"aaa"という内容のStringオブジェクト」の分だけ確保されます。 (2)  String型の参照を格納する変数aを宣言し、そのaに新しく生成(new)したStringオブジェクトの参照を代入する。  aに"aaa"というStringオブジェクトの参照を代入する。(これはaの参照先を"aaa"に書き換えただけで、上でnewしたStringオブジェクトに文字列"aaa"を代入したわけではありません。)  メモリでいうならば「参照用のa」「newしたStringオブジェクト」「"aaa"という内容のStringオブジェクト」の分だけ確保されます。  Stringであろうとオブジェクトは全て例外なく参照渡しです。Javaでは配列はオブジェクトなので配列も参照渡しです。このことを利用したのが#1さんの >ちょっとずるいですが、 >要素数1の配列にすればできます。 です。 >Stringというのは特別なクラスなのでしょうか?  Java内部の仕様に組み込まれた特別なクラスですが、プログラマはいちいちそのことを意識しなくてもいいと思います。  意識しなければならないのは、String同士を連結して代入する際、新しいオブジェクトが生成されるという点です。(#4参照)  このことを知らないと今回のteststrのように文字列の「内容」を別のメソッドで書き換えたつもりが、実は書き換わっていない、というバグに繋がる可能性があります。  「頻繁に内容が変更される文字列」を扱うのでしたらStringBufferを使用することをお勧めします。=や+での操作はできなくなりますが、メモリやパフォーマンスの面でStringBufferの方が上回ります。Stringは「固定長の文字列」を扱うのに便利なクラスであると心得てください。

sha-girl
質問者

お礼

ご回答ありがとうございます。 大変勉強になりました。

  • UKY
  • ベストアンサー率50% (604/1207)
回答No.5

プリミティブ型でもオブジェクト型でも、変数を宣言しただけでは、まだ実体は存在しないことに注意してください。 変数の中に実体が存在するのは、代入を行ってからです。(ただし、オブジェクト型変数にnullを代入した場合は、実体は実質的に存在しないことになりますが) > Cのポインタ渡しとは違うのでしょうか 「参照渡し」は、「ポインタ渡し」と同じことです。ただ、Javaではポインタとは言わずに参照という言葉を使うのです。 > String a = new String();とString a; > ではメモリ管理が変わるのでしょうか メモリ管理が異なるというより、処理の内容全体が異なります。 String a; というのは、変数を宣言しただけです。 まだ代入していないので、変数の中身を取り出すことはできません。(この点C言語とは若干異なります) String a = new String(); では、大きく分けて三つの処理が行われます。 一つ目は、上と同じく、変数領域の確保です。 二つ目は、新しいStringのインスタンス(実体)の生成です。 三つ目は、生成した文字列インスタンスを代入することです。(厳密には、代入されるのはインスタンスそのものではなくてインスタンスへの参照です) 上と異なる点は、代入《までも》行われる点です。つまり、このあと変数の中身を取り出すことができます。 最後に、 a = a + "bbb"; についてですが、これは、 「二つの文字列をつなげて、新しい文字列インスタンスを作り、それを代入する」 ということが行われます。 (厳密な処理内容は、4番目の回答でSephyさんがおっしゃっている通りですが) 注意する点は、もともと変数aに入っていた文字列インスタンスの中身が書き換えられるのではなく、まったく新しい文字列インスタンスが生成してそれが代入されるという点です。 > 関数teststrのString aの実体はコピーが渡されるているのでしょうか (Stringはオブジェクト型なので)渡されるのはあくまでも参照です。そして、変数の中身も参照です。 ただし、teststrメソッドの中で、 a = a + "bbb"; としても、これはteststrメソッドの中で使われている変数aに文字列を代入し直しただけです。 つまり、teststrメソッドの変数aの中身は、"aaa"への参照から"aaabbb"への参照に代わりますが(もちろんこの二つの文字列は別なインスタンスです)、mainメソッドの変数aの中身は、aaa"への参照が代入されたままだということです。

sha-girl
質問者

お礼

>String a; というのは、変数を宣言しただけです。 >まだ代入していないので、変数の中身を取り出すことはできません。(この点C言語とは若干異なります) 確かにString aの時点ではnull状態ですね。 a = "aaa";をはじめて実行したときにインスタンスが確保されるということですね? あと補足なんですがインスタンスが確保されているものに a = null;とかするのは問題あるでしょうか? なんとなくメモリリークが起きる気がするのですが、、

  • Sephy
  • ベストアンサー率35% (7/20)
回答No.4

teststrメソッド内の a = a + "bbb"; のところで混乱しているのだと思います。 Stringの代入 a = a + "bbb"; は、コンパイラによって a = new StringBuffer().append(a).append("bbb").toString(); のように書き換えられます。ここで新しくStringBufferがnewされていることに注目してください。

sha-girl
質問者

お礼

ご回答ありがとうございます。大変参考になりました。 コンパイラが値渡しであるかのように見せかけているのですね? Stringというのは特別なクラスなのでしょうか? 或いは他にも、StringとStringBufferの関係のクラスってあるのでしょうか?

  • tekebon
  • ベストアンサー率62% (36/58)
回答No.3

intやfloatなどはプリミティブタイプですのでその値が直接格納されます。 引数渡しにおいては値のコピーが渡されることになります。 そして、Stringはクラスですので引数渡しは参照渡しになります。 しかしStringはデータを変更できません。 String str="Hello"; str+=" world"; とした場合には、まず最初に「Hello」というデータもつStringオブジェクトを strが参照することになります。 しかし、その後「world」という文字列を追加しようとしても、もとのオブジェクトとは別の 「Hello world」というデータをもつオブジェクトを参照することになります。 よって「一応」参照渡しとなっていますが呼び出し元のオブジェクトを書き換えることが出来ません。 (値を見ることは出来ますが) 文字データを参照で扱う場合にはStringBufferクラスを使います。 プリミティブタイプを参照で扱うためにはIntegerクラスやDoubleクラスなどがあります。

sha-girl
質問者

お礼

ご回答ありがとうございます。 例えば下記この場合 関数teststrのString aの実体はコピーが渡されるているのでしょうか? class test{  public static void main(String[] args) throws NumberFormatException,IOException{   String a;   a = "aaa";   System.out.println(a);   teststr(a);   System.out.println(a);   return;  }    public static void teststr(String a){   a = a + "bbb";   System.out.println(a);  } }

sha-girl
質問者

補足

import java.util.Vector; class test{  public static void main(String[] args) throws NumberFormatException,IOException{   String a;   a = "aaa";   System.out.println(a);   teststr(a);   System.out.println(a);   return;  }    public static void teststr(String a){   a = a + "bbb";   System.out.println(a);  } } ちょっと混乱してきました。 これは参照渡しですよね? 先ほどのプログラムを String a = new String(); に書き換えると、最後のaaaが表示されなくなりました。 ただのString a;でも実体はありますよね? String a = new String();とString a; ではメモリ管理が変わるのでしょうか?

  • UKY
  • ベストアンサー率50% (604/1207)
回答No.2

intやdoubleなどの値型は必ず値渡しです。 Stringや配列などのオブジェクト型は必ず参照渡しです。 > 関数にStringを渡したとき内部的に自分のコピーを作っているということなのでしょうか そのようなことはありません。メソッド(Javaでは関数とは呼びません)に文字列を渡しても、インスタンスが勝手にコピーされるということはありません。なぜなら、参照渡しだからです。 見た目が値渡しであるかのように見えるのは、文字列のインスタンスの内容を書き換えられないからです。

sha-girl
質問者

お礼

ご回答ありがとうございます。ひょっとすると私が「参照渡し」という言葉の定義を勘違いしているのかもしれません。 Cのポインタ渡しとは違うのでしょうか?

  • ranx
  • ベストアンサー率24% (357/1463)
回答No.1

Stringも一応参照渡しだったと思います。 ただ、値を書き換えられないだけです。 値を書き換えたければ、ちょっとずるいですが、 要素数1の配列にすればできます。

sha-girl
質問者

お礼

早速のご回答有難うございます。 ところで「一応参照渡し」というとどういうことでしょう? 関数にStringを渡したとき内部的に自分のコピーを作っている ということなのでしょうか?

関連するQ&A

  • 参照・値渡しについて

    下記プログラム(ソース1)を実行すると「1」という値が出力されます。しかし、2行目をprivate static int a;とすると「0」という値が出力されます。 オブジェクトは参照渡しで基本データ型は値渡しと思ったのですが、2行目の値をString型で行ったところ全く変更されていない値が出力されました。(ソース2) 一体どういうことでしょうか? 回答のほどよろしくお願い致します。 (ソース1) public class X{ private static int a[] = new int[1]; public static void main(String []args){ modify(a); System.out.println(a[0]); } public static void modify(int a[]){ a[0]++; } } (ソース2) public class X{ static String a = "a"; public static void main(String []args){ modify(a); System.out.println(a); } public static void modify(String a){ a = "b"; } }

    • ベストアンサー
    • Java
  • javaでは基本型の参照渡しは無理ですか?

    先日のjavaの授業で値渡しと参照渡しについて学びました。 授業では オブジェクトは参照渡しになり 基本型は値渡しにされる(参照渡しは不可能) と教えられました。 オブジェクトを値渡しにできないのはなんとなく納得できたのですが 基本型を参照渡しにできないのが納得できません。 そこで 1.基本型を参照渡しにすることはできないのか? 2.基本型を参照渡しすることができないのはなぜか? 3.オブジェクトを値渡しすることができないのはなぜか? の3点を教えて頂きたいです。 よろしくお願いします。

    • ベストアンサー
    • Java
  • javaの参照渡しの問題

    javaの参照渡しの問題 javaの初心者で問題集で勉強しているのですが、 以下の問題の参照渡しの違いがわかりません。 ------------------------------------------- ソース1 class Samplea{ public void method(){ int b[] = new int[2]; set(b); System.out.println(b[0]); } public void set(int[] b){ b[0] = 30; } } class Sample{ public static void main(String srgs[]){ Samplea x = new Samplea(); x.method(); } } 実行結果 30 ------------------------------------------- ソース2 public class Test{ public static void main(String args[]){ String s1= "Hello"; String s2= "Good-Bye"; change(s1,s2); System.out.println(s1); } static void change(String s1,String s2){ s1 += ",Tom"; s1 = s2; } } 実行結果 Hello ------------------------------------------- 配列とString型は両方とも参照型なので ソース1の実行結果が「30」ならば、 ソース2の実行結果は「Good-Bye」になると思いました。 どなたか教えていただけないでしょうか。 宜しくお願いいたします。

    • ベストアンサー
    • Java
  • 参照渡しで分からないことがあります。

    参照渡し 参照渡しで分からないことがあります。 以下のコードです。一部抜粋のコードです。 > class CSample > { > public: > CSample(){ m_num = 123; } // コンストラクタ > int& get(){ return m_num; } // メンバ変数を参照戻し > private: > int m_num; > }; > ~~~~~~~ >int& alias1 = get(); >alias1 *= 2; >int& alias2 = get() + alias1; // このようにブロックの途中で宣言できる ~~~~~~~ このコードの中の >int& alias2 = get() + alias1; が分からないところです。 参照をalias2に設定しているところだと思われますがget()の参照戻しのアドレスと alias1の参照のアドレスと2つの参照を設定しているのが分かりません、この2つは同じアドレスをさしているのでこのサンプルでは支障はないように思えますが。 この場合は、式右辺のget()+alias1の2つの参照を足しているのが分からないので教えてください。 なおこのコードが掲載されているサイトは以下です。 http://www.geocities.jp/ky_webid/cpp/language/015.html

  • 参照渡しの間違ったコードの謎?

    現在、C++勉強中の初心者です。テキストの練習問題で値呼び出しと参照呼び出しを比較する問題に取組中に、以下のような間違ったコードを書いてしまいました。 (参照渡しのコードで、返値を設定してしまいました) ---------------------------------------- #include<iostream.h> int tripleCallByValue(int); int tripleByReference(int &); main(){ int count; cout << "count = " ; cin >> count; cout << "コピー: " << count << "\t" << tripleCallByValue(count) << endl; cout << "参照 : " << count << "\t" << tripleByReference(count) << endl; cout << "コピー: " << count << "\t" << tripleCallByValue(count) << endl; cout << "参照 : " << count << "\t" << tripleByReference(count) << endl; return 0; } int tripleCallByValue(int num){ return num *= 3; } int tripleByReference(int &num){ return num *= 3 ; } ---------------------------------------- 入力値を3倍するプログラムで、3を入力した場合の結果は   仮引数  返値 コピー  3     9 参照  9   9 コピー 9   27 参照  27   27 となりました。(Borland C++コンパイラ使用) わからないのは、2行目の参照渡しの仮引数が'9'であることです。1行目は値渡しなので、仮引数は影響を受けず、'3'が次の参照渡しの仮引数として使用されるとおもってました。 何が起こっているのか、まったく理解できません。これは、意味のある間違いでしょうか?だとしたら、どんな処理が行われた結果でしょうか? 解説よろしくお願いします。

  • C++ 関数プロトタイプと値渡し・参照渡しについて

    次のコードは、入門書にあった値渡しのサンプルです。 値渡しなので、a=5 ,b=10が出力されます。 void swap(int x,int y); //←抜けていた int main(){ int a=5; int b=10; swap(a,b); cout<<"a="<< a << "\n"; cout<<"b="<<b<<"\n"; } void swap(int x,int y){ int tmp=x; x=y; y=tmp; } しかし、自分で入力したところ何故かa=10,b=5が出力されました。 (VisualC++2008で実行しました。) よく見てみると、上記1行目の関数プロトタイプが抜けていました。 入門書を読んだ限りでは、次の2点が理解できません。 (1)main関数の後ろにswap関数があり、関数プロトタイプが無いのでコンパイルエラーになるはずなのにならない (2)値渡しのはずなのに参照渡しと同じ結果になる よろしくお願いします。

  • PHPは何故値渡しより参照渡しの方が遅いのでしょうか。

    PHPは何故値渡しより参照渡しの方が遅いのでしょうか。 値渡しの場合全て内容をコピーしなければならないので遅くなるように思うのですが。

    • ベストアンサー
    • PHP
  • PHP5での参照渡しについて

    お世話になっております。 3点質問させて下さい。 1.PHP5での参照渡しについて PHP5では、参照渡しがデフォルトという記事を読んだのですが、classを使わず、以下のようにfunctionのみで記述した場合、参照渡しになっている気配がありません。 - $test = "テスト"; function a($a){ $a = "参照渡し"; } a($test); echo $test; - 結果:テスト &$aとすると参照渡しになりますが、classを使わない場合はPHP5のデフォルトが参照渡しというのを意識する必要は無く、&を用いた参照渡しを利用する形で良いのでしょうか? 2.オブジェクトについて オブジェクト=class だと思っても良いのでしょうか? また、独立した関数では無く、classを利用した方が良い場面というのはどういう時なのでしょうか? classやオブジェクト指向というものへの私の理解が足りてない事でこのような疑問を抱く事になっていると思います。 classやPHP5のオブジェクト指向について学習するのに便利な書籍やサイトなどあれば紹介して頂けないでしょうか? 3.$_POSTや$_GETについて 他の方のソースを見ていると、何かの処理後にPOSTの値を別の変数に入れている方が多いように思えます。 私もそれにならってPOSTの値をいじる場合は、 変数 = 関数($_POST["test"]); とするようにしています。 ですが、 $_POST["test"] = 関数($_POST["test"]); とするのは何か都合が悪い事があるのでしょうか? 要領を得ない質問で申し訳ありませんが、回答頂けましたら嬉しいです。

    • ベストアンサー
    • PHP
  • これは参照渡し・値渡ししてる事になりますか?

    Dim a As String Sub マクロ1() a = "test" Call マクロ2 a = Empty End Sub Sub マクロ2() MsgBox a End Sub これは参照渡し・値渡ししてる事になりますか? ByRefやByValを使わない限り、 参照渡しまたは値渡ししてるとは言えないのでしょうか? ご回答よろしくお願いします。

  • 参照渡し と ポインタ渡し

    参照渡し と ポインタ渡し はどういう時に使い分けるんですか? VOID型の自作関数内でメインのブール値を書き替えたいんだけど #include <iostream.h> void ref( int &b ) { b = false; } void ptr( int *b ){ ( *b ) = true; } main(){  bool b = true;  ref( b );  cout << b;  ptr( &b );  cout << b; } だとコンパイルエラーでした。 うまくいくソースを教えてください。

専門家に質問してみよう