方法(1)- 参数传递

按值传递

c#的函数默认只能有0或者1个返回值,而输入参数可以有任意个。默认情况,参数都是按值传递的,即在方法内部改变,而方法外部看不到任何改变。不过,这要看参数本身是值类型还是引用类型。如果是值类型的话,那么相信大家都知道,方法内部怎么改,外面都看不见,因为传进去的是一个值的副本。而如果参数本身是引用类型,那么传进去的就是一个引用。(亦即按值传递传递的是栈上的对象)此时如果在方法内改变引用类型的值,相当于把引用指向的堆上的对象改了,自然而然的,所有指向该堆上的对象的引用将全部受到影响。

class Program
    {
        static void Main(string[] args)
        {
            rectangle a = new rectangle("info", 10, 20);
            rectangle b = a;
            rectangle c = a;
            change(a, 999);

            Console.WriteLine(string.Format("A: chang is {0} and kuan is {1}, info: {2}", a._chang, a._kuan, a._recinfo.infostring));
            Console.WriteLine(string.Format("B: chang is {0} and kuan is {1}, info: {2}", b._chang, b._kuan, b._recinfo.infostring));
            Console.WriteLine(string.Format("C: chang is {0} and kuan is {1}, info: {2}", c._chang, c._kuan, c._recinfo.infostring));

            Console.ReadKey();
        }

        public static void change(rectangle r, double chang)
        {
            r._chang = chang;

            //没有意义,引用类型按值传递,不能改变引用指针的指向
            r = new rectangle("newinfo", 1, 1);
        }
    }

    class rectangle
    {
        public shapeinfo _recinfo;
        public double _chang;
        public double _kuan;

        public rectangle(string recinfo, double chang, double kuan)
        {
            _recinfo = new shapeinfo(recinfo);
            _chang = chang;
            _kuan = kuan;
        }
    }

该例子中我们通过方法change修改了对象a的字段chang的值,但a,b,c三个对象全部受到了影响,这是因为这三个对象在栈上的引用的指针全部指向一个地方。下面的一个草图可能可以令大家加深一点印象。当我修改的时候,我修改的是堆上的字段chang的值,显然指向他的所有对象都有牵连。(这是对于具有可变性的引用类型来说的,对于具有不变性,或者不具有可变性的引用类型 - 字符串来说,我们无法修改它的值,也就是说我们做不到操作他堆上空间的值这件事,我们通过另一种方法进行修改,大家可以先思考一下这是什么方法 - 对了,如果我不能修改你,我可以另辟一块空间出来嘛,然后我把新的值放进去,然后把你的指针指向改成指到新的空间,不就可以了么,这正是修改字符串的时候发生的全部事情!)

