一番かんたんなJava入門

これからJavaを始めようという人の為の超入門サイトです。丁寧、簡単にこだわった解説なので初心者にぴったりです。

【Java】 staticって何?

time 2013/07/05

sponsored link

staticじゃないメンバ(インスタンスメンバ)

 今回は「static」の意味を解説したいと思います。「static」の意味がよく分からないという人も、書いたことは何回もあるんじゃないでしょうか?mainメソッドを書く時に出てきますよね。mainメソッドは「static」なメソッドなんです。
 staticなメソッドとかstaticな変数とかstaticなクラスなんかもあるんですが、このちょっと難解なstaticを理解するには、逆にstaticじゃない変数って何なのか?staticじゃないメソッドって何なのか?を理解すると分かりやすいです。なのでまずは非staticなメンバとはどういうものかを理解する為に以下のクラスを見てください。

Human.java

public class Human{
	String name;                         // メンバ1
        int birthday;                        // メンバ2
        int manpukudo;                       // メンバ3

        Human(String name, int birthday, int manpukudo){  // コンストラクタ1
                this.name = name;
                this.birthday = birthday;
                this.manpukudo = manpukudo;
        }
        Human(String name, int birthday){               // コンストラクタ2
                this(name, birthday, 50);
        }
        Human(){                                          // コンストラクタ3
                this("不明", 0, 50);
        }

        void eat(){                     // メンバ4
                this.manpukudo += 60;
        }
}

 続けて読んで頂いている人は知ってると思いますが、これは人間オブジェクトを作る為のHumanクラスです。
このクラスにはご覧のように4つのメンバと3つのコンストラクタが存在します。4つのメンバというのは、メンバ変数のnameとbirthdayとmanpukudo、それにメンバメソッドであるeat( )です。これらのメンバは全てstaticではありません。どこにもstaticとは書いていないですよね?staticな変数やメソッドにはstaticと書く必要があり、何も書いていなかったら非staticだということです。なので今のところこのクラスのメンバは全て非staticだということです。
 非staticな変数・メソッドというのは、インスタンス固有の変数・メソッドであるということです。これは感覚的に分かると思います。「名前」はもちろんそのインスタンスが持つ名前だし、「生年月日」も「満腹度」も「食べるという動作」も全て、インスタンス固有のものです。
 非staticな変数・メソッドというのはインスタンス固有のものなので、インスタンス変数インスタンスメソッドという風に表現します。両方合わせてインスタンスメンバとも言います。

staticな変数(クラス変数)

 ではこのクラスに一つstaticなメンバを加えたいと思います。

Human.java

public class Human{
        static int count_Human = 0;
	String name;
        int birthday;
        int manpukudo;

        //以下省略
}

 このように変数の宣言の前にstaticをつければstaticな変数になります。「count_Human」というint型変数を加えてみました。これはHumanのカウントです。つまり何人のHumanオブジェクトが作られたかをカウントする変数です。初めは0人なので0で初期化しています。
 インスタンスを作られた回数をカウントする為に、コンストラクタにちょこっと細工をします。

public class Human{
        static int count_Human = 0;
	String name;                                      
        int birthday;                                     
        int manpukudo;                                 

        Human(String name, int birthday, int manpukudo){  // コンストラクタ1
                this.name = name;
                this.birthday = birthday;
                this.manpukudo = manpukudo;
                count_Human++;
        }
        Human(String name, int birthday){               // コンストラクタ2
                this(name, birthday, 50);
        }
        Human(){                                          // コンストラクタ3
                this("不明", 0, 50);
        }

