【问题标题】:pass by reference/value - simple example按引用/值传递 - 简单示例
【发布时间】:2012-07-11 08:22:39
【问题描述】:

我知道这个问题已经解决了很多次 - 但我的 Java/C++ 知识太薄弱以至于几乎无法理解答案 :-( ...我真正想要的只是一个超级简单的例子。

在 C++ 中,我可以编写以下代码:

void func()
{
  int x = 3;
  add_one(x);
  // now x is 4.
}
void add_one(int &var)
{
  var++;
}

我现在想看的是用java实现同样效果的最简单的方法。

【问题讨论】:

标签: java


【解决方案1】:

你不能直接。最接近的方法是将值放入对象中,然后将引用(按值,因此引用被复制)传递给方法。

void func()
{
  int x = 3;
  int[] holder = [x];
  add_one(holder);
  // now holder[0] is 4.  x is still 3.
}

// container here is a copy of the reference holder in the calling scope.
// both container and holder point to the same underlying array object
void add_one(int[] container)
{
    container[0]++;
}

这里我使用了一个数组,但是包装器可以是任何对象。

【讨论】:

  • 不能用java的装箱和拆箱吗? Aka,使用原语的对象版本?我认为 that 在技术上更接近 C++ 中的引用传递示例,尽管它会产生其他副作用。
  • 整数对象是不可变的,所以不是。
【解决方案2】:

在 java 中方法参数是 pass-by-value,并且不能在函数中更改。您必须将 int - 或任何其他原始类型 - 包装在 Object 或数组中。传递对象或数组作为方法参数传递可用于修改对象的引用。

Java 已经为原始类型提供了基于对象的包装器,例如Integer,但这些在设计上是不可变的。一些库提供了这些包装器的mutable versions;您也可以创建自己的:

public class MutableInt
{
    private int val;

    public MutableInt(int val)
    {
        this.val = val;
    }

    public void setValue(int newVal)
    {
        this.val = newVal;
    }

    public int getValue()
    {
        return this.val;
    }
}

void func()
{
    int x = 3;
    MutableInt wrapper = new MutableInt(x);
    add_one(wrapper);
}

void add_one(MutableInt arg)
{
    arg.setValue(arg.getValue() + 1);
}

【讨论】:

    【解决方案3】:

    你不能这样做。 Java 只是按值传递。原语是显而易见的,但传递给对象的东西是引用,而不是对象本身。

    【讨论】:

      【解决方案4】:

      从其他答案中可以看出,Java 纯粹是按值传递。对象通过一些所谓的“值引用”传递。由于Java中的对象只是一个指针引用,因此您可以将“值”视为对象在堆上的地址。因此,当您进行方法调用时,您会将“值”(也称为地址)复制到方法参数中:

      Object x = new Object();
      foo(x);
      

      对象创建期间

      堆 --> 分配对象 (5000)

      变量声明

      堆栈 --> 分配局部变量 (1000)

      变量赋值

      堆栈地址1000设置为5000(指向对象实例)

      所以你可以看到这里有两个独立的内存分配。变量的“值”被认为是它在堆上的地址。

      方法调用

      堆栈 --> 分配方法参数 8000

      堆栈地址 8000 设置为与传递的参数 5000 相同的值

      这就是为什么如果您在方法中重新分配对象实例,它不会传播回调用者。您将更改堆栈位置 8000 处的堆位置。调用方法的堆栈位置 1000 仍然具有值 5000(原始对象实例)。

      在 C 中这样想:

      void method(myobject * obj);
      

      您当然可以更改“obj”的字段,并且可以在本地执行此操作:

      obj = new myobject();
      

      但是调用者仍然会看到它传递的原始值。

      Java 没有与 & 引用运算符类似的东西。

      并且有内置的类可以用于您的目的。 AtomicInteger、AtomicLong 等...是可变的,但您可能会因涉及同步而遭受性能损失。

      我会推荐一个通用的 ValueHolder 类来解决您想要模拟通过引用传递的所有情况:

      public class ValueHolder<T> {
          private T value;
          // getter/setter/constructor
      }
      

      【讨论】:

      • 很有趣 - 但你能添加一个以我的 C++ sn-p 为模型的完整工作示例吗?
      • 我没有时间做那种事。我花了一点时间进一步解释了当你分配一个新实例以及当你进行方法调用时 java 做了什么。由你决定是否更进一步。我给了你基本的值持有者,所以你可以完成这个类,并将它作为方法参数传递到任何你想改变它持有的值的地方。
      【解决方案5】:

      Java 允许对象的引用复制和原始类型(int、float 等)的 vlaue 复制。默认情况下是这样,并且不会更改。如果你需要在函数中改变一个 int 的值,那么你可以使用 Integer 类来举例

      【讨论】:

      • 不,Java 是按值传递的。根据詹姆斯·高斯林的说法,只有一种机制。
      • 这是不对的,java引用是传值的,也就是传值。仅有的。 100% 的时间。
      • 请查看this answer。可能对你有帮助。
      • 另外,Integer 是不可变的,所以不能在这种情况下使用。
      【解决方案6】:
      public int getOneMore(int val) {
        return val + 1;
      }
      

      【讨论】:

      • 这个答案与问题无关。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-04-12
      • 2012-01-16
      • 2012-10-14
      • 2014-08-23
      • 2015-05-23
      • 1970-01-01
      相关资源
      最近更新 更多