值类型和引用类型及参数传递

值类型和引用类型:java

C#数据类型分为两大类:值类型和引用类型。数组

值类型数据主要有:结构体struct,枚举体enum,布尔型bool,浮点型,整型。函数

引用类型数据主要有:数组,字符串,接口,委托,类。spa

值类型和引用类型的区别:.net

  引用类型继承自System.Object,值类型继承自System.ValueType。指针

  引用类型保存到内存的堆heap中,值类型保存在内存的堆栈stack中。在.net中,栈的内存是自动释放的,而堆会有垃圾回收器GC来释放。code

  引用类型能够派生出新的类型,而值类型不能够。引用类型能够包含null值,而值类型不能够。对象

  引用类型变量赋值只复制对象的引用,不复制对象自己。而将一个值类型变量赋给另外一个值类型变量时,将复制包含的值。blog

下面一个小例子能够简单说明值类型和引用类型:继承

class PointR
    {
        public int x, y;
    }
    struct PointV
    {
        public int a, b;
    }

    class Program
    {
        static void Main(string[] args)
        {
            //给一个引用类型赋值将复制到一个对象的引用,而给一个值类型赋值将复制一个对象的值
            PointR r;
            PointV v;
            r = new PointR();
            v = new PointV();
            r.x = 7;
            v.a = 7;

            PointR pr = r;
            PointV pv = v;

            pr.x = 9;
            pv.a = 9;
            Console.WriteLine(r.x);//9
            Console.WriteLine(v.a);//7

            Console.Read();
        }
    }

C#参数传递:

.net默认的是经过值传送变量,可是也能够迫使值参数经过引用传送给方法。C#要求对传递给方法的参数进行初始化。在传递给方法以前,不管时按值传递,仍是按引用传递,变量都必须初始化。 ref关键字:能够迫使值参数经过引用传送给方法。即:在.net中,若是把一个参数传递给方法,且这个方法的输入参数前带有ref关键字,则该方法对变量所作的任何改变都会影响原来对象的值。下面一个小例子说明按值传递和ref参数传递:

class Program
    {
        //默认值,C#的参数是按值传递的,这也是最多见的状况
        static void Method1(int p)
        {
            ++p;
        }

        //为了按引用传递,C#提供了参数修饰字ref,。ref修饰字要求变量在传递给方法以前必须赋值
        static void Method2(ref int p)
        {
            ++p;
        }

        static void Main(string[] args)
        {
            int x = 9;
            int y = 9;
            Method1(x);
            Method2(ref y);
            Console.WriteLine(x);//9
            Console.WriteLine(y);//10

            Console.Read();
        }
    }

在方法的输入参数前面加上out关键字时,传递给该方法的变量能够不初始化。该变量经过引用传递,因此在从被调用的方法中返回时,方法对该变量进行的任何改变都会保留下来。在调用该方法时,还须要使用out关键字,这与在定义该方法时同样。而且out修饰字要求变量在从方法返回时必须赋值。举例说明:

class Program
    {
        //out修饰字要求变量在从方法返回时必须赋值
        static void Split(string name, out string firstName, out string lastName)
        {
            int i = name.LastIndexOf(' ');
            firstName = name.Substring(0, i);
            lastName = name.Substring(i + 1);
        }

        static void Main(string[] args)
        {
            string a, b;
            Split("zhou enlai", out a, out b);
            Console.WriteLine("{0}+ {1}", a, b);//zhou+ erlai

            Console.Read();
        }
    }

还有一个params修饰传递参数,很少说,直接举例:

class Program
    {
        //params 修饰字可使用在方法的最后一个参数上,这样方法就能够接受任意数目的某种类型的参数
        static int Add(params int[] arr)
        {
            int sum = 0;
            foreach (int i in arr)
            {
                sum += i;
            }
            return sum;
        }

        static void Main(string[] args)
        {
            int i = Add(1, 1, 2, 3, 4, 5, 6);
            Console.WriteLine(i);//22

            Console.Read();
        }
    }

 

