引用类型就理应这样吗?——浅析“引用”

2023-12-04 02:10
文章标签 类型 引用 浅析 理应

本文主要是介绍引用类型就理应这样吗?——浅析“引用”,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

C#中引用类型继承自System.Object.引用类型的对象的值存放在托管堆上,在栈中只存放对它的索引(地址)。因为这个原因,引用类型对象之间的赋值操作默认情况下都是浅拷贝,只拷贝栈中的一份索引,它们指向一块相同的托管堆内存。如Person p=new Person();Person p1=p;第二个赋值语句的意思就是让p1指向p所指向的对象,即二者共同指向一个Pernson的实例new Person()。可是这句话说起来简单,但是应该不是那么好理解的,至少对我来说很长一段时间是这样。下边谈谈本人的拙见,学的东西有限,欢迎指正。

我们可以问自己几个问题:

1p1p既然指向同一个对象,那么他们本身也就是同一个对象?

2、既然他们指向同一个对象,那么对p指向的对象做了修改也会导致p1指向的对象改变?

3、如果问题二答案是肯定的,那么也就是说操作p对象也会同样操作p1对象?

4、如果问题三的答案是肯定的,那么对引用类型对象的任意操作就会同时更改另一个和它具有相同类型并且指向同一个对象的对象的值?也就是说ref关键字对于引用类型的参数传递没有意义?(因为按照这种逻辑引用类型的变量在方法中的操作同样会反应到方法外边来,无需使用ref关键字也能达到这样的效果)带着这几个问题,浅析下c#中引用类型的“引用”。

         先贴段代码吧。

    class Person

    {

        publicPerson(int age, stringname) { this.age = age; this.name = name; }

        public int age;

        public string name;

        public void DoSomthing() { Console.WriteLine("我的name是{0},age是{1}", name, age); }

}

 

    class Program

    {

        static void Main(string[]args)

        {

            Personp = new Person(100,"张三");

            TestRef(p);

            p.DoSomthing();

        }

 

        static void TestRef(Personp)

        {

            p.name = "李四";

        }

}

运行结果:                             

                        图一

1、保持其它部分不变,将方法TestRef修改为以下代码

        static void TestRef(Personp)

        {

            p = newPerson(99,"李四");

        }

 

运行结果: 

图二

2、保持其它部分不变,将方法TestRef修改为以下代码

        static void TestRef(ref Person p)

        {

            p = newPerson(99,"李四");

        }

 

运行结果: 

                            图三

 

现在解释上边代码的运行结果并回答开头的四个问题。

三段代码中p都是引用类型Person的对象,调用方法TestRef的本质是将Main方法中实参p的值赋值给TestRef方法的形参p,这种赋值在前边已说过,只是浅层拷贝,两个p都指向同一个对象,所以在方法中对p指向的对象进行操作 p.name= "李四" 将同样反应到方法外边来。但即使是这样,两个p并不是同一个对对象,也就是说Person.ReferenceEquals对于这两个对象来说是false。说的直白点,形参p在栈中地址和实参p在栈中的地址并不相同。一个很简单的例子,Personp=new Person();Person p1=p;p=null;在进行了这段操作之后难道p1也为null?答案显然是否定的。

这样就解释了图一和图二的运行结果以及问题一的答案。

至于图三,因为加了ref关键字,所以在实参和形参传值时的并不是做简单的拷贝,而是让形参直接和实参共用同一段堆内存,也就是说他们现在是同一个对象,这点就像是c语言中指针存放的地址和它指向的变量的地址的关系一样(注意:并不是指针本身的地址而是它存放的地址也就是他的值)。所以形参和实参完全是等价的。这就是ref关键字的价值所在。

这样也回答了问题四。

关于问题二,答案时肯定的,因为图一中修改了形参p所指向的对象的值,也同时修改了实参p所指向对象的值。但是之中修改也是有限制的。假如当修改p1所指对象的值时p已经指向了一个新的对象,那么这个修改就不会在p中反应出来,所以如果要想将引用类型对象的值的修改反应到方法体外边来而又不想用ref关键字,那么请勿在方法体内改变形参的指向,诸如 p=new Personp=null之类的操作都会改变p的指向。这样的操作对方发体外的实参是无效的,因为他们并不是同一个对象,他们仅仅是指向同一个对象而已。

