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

问题描述 投票:9回答:8

我是一个完整的Java新手。我知道Java将所有参数都视为按值传递,并且还有其他几个线程可以解释这一点。

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

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

哪个会输出3。我知道在Java中,所有参数都是按值传递的,因此您不能操纵传入的参数。在Java中,是否有标准方法通过引用进行模拟传递?有没有办法调用一个函数来处理传入的变量?对于我来说,很难绕开没有办法做到这一点的想法。

java pass-by-reference
8个回答
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开始,它是按值传递对象的references(该对象本身从不传递),在ref中将3设置为makeAThree会更改由引用的相同对象myInt中的main()

免责声明:Reference不是仅可用于现成的Java的类。我在这里将其用作其他任何对象类型的占位符。这是一个非常简单的实现:

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;
    }
}

编辑

并不是说修改方法的参数是一个好习惯。通常,这将被视为副作用。通常,最佳做法是将方法的输出限制为返回值和this(如果该方法是实例方法)。修改参数是设计方法的非常“ C”的方式,并且不能很好地映射到面向对象的编程。


7
投票

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


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。因此这可以成为您用来执行所需操作的方式。将值封装在对象中,然后将其传递到要更改它的方法。


2
投票

我运行了上述各种方案中的一些。

是的,如果您想在函数外部更改值而不返回相同的原语,则必须将其传递给该原语的单个单位数组。但是,在Java中,数组都是内部对象。请注意,如果按名称将“值”传递给println(),则不会发生编译错误,并且由于内部数组类的本机是toString(),因此它会打印散列。您会注意到,这些名称在打印时会发生变化(长时间循环观看)。可悲的是,由于某些原因,Java还没有想到我们会想要一个受保护但物理上静态的地址空间。但这会损害Java的安全性。我们不能依赖已知地址这一事实意味着更难以破解。 Java性能出色,因为我们拥有快速的处理器。如果您需要更快或更小,则适用于其他语言。我回想起1999年阅读Dobbs中有关该论点的文章时的情景。由于它是一种可在线运行的网络感知语言,因此这是安全性的重大设计让步。您的PC在1999年拥有64mb至256mb RAM,运行速度约为800MHz如今,您的移动设备的内存是ram的2到8倍,速度提高了200-700mhz,每跳动次数增加了很多,而Java是Android的首选语言,是单位销量占主导地位的OS(iOS仍然很困难,我必须学习Objective我猜有一天C,讨厌我见过的语法)。

如果将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;
   }

上面的代码仍将显示4,因为所传递的对象是本地声明所隐藏的。另外,这在方法内部,所以我认为即使调用this和super也无法正确阐明它。


如果未在方法中局部隐藏,则它将更改从外部传递的对象的值。


1
投票

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

1]如果要用其他方法更改基元的值,可以将基元包装在“ java bean”对象中,该对象本质上就像一个指针。

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

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


1
投票

Java是pass-by-value


0
投票

Java将按值传递用于everything


0
投票

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

© www.soinside.com 2019 - 2024. All rights reserved.