所以字符串是特例,字符串虽然是引用类型,但它具有不变性,也就是说一经赋值就不能改变(堆上的空间)了。每次当改变某个字符串的值的时候,实际上是在堆上新开辟了一块内存,然后把新的值储存在那里,然后改变栈上引用的指针的指向,令其指向了新的内存。例如(例子来源:http://www.cnblogs.com/zhili/archive/2013/06/11/ParameterPass.html)。所以说多次操作字符串将会对系统性能产生不好的影响:

  1. 开辟大量新的空间,占用过多堆上的空间
  2. 会开辟新的空间,然后指针指向也改变了。那么旧的那块空间呢,回收了么,显然没有,因为旧的那块空间也是字符串类型的,是一个引用类型,而引用类型是要等待垃圾收集器回收的,所以一时半会回收不了,这也影响性能

一个解决方法是使用StringBuilder,因为其具有可变性,于是上面两个问题都没有了。

class Program
    {
        static void Main(string[] args)
        {
            string str = "old string";
            ChangeStr(str);
            Console.WriteLine(str);

        }

        private static void ChangeStr(string oldStr)
        {
            oldStr = "New string";
            Console.WriteLine(oldStr);
        }
}

这就是引用类型的按值传递,传递的是栈上的引用,而指针的指向不能被改变。那么如何可以改变指针的指向呢?那就要借助按引用传递了。

按引用传递(ref关键字)

默认方法是按值传递的,如果要按引用传递,必须借助ref关键字。先说说值类型。如果是以ref传入值类型的话,可以预见,外部的值类型也会发生变化(此时值类型就拥有了一个类似引用类型的行为)。显而易见,如果传进去的引用指向null,那么在方法内部操作相当于对null进行操作,编译器将给出NullException。所以传入的引用必须已经初始化了一个值。例如下面的例子:

static void Main(string[] args)
        {
            string a = "123";
            string b = "abc";

            //这里也要显式的加上ref
            swap(ref a, ref b);

            Console.WriteLine(string.Format("a= {0}, b={1}", a, b));
            Console.ReadKey();
        }

        //值类型的按引用传递,不会为值类型装箱
        public static void swap(ref string a, ref string b)
        {
            string temp = a;
            a = b;
            b = temp;
        }

这个简单的例子演示了按引用传递两个值类型,当方法运行完之后,外部的两个字符串也发生了变化。要注意的是,当值类型按引用传递时,不会对值类型装箱。传进去的仅仅是地址而已。对引用类型按引用传递时,传进去的也是地址(或者是指针),此时我们可以操作这个地址,也就是改变指针的指向。我们也可以和按值传递时候的行为一样,改变引用类型字段的值。

        static void Main(string[] args)
        {
            rectangle a = new rectangle("info", 10, 20);
            rectangle b = a;
            rectangle c = a;
            change(ref a);

            Console.WriteLine(string.Format("A: chang is {0} and kuan is {1}, info: {2}", a._chang, a._kuan, a._recinfo.infostring));
            Console.WriteLine(string.Format("B: chang is {0} and kuan is {1}, info: {2}", b._chang, b._kuan, b._recinfo.infostring));
            Console.WriteLine(string.Format("C: chang is {0} and kuan is {1}, info: {2}", c._chang, c._kuan, c._recinfo.infostring));

            Console.ReadKey();
        }

        public static void change(ref rectangle r)
        {
            //引用类型按引用传递,更改指针的指向使其指向一个新的对象
            r = new rectangle("newinfo", 1, 1);
        }

注意如果不是按引用传递的话,方法内部的

r = new rectangle("newinfo", 1, 1);

没有任何意义。

				
时间: 2024-08-25 21:21:02

方法(1)- 参数传递的相关文章

java 对象的this使用 java方法中参数传递特性 方法的递归

一.this关键字,使用的情形,以及如何使用. 1.使用的情形 类中的方法体中使用this  --初始化该对象 类的构造器中使用this --引用,调用该方法的对象 2.不写this,调用 只要方法或者构造器中  不存在成员变量与局部变量同名的情况,可直接不写this 否则方法中或构造器中使用的就是局部变量 3.static 静态方法不能调用this,不能调用任何非static修饰的成员变量 或者方法 二.java方法中  参数传递特性 1.基本数据类型--实际是新增变量,并赋值而已   不过代

方法的参数传递机制(C#)

六 方法的参数传递机制 值参数,引用参数,输出参数 //参数的传递机制 using System; class Method { //值参数,传递的是数值本身,不改变外部变量的值 public static void ValueMethod(int i) { i++; } //引用参数,传递的是数据地址,直接对数据进行操作,原值要变化 //要注意的是string类型,赋值以后原值就不好改变了 public static void ReferenceMethod(ref int i) { i++;

方法的参数传递

方法的参数传递(重点.难点) 1.形参:方法声明时,方法小括号内的参数    实参:调用方法时,实际传入的参数的值 2.规则:java中的参数传递机制:值传递机制 1)形参是基本数据类型的:将实参的值传递给形参的基本数据类型的变量 2)形参是引用数据类型的:将实参的引用类型变量的值(对应的堆空间的对象实体的首地址值)传递给形参的引用类型变量. 图解如下: package com.atguigu.java; /* * 方法的参数传递(重点.难点) * 1.形参:方法声明时,方法小括号内的参数 *

JAVA学习--方法的参数传递

* 方法的参数传递(重点.难点)  * 1.形参:方法声明时,方法小括号内的参数  *   实参:调用方法时,实际传入的参数的值  *     * 2.规则:java中的参数传递机制:值传递机制  *   1)形参是基本数据类型的:将实参的值传递给形参的基本数据类型的变量  *   2)形参是引用数据类型的:将实参的引用类型变量的值(对应的堆空间的对象实体的首地址值)传递给形参的引用类型变量.  * 1 public class TestArgsTransfer { 2 public stati

初学笔记(C#方法的参数传递)

在声明方法时,所定义的参数是形式参数(简称形参),这些参数的值由调用方负责为其传递,调用方传递的是实际数据,成为实际参数(简称实参),在调用方法时,,必须严格按照方法所定义的参数类型和顺序指定实参.方法的参数传递按性质分为按值传递和按引用传递. 1.安值传参      按值传递时,把实参变量的值赋给相应的行参变量,即被调用的方法接受的只是实参的数据值.当方法内部更改了形参数据时,不会影响到是参变量的值,即实参和形参变量是两个不相同的变量,它们具有各自的内存地址和数据值.故实参传递给形参是一个单向

我的Java开发学习之旅------>Java语言中方法的参数传递机制

实参:如果声明方法时包含来了形参声明,则调用方法时必须给这些形参指定参数值,调用方法时传给形参的参数值也被称为实参. Java的实参值是如何传入方法?这是由Java方法的参数传递机制来控制的,Java里方法的参数传递方式只有一种:值传递.所谓值传递,就是将实际参数的副本(复制品)传入方法内,而参数本身不会收到任何影响. 一.参数类型是原始类型的值传递 下面通过一个程序来演练 参数类型是原始类型的值传递的效果: public class ParamTransferTest { public sta

java方法的参数传递

java中方法的参数传递只有一种:值传递public class SwapMethod { /**  * 交换方法  * @param a  * @param b  */ public static void Swap(int a , int b){  int temp ;  temp =a;  a = b;  b = temp;  System.out.println("交换后的a = "+a+";  b = "+b); } public static void

尚硅谷面试第一季-04方法的参数传递机制

面试题代码: 1 package 方法的参数传递机制; 2 3 import java.util.Arrays; 4 5 /** 6 * @author zsh 7 * @company wlgzs 8 * @create 2019-03-27 9:37 9 * @Describe 方法的传递机制 10 * (1)形参是基本数据类型的 11 * 传递数据值 12 * (2)形参是引用数据类型的 13 * 传递地址值 14 * 特殊的类型:String.包装类等对象不可变性 15 */ 16 pu

深入理解Java中方法的参数传递机制

形参和实参 我们知道,在Java中定义方法时,是可以定义参数的,比如: public static void main(String[] args){ } 这里的args就是一个字符串数组类型的参数. 在程序设计语言中,参数有形式参数和实际参数之分,先来看下它们的定义: 形式参数:是在定义函数名和函数体的时候使用的参数,目的是用来接收调用该函数时传入的参数,简称"形参". 实际参数:在主调函数中调用一个函数时,函数名后面括号中的参数称为"实际参数",简称"

JavaSE 面试题: 方法的参数传递机制

JavaSE 面试题 方法的参数传递机制 import java.util.Arrays; public class Test { public static void main(String[] args) { int i = 1; String str = "hello"; Integer num = 200; int[] arr = {1, 2, 3, 4, 5}; MyData my = new MyData(); change(i, str, num, arr, my); S