とんちゃんといっしょ

Cloudに関する技術とか日常とかについて書いたり書かなかったり

初心者に変数を教える方法を考えてみる

変数とは

プログラミングにおいて、変数(へんすう、variable)とは、プログラムのソースコードにおいて、扱われるデータを一定期間記憶し必要なときに利用できるようにするために、データに固有の名前を与えたものである。 一人一人の人間が異なる名前によって区別されるように、一つ一つの変数も名前によって区別される。これにより、複数のデータを容易に識別することができる。変数を区別するための名前を特に識別子という。また一般に、変数が表しているデータをその変数の値(あたい)という。

http://ja.wikipedia.org/wiki/変数_(プログラミング)

簡単に言ってしまえば人間にはメモリ上のデータが目で見れないから、
なんかそれっぽい名前をつけておくことで可視化しようってことだと思う。
その際に同じ名前付けておくと区別がつかないので固有の名前をつけて区別してるって話。

変数の宣言

変数を宣言する際に動的型付け言語と静的型付け言語に違いが出てくる。
静的型付け言語のJavaの場合だとint型の変数を宣言する場合

// 型宣言 変数名 ;
int x;

Rubyの場合

# 変数名
x

ちなみに初期値を指定していない場合Javaだとプリミティブ型は0で初期化されてたはず。
Rubyだと初期化してない変数にアクセスするとnilが返ってくる。
ちなみに変数宣言は上記のもの以外にも以下のものが可能。

// 型宣言 変数名 = 初期値;
int x = 10;

// 型宣言 変数名 = new クラス名;
String x = new String();

// 型宣言 変数名, 変数名, ... ;
int x, y, z;

Javaだと複数個の宣言後に初期化が出来ないっぽい。
Rubyの場合だと

# 変数名, 変数名, ... = 初期値, 初期値, ...;
x, y, z = 1, 2, 3

# 変数名, 変数名, ... = [初期値, 初期値, ...];
x, y, z = [1, 2, 3]

変数への代入

基本的にはどのプログラミング言語も共通。
既に宣言済みの変数xに対して値を代入する場合

int x;

// 変数 = 値
x = 1;

こんだけ。


Javaでオブジェクトへの参照を渡すときはnew演算子とクラス名()を使う。

String x;

// 変数名 = new クラス名();
x = new String();

変数の命名規則

個人的な経験則からすると変数を宣言する際に気をつけるべきなのは、
その変数に格納されてる型が何なのかを把握しておくことだと思ってる。


プログラミングを始めたばっかりのころはその変数が何なのかよくわからずに扱って、
よくエラーの原因になってた(最近はコード補完機能とか使うから困らんけど)。


そういったことを避けるためにも、
変数にはどういったデータが格納されてるかがわかる名前をつけておくのが重要。
命名規則に関しては多分後でまとめて書くと思う。


とりあえずJavaだと変数はこんな感じかな。

  • 先頭:英字小文字, $, _
  • 先頭以外:英数字, $, _
  • 予約語は除く

変数の型

Rubyはすべてがオブジェクト型なので全部オブジェクトで考えて問題がない。
ただJavaの場合はプリミティブ型とオブジェクト型が存在する。


Javaのプリミティブ型

  • boolean
  • char
  • byte
  • short
  • int
  • long
  • float
  • double


Javaのオブジェクト型(例)

変数の参照と比較

上記のプリミティブ型は==で値を比較することが可能。
これはJavaの==が同一性(同じメモリ番地を参照している)の比較をしていることから、
Javaのプリミティブ型は同値==同一性が一緒になっていると考えられる(詳しくは確認してない)。
ちなみにプリミティブ型はメソッドを持ってないのでequals()はできないw

int x = 1;
if(x == 1){
  System.out.println("True");
}else{
  System.out.println("False");
}

// => True

オブジェクト型の場合は==は同一性、
equals()メソッドは同値性を比較しているので必ずしも一緒になるとは限らない。

String x = "hoge";
if(x == "hoge"){
  System.out.println("True");
}else{
  System.out.println("False");
}

// => False

if("hoge".equals(x)){
  System.out.println("True");
}else{
  System.out.println("False");
}

// => True

変数のキャスト

キャスト=型の変換。
変数は代入の際に明示的に型を指定してやる場合と暗黙的なキャストが可能。

double d = 1.2;
int i = 1;

d = (double)i;
double d = 1.2;
int i = 1;

d = i;

ただしキャストできない場合もある。

String s = "test";
int i = 1;

i = (int)s;  //error

むしろ出来ない場合の方が多い。


キャスト可能なのはスーパークラスの型に対してサブクラスを代入する場合と、
基本データ型のときぐらいしかないと思って問題はないと思う。

// スーパークラス型の変数にサブクラスのインスタンスを代入。
List<int> list = new ArrayList<int>();

変数のスコープと寿命

変数のスコープ=変数がソースコードの中でどの範囲で有効かを示す。
ちなみに変数が扱える期間を変数の寿命と言う。
誰にも参照されなくて寿命による孤独死を迎えるとGCというお迎えが来る。


変数のスコープは基本的に小さい方が優先される。

// グローバル
static int x = 0;

// メソッド内
static void sample(){
  int x = 100;
  System.out.println(x);
}

public static void main(String[] args){
  System.out.println(x);
  sample();
  System.out.println(x);
}

/* 
=> 0
   100
   0
*/