【Javaの基礎知識】変数のスコープ

#はじめに

こちらの記事は、
- Javaをこれから学習し始める
- 基本的なことをおさらいしたい

という方向けです。

#スコープについて
スコープとは、変数が扱える範囲のことを指します。
`「ココからココまではこの変数が使えるけど、ココからココまではこの変数が使えないよ」`
こんな感じです。

変数を宣言したら、{}の間がその変数を使える範囲になってきます。

このスコープを意識しないとコンパイルエラーになったりするので、
これから説明する変数でスコープの説明をしていきます。


#ローカル変数
{から}までをブロックというんですが、そのブロック内で扱える変数のことをローカル変数と呼びます。
宣言した位置より後で参照することができます。

```java
public class local {
  public static void main(String args[]){
    int a = 0;

    if(true){
      int b = 0;
    }
    a = 1;// aはmainの{}の間で参照できる
    b = 1;// bはifの外なのでコンパイルエラー
  }
   a = 2;// mainの外なのでコンパイルエラー

   public static void sub(){
     a = 3;// mainの外にあるメソッドなのでコンパイルエラー
   }
}
```

ローカル変数があれば、グローバル変数もあると思うかもしれませんが、
Javaにはグローバル変数というものはありません（※Javaではグローバル変数は原則使わない）。


#インスタンス変数
newされる度にメモリ領域にインスタンスが作成されます。
**オブジェクト.インスタンス変数名**でアクセスできます。

```java:food.java
class Food{
  String menu;//インスタンス変数
  int price;//インスタンス変数

  public void Info(){
    System.out.println("こちらは"+ menu + "です");
    System.out.println("値段は"+ price + "円です");
  }

  public void say(){
    System.out.println("揚げたて"+ menu + "は最高");
  }
}
```

```java:Main.java
public class Main {
  public static void main(String args[]){
    Food potato = new Food();//メモリ上に新しい番地が確保される(Foodクラスのインスタンス化)

    potato.menu = "ポテイト";//potato(オブジェクト).menu(インスタンス変数)に"ポテイト"を代入
    potato.price = 270;//potato(オブジェクト).price(インスタンス変数)に"270"を代入

    System.out.println(potato.menu);// ポテイト

    potato.Info();
    // こちらはポテイトです
    // 値段は270円です

    potato.say();// 揚げたてポテイトは最高

    Food nugget = new Food();//メモリ上に新しい番地が確保される

    nugget.menu = "ナゲット";//nugget(オブジェクト).menu(インスタンス変数)に"ナゲット"を代入
    nugget.price = 580;//nugget(オブジェクト).price(インスタンス変数)に"580"を代入

    System.out.println(nugget.menu);// ナゲット

    nugget.Info();
    // こちらはナゲットです
    // 値段は580円です

  }

}
```

では、次にコンパイルエラーとなってしまう例はこちら

```java:food.java
  public static void say(){
    System.out.println("揚げたて"+ menu + "は最高");
  }
```
food.javaのsayメソッドをstaticメソッドにすると、
`Cannot make a static reference to the non-static field menu`
てな感じで怒られるし、


```java:Main.java
 potato.say();
```
この部分も、

`The static method say() from the type Food should be accessed in a static way`
てな感じで怒られます。

後ほど説明しますが、
staticメソッドにするなら、static変数で定義しないといけません。


##thisについて
自分自身のインスタンスを指す時、thisというキーワードを用いることができます。
**this.変数名**でアクセスできます。なお、this.は省略可能です。

クラスのフィールドで定義されている変数と、ローカル変数の名前が同じ場合に、対象を特定するために利用されることが多いです。
クラス変数より、ローカル変数の方が優先されます。

一旦こちらの例をみてください。

