Day 37 のゴールと全体像
Day 37 のテーマは static です。 ここまで「インスタンス(オブジェクト)」を中心に見てきましたが、 今日は少し視点を変えて、
- static
- クラスメンバー
- インスタンスメンバー
- staticメソッド
というキーワードを通して、
「オブジェクトを作らなくても使えるもの」
を理解していきます。
雑誌の記事を読むような気持ちで、 「クラス全体で共有するもの」と「インスタンスごとに違うもの」の違いを、 ゆっくり整理していきましょう。
インスタンスメンバーとクラスメンバーの違い
まずはインスタンスメンバーのおさらい
これまでたくさん書いてきた、
- フィールド
- プロパティ
- メソッド
は、基本的に インスタンスメンバー でした。
インスタンスメンバーとは、
「インスタンス(オブジェクト)ごとに別々の値や動きを持つメンバー」
のことです。
例として、Person クラスを見てみます。
class Person
{
// インスタンスごとに違う値を持つプロパティ
public string Name { get; set; }
public int Age { get; set; }
// インスタンスごとに動くメソッド
public void Introduce()
{
Console.WriteLine($"こんにちは、{Name} です。年齢は {Age} 歳です。");
}
}
class Program
{
static void Main(string[] args)
{
Person p1 = new Person { Name = "太郎", Age = 20 };
Person p2 = new Person { Name = "花子", Age = 25 };
p1.Introduce(); // 太郎の情報で動く
p2.Introduce(); // 花子の情報で動く
Console.ReadLine();
}
}
C#ここでは、
p1とp2は別々のインスタンスNameとAgeの値もインスタンスごとに違うIntroduce()の結果もインスタンスごとに違う
という状態になっています。
これが「インスタンスメンバー」です。
クラスメンバーとは何か
一方で、クラスメンバー は、
「クラス全体で共有されるメンバー」
です。
インスタンスごとに違うのではなく、 「そのクラスに属するものはみんな同じ値を共有する」 というイメージです。
クラスメンバーを作るために使うのが、 今日の主役である static です。
static の基本イメージ
「クラスに属するもの」にするキーワード
static は、
「このメンバーはインスタンスではなく、クラスに属する」
という意味のキーワードです。
例えば、Person クラスに「人数カウンタ」を付けてみます。
class Person
{
// クラス全体で共有する人数カウンタ(static フィールド)
public static int Count = 0;
public string Name { get; set; }
public int Age { get; set; }
public Person()
{
// インスタンスが生成されるたびに、人数カウンタを増やす
Count++;
}
public void Introduce()
{
Console.WriteLine($"こんにちは、{Name} です。年齢は {Age} 歳です。");
}
}
class Program
{
static void Main(string[] args)
{
Person p1 = new Person { Name = "太郎", Age = 20 };
Person p2 = new Person { Name = "花子", Age = 25 };
Person p3 = new Person { Name = "次郎", Age = 30 };
// static フィールドは、クラス名からアクセスします
Console.WriteLine($"Person のインスタンス数: {Person.Count}");
Console.ReadLine();
}
}
C#ここでのポイントは、
Countはstaticなので、インスタンスではなくクラスに属しているPersonが何個生成されても、Countは 1 つだけPerson.Countという形で、クラス名からアクセスする
というところです。
重要ポイント:
staticを付けると、「インスタンスごと」ではなく「クラス全体で共有」になります。staticメンバーには、インスタンスではなく クラス名 からアクセスします。
static フィールドとインスタンスフィールドの違い
並べて見ると分かりやすい
static あり/なしを並べてみると、違いがはっきりします。
class Sample
{
// クラス全体で共有される static フィールド
public static int StaticValue = 0;
// インスタンスごとに違う値を持つフィールド
public int InstanceValue = 0;
}
class Program
{
static void Main(string[] args)
{
Sample s1 = new Sample();
Sample s2 = new Sample();
// インスタンスごとの値を変更
s1.InstanceValue = 10;
s2.InstanceValue = 20;
// クラス全体の値を変更
Sample.StaticValue = 100;
Console.WriteLine($"s1.InstanceValue: {s1.InstanceValue}"); // 10
Console.WriteLine($"s2.InstanceValue: {s2.InstanceValue}"); // 20
Console.WriteLine($"Sample.StaticValue: {Sample.StaticValue}"); // 100
Console.ReadLine();
}
}
C#ここでは、
InstanceValueはインスタンスごとに違う値を持つStaticValueはクラス全体で 1 つだけ存在する
という違いがあります。
重要ポイント:
- 「インスタンスごとに違うべきもの」はインスタンスメンバー
- 「クラス全体で共有したいもの」は static メンバー
というふうに、役割で使い分けるのがコツです。
static メソッドとは何か
「インスタンスを作らずに呼べるメソッド」
static は、メソッドにも付けることができます。 これが staticメソッド です。
staticメソッドは、
「インスタンスを作らずに、クラス名から直接呼び出せるメソッド」
です。
例として、簡単な計算用クラスを作ってみます。
class MathUtil
{
// static メソッド:足し算
public static int Add(int a, int b)
{
return a + b;
}
// static メソッド:掛け算
public static int Multiply(int a, int b)
{
return a * b;
}
}
class Program
{
static void Main(string[] args)
{
// インスタンスを作らずに、クラス名から直接呼び出せます
int sum = MathUtil.Add(3, 5);
int product = MathUtil.Multiply(4, 6);
Console.WriteLine($"3 + 5 = {sum}");
Console.WriteLine($"4 * 6 = {product}");
Console.ReadLine();
}
}
C#ここでは、
MathUtilのインスタンスを作っていないMathUtil.Add(...)/MathUtil.Multiply(...)と、クラス名から直接呼んでいる
という形になっています。
重要ポイント:
- staticメソッドは「インスタンスに依存しない処理」を書く場所です。
- そのメソッドが「特定のインスタンスの状態」を使わないなら、static にする候補になります。
static メソッドとインスタンスメソッドの違い
インスタンスの状態を使うかどうか
インスタンスメソッドと staticメソッドの違いは、
「インスタンスの状態(フィールドやプロパティ)を使うかどうか」
です。
例として、Circle クラスを考えてみます。
class Circle
{
// 半径(インスタンスごとに違う)
public double Radius { get; set; }
// 円周率(クラス全体で共有してよい)
public static double Pi = 3.14159265358979;
// インスタンスメソッド:この円の面積を計算する
public double GetArea()
{
return Pi * Radius * Radius;
}
// static メソッド:半径を渡して面積を計算するユーティリティ
public static double CalcArea(double radius)
{
return Pi * radius * radius;
}
}
class Program
{
static void Main(string[] args)
{
// インスタンスメソッドの例
Circle c = new Circle { Radius = 10 };
Console.WriteLine($"半径 10 の円の面積(インスタンスメソッド): {c.GetArea()}");
// static メソッドの例
double area = Circle.CalcArea(10);
Console.WriteLine($"半径 10 の円の面積(static メソッド): {area}");
Console.ReadLine();
}
}
C#ここでは、
GetArea()はインスタンスメソッドRadiusというインスタンスごとの値を使っている
CalcArea()は staticメソッド- 引数として半径を受け取り、インスタンスに依存しない形で計算している
という違いがあります。
重要ポイント:
- 「このインスタンスの状態を使って処理する」ならインスタンスメソッド
- 「インスタンスに依存せず、引数だけで処理できる」なら staticメソッド
というふうに、役割で使い分けると整理しやすいです。
Day 37 用の練習テンプレート
最後に、static とインスタンスの違いを練習するためのテンプレートを紹介します。
ログ出力ユーティリティの例
using System;
class Logger
{
// ログの出力回数をクラス全体で共有する static フィールド
public static int LogCount { get; private set; } = 0;
// インスタンスごとに違う「名前」を持てるようにする
public string Name { get; set; }
public Logger(string name)
{
Name = name;
}
// インスタンスメソッド:このロガーの名前付きでログを出す
public void Log(string message)
{
LogCount++; // クラス全体のログ回数を増やす
Console.WriteLine($"[{Name}] {message}");
}
// static メソッド:現在のログ回数を表示する
public static void ShowLogCount()
{
Console.WriteLine($"ログ出力回数: {LogCount}");
}
}
class Program
{
static void Main(string[] args)
{
Logger appLogger = new Logger("App");
Logger dbLogger = new Logger("DB");
appLogger.Log("アプリケーションを開始しました。");
dbLogger.Log("データベースに接続しました。");
appLogger.Log("処理が完了しました。");
// クラス名から static メソッドを呼び出す
Logger.ShowLogCount();
Console.ReadLine();
}
}
C#このテンプレートを眺めながら、
LogCountはクラス全体で共有されていることNameはインスタンスごとに違うことLog()はインスタンスメソッドで、Nameを使っていることShowLogCount()は staticメソッドで、クラス全体の状態だけを使っていること
を意識してみると、 static とインスタンスの違いがぐっとクリアになります。
Day 37 のまとめ
Day 37 では、
- インスタンスメンバー = インスタンスごとに違う値や動きを持つメンバー
- クラスメンバー = クラス全体で共有されるメンバー(
static) - static フィールド = クラス名からアクセスし、全インスタンスで共有される値
- static メソッド = インスタンスを作らずに呼べる、インスタンスに依存しない処理
という流れで、 「クラス全体で共有するもの」と「インスタンスごとに違うもの」 を見分ける視点を育てました。
ぜひ、
- 自分でクラスを 1 つ作って、「これは全体で共有したい」「これはインスタンスごとに違うべき」と考えてみる
- インスタンスに依存しない処理を、staticメソッドとして切り出してみる
- 「クラス名から呼ぶもの」と「インスタンスから呼ぶもの」を意識してコードを書いてみる
といった練習を通して、 static を 「ただのキーワード」ではなく、 クラスの役割を整理するための道具として、少しずつ自分の感覚に馴染ませていってください。
