• ベストアンサー

二つの変数の値を入れ替えるメソッドを作成できますか?

メソッドに二つの同じ型の変数を渡し、その値を入れ替えるメソッドを作りたいのですが、Java では、関数の参照渡しができないためにできません。 できるだけシンプルな記述にしたいのですが、何か方法のわかる方、降りましたら書き込みお願いします。 ちなみにクラスをひとつ作ればできることはわかっています。 <例> public class MainProc { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub ObjectPair objPair = new ObjectPair(); objPair.setObjValue1(new Integer(1)); objPair.setObjValue2(new Integer(2)); objPair.ReplaceValue(); System.out.println("intValue1:"+objPair.getObjValue1()); System.out.println("intValue2:"+objPair.getObjValue2()); } } public class ObjectPair { private Object objValue1 = null; private Object objValue2 = null; public void ReplaceValue(){ Object objWork = objValue1; objValue1 = objValue2; objValue2 = objWork; } public Object getObjValue1() { return objValue1; } public void setObjValue1(Object objValue1) { this.objValue1 = objValue1; } public Object getObjValue2() { return objValue2; } public void setObjValue2(Object objValue2) { this.objValue2 = objValue2; } } よろしくお願いします。

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

  • ベストアンサー
  • aton
  • ベストアンサー率47% (160/334)
回答No.6

もはや当初の質問からは外れてしまっているような気もしますが。 >このような意味で、名前とそれが表す意味は、 >できるだけ厳密に対応させることがほ保守性を >高める上で大切かなと私は思っているのです。 オブジェクト指向的には正しいと思います。実際JavaのExceptionクラスの大半は,そういう目的のために作られているように思われます。 #「保守性」は,try~catchのやりやすさも含むとして。 >話は戻るのですが、戻り値をひとつにまとめることが >関数型言語の考え方とありましたが、その言語は、 >何と言う言語なのでしょうか? すいません。この表現は正確ではありませんでした。関数型言語では,「引数の値を書き換えることで複数の戻り値を実現する」ことが無いだけで,値としての戻り値は複数あっても定義上は問題ないと思います。 ちなみに私はプログラミング言語については門外漢で,関数型言語はLispしか使ったことがありません。Lispでは,関数の戻り値は基本的にはプリミティヴ型の値一つか,listが一つか,どちらかなので,「戻り値が一つ」という条件は満たしてはいると思いますが…。 関数型言語について詳しく知りたければ,今だとHaskellについて調べてみるのが良いのではないでしょうか? http://ja.wikipedia.org/wiki/%E9%96%A2%E6%95%B0%E5%9E%8B%E8%A8%80%E8%AA%9E >例えば、デザインパターンで振る舞いクラスと言うのが出てきて、 >「ん?」と思ったのです。学会とかでは、振る舞いと言う概念は、 >当時、よく研究されていた概念なのかもしれないんですが、 >それって結局、プロシージャじゃないのという印象を受けたのです。 「振る舞い」もクラス化しようと思えばできるところが,オブジェクト指向のいいところではないでしょうか? 例えばJavaにはreflectionという機能があって,そのためのものとしてjava.lang.Methodというクラスがありますが,これを使うと,例えばあるクラスにメソッドを追加するというようなことを,動的に(=プログラム実行中に)行うことも可能になります。 http://www.wakhok.ac.jp/biblion/1997/javadoc/beansdoc/node19.html Javaの初期の頃にあったHORBなどのエージェント・プログラミング環境は,このreflectionを応用していたのではなかったかと記憶しています。またEclipseなどでも,例えばメソッド名を入力すると取りうる引数の型を教えてくれる機能の辺りは,やはりreflectionを使っているのではないかと思います。 #完全に余談ですが。

den2007
質問者

お礼

とても勉強になりました。ありがとうございました。

すると、全ての回答が全文表示されます。

その他の回答 (5)

  • aton
  • ベストアンサー率47% (160/334)
回答No.5

