深层次探究值类型与引用类型,以及值传递引用传递

数据类型

  类型的分类

    所有的类型都可以划分为两类:值类型和引用类型.

  值类型和引用类型的区别在于使用的内存位置不同:值类型数据存储在栈上,而引用类型数据存储在堆上.(至于栈和堆就不在这里多做解释)

  ①.值类型

    值类型在储存时直接包含值,即变量引用的位置就是值在内存中实际存储的位置,可看做是变量的值本身.因此,将第一个变量的值赋给第二

    个值会在新变量的位置创建原始变量的值的一个内存副本.相同值类型的第二个变量不能引用和第一个变量相同的内存地址.所以更改第一

    个变量的值不会影响第二个变量的值.如下图:

    

   类似地,将一个值类型传给一个方法,也会生成一个内存副本.在方法内部对参数值进行任何修改都不会影响调用函数中的原始值.由于值类型要

   求一个内存副本,因此不要让它们消耗太多的内存.(通常应该小于16字节)

   既然这里说到了参数的传递,不得不说一下形参与实参,也可以从这方面理解值类型传递

   1.形参的定义:定义函数名和函数体的时候使用的参数;

   2.形参的作用:实现主调函数与被调函数之间的联系,通常将函数所处理的数据,影响函数功能的因素或者函数处理的结果作为形参。没有形

                参的函数在形参表的位置应该写void.main 函数也可以有形参和返回值,其形参也称为命令行参数,由操作系统在启动程序时

                初始化,其返回值传递给操作系统.

   3.形参与实参的特点:

      a.形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只在函数内部有效.函数调用结束返

        回主调用函数后则不能再使用该形参变量

      b.实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给

        形参。因此应预先用赋值,输入等办法使参数获得确定值。

      c.实参和形参在数量上,类型上、顺序上应严格一致,否则就会发生类型不匹配的错误

      d.在一般传值调用的机制中只能把实参传送给形参,而不能把形参的值反向地传送给实参。因此在函数调用过程中,形参值发生改变,而实参

        中的值不会变化。而在引用调用的机制当中是将实参引用的地址传递给了形参,所以任何发生在形参上的改变实际上也发生在实参变量上

     根据形参和实参的特点我们不难看出:值传递给方法值类型时,可以看做对形参内存的释放,方法体中的语句可视为不存在.

    值类型需要的内存量会在编译时固定下来,而且不会再运行时改变.因为大小固定,所以值类型可以存储在栈的内存区域中.

 

  ②.引用类型

    引用类型和引用它们的变量指向数据存储的位置.引用类型并不直接存储值,它们存储的是对一个内存位置的引用(内存地址),只有在那个位置才

    能找到真正的数据.因此为了访问数据,"运行时"要从变量中读取 内存位置,然后跳转到包含数据的内存位置.引用类型指向的内存区域称为堆.

   

    由于访问引用类型的数据需涉及一次额外的跳转,所以速度会慢一下,然而,由于与值类型不同,其不要求相同数据的内存副本,所以在内存的利用

    率上显得更好.将一个引用类型的变量赋值给另一个引用类型的变量,只会多出一个地址的一个内存副本.所以,引用类型需要的内存副本总是地

    址本身的大小.如果在数据量较大的情况下,由于不需要复制实际的数据,故引用类型比值类型更有效.

    由于引用类型只复制数据的地址,所以两个不同的变量可以引用相同的数据.若其中一个变量更改数据,也会改变另一个变量引用的数据,因此,如

    果在一个方法内部修改引用类型的数据,在调用方那也会发生同样的改动.

       

     图中原来的Y指向的实际位置,即MyClass y 数据的实际内存空间将在CPU空闲时释放.

     在定义一个类时(不含静态成员或变量),一般不会在内存中给其分配一个存储结构,而是在定义对象时才会分配,当利用同一个

     类定义不同对象时,系统会在内存中为不同对象创建不同的存储结构,对应不同的内存地址.

原文地址:https://www.cnblogs.com/Serean/p/4601266.html