###認識
Javaのメソッドについて教えることになりました。私の認識は以下のとおりです。
Javaの変数には「プリミティヴ型」と「参照型」がある。どちらもメソッドの引数として渡す場合は「値呼び」される。Javaに「参照呼び」は存在しない。
###質問
0. 「」の用語について解説をお願いします。そのうえで上の認識についてコメントをお願いします。
2. 他の言語はどうなのか。Visual Basicや、PL/SQLには「参照呼び」があると聞きました。他の言語で「値呼び」「参照呼び」のコード例を示してください。
3. 「値呼び」「参照呼び」以外に呼び出し方法がありますか。「名前呼び」や「正格」などのキーワードは知っていますが、それがどんなものかわかりません。その他、自由に記述してください。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答5件
0
メソッドについて誰に教えるのかが不明ですが、Java に参照呼びが無いならそこは教えなくていいと思います。これから参照型を教えるような生徒なら猶更です。
C# の場合、
C#
1int result; 2CalcSomething(out result);
以上のように result の参照を渡すことによって result の値を書き換えることができます。この場合 result は値型ですが、値型であろうと参照型であろうと関係ありません。参照型を通常の方法で渡した場合にはプロパティの変更はできますがそれを入れている変数の中身の変更はできません。
このことから、C# では参照渡しと値渡しが明確に区別され、参照型や値型の区別とは無関係であることがわかると思います。同じライブラリを使っている VB.NET でも同様です。
この概念がそもそもない言語において、しかも参照型と値型の区別もあいまいな人にこのことを教える必要性はないと思いますし、それどころかいたずらに混乱を招くだけだと思います。
追記
「参照呼び」という名前ですが、どの程度使われている言葉なのかは知りませんが、私は違和感を覚えます。呼ばれているのはメソッドであってパラメーターではありません。パラメーターは渡されるものです。
たとえば次のようなコード
C#
1int result; 2DoSomething(out result, 100);
この場合、result は参照渡しされていますが、100 は値渡しされています。これを参照呼びと言うなら、値渡しされている 100 の立場はどうなるのでしょうか?
投稿2017/03/17 00:05
編集2017/03/17 00:12総合スコア28660
0
解説をお願いします
ご質問に書かれた質問者さんの解釈は「あってます」ということはできますがそれで何が得られるのだろうとも思ってしまいました。もう少し自分の解釈に感じている不安を具体的に述べた方がよいと思います。
参照渡しについて思うことをコメントします。
言語仕様をある程度詳しく理解し普段から活用しているレベルの人たちの中で「Javaは参照渡しがないわけだが・・・」と会話をするのと、言語を学び始めの人たちが集まって「Javaには参照渡しがないらしいけど参照渡しっていってるサイトもあるよ???」と会話するのでは、前者の文脈が明確なのに対し後者はそうでないため「混乱を解消できる適切なアドバイスは何か」については慎重に考えるべきと思います。生徒の習熟度や理解度によっても結果は違い、例えば「Javaでは参照型を示す値は実体への参照なんだよ」というような説明をしただけで「なるほど」とわかってくれるかも知れませんし「先生何いってるかわかんないよ」という結果にもなりかねません。後者の生徒は「実体」「参照」「値」の意味が頭の中で曖昧な状態なのでしょうからその言葉を使っても理解できないのは当然でしょう。
少なくとも初心者に「参照渡し」「値渡し」の概念をある程度のプログラミング知識・経験なしに最初から教えようとするのは難しい気がします。まずは「こう書くと何が起こるか」を教えた上で「実体」「参照」「値」についてJavaの構文や意味と関連させながら説明するのがよいのではないでしょうか。
またこれらの用語は言葉では伝わりにくい面もあるので「情報がどのような形で記録されていてこう書くとこのように渡される」とホワイトボードにメモリーレイアウトのような絵を書くなどして説明すると理解の助けになると思います。
他の言語で「値呼び」「参照呼び」のコード例を示してください。
C++, C#, Visual Basic等々例を示すことも容易ではありますが・・・失礼ながら、教えるために知ろうとするなら調べようするのが相応の態度だと思います。
「名前呼び」や「正格」などのキーワード
そのキーワードで調べればなんらかの意味は見えてくるように思います。調べた上で何を掴んだか・何が不明かについて言及されればもう少し有意な質問になる気がしますが・・・
「名前渡し」「正格」はいずれも実引数の評価タイミングに関する話だと思いますが、参照渡し・値渡しと同時に教えると混乱をきたしそうな気がします。Javaでは「名前渡しはなく実引数は正格」と言えはするでしょうがそれだけ教えても不十分でしょう。確かに言語仕様にはないのですがこれらの手法が意図することを達成するためのテクニックは考えられるからです。あることをしようとしたとき「どのように記述できるか」を理解してからそれを積極的に採用した言語(例えばScalaとか)と比較する段階になったときに初めて「名前渡し」「正格」に言及しても遅くないのでは?
投稿2017/03/17 01:55
総合スコア18394
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
ベストアンサー
教える対象者がプログラミング言語を知っているか、特にCやC++を知っているかどうかで大分教え方が異なるのですが、プログラミング初心者であることを前提に話をします。
###型(type)
変数(variable)に入るデータの値(value)の型(type)は大きく分けて二つです。
####プリミティブ型 (primitive type)
Javaの基礎となる型です。整数(byte, short, int, long, char)、浮動小数点数(float, double)、真偽値(boolean)が該当し、これしかありません。これらは変数にそのままの値で代入されます。
「変数は箱である」というのを聞いたことがあるかと思います。全てのプログラミング言語でそうであるとは言えませんが、Javaでは正しいです。ある変数を宣言したとき、そこにはひとつの箱が作られます。その箱の中にこれらの値が入る形になります。なお、箱は大きさや形が決まっているため、宣言したときの型の物しか入りません。
Java
1int a = 1;
上はintが入るような形・大きさのa
という箱を用意して、1
というリテラルが表す整数を入れると言うことです。
※ charは文字を表す型ですが、扱いとしては符号無しの整数です。また、charは0〜65535(\u0000〜\uffff)までしかないため、Unicode文字全て(U+0000〜U+10FFFF)を単独で表すことはできません。
####参照型 (reference type)
プリミティブ型以外は全て参照型です。クラスまたはインターフェス型(class or interface type)、型変数(type variable)、配列型(array type)の三つに分かれます。クラスまたはインターフェス型(class or interface type)はさらにクラス型(class type)とインターフェース型(interfarce type)にわかれます。
クラス型とインターフェース型はよくあるオブジェクトを表す型です。これらの型では変数に参照値(reference value、単に参照/referenceと言うこともある)を入れます。特別な値としてオブジェクトが無い事を表すnull参照も入れることができます。先ほど「変数は箱である」と言いましたが、そう、この箱に入るのがこの参照値です。オブジェクトそのものが変数に入っているのではありません。参照値はオブジェクトを示す物(pointer)です。Javaでは、オブジェクトそのものに直接アクセスはしておらず、常にこの参照値を経由して、オブジェクトの中身にアクセスしています。
参照値とあるように何らかの値です。整数のような値であると思ってください。この値単独で見ても、指し示すオブジェクトがどのようなものかはわかりません。あくまで、変数に入っているのはただの値だけで、オブジェクトの実体は別に存在し、そこへ辿り着くためのヒントだけが書いてあると言うことです。
なお、何でも入れられるというわけではなく、変数を宣言したときのクラスやインターフェースの型に制限されます。どういう風に制限されるのか、その回避策はどうなのかは、ポリモーフィズムの話をしなくてはならなくなりますので、今回は割愛します。
型変数はジェネリックで使用する特殊な型です。実行時にクラス型やインタフェース型、配列型に置き換わる物です。ジェネリックを学ぶときに説明があると思います。
配列型は配列のための型です。これもクラス型やインターフェース型と同じく、参照値を変数に入れることになります。配列を学ぶときに説明あると思いますが、クラス型やインターフェース型と同じと思っていればだいたい問題ありません。
###評価戦略
関数やメソッドの呼び出しをどう解釈し、引数をどう扱うかは言語によって異なり、評価戦略と言います。
####値渡し、値呼び(call by value, pass by value)
※ 日本語では「値呼び」よりも「値渡し」と言われることが多いですが、示している動作は同じものになります。**別の物ではありません。**他の方法についても言葉の違いは同様です。
関数(Javaにはメソッドしかありませんが、汎用的に説明するため関数と表現します)を呼び出した時に、引数が値として関数に渡されるものをいいます。なお、値はコピーして渡されますので、渡し後も元の変数には値はそのまま残っています。
プリミティブ型では値そのものが変数に入っていますので、その値そのものです。参照型では参照値が変数に入っていますので、その値そのものです。値しか渡されていませんので、呼び出し先の関数でどのような操作を行っても変数の中の値が変更されることはありません。
参照型で説明したとおり、変数に入っているのは参照値であり、オブジェクトではないことに注意してください。参照値を渡すことで、オブジェクトそのものは変更できます。詳しくは後述の参照の値渡しで説明します。
####参照渡し、参照呼び(call by reference、pass by reference)
関数を呼び出した時に、引数が参照としてメソッドに渡されるものをいいます。ここでの参照はJavaとの参照値とは異なる概念ですので、注意してください。Javaにはない機能です。
渡される参照は変数そのものへの参照です。別の見方をすると、呼び出された先の関数で、引数に指定した変数の別名として、仮引数が使えるようになるというものです。別名ですので、呼び出される元の変数を変えることができます。
この機能を実装している言語はそう多くはありません。メジャーどころではC++、.NET系(C#、F#、VB.NET)、Perl、PHPです。値渡しとの違いは下記を参考にしてください。
C++
1#include <iostream> 2// 値渡し 3void funcByVal(int a) 4{ 5 a = 1; 6} 7// 参照渡し 8void funcByRef(int& a) 9{ 10 a = 1; 11} 12int main() { 13 int x = 0; 14 std::cout << "x: " << x << std::endl; 15 funcByVal(x); // 値渡しなのでxは変更されない。 16 std::cout << "x: " << x << std::endl; 17 funcByRef(x); // 参照渡しなのでxは変更される。 18 std::cout << "x: " << x << std::endl; 19 return 0; 20}
上記をpaiza.ioで実行
####参照の値渡し、共有渡し、共有呼び(pass by value of reference、call by sharing、call by object、call by object-sharing)
実装上は値渡しの一種です。「共有」とあるように呼び出し元の呼び出し先でオブジェクトを共有します。参照渡しとは違って、値を共有しているわけでも、変数を共有しているわけでもありません。変数や変数に入っている値は独立していますが、その値が示す先が同じであると言うことです。
参照の値渡しでは、オブジェクトを共有することで、オブジェクトそのものの変更が可能になります。呼び出し先で共有しているオブジェクトを変更すると、呼び出し元の変数が保持している値はそのままですが、その値が指し示す先のオブジェクトには変更が反映されているということです。
Javaでは参照型でのみ、参照の値渡しになります。実際は値渡しですが、動作としては参照の値渡しになるというわけです。値渡ししかないCでも、ポインタを渡す事で、この参照の値渡しと同じになります。
Python、Ruby、JavaScriptなどオブジェクト指向言語の多数で採用されている方法です。ただ、実装は必ずしもJavaのように参照値を渡しているとは限りません。もし、オブジェクトがイミュータブル(変更不可)の場合、単純な値渡しと参照の値渡しは言語仕様上で動作に違いが出ません。そのため、一部のオブジェクトは値渡しになっている場合もあります(Rubyの即値がその例)。その意味では参照の値渡しという表現は正しくないのかも知れませんが、言葉のわかりやすさからこういう場合が多いと感じます。
####その他
複数呼びの結果返し(call by copy-restor)、名前呼び・名前渡し(call by name、pass by name)、必要呼び・必要渡し(call by need、pass by need)、マクロ展開呼び(call by macro expansion)などがあります。概要はWikipdeia[ja]:評価戦略を参考にしてください。
Haskell等の遅延評価を行う言語では必要呼びは重要な概念です。考え方によっては、ラムダ式の中身(ラムダ式自体ではなく、ラムダ式の中にある各式)は必要呼びになっていると言えます。
投稿2017/03/17 23:50
総合スコア21735
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
まあ、大雑把に述べるとこんな感じ
1
プリミティブ型:クラスでない単独の変数型(new不要)
参照型:クラスの型(オブジェクト生成時はnewが必要)
値呼び(多分「値渡し」の意味):関数の中で仮引数を書き換えたところで実引数は変わらない。
参照呼び(多分「参照渡し」の意味):関数の中で仮引数を書き換えると実引数も影響を受ける。
Cやjavaの関数は「値渡し」となっております。が、Cではポインタを介すことで参照渡しに近いことを実現できるようになっております。また、javaの参照型も性質的にはCのポインタに近いのでこれに類似した機能があります。
2
C++では&記号で参照渡しとなります
void set100(int & x){x = 100;}
こんな感じ
3
呼び出し型のルールはいろいろあります。が、実引数と仮引数の関係についてのルール以外のものまで言い出したらキリがありません。
投稿2017/03/17 14:05
編集2017/03/17 14:07総合スコア4830
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
退会済みユーザー
2017/03/22 21:59
0
投稿2017/03/17 00:30
編集2017/03/17 00:33総合スコア70
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
退会済みユーザー
2017/03/22 21:52
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/03/17 00:22
2017/03/17 05:02
2017/03/17 13:31
2017/03/17 22:45
退会済みユーザー
2017/03/22 21:51