No.4です。 >この場合も Java では、「戻り値は、ひとつのクラスにまとめて >ください」と言われている気がします。 基本理念はその通りだと思います。実際,関数型言語では厳密にその通りです。でもJavaであれば,引数の中身は書き換え可能なので,例えば,ある整数列を奇数と偶数に分けるようなメソッド(これは2つの戻り値を必要とします)を書く時, static void oddEven(List<Integer> in, List<Integer>, oddOut, List<Integer> evenOut) { oddOut = new LinkedList<Integer>(); evenOut = new LinkedList<Integer>(); //本当はiteratorで書くのが良いんだけど面倒なのでforループで Integer iv = null; for(int i = 0; i < in.size(); i++) { iv = in.get(i); if ((iv.intValue() % 2) == 0) { evenOut.add(iv); } else { oddOut.add(iv); } } } static void main(String[] args) { List<Integer> input = Arrays.asList(new Integer(2),new Integer(8),new Integer(9),new Integer(3),new Integer(1),new Integer(6),new Integer(0)); List<Integer> oddOutput; List<Integer> evenOutput; oddEven(input, oddOutput, evenOutput); } などとすれば,2つの戻り値を得ることも可能です。C++などでも,複数の戻り値を得るときは,基本的にこの方法をとるはずです。 >でも、Java は、「何でもかんでもクラスにしてしまいましょう」 >という気がして、「それってどうなの。。。」という疑問もあり >ます。 Javaはオブジェクト指向言語ですから,「何でもかんでもクラスにしてしまう」のは当然かと…。RubyなんかJavaよりもっと徹底しています。クラスにするのは,再利用性を高めるためですが,クラスにしたからといって再利用しなければいけないわけではないので,「何でもかんでもクラスにしてしまう」ことが悪,というのはよくわからないのですが。 >Visual Basic .Net を見てみると、アプリケーションを構築する >ために必要なクラスは、はじめから準備されているなという印象 >を受けます。 Javaもかなり揃っていると思いますが…。例えば,ObjectPairクラス相当の処理は,既存のjava.util.LinkedListクラスを使って以下のように書くこともできます。 static LinkedList swap(LinkedList in) { if (in.size() != 2) throw new Exception(); LinkedList res = new LinkedList(); res.add(in.getLast()); res.add(in.getFirst()); } static void main(String[] args) { LinkedList objPair = new LinkedList(); objPair.add(new Integer(1)); objPair.add(new Integer(2)); LinkedList outObjPair = swap(objPair); System.out.println("intValue1:"+outObjPair.getFirst()); System.out.println("intValue2:"+outObjPair.getLast()); } mainメソッドの複雑度は殆ど変わっていないと思います。 >なのでプログラマや設計者が独自にクラスの集合を作って >しまうのは、可読性というか保守性の観点では、あまり良 >くないのではと思うのです。 車輪の再発明は良くないことなので,それはおっしゃる通りだと思います。ですからJavaにも多くのクラスを含む標準ライブラリー(java.*,javax.*)があるのだと思います。

参考URL:
http://java.sun.com/j2se/1.5.0/ja/docs/ja/api/java/util/LinkedList.html
den2007
質問者

お礼

そうですね。既にあるクラスをわざわざ別の名前で作ることはないと思います。 今回の場合、ObjectPair というのは、厳密には、List とは異なります。 ObjectPair では、要素を二つしか持たないからです。 このような意味で、名前とそれが表す意味は、できるだけ厳密に対応させることがほ保守性を高める上で大切かなと私は思っているのです。 戻り値の集合のクラスなら SetOfReturnValues とかいうクラスの名前がいいんじゃないかなとか、個人的には思ったりします。 それも個人的な思い込みの域は出ないかもしれないですね。 話は戻るのですが、戻り値をひとつにまとめることが関数型言語の考え方とありましたが、その言語は、何と言う言語なのでしょうか? 関数型言語と言うと私の場合、ML しか分からないのです。 これも勉強不足ですが。。。。 ML には、戻り値としてユーザー定義型のようなものは返せない気がするのですが、そんなことはないのでしょうか。 「何でもかんでもクラスにするのは。。。」というのは、オブジェクト指向の本を読んでいたりして「そんなのクラスにするなよ。」という印象を受けることがあったからです。 例えば、デザインパターンで振る舞いクラスと言うのが出てきて、「ん?」と思ったのです。学会とかでは、振る舞いと言う概念は、当時、よく研究されていた概念なのかもしれないんですが、それって結局、プロシージャじゃないのという印象を受けたのです。 プログラムの基本単位がクラスなのだからなんでもかんでもクラスにするのは、自然なことなのかもしれないですね。

すると、全ての回答が全文表示されます。
  • aton
  • ベストアンサー率47% (160/334)
回答No.4

●所謂swap(a,b)をJavaで実現する方法について 複雑な方法でもよければ,introspectionを使ってオブジェクトの中身を全て入れ替えれば(たぶん)できるのではないかと思いますが…。シンプルな方法では無理だと思います。当初はjava.lang.reference.*を使えばできるかと思ったのですが,結局これでは意味がなさそうです。他には,例えば static Object[] swap(Object a, Object b) { Object[] res = new Object[2]; res[0] = b; res[1] = a; return res; } static void main(String[] args) { Object a = args[0]; Object b = args[1]; Object[] res = swap(a,b); a = res[0]; b = res[1]; } みたいな方法もありますが,これではご要望にお応えしてないでしょうし。 ●Javaに引数の参照渡しがない理由 計算機言語論的な観点からは,おそらくこのあたり↓ http://ja.wikipedia.org/wiki/%E5%BC%95%E6%95%B0 に書かれているように,関数(≒メソッド)が副作用を持たないようにという考えに基づくものではないかと思います。C++の複雑さへの反省というよりは,関数型言語のより進んだ考え方を取り入れたものではないでしょうか? オブジェクト指向的にも,隠蔽の理念からは,副作用が無いほうが正しいように思われる(∵例えば副作用があるとメソッド内の処理が失敗した時,内部の手続きがどうなっているかを知らないと対処が難しい)ので,そういう理由かもしれません。 また,このページ↓ http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-list/620 に参照渡しがしたい時として, (1)オブジェクトのサイズが大きい時 (2)複数の戻り値をメソッドから受け取りたい時 (3)複数の変数に対する操作を抽象化したい時(例:swap(a,b)) などが挙げられているのですが,(1)はRuby同様Javaでも問題ありませんし,(2)もRubyのようなことはJavaではできませんが,所謂Out引数を与えることで問題なく解決できます。 そうすると残るは(3)なのですが,私なりにいろいろ考えてもswap以外にこういうことをしたい例を思いつけないのです。それに,上記ページでは(3)へのRubyでの解決策として, a, b = swap(a, b) が取り上げられているのですが,これって私が最初に書いたコードとあまり差が無いように見えるのです。もちろんこれは参照渡しでもなんでもなく,どちらかというとメソッドの戻り値が配列の場合それを順次受け取れるよう記述できるという syntax sugar 的なもののように思われるのですが,単にswapを簡単に実現するだけならこれでも十分そうです。 長々と書きましたが,何が言いたかったかというと,参照渡しの実際の使い途はswapぐらいしかなさそうで,だとするとswapのためだけに参照渡しのような機構を入れるのはコスト面で割に合わないのではないかということです。 もちろん,swap以外にも参照渡しでしかできない重要な処理があれば,別なのですが。

参考URL:
http://ja.wikipedia.org/wiki/%E5%BC%95%E6%95%B0, http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-list/620
den2007
質問者

お礼

とても勉強になりました。ありがとうございました。 私としては、これ以上、簡単な記述がないのなら、自分ではじめに記述した ObjectPair クラスのようなもの、又は、CommonLibs クラスという名前でもいいかもしれないのですが、こんなクラスが分かりやすいのかなという気がしています。 自画自賛ですが。。。。 > (2)複数の戻り値をメソッドから受け取りたい時 この場合も Java では、「戻り値は、ひとつのクラスにまとめてください」と言われている気がします。 その方が分かりやすくなるのかもしれないですね。 でも、Java は、「何でもかんでもクラスにしてしまいましょう」という気がして、「それってどうなの。。。」という疑問もあります。 Visual Basic .Net を見てみると、アプリケーションを構築するために必要なクラスは、はじめから準備されているなという印象を受けます。 私は、アプリケーションの分野によって、必要なクラスというのは、限られてくるのかなと言う気がしています。 なのでプログラマや設計者が独自にクラスの集合を作ってしまうのは、可読性というか保守性の観点では、あまり良くないのではと思うのです。

すると、全ての回答が全文表示されます。
  • den256
  • ベストアンサー率70% (7/10)
回答No.3

回答いただきありがとうございます。 不変オブジェクトというのは、始めて聞きます。勉強不足ですみません。 不変オブジェクトというのは、「値を変更するメソッドのないクラスから生成されたオブジェクト」という理解でいいのでしょうか? 「値を変更したければ、オブジェクトごと入れ替えろ!」というクラスなのかな。 それは置いといて、 私は、「参照渡しができたほうが便利な関数が作れるんじゃないか」、と思っていたのですが、その機能がないのは、Java のそれ以前の言語に対するアンチテーゼ「参照渡しなんてなくてもいいじゃん」なのでしょうね。 参照渡しがなくなったのは、どういう配慮からなのでしょうか? 「Java は、C++ の簡略化版である」と聞いたことがあります。 それと 「C++ は、言語の実行が複雑で遅いので組み込みシステムには使えない」とも聞いたことがあります。 参照渡しがないのもアンチC++の理由によるのでしょうか?

すると、全ての回答が全文表示されます。
回答No.2

function void Replace(Object *objValue1, Object *objValue2){ となっていますが、引数がInteger型の場合なのでしょうか? Integer型の場合、String型と同じ不変オブジェクトの為、 期待される処理が行われません。 String型の場合ですが、下のURLを参考にしてみて下さい。 ご期待に添える回答でなかった場合、何度も投稿してすいません。

参考URL:
http://www.itarchitect.jp/technology_and_programming/-/27074-2.html
すると、全ての回答が全文表示されます。
回答No.1

getterでの値が変わればいいのであれば、こんなのどうでしょうか? public class ObjectPair { private boolean isBoo = true; private Object objValue1 = null; private Object objValue2 = null; public void ReplaceValue(){ isBoo = !isBoo; } public Object getObjValue1() { return isBoo ? objValue1 : objValue2; } public void setObjValue1(Object objValue1) { this.objValue1 = objValue1; } public Object getObjValue2() { return isBoo ? objValue2 : objValue1; } public void setObjValue2(Object objValue2) { this.objValue2 = objValue2; } } フラグで、getする値を決定します。

den2007
質問者

補足

この方法でも悪くはないのですが、私としては、C や Visual Basic のような参照渡しができる言語で関数に参照渡ししたようなものをイメージしています。 function void Replace(Object *objValue1, Object *objValue2){ } 見たいな感じです。 こういうのを Java では、どうやるのでしょうか? できないことにも理由があると思いますので、なぜできないのかが知りたいです。

すると、全ての回答が全文表示されます。

関連するQ&A