繁体   English   中英

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

[英]How can I simulate pass by reference in Java?

我是一个完整的 Java 菜鸟。 我知道 Java 将所有参数视为按值传递,并且还有其他几个线程对此进行了解释。

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

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

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

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

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中,它是由值(对象本身从不在全部通过)传递对象的引用,设置ref3makeAThree改变相同的对象称为由myIntmain()

免责声明: 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”的方式,不能很好地映射到面向对象的编程。

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

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。所以这可以是你可以用来做你想做的事情的方式。 将值封装在一个对象中,并将其传递给要更改它的方法。

我运行了上面的一些不同场景。

是的,如果您想在不返回相同原语的情况下更改函数外部的值,则必须向它传递该原语的单个单元数组。 但是,在 Java 中,Array 都是内部对象。 请注意,如果按名称将“值”传递给println()则不会出现编译错误,并且由于内部数组类的toString()原生,它会打印哈希值。 您会注意到这些名称在打印时会发生变化(将其放入一个长循环中并观察)。 可悲的是,Java 还没有意识到出于某些原因,我们会想要一个受保护但物理上静态的地址空间可供我们使用。 不过,这会损害 Java 的安全机制。 我们不能依赖已知地址的事实意味着更难破解。 Java 性能非常棒,因为我们有快速的处理器。 如果您需要更快或更小,那就是其他语言。 我记得这要追溯到 1999 年在 Dobbs 上读到的一篇关于这个论点的文章。 由于它是一种旨在在线运行的网络感知语言,因此这是对安全性的重大设计让步。 1999 年你的 PC 有 64mb 到 256mb 的内存,运行速度大约为 800mhz 今天,你的移动设备的内存是它的 2 到 8 倍,速度快 200-700mhz,并且每滴答执行更多的操作,Java 是 Android 的首选语言,单位销售额占主导地位的操作系统(iOS 仍然很摇滚,我想有一天我必须学习 Objective C,但我讨厌我见过的语法)。

如果你将int[]而不是 int 传递给这段代码,你会从someMethod()调用它得到5


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 ,因为传递的对象是本地声明的 HIDDEN FROM SCOPE 。 此外,这是在一个方法中,所以我认为即使调用 this 和 super 也不会正确地澄清它。


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

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

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

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

1)如果您想以不同的方法更改原语上的值,您可以将原语包装在“java bean”对象中,该对象本质上就像一个指针。

或者

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

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

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

PS只是将方法设为static以便在没有类对象的情况下使用它。 没有其他意图。 ;)

这会让你更好地理解。

Java 对一切都使用按值传递。

据我了解,您不确定是否可以修改传入的变量。

当您将一个对象传递给一个方法,并且如果您在该方法中使用该对象时,您实际上是在修改该对象。 但是,您正在修改该对象的副本,该副本仍然指向同一个对象。 所以实际上当你将一个对象传递给一个方法时,你可以修改它。

再一次,java 中的一切都是通过 value.period 传递的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM