Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/postgresql/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Language agnostic 按引用传递还是按值传递?_Language Agnostic_Oop_Parameters_Pass By Reference_Pass By Value - Fatal编程技术网

Language agnostic 按引用传递还是按值传递?

Language agnostic 按引用传递还是按值传递?,language-agnostic,oop,parameters,pass-by-reference,pass-by-value,Language Agnostic,Oop,Parameters,Pass By Reference,Pass By Value,学习一种新的编程语言时,可能遇到的一个障碍是,默认情况下,该语言是按值传递还是按引用传递 这是我用你们最喜欢的语言问你们的问题,到底是怎么做到的?可能的陷阱是什么 当然,你最喜欢的语言可以是你玩过的任何东西: 首先是一些代码: public void swap(int x, int y) { int tmp = x; x = y; y = tmp; } 调用此方法将导致以下结果: int pi = 3; int everything = 42; swap(pi, everythi

学习一种新的编程语言时,可能遇到的一个障碍是,默认情况下,该语言是按值传递还是按引用传递

这是我用你们最喜欢的语言问你们的问题,到底是怎么做到的?可能的陷阱是什么


当然,你最喜欢的语言可以是你玩过的任何东西:

首先是一些代码:

public void swap(int x, int y)
{
  int tmp = x;
  x = y;
  y = tmp;
}
调用此方法将导致以下结果:

int pi = 3;
int everything = 42;

swap(pi, everything);

System.out.println("pi: " + pi);
System.out.println("everything: " + everything);

"Output:
pi: 3
everything: 42"
即使使用“真实”对象也会显示类似的结果:

public class MyObj {
    private String msg;
    private int number;

    //getters and setters
    public String getMsg() {
        return this.msg;
    }


    public void setMsg(String msg) {
        this.msg = msg;
    }


    public int getNumber() {
        return this.number;
    }


    public void setNumber(int number) {
        this.number = number;
    }

    //constructor
    public MyObj(String msg, int number) {
        setMsg(msg);
        setNumber(number);
    }
}

public static void swap(MyObj x, MyObj y)
{
    MyObj tmp = x;
    x = y;
    y = tmp;
}

public static void main(String args[]) {
    MyObj x = new MyObj("Hello world", 1);
    MyObj y = new MyObj("Goodbye Cruel World", -1); 

    swap(x, y);

    System.out.println(x.getMsg() + " -- "+  x.getNumber());
    System.out.println(y.getMsg() + " -- "+  y.getNumber());
}


"Output:
Hello world -- 1
Goodbye Cruel World -- -1"
因此,很明显,Java通过值传递其参数,因为pi和所有对象以及MyObj对象的值不会交换。 请注意,“按值”是java中向方法传递参数的唯一方法。(例如,C++之类的语言允许开发人员在参数类型

之后使用‘<强>和<强>引用来传递参数。 现在是棘手的部分,或者至少是会让大多数新java开发人员感到困惑的部分:(借用)
原作者:托尼·辛茨

public void tricky(Point arg1, Point arg2)
{
    arg1.x = 100;
    arg1.y = 100;
    Point temp = arg1;
    arg1 = arg2;
    arg2 = temp;
}
public static void main(String [] args)
{
    Point pnt1 = new Point(0,0);
    Point pnt2 = new Point(0,0);
    System.out.println("X: " + pnt1.x + " Y: " +pnt1.y); 
    System.out.println("X: " + pnt2.x + " Y: " +pnt2.y);
    System.out.println(" ");
    tricky(pnt1,pnt2);
    System.out.println("X: " + pnt1.x + " Y:" + pnt1.y); 
    System.out.println("X: " + pnt2.x + " Y: " +pnt2.y);  
}


"Output
X: 0 Y: 0
X: 0 Y: 0
X: 100 Y: 100
X: 0 Y: 0"
成功更改pnt1的值! 这意味着对象是通过引用传递的,事实并非如此! 正确的语句应该是:对象引用按值传递。

更多来自Tony Sintes:

该方法成功地改变了 pnt1的值,即使是 按值传递;然而,交换 pnt1和pnt2失败!这是少校 混乱的根源。大体上 方法,pnt1和pnt2仅此而已 而不是对象引用。当你经过的时候 pnt1和pnt2到tricky()方法, Java按值传递引用 就像任何其他参数一样。这 是指传递给 方法实际上是 原始参考资料。下图1 显示两个指向 Java通过 方法的对象


(来源:)

结论或长话短说:

  • Java通过值传递它的参数
  • 在java中,“按值”是将参数传递给方法的唯一方法
  • 使用作为参数给定的对象中的方法将改变对象,因为引用指向原始对象。(如果该方法本身改变了某些值)
有用链接:


按值计算

  • 由于系统必须复制参数,因此速度比通过引用慢
  • 仅用于输入
参考

  • 速度更快,因为只传递一个指针
  • 用于输入和输出
  • 如果与全局变量一起使用,可能会非常危险

    • 别忘了还有按名称传递,以及按值传递结果

      “按值传递”结果与“按值传递”结果类似,增加了一个方面,即在作为参数传递的原始变量中设置值。在某种程度上,它可以避免对全局变量的干扰。显然在分区内存中更好,在分区内存中,通过引用传递可能会导致页面错误()


      “按名称传递”表示仅在实际使用时计算值,而不是在过程开始时计算值。Algol使用pass-by-name,但一个有趣的副作用是编写交换过程()非常困难。此外,通过名称传递的表达式在每次访问时都会重新计算,这也可能有副作用

      c#通过值传递其参数(默认情况下)

      因此,调用此版本的swap将不会产生任何结果:

      string x = "foo";
      string y = "bar";
      swap(x, y);
      
      "output: 
      x: foo
      y: bar"
      
      但是,c#确实给开发人员提供了通过引用传递参数的机会,这是通过在参数类型之前使用“ref”关键字来实现的:

      private void swap(ref string a, ref string b) {
        string tmp = a;
        a = b;
        b = tmp;
      } 
      
      string x = "foo";
      string y = "bar";
      swap(x, y);
      
      "output: 
      x: bar
      y: foo"
      
      此交换将更改引用参数的值:

      private void swap(ref string a, ref string b) {
        string tmp = a;
        a = b;
        b = tmp;
      } 
      
      string x = "foo";
      string y = "bar";
      swap(x, y);
      
      "output: 
      x: bar
      y: foo"
      
      c#还有一个out关键字,ref和out之间的区别很微妙。

      采用 输出参数不需要 分配给作为 调用前输出参数; 但是,被调用方必须 在指定之前,先指定out参数 返回

      相反,参考参数是 最初被认为是由 卡利。因此,被调用方不是 需要分配给ref 参数,然后再使用。参考参数 都被传递到一个 方法

      一个小陷阱是,与java一样,通过值传递的对象仍然可以使用其内部方法进行更改

      结论:

      • 默认情况下,c通过值传递其参数
      • 但在需要时,也可以使用ref关键字通过引用传递参数
      • 传递的参数的内部方法将改变对象(如果该方法本身改变某些值)
      有用链接:

        • 有一个针对.NET的


          很多人对引用对象实际上是按值传递(在C#和Java中)感到惊讶。它是堆栈地址的副本。这可以防止方法更改对象实际指向的位置,但仍然允许方法更改对象的值。在C#中,可以通过引用传递引用,这意味着您可以更改实际对象指向的位置。

          PHP也是通过值传递的

          <?php
          class Holder {
              private $value;
          
              public function __construct($value) {
                  $this->value = $value;
              }
          
              public function getValue() {
                  return $this->value;
              }
          }
          
          function swap($x, $y) {
              $tmp = $x;
              $x = $y;
              $y = $tmp;
          }
          
          $a = new Holder('a');
          $b = new Holder('b');
          swap($a, $b);
          
          echo $a->getValue() . ", " . $b->getValue() . "\n";
          
          然而,在PHP4中,对象被视为。这意味着:

          <?php
          $myData = new Holder('this should be replaced');
          
          function replaceWithGreeting($holder) {
              $myData->setValue('hello');
          }
          
          replaceWithGreeting($myData);
          echo $myData->getValue(); // Prints out "this should be replaced"
          

          Python使用pass-by-value,但由于所有这些值都是对象引用,因此净效果类似于pass-by-r
          >>> def do_something(a, b):
          ...     a = "Red"
          ...     b.append("Blue")
          ... 
          >>> a = "Yellow"
          >>> b = ["Black", "Burgundy"]
          >>> do_something(a, b)
          >>> print a, b
          Yellow ['Black', 'Burgundy', 'Blue']
          
          >>> a = ["Purple", "Violet"]
          >>> do_something(a, b)
          >>> print a, b
          ['Purple', 'Violet'] ['Black', 'Burgundy', 'Blue', 'Blue']
          
          >>> a = "Yellow"
          >>> b = ("Black", "Burgundy")
          >>> do_something(a, b)
          Traceback (most recent call last):
            File "<stdin>", line 1, in <module>
            File "<stdin>", line 3, in do_something
          AttributeError: 'tuple' object has no attribute 'append'
          
          spaceused=: [: 7!:5 <
          exectime =: 6!:2
          big_chunk_of_data =. i. 1000 1000 100
          passbyvalue =: 3 : 0
              $ y
              ''
          )
          locale =. cocreate''
          big_chunk_of_data__locale =. big_chunk_of_data
          passbyreference =: 3 : 0
              l =. y
              $ big_chunk_of_data__l
              ''
          )
          exectime 'passbyvalue big_chunk_of_data'
             0.00205586720663967
          exectime 'passbyreference locale'
             8.57957102144893e_6
          
          void swap(int *x, int *y);   //< Declared as pass-by-reference.
          void swap(int x, int y);     //< Declared as pass-by-value (and probably doesn't do anything useful.)
          
          float *FtoC(float temp)
          {
              float c;
              c = (temp-32)*9/5;
              return &c;
          }
          
          float *FtoC(float *temp)
          {
              *temp = (*temp-32)*9/5;
              return temp;
          }
          
          sub incr {
            my ( $x ) = @_;
            $x++;
          }
          
          my $value = 1;
          incr($value);
          say "Value is now $value";
          
          sub incr {
            $_[0]++;
          }
          
          my $value = 1;
          incr($value);
          say "Value is now $value";
          
          sub incr_ref {
            my ( $ref ) = @_;
            $$ref++;
          }
          
          my $value = 1;
          incr(\$value);
          say "Value is now $value";