```java
public class Soccer {

  //インスタンス変数
  String player = "メッシ";

  public static void main(String[] args){

    //ローカル変数
    String player = "イニエスタ";

    System.out.println(player + "です");// イニエスタです
  }
}
```
先ほど述べたように、ローカル変数が優先されました。
クラス変数の方のplayerにアクセスする場合、this.変数名としてあげることで、指定できます。

```java:thisを使ったダメな例：Soccer.java
public class Soccer {

  //インスタンス変数
  String player = "メッシ";

  public static void main(String[] args){

    //ローカル変数
    String player = "イニエスタ";

    System.out.println("ローカル変数" + player + "です");// ローカル変数イニエスタです
    System.out.println("インスタンス変数" + this.player + "です");// Cannot use this in a static context
  }
}
```
ダメな例にあるように、そのままthisと書けばいいというわけではありません。

```java:正しい例：Soccer.java
class Soccer {
  String player = "メッシ";

  public void say(String player) {// 引数で区別できるようにする
      System.out.println("ローカル変数" + player + "です");// ローカル変数イニエスタです
      System.out.println("インスタンス変数" + this.player + "です");// クラス変数メッシです
  }
}

```

```java:正しい例：Print.java
public class Print {
  public static void main(String[] args) {
      String player = "イニエスタ";
      Soccer sc = new Soccer();
      sc.say(player);
  }
}
```



#static変数(クラス変数)
static修飾子は、クラス領域に定義します。
**クラス名.static変数名**でアクセスできます。
static変数は、オブジェクト毎に値をもちません。

例をみてみましょう。

```java:Meiji.java
public class Meiji {
  public static String snack;// static変数化

  public void saySnack(){
    System.out.println(snack);
  }
}
```

```java:Meiji2.java
public class Meiji2 {
  public static void main(String[] args){
    Meiji.snack = "きのこの山";// snackに"きのこの山"が格納される
    Meiji say1 = new Meiji();// Meijiクラスのインスタンス化
    say1.saySnack();// きのこの山
    Meiji say2 = new Meiji();
    say2.saySnack();// きのこの山

    Meiji.snack = "たけのこの里";// snackに"たけのこの里"が格納される
    say1.saySnack();// たけのこの里
    say2.saySnack();// たけのこの里
  }
}
```
このように、オブジェクトごとに値を持たないので、
say1とsay2が同じメモリ上の値を参照しています。

static変数の使い道としては、
まだまだ勉強中ですが、クラスからいくつインスタンスができたかを数える方法で活用できます。
先ほどのMeiji.javaとMeiji2.javaを少し書き換えてみました。

```java:Meiji.java
public class Meiji {
  public String snack;// インスタンス変数
  public static int count = 0;// static変数を初期化する

  public void saySnack(){
    System.out.println(snack);
    Meiji.count++;// クラス名.count(static変数)で指定して、１ずつ増やす
  }

  public static void snackCnt(){ // staticメソッド（クラスメソッド）
    System.out.println(Meiji.count);
  }
}
```

```java:Meiji2.java
public class Meiji2 {
  public static void main(String[] args){
    Meiji.snackCnt();// 0

    Meiji kinoko = new Meiji();// Meijiクラスのインスタンス化
    kinoko.snack = "きのこの山";//kinoko(オブジェクト).snack(インスタンス変数)に"きのこの山"を代入
    kinoko.saySnack();// きのこの山

    Meiji.snackCnt();// 1

    Meiji takenoko = new Meiji();
    takenoko.snack = "たけのこの里";
    takenoko.saySnack();// たけのこの里

    Meiji.snackCnt();// 2

  }
}
```
saySnackメソッド内でカウントアップしているので、
そのメソッドが呼ばれる度に数字が増えているのがわかります。

#最後に

今回は変数とスコープについて学習をしました。
そして、以下の変数について特徴を記載しました。
- ローカル変数
- インスタンス変数
- static変数（クラス変数）

thisの使い方などまだ方法はいくつかあると思いますが、
ここでは割愛させていただきます。

ありがとうございました☕️