C#でクラスを学び始めると、必ず登場するのがnewキーワードです。
なんとなく「インスタンスを作るもの」という印象はあっても、どんな仕組みでメモリが確保され、どこでコンストラクタが呼ばれ、どんな場面で省略できたりできなかったりするのかは、意外とあいまいになりがちです。
本記事では、newによるインスタンス生成の基本から、実際のメモリのイメージ、使い方のパターンまでを、図解とサンプルコードで詳しく解説します。
C#のnewとは何か
newキーワードの役割
newは「インスタンスを作るための演算子」です。
クラスや構造体などの型から、実際に使える「モノ」(オブジェクト)をメモリ上に作成します。
C#では、次のような役割を持ちます。
- ヒープ(またはスタック)上にメモリを確保する
- フィールドを既定値で初期化する
- コンストラクタを呼び出す
- そのオブジェクトへの参照を返す
基本的な書き方
もっとも基本的な書き方は次の形です。
クラス名 変数名 = new クラス名(引数...);
例として、Personクラスのインスタンスを生成するコードを見てみます。
Person p = new Person("Taro", 20);
この1行で、Person型のオブジェクトがヒープ上に作られ、その場所を指す参照が変数pに格納される、という処理が行われています。
インスタンス生成の流れを図解で理解する

メモリ上で何が起きているか
インスタンス生成は、次のようなステップで進みます。
- ヒープ領域に必要なサイズのメモリが確保される
- その型のフィールドが既定値(数値なら0、参照ならnull、boolならfalseなど)に初期化される
- 対応するコンストラクタが呼ばれ、初期化ロジックが実行される
- 生成されたオブジェクトのアドレス(参照)が、左辺の変数に代入される
変数自体はスタックにあり、中身として「ヒープ上のオブジェクトの場所」を保持する、というイメージを持つと理解しやすくなります。
newの基本的な使い方
クラスのインスタンス生成
まずは最もよく使うパターンです。
using System;
class Person
{
public string Name;
public int Age;
// 引数なしコンストラクタ
public Person()
{
Name = "NoName";
Age = 0;
}
// 引数ありコンストラクタ
public Person(string name, int age)
{
Name = name;
Age = age;
}
public void Introduce()
{
Console.WriteLine($"Name: {Name}, Age: {Age}");
}
}
class Program
{
static void Main()
{
// 引数なしコンストラクタを使ったインスタンス生成
Person p1 = new Person();
p1.Introduce();
// 引数ありコンストラクタを使ったインスタンス生成
Person p2 = new Person("Taro", 20);
p2.Introduce();
}
}
Name: NoName, Age: 0
Name: Taro, Age: 20
ここでnew Person()やnew Person(“Taro”, 20)が、それぞれ異なるコンストラクタを呼び出しています。
配列のインスタンス生成
配列も、newによるインスタンス生成が必要なオブジェクトです。
using System;
class Program
{
static void Main()
{
// int型の配列を長さ5で生成
int[] numbers = new int[5];
// すべて0で初期化されている
for (int i = 0; i < numbers.Length; i++)
{
Console.WriteLine(numbers[i]);
}
// 文字列配列を初期化と同時に生成
string[] names = new string[] { "A", "B", "C" };
foreach (string name in names)
{
Console.WriteLine(name);
}
}
}
0
0
0
0
0
A
B
C
配列のnew int[5]のように、型と要素数を指定する形も、インスタンス生成の一種です。
コンストラクタとnewの関係
newが呼び出すコンストラクタ
newは必ずコンストラクタを呼び出します。
コンストラクタは、オブジェクト生成時に1回だけ実行される特別なメソッドです。

