不安が募って毎日勉強しています。薬が効いていないのでしょうか。el(える)です。
今回は値型と参照型のお勉強をしていきます。
作成したクラスはint型などと同様に型として使えると勉強してきました。
ただし、一点だけ大きな違いがあるみたいです。
値型と参照型
C#には大きく分けて値型と参照型の2種類の型があります。
値型は変数に直接値を代入 します。 参照型は変数に値がある場所の情報を代入 します。値型には、int型、float型、double型、bool型などがあり、
参照型のものにはクラスや配列、コレクション、string型などがあります。
float[] weights = new float[7];
List<float> weights = new List<float>();
Player player = new Player();
new演算子を使ってインスタンスを生成し、変数に代入しています。
変数の箱にはインスタンスを直接入れているわけではありません。
new演算子によって作られたインスタンスはメモリ上のどこかに作られます。
変数の箱には、 インスタンスはメモリ上のあの位置にある という参照情報が代入されます。
なぜ参照型が必要なのか
クラスも配列も文字列も全て箱の中に直接値を入れれば、値型と参照型の違いを気にしなくてすむはずです。
参照型に分類される型の特徴は 変数の箱に入れる値のサイズが大きくなる可能性があるもの です。
string型は非常に長い文字列が入るかもしれませんし、
配列は膨大な数の要素を持つかもしれません。
クラスにしても非常に多くのメンバを持つかもしれません。
これだけたくさんの値を変数の箱の中に入れていた場合、
この変数を別の変数にコピーするだけで結構な時間がかかってしまいます。
そのため、箱に入れる値のサイズが大きくなる可能性のあるものは、
値を直接箱に入れるのではなく、 参照を介してインスタンスにアクセスする ようになっています。
参照型は効率的にコピーができる一方で、コピー時には注意も必要です。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace SampleRPG { class Program { static void Main(string[] args) { int num1 = 35; int num2 = num1; Console.WriteLine(num2); num1 = 0; Console.WriteLine(num2); } } }
値型の変数同士を代入する場合、右辺の変数の中に入っている値のコピーが
左辺に代入されるので、num1の値を書き換えてもnum2変数が書き換わることはありません。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace SampleRPG { class Program { static void Main(string[] args) { Player player1 = new Player("ほげ", 35); Player player2 = new Player("ふが", 100); player2 = player1; Console.WriteLine(player2.hp); player1.hp = 0; Console.WriteLine(player2.hp); } } }
Playerクラスのインスタンスを作り、player1に35、player2に100を設定しています。
player1を0にするとplayer2も0になります。
player1のインスタンスは○○にありますという参照情報 です。その結果、 player1とplayer2は同じインスタンスを参照 します。
player1を0に書き換えるとplayer2のhpも0に変わるのです。
このように参照型の値をコピーすると値型のような結果にはならないので、
注意が必要です。
メソッドに参照型をの値を渡す場合
メソッドの引数に引数を渡す場合にも値のコピーが発生します。
メソッドの引数に参照型を渡す場合にも同様の注意が必要です。
メソッドの引数に参照型の値を渡した場合、呼び出し元の変数とメソッド内の引数は同じインスタンスを指しているため、
メソッド内で値を書き換えると呼び出し元の変数にも影響 します。
refキーワード
メソッドの引数にrefキーワードをつけると、値型の変数を参照型のように渡すことができます。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Sample { class Program { static void Test(ref int val) { val = 10; } static void Main(string[] args) { int a = 3; Test(ref a); Console.WriteLine(a); } } }
Testメソッドの引数にrefがついています。
refをつけた引数は 参照渡し になり、値がコピーされるのではなく値の参照が渡されます。
引数にrefが付いているメソッドの呼び出しは引数を渡すときにもrefをつけます 。
終わりに
今回の勉強で値型と参照型があるのが分かりました。
この辺は適当に何とかしていたので、いい勉強になりました。
残りのお勉強はカプセル化と継承とポリモーフィズムとなりました。
あと少し。がんばって覚えていきましょう!
僕の欲しい本です。
ゆくゆくはアプリゲーム作りたいので、この本欲しいです。
もう少しお金に余裕があればなぁ。
それではまた次回。