浅谈C#中对引用类型的误解
作者:qylost 发布时间:2021-10-18 12:40:37
值类型和引用类型作为两个非常基础而且很重要的概念,一般我们都是在最开始的时候学的,你听到的可能是这样的:值类型传递的是具体的值(副本),引用类型传递的是引用,对于前者大家都不会有什么疑惑,但是在引用类型上就可能会进入一些误区。
概念插入:
值类型:值类型传递的是数据的副本,也就是将整个数据进行Copy然后赋值给另一个变量。
引用类型:传递的是对象的地址/路径(一般都会叫做引用),在对象的赋值过程中实际上是把目标对象的地址以副本的形式给了接收的对象。
实例说明
如下我们新建了一个Student类,定义了一个变量student1,然后定义了一个变量student2并将student1赋值给了它,紧接着创建了student3并将student3赋值给了student1。
输出结果:1
class Program
{
static void Main(string[] args)
{
//step1
Student student1 = new Student() { StudentId = 1 };
Student student2 = student1;
Student student3 = new Student() { StudentId = 3 };
//step2
student1 = student3;
Console.WriteLine(student2.StudentId.ToString());
Console.ReadKey();
}
}
public class Student
{
public int StudentId { get; set; }
}
Step1的操作如下图所示:
在图中的右侧我们使用矩形代替两个通过new关键字创建的对象,并为其标识了两个虚拟的ID,在左侧我们定义了三个变量,如图的圆角矩形所示,这三个变量不是真正意义上的对象,只是对象的一个所在地址而已,也就是我们通过这个变量就可以找到一个特定的地址。其中student1变量持有的ID(内存地址)为1001,student2也是1001,student3为1002。这里需要注意的是student1的1001和student2的1001虽然都是指向的1001,但是这两个1001都只是对象地址的一个副本,也就是说student1的1001和student2的1001并不是同一个,只是被Copy了而已(可以理解为这个地址是以值类型的方式进行传递的)。
这里要注意的是变量student2和student1是没有关系的,它们只和右侧的1001有关系,只是它们地址的值是相等的。
new关键字:
创建特定对象的实例并返回其引用地址(只是返回了地址的一个副本,而不是真正的对象)
When the object is created, the memory is allocated on the managed heap, and the variable holds only a reference to the location of the object.(来源于官方文档:https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/types/)
译:创建对象后,内存会在托管堆上进行分配,并且变量只保留对对象位置的引用。
Step2的操作如下图所示:
在Step2的代码中我们将student3的变量赋值给了student1,那么这段代码执行的是将student3对应的ID(引用地址)以副本的方式给了student1。
//step2
student1 = student3;
Console.WriteLine(student2.StudentId.ToString());
Console.ReadKey();
如果你对引用传递理解有有偏差的话你可能会认为student2的地址也会变成1002,也就是student2.StudentId变成了3。这样理解是不正确的,我们刚才说过了虽然它们的引用地址是都是1001,但是这个地址也是通过副本进行传递的。也就是说当student1的地址发生改变并不会影响student2的地址。
再述:
当右侧对象中的值发生改变时,通过左侧变量来获取拿到的就是改变后的值,而当左侧变量值的改变时并不会影响右侧对象值的。左侧变量值的改变只是对应的地址发生了改变而不是对象的值发生了改变。
举例分析
这里从我们常用的两个购物平台淘宝、京东来举例说明引用地址传递。
右侧有两个对象分别是淘宝和京东,左侧我们定义了三个变量来保存这个对象的地址(和上边的例子是一样的)
如下图,我们将valA变量存放的地址改成了www.jd.com ,我们只是改变了变量存放的地址而并没有改变valA之前所对应的对象的值。
总结
引用类型传递的是对象的引用,是将引用地址以副本的方式进行传递。
来源:https://segmentfault.com/a/1190000019968579


猜你喜欢
- 一、概念String代表字符串,java语言中所有双引号的字符串都是String的对象,不管是否是new出来的对象。二、特点1.String
- Jackson,我感觉是在Java与Json之间相互转换的最快速的框架,当然Google的Gson也很不错,但是参照网上有人的性能测试,看起
- 前言 这其实是一道面试题,是我在面试百度的时候被问到的,当时没有答出来(因为自己真的很菜),后来在网上寻找答案,看到也是一头雾水,
- spring cloud常用依赖和配置整理常用依赖// pom.xml<?xml version="1.0" en
- 1 Excel上传针对Excel的上传,采用的是比较常规的方法,其实和文件上传是相同的。具体源码如下: @PostMapping
- 本文实例讲述了C#操作session的类。分享给大家供大家参考。具体分析如下:这个C#类对session操作进行了再次封装,可以大大简化se
- 类加载是什么把磁盘中的java文件加载到内存中的过程叫做类加载当我们用java命令运行某个类的main函数启动程序时,首先需要通过类加载器把
- Home键(小房子键)在键盘上映射的就是home键,这倒是很好记。Menu键用于打开菜单的按键,在键盘上映射的是F2键,PgUp键同样可以。
- 1、泛型的基础概念1.1 为什么需要泛型 List list = new ArrayList();//默认类型是Object
- 本文,将介绍如何通过Java后端程序代码在PDF中创建工具提示。添加工具提示后,当鼠标悬停在页面上的元素时,将显示工具提示内容。导入jar包
- Druid动态数据源配置 主要是继承AbstractRoutingDataSource再通过AOP来实现动态数据源切换.下面给大家介绍Dru
- let 和 var(a): let 声明的变量只在 let 命令所在的代码块内有效(b): let 是在代码块内有效,var 是在全局范围内
- HTTP请求,在日常开发中,还是比较常见的,今天给大家分享HttpUtils如何使用。阅读本文,你将收获:简单总结HTTP请求常用配置;Ja
- 本文实例讲述了C#日期格式字符串的相互转换操作。分享给大家供大家参考,具体如下:方法一:Convert.ToDateTime(string)
- Java 判断字符串中是否包含中文的实例详解 Java判断一个字符串是否有中文是利用Unicode编码来判断,因为中
- — 遇到问题今天在IDEA里面运行项目的时候报了一个错,如下图所示:— 找到问题根源其实控制台给出的错误信息提示说的很明显:类加载器加载文件
- 前言《接月饼小游戏》是一个基于java的自制游戏,不要被月亮砸到,尽可能地多接月饼。此小项目可用来巩固JAVA基础语法,swing的技巧用法
- 实现效果图:下面是具体代码,可直接复制:package com.lcw.rabbit.widget;import android.anima
- 一、讲个事故接口安全老生常谈了过年之前做了过一款飞机大战的H5小游戏,里面无限模式-需要保存用户的积分,因为使用的Body传参,参数是可见的
- 代码如下所示: public static Bitmap