        //以下省略
}

 一つ目のコンストラクタに「count_Human++」を足しました。これで一つ目のコンストラクタが呼ばれたら「count_Human」が1増えます。2つ目、3つ目のコンストラクタが呼ばれた時は増えないのか?と心配していただいた方、大丈夫です。2つ目、3つ目のコンストラクタが呼ばれたら「this( )」で1つ目のコンストラクタが呼ばれるようになっていますので、newする時に引数がいくつであろうと結局1つ目のコンストラクタが呼ばれてカウントは1増えます。(参考:〔コンストラクタとは〕 〔this( )の意味〕
 この「count_Human」つまり「人数」はインスタンス固有の値ではないというのは感覚的に分かりますよね?「名前」や「満腹度」はノブオ固有のものですが、「人数」はノブオ固有のものとは言えないですね。ノブオの人数ではないですから。じゃあ「人数」は何の固有の値と言えるか??「Humanクラス」の固有の値と言えるのではないでしょうか?例えばHumanクラスとは別にDogクラスがあったとしてDogクラスにもその数をカウントするstaticな変数「count_Dog」があったとすると、それはDogクラスの固有の値と言えます。このようにstaticなメンバというのは、インスタンス固有のメンバではなく、クラス固有のメンバという意味でとらえることができます。なので、staticな変数、staticなメソッドのことをクラス変数クラスメソッドと表現します。両方合わせてクラスメンバ、あるいは静的メンバとも言います。静的というのはstaticのことです。

クラス変数(staticな変数)にアクセスする

 オブジェクトって何? 〔メンバ変数とは〕で説明した通り、インスタンス変数(非static変数)にアクセスするには、

インスタンスを表す変数名.メンバ

の形でした。具体的には、

Human human1 = new Human();
human1.name = "ノブオ";
System.out.print(human1.name);

こういうことです。Human型の変数human1を宣言して、そこにnewで作ったインスタンス(の参照)を代入することで、変数human1がHumanインスタンスを表す変数になり、「human1.name」の形で、「human1の名前」にアクセスできるので、そこにノブオを代入したり、その値を出力したりできるわけです。しかし、クラス変数(static変数)にアクセスする方法はちょっと違います。もし、同じように「human1.count_Human」とやってしまうと「human1の人数」という意味になってしまいます。意味がおかしいのが感覚的に分かりますよね?Humanオブジェクトをhuman1、human2、human3、・・・と作っていっても、「human1の人数」は1人です。
 「count_Human」とは何かというと「human1の人数」ではなく「Humanの人数」です。大文字になっていることに注意してほしいのですが、つまり「count_Human」とはHumanクラス(オブジェクト)の数です。インスタンスに属するパラメータではなく、クラス自体に属するパラメータというのはそういうことです。繰り返しになりますが、そういうクラスに属するパラメータをクラス変数、static変数、静的変数(全部、同義)と言うわけです。
 ではクラス変数(static変数)にアクセスするにはどうするか?

クラス名.メンバ

この形で、そのクラスのstaticなメンバにアクセスできます。クラスに属するパラメータなので、「クラス名.」の形になるのは意味的に理解できますね。
 では具体的にやってみます。

Human human1 = new Human();
System.out.print(Human.count_Human);

 これで実行すると「1」と出力されます(mainメソッド等省略してます)。Humanインスタンスが一つ作られたから「count_Human」は1になっていますね。
 ↓こんな風にもできます。

HumanTest.java

public class HumanTest{
	public static void main(String[] args){
                System.out.println(Human.count_Human);  //①
		
                Human human1 = new Human();
                System.out.println(Human.count_Human);  //②
                
                Human human2 = new Human();
                System.out.println(Human.count_Human);  //③
	}
}

 ①の時点ではまだHumanオブジェクトは作られていないので「count_Human」の値は「0」、②の時点では「1」、③の時点では「2」になるので、このクラスを実行すると、

static1

という風に出力されます。
 ところで、①に注目してもらいたいのですが、クラス変数(static変数)に関してはそのクラスのインスタンスが存在しなくても、「Human.count_Human」というように、その値にアクセスすることができます。逆にインスタンス変数の場合は、もちろんインスタンスが存在しなければそのパラメータ自体存在しないので、インスタンスを作ってからでないとアクセスできません。当然ですね、「human1.name」としなければならないのにインスタンスが存在しないということは、変数「human1」が存在しないわけですからアクセスのしようがありません。もちろんインスタンス変数だけでなくインスタンスメソッドについても同様です。

まとめ & 注意

 staticのニュアンスがなんとなく理解できましたでしょうか?
 一言でいうと、クラスに属するのがstatic、インスタンスに属するのが非staticだということです。

何に属するか 呼び出し方
staticなメンバ クラス クラス名.メンバ
例)Human.count_human
非staticなメンバ インスタンス インスタンスを表す変数名.メンバ
例)human1.eat( )

 そして一つ注意。
 staticなメソッドから、非staticなメンバにアクセスすることはできません。普通に考えたら分かると思いますが、非staticな変数というのはインスタンスがそれぞれ固有に持つパラメータなので、インスタンスのあるなし関係なく使えるstaticメソッドからインスタンス変数にアクセスしようとしても、どのインスタンスのパラメータにアクセスしようとしているのか判断のしようがありませんよね。
 「このインスタンス」を意味する「this」はインスタンスメソッド内で使うからこそ、「このインスタンス」がどのインスタンスを指しているか分かるのであって、インスタンスとは無関係に呼ばれるstaticメソッド内から「this.name」とやっても、誰の名前やねん!ってことになるのでコンパイルエラーになります。
 例えば、

