一个小程序引发的思考

   既然是一个小程序引发的思考,那么我们就先看看这个小程序,看看他有何神奇之处:

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            MyClass s = new MyClass();
            s.val = 10;
            int i = 20;
            Console.WriteLine("s.val={0},i={1}",s.val,i);
            MyMethod(s, i);
            Console.WriteLine("s.val={0},i={1}", s.val, i);
            Console.Read();
        }
        static void MyMethod(MyClass f1,int f2)
        {
            f1.val = f1.val + 5;
            f2 = f2 + 5;
        }
    }
    class MyClass
    {
        public int val = 20;
    }
}

呵呵,大家看了以后可能会感觉这不是很简单的代码吗?有什么特别的地方吗?没有,真没有!但是我想问下大家这两次输出结果会有什么不同吗?分别是什么?有没有得出两次结果都是一样的?这个程序输出的结果是:

    可能有些童鞋可能会问,不应该是一样的吗?为什么一个值变了,另外一个没有变呢?这是为什么呢?仔细的同学可能会发现static void MyMethod(MyClass f1,int f2)这个方法两个参数的类型不一样,f1属于引用类型,f2属于类型,是不是因为这个原因才导致两个变量经过同样的处理,s.val的值改变了,i的值却没有变。首先我们了解下什么是值类型,什么是引用类型。

值类型与引用类型(这个面试的时候经常会被问到)

    值类型:值类型只需要一段单独的内存,用于存储实际的数据,他存在栈里面

    引用类型:引用类型需要两段内存。

  • 第一段存储实际的数据,它总是位于堆中。
  • 第二段是一个引用指向数据在堆中的位置,它通常位于栈中。

那这样说,像上面s对象,它是一个引用类型,那它应该存放在堆中,但是val又是个值类型,那它不是应该存放在栈中吗?

    请记住,对于一个引用类型,其实例部分始终存放在堆里。既然val是对象s的一部分,那么它们都会被存放在堆里,无论它们是值类型还是引用类型。

这里顺便介绍下栈和堆

栈:栈是一个内存数组,是一个LIFO(last-in first- out,后进先出)的数据结构,栈存储几种类型的数据。

  • 某些类型变量的值
  • 程序当前的执行环境
  • 传递给方法的参数 栈有以下几个特征:
  • 数据只能从栈的顶端插入和删除。                                                                       
  • 把数据放到栈顶叫入栈(push)。
  • 从栈顶删除数据叫出栈(pop) 堆:堆是一块内存区域,在堆里可以分配大块的内存用于存储某些的类型的对象。与栈不同,堆里的内存能够任意顺序存入或移除。    虽然可以在堆里保存数据,但并不能显式地删除它们。CLR的自动GC在判断出程序的代码不会再访问某些数据时,自动清除无主的堆对象。我们因此可以不用操心这项使用其它编程语言时非常容易出错的工作了。       在介绍了值类型、引用类型与堆和栈,那我们解析下上面程序的执行步骤:
    • 在方法被调之前,用作实参的变量s已经在栈里了。
    • 随着方法的开始,系统在栈中为形参分配空间,并从实参复制值。
    • 因为s是引用类型所以引用被复制,结果实参和形参都引用堆中的同一个对象。
    • 因为i是值类型,所以值被复制,产生了一个独立的数据项。
    • 在方法的结尾,f2和对象f1的字段都被加上5.
    • 方法执行后,形参被从栈中弹出。
    • i,值类型,它的值不受方法行为的影响。
    • s,引用类型,它的值被方法的行为改变了。

    亲爱的童鞋们,你们明白了吗?别看一点小程序,原来深挖可以得出那么多信息。其实也侧面说明了基础的重要性,童鞋们加油吧!

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏腾讯IVWEB团队的专栏

你可能不知道的 ECMAScript 2016 的变化(英译)

与 ECMAScript 6(也称为ECMAScript 2015)相比,ECMAScript 2016 是对 JavaScript 语言规范的一个小更新。 ...

1520
来自专栏沈唁志

几道PHP试题,来试试看看你会不会也掉入陷阱

1423
来自专栏Golang语言社区

Golang语言之异常处理

在编写Go语言代码的时候,我们应该习惯使用error类型值来表明非正常的状态。作为惯用法,在Go语言标准库代码包中的很多函数和方法也会以返回error类型值来表...

33313
来自专栏拭心的安卓进阶之路

Java 集合深入理解(3):Collection

今天心情有点粉,来学学 Collection 吧! 什么是集合? 集合,或者叫容器,是一个包含多个元素的对象; 集合可以对数据进行存储,检索,操作; 它们可以...

1985
来自专栏java一日一条

Java 泛型详解

泛型是Java中一个非常重要的知识点,在Java集合类框架中泛型被广泛应用。本文我们将从零开始来看一下Java泛型的设计,将会涉及到通配符处理,以及让人苦恼的类...

635
来自专栏葡萄城控件技术团队

C#7.0中有哪些新特性?

以下将是 C# 7.0 中所有计划的语言特性的描述。随着 Visual Studio “15” Preview 4 版本的发布,这些特性中的大部分将活跃起来。现...

1828
来自专栏GreenLeaves

C# foreach循环较for循环的优势与劣势

一、foreach循环的优势 C#支持foreach关键字,foreach在处理集合和数组相对于for存在以下几个优势: 1、foreach语句简洁 2、效率比...

1798
来自专栏java达人

最有价值的50道java面试题(一)

来自骆昊的技术专栏 1、面向对象的特征有哪些方面? 答:面向对象的特征主要有以下几个方面: 1)抽象:抽象是将一类对象的共同特征总结出来构造类的过程,...

23310
来自专栏用户2442861的专栏

json格式

  1. “名称/值”对的集合(A collection of name/value pairs)。不同的语言中,它被理解为对象(object),记录(reco...

582
来自专栏程序员互动联盟

【编程基础】聊聊C语言-兵马未动粮草先行(1)

上一篇我们讲的聊聊C语言-我的地盘我做主,相信大家对变量的存储类型和变量的作用域有了一定的了解。现在我们马上公布上期的答案如下: #include<stdio....

3178

扫码关注云+社区