补充:

原由是网上看到一句话:java里面的参数传递都是按值传递的。不理解,因而查询资料:

java数据类型分类两大类:基本类型和对象类型,相应的,变量也分为基本类型和引用类型。

基本类型数据有:byte\short\int\long\float\double\char\boolean

整数类型:byte是8位字节,范围是-128-127,short是16位的,int是32位,long是64位

浮点数:float是32位,1位符号位,7位指数,23位有效尾数;double是64位,1位符号位,11位指数,52位有效尾数;

字符:char是16位字节

布尔类型:boolean。

基本类型的变量保存自己的数值,“引用值”则保存内存空间地址,表明了对某个对象的引用,而不是对象自己。

基本类型的变量在声明时则由系统自动分配内存空间,不能包含null;而引用类型的变量在声明时仅仅是对变量分配了引用空间,而不分配数据空间,能够赋予null值。

 

值传递:

值传递在进行方法调用时,实际参数把它的值传递给对应的形参,函数接收的形参数组实际上是实参数值的拷贝,对形参进行修改不会影响实际参数的数值。

引用传递:

引用传递在进行方法调用时,实际参数把它对对象的引用传递给形参变量,而不是将对象传递给形参变量,在进行方法调用过程当中,实参变量和形参变量具备相同的数值,都是指向同一块内存地址,对形参数值进行改变,改变的是内存地址中的实际对象,形参变量自己的引用数值不会获得改变。

此处须要考虑String、Integer、Double等基本基本类型包装类,它们都是immutable类型,由于它们都没有自身修改操做的函数,因此对它们的每次操做都是从新建立一个对象,所以能够将它们看成基本类型使用,在参数传递时能够按照值传递来考虑。

综合,上文说的java都是按值传递的,能够这么理解,这个值传递实际上是实参地址的拷贝,获得这个拷贝地址后,你能够经过它修改这个地址的内容,由于此时这个内容的地址和原地址是同一个地址,可是你不能修改这个地址自己使其从新引用其它的对象,因此也能够说成是指传递。但同时由于形参的引用地址和实参的引用地址是相同的,所以对形参的修改也会影响实参变量。

 

说明:不论是对象、基本类型仍是对象数组、基本类型数组,在函数中都不能改变其实际地址但能改变其中的内容。

这里加入一张网上拷贝的图片便于理解:

 

 

关于值传递和引用传递,网上还有这么一种说法:其实都是对“=”的理解

一、= 是赋值操做(任何包含=的如+=、-=、 /=等等,都内含了赋值操做)。再也不是你之前理解的数学含义了,而+ - * /和 = 在java中更不是一个级别,换句话说, = 是一个动做,一个能够改变内存状态的操做,一个能够改变变量的符号,而+ - * /却不会。这里的赋值操做实际上是包含了两个意思:一、放弃了原有的值或引用;2获得了 = 右侧变量的值或引用。Java中对 = 的理解很重要啊!!惋惜好多人忽略了,或者理解了却没深思过。

二、对于基本数据类型变量,= 操做是完整地复制了变量的值。换句话说,“=以后,你我已无关联”;至于基本数据类型,就不在这科普了。基本类型:Byte\Short\int\long\float\double\char\boolean.

三、对于非基本数据类型变量,= 操做是复制了变量的引用。换句话说,“嘿,= 左侧的变量,你丫别给我瞎动!咱俩如今是一根绳上的蚂蚱,除非你再被 = 一次放弃现有的引用!!上面说了 = 是一个动做,因此我把 = 看成动词用啦!”。而非基本数据类型变量你基本上能够

四、参数自己是变量,参数传递本质就是一种 = 操做。参数是变量,全部咱们对变量的操做、变量能有的行为,参数都有。因此把C语言里参数是传值啊、传指针啊的那套理论全忘掉,参数传递就是 = 操做。

相关文章
相关标签/搜索