类与对象
本教程共 100 篇 · 第 28 篇 · 更新于 2026-07-31 · 约 8 分钟阅读
28. 类与对象
本节目标:理解类是一张蓝图,对象是按蓝图造出的实例,并会定义字段、写方法、用 new 创建对象。
为什么需要”类”
写程序越往后,你会发现光有 int、string 这种零散变量不够用。描述一个”学生”,他需要名字、年龄、成绩,还要能选课、能打印简历。把这些数据和行为各放各的,既难管理又容易乱。
类(class)就是为解决这件事而生:它把”一类事物长什么样(数据)“和”能做什么(行为)“打包成一个自定义类型。这正是面向对象编程(object-oriented programming,OOP)的起点,也是 C# 这类语言组织代码的基石。
类是一张蓝图
类本身不是那个具体的人或物,而是一张”设计图”。比如 Person 描述”人”这种概念:有名字、有年龄,能打招呼。真正按图造出来的”那个叫小明的人”,才叫对象(object),也叫实例(instance)。
Note记住一句口诀:类是图纸,对象是照图造出的实物。你家里有”手机”这个类吗?没有,你手里那台才是对象;“手机”只是对它共性的一张抽象描述。
定义与使用一个类
先看看用起来是什么样,再回头看类的定义:
namespace CSharpDemo;
// 用起来:new 一个对象,给字段赋值,调用方法
Person p = new();
p.Name = "小明";
p.Age = 20;
p.Introduce(); // 输出:我是小明,20岁
// 类的定义(类型声明写在顶级语句之后)
class Person
{
public string Name = ""; // 字段:姓名
public int Age; // 字段:年龄
public void Introduce() // 方法:打招呼
{
Console.WriteLine($"我是{Name},{Age}岁");
}
}
Note注意这里的写法:顶级语句(使用对象的代码)写在前面,类的定义写在后面。这是 C# 顶级语句(top-level statements)的要求——类型声明必须放在语句之后。代码能正常编译运行,放心复制。类只是图纸,要用
new才能”施工”出真实对象。
字段:对象的状态
字段(field)是类里存数据的变量,表示对象当前”是什么样”。上面 Name、Age 就是字段,它们构成了对象的状态。
Tip类成员默认是
private(私有),类外访问不到。这里写public是为了能在类外面读写,方便演示。访问修饰符(谁能看、谁能改)下一章专门细讲。
方法:对象的行为
方法(method)是类里的一段代码,表示对象能做的”动作”。Introduce 就是 Person 的一个行为,它会用对象自己的字段做事。在面向对象里,方法就是”对象的行为”的载体。
用 new 创建对象
类只是图纸,要用 new 才能”施工”出真实对象。C# 9 起可用 new() 让编译器推断类型,少写一遍类型名。
namespace CSharpDemo;
Person p = new(); // 等价于 new Person()
p.Name = "小明";
p.Introduce();
class Person
{
public string Name = "";
public void Introduce() => Console.WriteLine($"我是{Name}");
}
Note变量
p存的不是对象”本身”,而是对象在内存里的”地址”(引用,reference),指向堆上的那个对象。把p赋给另一个变量,两个变量会指向同一个对象,而不是各自复印一份。
多个对象各自独立
每次 new 都得到一个全新对象,字段互不干扰:
namespace CSharpDemo;
Person a = new();
a.Name = "小明";
Person b = new();
b.Name = "小红";
Console.WriteLine(a.Name); // 小明
Console.WriteLine(b.Name); // 小红
class Person
{
public string Name = "";
}
引用共享的小实验
变量存的是”引用”(对象在内存中的地址),所以两个变量指向同一个对象时,改一个另一个也跟着变:
namespace CSharpDemo;
Person a = new();
a.Name = "小明";
Person b = a; // b 和 a 指向同一个对象
b.Name = "小刚";
Console.WriteLine(a.Name); // 小刚(a 也变了)
class Person
{
public string Name = "";
}
Tip这是”引用类型(reference type)“的核心特征,正好和后面要学的
struct(值类型,赋值会复制整份数据)相反。理解引用共享,能帮你避开很多”明明没改它却变了”的隐蔽 bug。
现代简写:主构造器
C# 12 起支持主构造器(primary constructor),把参数直接写在类名后的括号里,省去手动声明字段再赋值的样板代码:
namespace CSharpDemo;
Person p = new("小明", 20);
p.Introduce(); // 输出:我是小明,20岁
class Person(string Name, int Age)
{
public void Introduce() => Console.WriteLine($"我是{Name},{Age}岁");
}
括号里的 Name、Age 自动成为类内可用的参数,构造时直接传值,相当于”先声明字段、再在构造里赋值”的简写。
Tip主构造器是语法糖,初学先掌握传统写法,再认识这个简写即可。本教程后续很多示例会用到它,看到
class X(int Id)这种形式别慌。
构造函数的预告
new Person() 实际调用了一个”构造函数(constructor)“,负责对象出生时的初始化。上面用的是编译器自动给的”无参构造”,构造函数专章会讲如何自定义它。现在只要知道:对象一出生,就由构造函数把它安顿好。
什么时候该用类
- 一组数据经常一起出现(用户有 id、名字、邮箱)→ 用类打包。
- 数据要配套操作(订单能算总价、能打印)→ 操作写成方法。
- 会有多个”同类但内容不同”的个体(多个用户、多个商品)→ 类 + 多次
new。
只想临时算两个数,一个独立方法就够了,不必硬造类。
常见坑
- 忘了 new:声明
Person p;就直接p.Name = ...,此时p是null,运行报空引用异常。必须先new。 - 误以为赋值会复制:把
a赋给b,改b会影响a(同一对象)。要独立副本得另行拷贝。 - 字段未初始化就读取:数值字段默认 0、引用字段默认
null,字符串字段建议给= ""默认值更稳。
Warning引用类型”赋值即共享”最容易翻车。当你疑惑”数据怎么自己变了”,先想想是不是两个变量指向了同一个对象。
最佳实践
- 用类把”相关数据 + 操作”聚到一起,别让零散变量满天飞。
- 初学显式用
public字段便于练习,真实项目更推荐用”属性(property)“封装(后续章节讲)。 - 见
class X(int Id)主构造器写法,理解它等价于”先声明字段、再在构造里赋值”。 - 对象用前确保
new过,引用字段给合理默认值。
类 vs 结构体:以后会讲
C# 里除了 class,还有 struct(结构体)。关键区别:class 是引用类型,赋值共享;struct 是值类型,赋值复制整份数据。描述”有身份、要共享”的事物(人、订单)用 class;描述”轻量、纯数据”的小结构(坐标、颜色)更适合 struct。这块后面有专章对比,现在知道有这两种选择即可。
对象用完会怎样
new 出来的对象放在”堆”上,不用时由垃圾回收器(Garbage Collection,GC)自动清理,你基本不用手动释放。这和 C/C++ 要自己 free 不同,是 C# 让人省心的地方。只有涉及文件、网络等非托管资源时,才需要 using 释放,那是后面的话题。
Tip初学只要记住:普通对象只管
new着用,内存有 GC 兜底,别总想着手动”释放”。
小结
类是蓝图,对象是实例;字段存状态,方法写行为;new 把图纸变成真实对象。理解”引用共享”是面向对象第一块基石。下一章我们给成员加上”谁能看、谁能改”的边界——访问修饰符。