引用类型就像 “快递单”
比如你买了一个手机(数据),快递单上写着收货地址(引用)。别人拿到快递单,不是直接拿到手机,而是按地址找到手机。
和值类型的区别(一句话分清):
为什么要用引用类型?
类是引用类型的 “代表”,之前学的Student“学生类”、Animal“动物类” 都是引用类型。
特点:
例子:
class Person // 类是引用类型
{
public string name;
}
// 使用
Person p1 = new Person(); // p1存的是地址(指向堆里的Person对象)
p1.name = "小明";
Person p2 = p1; // p2和p1存的是同一个地址(指向同一个对象)
p2.name = "小红"; // 修改p2的name,p1的name也会变
Console.WriteLine(p1.name); // 输出“小红”(因为p1和p2指向同一个对象)
关键:多个变量可以指向同一个对象,改一个会影响其他(就像多人共享同一个快递地址,改地址里的东西,所有人看到的都变)。
接口就像 “说明书”,只规定必须有哪些功能,不规定怎么实现。
特点:
例子:
// 定义接口(说明书:必须能吃饭和睡觉)
interface ICanDo
{
void Eat(); // 只说要吃饭,不说怎么吃
void Sleep();
}
// 实现接口(人类符合这个说明书)
class Person : ICanDo
{
public void Eat() // 具体实现“吃饭”
{
Console.WriteLine("用筷子吃饭");
}
public void Sleep() // 具体实现“睡觉”
{
Console.WriteLine("躺着睡");
}
}
// 使用
ICanDo person = new Person(); // 接口变量指向实现类的对象
person.Eat(); // 输出“用筷子吃饭”
关键:接口让不同的类有统一的功能(比如 “鸟” 和 “飞机” 都实现 “能飞” 接口),方便统一调用。
数组就像 “编号的抽屉”,每个抽屉放一个数据,按顺序排列。
特点:
例子:
int[] arr1 = new int[3]; // 数组是引用类型,arr1存的是地址
arr1[0] = 10;
int[] arr2 = arr1; // arr2和arr1指向同一个数组
arr2[0] = 20;
Console.WriteLine(arr1[0]); // 输出20(因为改的是同一个数组)
关键:数组变量赋值时,传递的是地址(就像复制抽屉的地址,两个地址指向同一个抽屉组)。
字符串就像 “写死的纸条”,一旦创建就不能改(不可变)。
特点:
例子:
string s1 = "hello"; // s1存的是“hello”的地址
string s2 = s1; // s2存的是同一个地址
s2 = "world"; // 给s2赋新值,会创建新字符串,s2指向新地址
Console.WriteLine(s1); // 输出“hello”(s1的地址没变,不受影响)
为什么特殊?
普通引用类型改内容会影响其他变量,但字符串改内容时,会新造一个字符串(就像你改了纸条内容,会换一张新纸条,原来的纸条不变)。
委托就像 “遥控器”,可以指向一个方法,按遥控器就执行对应的方法。
特点:
例子:
// 定义委托类型(遥控器类型:能控制“无参数、无返回值”的方法)
delegate void MyDelegate();
class TV
{
public void TurnOn() { Console.WriteLine("开电视"); }
public void TurnOff() { Console.WriteLine("关电视"); }
}
// 使用
TV tv = new TV();
MyDelegate remote = tv.TurnOn; // 遥控器指向“开电视”方法
remote(); // 按遥控器,执行开电视(输出“开电视”)
remote += tv.TurnOff; // 遥控器再加上“关电视”方法
remote(); // 按遥控器,先开电视再关电视(输出“开电视”和“关电视”)
关键:委托让方法可以像变量一样传递(比如把 “开电视” 方法传给遥控器,再传给别人)。
object 就像 “万能容器”,能装任何类型的数据(值类型、引用类型都能装)。
特点:
例子:
object obj1 = "字符串"; // 装引用类型
object obj2 = 123; // 装值类型(会装箱)
object obj3 = new Person(); // 装类对象
// 用的时候需要“拆箱”(转成原来的类型)
int num = (int)obj2; // 把object里的123转成int
关键:万能但麻烦,用的时候要转类型(就像万能插座能插任何插头,但有时需要转接头)。
就像快递单(变量)存地址,货物(数据)在仓库(堆)里。
复制变量时,两个变量指向同一个对象(比如复印快递单,两张单指向同一个货物)。
当没有变量指向对象时(没人要的货物),系统会自动删除(不用手动清理内存)。
对比项 |
引用类型(如类、字符串) |
值类型(如 int、struct) |
存储方式 |
变量存地址,数据在堆里 |
变量直接存数据,在栈里 |
赋值效果 |
复制地址,多变量指向同一数据 |
复制数据,多变量各有一份 |
内存管理 |
系统自动回收(垃圾回收) |
超出作用域自动释放 |
适合场景 |
复杂数据(学生、汽车) |
简单数据(数字、布尔值) |
例子 |
class、string、int[] |
int、bool、struct |
因为字符串是 “不可变” 的引用类型,修改时会创建新字符串,原来的字符串不变(就像改快递单上的地址,原来的地址对应的货物还在)。
数组本身是引用类型,但元素可以是任何类型:
记住:遇到引用类型,就想 “快递单和货物” 的关系,理解起来超简单!