如何在Java中模拟引用传递?

时间:2011-10-25 04:05:42

标签: java pass-by-reference

我是一个完整的Java菜鸟。我知道Java将所有参数视为按值传递,并且还有其他一些线程可供人们解释。

例如,在C ++中我可以这样做:

void makeAThree(int &n)
{
   n = 3;
}
int main()
{
   int myInt = 4;
   makeAThree(myInt);
   cout << myInt;
}

将输出3.我知道在Java中,所有参数都是按值传递的,因此您无法操纵传入的参数。是否有一种标准的方法来模拟在Java中通过引用传递?有没有办法调用一个操作传入的变量的函数?我很难理解无法做到这一点的想法。

8 个答案:

答案 0 :(得分:15)

模拟传递引用的主要方法是传递一个容纳值的容器。

static void makeAThree(Reference<Integer> ref)
{
   ref.set(3);
}

public static void main(String[] args)
{
  Reference<Integer> myInt = new Reference<>(4);
  makeAThree(myInt);
  System.out.println(myInt.get());
}

因为在Java中,引用是通过值传递的对象(对象本身永远不会传递),在{{中将ref设置为3 1}}更改makeAThreemyInt引用的同一对象。

免责声明:main()不是一个可以用于现成Java的类。我在这里使用它作为任何其他对象类型的占位符。这是一个非常简单的实现:

Reference

修改

这并不是说修改方法的参数是很好的做法。通常这会被视为副作用。通常,最佳做法是将方法的输出限制为返回值和public class Reference<T> { private T referent; public Reference(T initialValue) { referent = initialValue; } public void set(T newVal) { referent = newVal; } public T get() { return referent; } } (如果方法是实例方法)。修改参数是一种非常“C”的方法来设计方法,并且不能很好地映射到面向对象的编程。

答案 1 :(得分:7)

您可以使用大小为1的数组

答案 2 :(得分:2)

Java按值传递所有内容,如果它是一个对象,那么传递的是对象的引用值。就像,

void someMethod()
{
   int value = 4;
   changeInt(value);
   System.out.printlin(value); 
}

public void changeInt(int x)
{
   x = x + 1;
}

上面的代码将打印4,因为它是按值传递的

class SomeClass
    {
       int x;
    }

void someMethod()
    {
       SomeClass value = new SomeClass();
       value.x = 4;
       changeCls(value);
       System.out.printlin(value.x); 
    }

    public void changeCls(SomeClass cls)
    {
        cls = new SomeClass();
        cls.x = 5;
    }

上面的代码仍会打印4,因为对象是按值传递的,对象的引用是在这里传递的,即使它在方法内部改变了,它也不会反映到方法'someMethod'。

class SomeClass
{
   int x;
}

void someMethod()
    {
       SomeClass value = new SomeClass();
       value.x = 4;
       changeCls(value);
       System.out.printlin(value.x); 
    }

    public void changeCls(SomeClass cls)
    {
        cls.x = cls.x + 1;
    }

这里它也按值传递对象,该值将是对象的引用。因此,当您更改此对象的某个字段时,它将反映到引用该对象的所有位置。因此它会打印5.所以这可以是你可以用来做你想要的方式。将值封装在对象中并将其传递给要更改它的方法。

答案 3 :(得分:2)

我运行了上面的各种场景。

是的,如果你想在函数之外更改一个值而不返回相同的原语,你必须将它传递给该原语的单个单元数组。但是,在Java中,Array是所有内部对象。请注意,如果您将'value'按名称传递给println(),则没有编译错误,并且由于内部数组类的toString()本机,它会打印哈希值。您会注意到这些名称在打印时会发生变化(将其置于长循环并观察)。可悲的是,Java并没有得到这样的想法,即我们可能因为某些原因而喜欢受保护但物理上静态的地址空间。但这会伤害Java的安全机制。我们不能依赖已知地址的事实意味着它更难以破解。 Java性能非常棒,因为我们拥有快速处理器。如果您需要更快或更小,那就是其他语言。我在1999年读到Dobbs的一篇关于这个论点的文章的时候就记得这个。由于它是一种意味着在线运行的网络感知语言,这对安全性来说是一个很大的设计让步。 1999年你的电脑有64mb到256mb的RAM,运行速度大约为800mhz  今天,你的移动设备有2到8倍的RAM,并且速度提高了200-700mhz,并且每次打勾都有更多操作,而Java是Android的首选语言,是单位销售的主导操作系统(iOS仍然摇滚,我必须学习目标有一天我想,我讨厌我见过的语法)。

如果您将int[]而不是int传递给此代码,则会从5调用someMethod()返回public void changeInt(int x) { x = x + 1; }


public void changeInt(int[] x)
{
   x[0] += 1; 

}

  public void changeCls(SomeClass cls)
   {
       cls = new SomeClass();
       cls.x = 5;
   }

这是一个令人困惑的选择。如果作者没有通过声明一个同名的局部变量来隐藏传递的变量,则代码WOULD会起作用。虽然这是行不通的,但为了清楚起见,请忽略上面引用的以下示例。


4

上面的代码仍会打印{{1}},因为传递的对象是本地声明隐藏的SCOPE。此外,这是一个方法,所以我认为即使调用这个和超级也不会正确澄清它。


如果它没有在方法中本地隐藏,那么它将改变从外部传递的对象的值。

答案 4 :(得分:1)

要在方法中完成原始变量的更改,有两个基本选项:

1)如果要在不同方法中更改基元上的值,可以将基元包装在“java bean”对象中,该对象基本上类似于指针。

或者

2)当许多线程可能需要修改变量时,您可以使用用于并发的AtomicInteger / AtomicLong类....因此变量必须具有一致的状态。这些课为你包装原语。

警告:从维护性角度来看,通常最好不要返回新值,而不是在方法内部设置/编辑它。

答案 5 :(得分:1)

Java 按值传递表示按副本传递。我们不能像在C ++中那样对引用变量进行算术运算。简而言之,Java不是C / C ++。 因此,作为一种解决方法,您可以执行此操作:

public static void main (String [] args) {
    int myInt = 4;
    myInt = makeAThree(myInt);

}
static int makeAThree(int n)
{
   return n = 3;
}

P.S。刚刚创建了方法static,以便在没有类对象的情况下使用它。没有其他意图。 ;)

This will make you understand better.

答案 6 :(得分:1)

一种通过引用实现模拟传递的快速方法是将参数移动到封闭类的成员变量

尽管有多种方法可以做到这一点,例如使用类或数组包装器或将它们移到函数返回类型,但是代码可能不会干净。如果您像我一样,提出这样一个问题的原因是,已经用C ++方式编码了一段Java代码(这种方法不起作用),并且需要快速修复。例如,在诸如深度优先搜索之类的递归程序中,我们可能需要在C ++递归函数的参数列表(例如搜索路径)中保留多个变量,以标记搜索是否应结束。如果遇到这种情况,最快的解决方法是将这些参数变量变成类成员变量。不过请注意可变生命周期,并在必要时重置其值。

答案 7 :(得分:0)

Java使用所有内容的传递值。

据我所知,你不确定是否可以修改传入的变量。

将对象传递给方法时,如果在该方法中使用该对象,则实际上是在修改该对象。但是,您要在其副本上修改该对象,该副本仍指向同一对象。实际上,当您将对象传递给方法时,您可以对其进行修改。

再一次,java中的所有内容都是通过value.period传递的。