关于问题三,其实在上边已作了回答。答案当然是否定的,它们又不是同一个对象,操作对象p和对象p1毛线关系都没有。只是说当pp1指向同一个对象时,对p的操作有可能是对p所指向对象的操作(如p.name=”李四,但也有可能不是,如p=new Person(),那么也当然会操作到p1所指向的对象,这样就会反应到p对象上来,仅此而已。

补充一点,对引用类型对象的赋值操作 如:Personp=new person(),实际的做的事情大概是在托管堆上创建Person 类的对象new Person()并返回该对象的指针,然后在栈上创建Person类型的对象的引用,并使该引用的值为刚刚返回的指针值。

综上所述,我觉得说xx对象所指向的对象,追根朔源指的应该就是类似于new Person()的这个对象,其它对象可能会指向xx这个对象所指向的对象,即new Person。要搞清楚引用类型的各种细节,起码得搞清哪个对象是哪个。

转载于:https://www.cnblogs.com/eval_anrong/p/3527691.html

这篇关于引用类型就理应这样吗?——浅析“引用”的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/451717

相关文章

浅析Java中如何优雅地处理null值

《浅析Java中如何优雅地处理null值》这篇文章主要为大家详细介绍了如何结合Lambda表达式和Optional,让Java更优雅地处理null值,感兴趣的小伙伴可以跟随小编一起学习一下... 目录场景 1:不为 null 则执行场景 2:不为 null 则返回,为 null 则返回特定值或抛出异常场景

MySQL 中查询 VARCHAR 类型 JSON 数据的问题记录

《MySQL中查询VARCHAR类型JSON数据的问题记录》在数据库设计中,有时我们会将JSON数据存储在VARCHAR或TEXT类型字段中,本文将详细介绍如何在MySQL中有效查询存储为V... 目录一、问题背景二、mysql jsON 函数2.1 常用 JSON 函数三、查询示例3.1 基本查询3.2

Pydantic中Optional 和Union类型的使用

《Pydantic中Optional和Union类型的使用》本文主要介绍了Pydantic中Optional和Union类型的使用,这两者在处理可选字段和多类型字段时尤为重要,文中通过示例代码介绍的... 目录简介Optional 类型Union 类型Optional 和 Union 的组合总结简介Pyd

Oracle数据库常见字段类型大全以及超详细解析

《Oracle数据库常见字段类型大全以及超详细解析》在Oracle数据库中查询特定表的字段个数通常需要使用SQL语句来完成,:本文主要介绍Oracle数据库常见字段类型大全以及超详细解析,文中通过... 目录前言一、字符类型(Character)1、CHAR:定长字符数据类型2、VARCHAR2:变长字符数

Spring Boot 配置文件之类型、加载顺序与最佳实践记录

《SpringBoot配置文件之类型、加载顺序与最佳实践记录》SpringBoot的配置文件是灵活且强大的工具,通过合理的配置管理,可以让应用开发和部署更加高效,无论是简单的属性配置,还是复杂... 目录Spring Boot 配置文件详解一、Spring Boot 配置文件类型1.1 applicatio

浅析CSS 中z - index属性的作用及在什么情况下会失效

《浅析CSS中z-index属性的作用及在什么情况下会失效》z-index属性用于控制元素的堆叠顺序,值越大,元素越显示在上层,它需要元素具有定位属性(如relative、absolute、fi... 目录1. z-index 属性的作用2. z-index 失效的情况2.1 元素没有定位属性2.2 元素处

Python如何查看数据的类型

《Python如何查看数据的类型》:本文主要介绍Python如何查看数据的类型方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录python查看数据的类型1. 使用 type()2. 使用 isinstance()3. 检查对象的 __class__ 属性4.

Python容器类型之列表/字典/元组/集合方式

《Python容器类型之列表/字典/元组/集合方式》:本文主要介绍Python容器类型之列表/字典/元组/集合方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1. 列表(List) - 有序可变序列1.1 基本特性1.2 核心操作1.3 应用场景2. 字典(D

Python如何在Word中生成多种不同类型的图表

《Python如何在Word中生成多种不同类型的图表》Word文档中插入图表不仅能直观呈现数据,还能提升文档的可读性和专业性,本文将介绍如何使用Python在Word文档中创建和自定义各种图表,需要的... 目录在Word中创建柱形图在Word中创建条形图在Word中创建折线图在Word中创建饼图在Word

SpringBoot接收JSON类型的参数方式

《SpringBoot接收JSON类型的参数方式》:本文主要介绍SpringBoot接收JSON类型的参数方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、jsON二、代码准备三、Apifox操作总结一、JSON在学习前端技术时,我们有讲到过JSON,而在