Main.java

public class Main{
        int a;
	public static void main(String[] args){
                a = 10;
	}
}

 こんなことはできません。コンパイルエラーになります。「a」は非staticなので、このMainクラスのインスタンス変数として宣言されています。それをstaticメソッドであるmainメソッドから触ることはできません。
 これもアウトです。↓

Main.java

public class Main{
        int a;
	public static void main(String[] args){
                this.a = 10;
	}
}

 上述した通り、staticメソッド内で「this」を使うことはできません。インスタンスを作ってもいないのに「このインスタンス」も何もありません。
 mainメソッドがあるクラスは特別扱いしてしまいがちですが、mainメソッドを持つクラスでもnewすることでインスタンスを作ることもできます。なので、インスタンスを作りさえすれば、一応コンパイルは通ります。

Main.java

public class Main{
        int a;
	public static void main(String[] args){
                Main main = new Main();
                main.a = 10;
	}
}

 こんなことを実際することがあるのか知りませんが。。もちろんインスタンスを作ろうが、staticメソッド内で「this.」は使えません。

 staticなフィールド(変数)なら、staticなメソッドからでもアクセスできます。staticな変数というのはインスタンスに関係なく存在するものなので、同じくインスタンスとは関係ないstaticなメソッドから触るのは全然OKです。↓

Main.java

public class Main{
        static int a;
	public static void main(String[] args){
                a = 10;
	}
}

 これでも大丈夫です。↓

Main.java

public class Main{
	public static void main(String[] args){
                int a;
                a = 10;
	}
}

 これなら、「a」はMainクラスのメンバとしてではなく、mainメソッド内のローカル変数として宣言されていることになるので、もちろんそのメソッド内では自由に触れます。ローカル変数というのはこのようにメソッド内や、あるいはfor文やif文のブロック内で宣言された変数のことを言います。ローカル変数のスコープ(存在範囲)はその宣言されたブロック内だけです。逆に言えば、クラスブロック直下に宣言されているのがメンバ変数・メンバメソッドです。混乱しないように整理して覚えておきましょう。ちなみにローカル変数にstaticを付けることはできません。staticか非staticかというのは、そのクラスのメンバに限り設定できるということです。
 次回は、アクセス修飾子とゲッターについての説明です。

sponsored link

Androidアプリを作ろう

コメント

  • すごくわかりやすかったです!
    プログラム経験は一応あるものの、staticが何なのかイメージが掴めず困っていたところにこのページに出会い、理解することができました。
    プログラムに対する苦手意識が消えました!

    by 匿名 €2015/09/27 16:07

  • 前半のときのように一例を出して実行などして画面をたくさんみせてほしかったです。最後のほうで理論的な話が多くなってしまって前半に比べてわかりづらかったです。続編期待しています。

    by とおりすがり €2015/11/22 20:57

  • ご意見ありがとうございます。

    by Nobuo@管理人 €2015/11/23 22:17

down

コメントする



CAPTCHA


一番かんたんなJava入門

Androidアプリの作り方

忘備録

私の作ったAndroidアプリ

私の作ったWordPressテーマ

プロに教わるオンライン学習

管理人

Nobuo_CREATE

Nobuo_CREATE

WordPressテーマPrinciple、マテリアルを作ったり、Androidアプリを作ったり、Java入門サイトを作ったり、本を書いたりしています。どうぞよろしく。 [詳細]



sponsored link

オススメ書籍

[オススメpoint]

 この本は全く何も分からない初心者の方にお勧めです。プログラミングをするには覚えなければならない事が無茶苦茶いっぱいありますが、この本は教えてくれる順番、その構成が素晴らしいです。RPGのゲームを作るというストーリーにのっとってちょっとずつ難しいことを教えてもらえます。
 無機質で膨大なデータが載っているような本は読む気にならないという方は、こういうストーリー仕立ての本でチャレンジしてみてはいかがでしょうか?(注:RPGを作る為の本ではありません。)

[オススメpoint]

 ある程度、Javaを読み書きできるようになったら、オブジェクト指向について学ぶべきです。本書は、抽象的で分かったような分からんようなオブジェクト指向について、非常に分かりやすい例を出して説明してくれています。オブジェクト指向とは何なのか?という本質を掴むのにこれほど適した本はないと思います。オブジェクト志向の理念を理解できれば、より効率のいいコードをより楽に書けるようになるはずです。Java上級者を目指すなら必読の一冊!

只今、急拡大中

ゲームを作りたい人専門

個人フットサル予約サイト

ガチ専門

JavaからのRuby on Rails入門

JavaからのRuby on Rails入門