class Sample
{
public int Value;
// コンストラクタ(引数なし)
public Sample()
{
Value = 10;
}
// コンストラクタ(引数あり)
public Sample(int initialValue)
{
Value = initialValue;
}
}
class Program
{
static void Main()
{
// 引数なしコンストラクタが呼ばれる
Sample s1 = new Sample();
Console.WriteLine(s1.Value); // 10
// 引数ありコンストラクタが呼ばれる
Sample s2 = new Sample(99);
Console.WriteLine(s2.Value); // 99
}
}
10
99
どのコンストラクタが呼ばれるかは、newの後ろに書く引数の型と数で決まる点が重要です。
値型と参照型でのnewの違い
参照型(クラス)の場合
クラスは参照型であり、newによりヒープ上にオブジェクトが作られます。
変数はその場所を指す参照を保持します。
値型(構造体)の場合
構造体は値型であり、通常はスタック上に値そのものが置かれます。
値型にもnewを使う場合と使わない場合があります。
using System;
struct Point
{
public int X;
public int Y;
}
class Program
{
static void Main()
{
// 値型にnewを使う例
Point p1 = new Point(); // フィールドは0で初期化される
Console.WriteLine($"p1: X={p1.X}, Y={p1.Y}");
// newを使わない場合、すべてのフィールドを手動で初期化する必要がある
Point p2;
p2.X = 10;
p2.Y = 20;
Console.WriteLine($"p2: X={p2.X}, Y={p2.Y}");
}
}
p1: X=0, Y=0
p2: X=10, Y=20
値型でもnewを使うと、フィールドが既定値で初期化されるので、安全に扱えるようになります。
ただし、値型のnewはヒープではなく、値そのものを初期化している点が参照型と異なります。
newを省略できるケース
型推論(var)でもnewは必要
C#にはvarによる型推論がありますが、varは左辺の型指定を省略するだけで、newそのものは省略できません。
using System;
class Person
{
public string Name;
}
class Program
{
static void Main()
{
// 明示的な型指定
Person p1 = new Person();
// varによる型推論(右辺のnew Person()を見てPerson型と推論)
var p2 = new Person();
Console.WriteLine(p2.GetType().Name); // Person
}
}
Person
コレクション初期化子との組み合わせ
C#では、newと初期化子を組み合わせることで、すっきりとした記述ができます。
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
// List<int>を生成し、初期値をまとめて指定
List<int> numbers = new List<int> { 1, 2, 3, 4 };
foreach (var n in numbers)
{
Console.WriteLine(n);
}
}
}
1
2
3
4
newのいろいろな使いどころ
無名型(anonymous type)の生成
LINQなどでよく使われる無名型も、実はnewで生成しています。
using System;
class Program
{
static void Main()
{
// new { プロパティ = 値 } の形で無名型のインスタンスを生成
var person = new { Name = "Taro", Age = 20 };
Console.WriteLine($"{person.Name}, {person.Age}");
}
}
Taro, 20
型名は書けませんが、コンパイラが内部でクラスを生成し、newでインスタンスを作っているイメージです。
new演算子とnew修飾子の違いに注意
C#には、newという単語を「演算子」として使う場合と、「修飾子」として使う場合があります。
本記事のテーマは前者ですが、後者も名前が同じなので混同しがちです。
class Base
{
public void Show()
{
Console.WriteLine("Base.Show");
}
}
class Derived : Base
{
// new修飾子: 基底クラスの同名メンバーを隠す
public new void Show()
{
Console.WriteLine("Derived.Show");
}
}
このnew void Show()のnewはインスタンス生成とは関係がありません。
「同名メンバーを隠す」ための修飾子として使われています。
newによるインスタンス生成の注意点
生成しすぎによるメモリ消費
newでインスタンスを作るということは、その分だけメモリを占有することになります。
C#ではガベージコレクタ(GC)が不要になったオブジェクトを自動で回収しますが、大量のオブジェクトを頻繁にnewし続けると、GCのコストが増えパフォーマンス低下の原因になります。
特に以下のようなケースでは注意が必要です。
- 毎フレーム大量のオブジェクトを生成するゲームやリアルタイム処理
- 高頻度のループ内で短命なオブジェクトを何度もnewしているコード
インスタンス生成が必要な場面/不要な場面
staticメンバーはインスタンス生成なしで使える、という点も合わせて理解しておくと混乱が減ります。
using System;
class Util
{
public static void PrintHello()
{
Console.WriteLine("Hello");
}
}
class Program
{
static void Main()
{
// staticメソッドはインスタンス生成(new)なしで呼べる
Util.PrintHello();
// インスタンスメソッドを呼ぶにはnewが必要
Person p = new Person();
p.Name = "Taro";
// p.Introduce() のように使用
}
}
class Person
{
public string Name;
public void Introduce()
{
Console.WriteLine($"I am {Name}");
}
}
Hello
「状態を持たないユーティリティ処理」はstaticで、「個別の状態を持つもの」はインスタンスとnewという使い分けが基本になります。
まとめ
newは、C#におけるインスタンス生成の中核となるキーワードです。
クラスや配列、値型などに対してメモリを確保し、フィールドを初期化し、コンストラクタを呼び出して、使用可能なオブジェクトを作り出します。
参照型と値型ではnewの意味合いが少し異なり、varやコレクション初期化子と組み合わせることで、より読みやすいコードを書くことができます。
また、同じnewでも「修飾子」として使われる場合もあるため、文脈に注意することが大切です。
インスタンス生成の仕組みを理解することで、メモリのイメージや設計の判断がしやすくなり、C#のコードがぐっと扱いやすくなります。
