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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7884581/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 21:50:12  来源:igfitidea点击:

How can I simulate pass by reference in Java?

javapass-by-reference

提问by Casey Patton

I'm a complete Java noob. I know that Java treats all parameters as pass by value and there are several other threads where people explain this.

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

For example, in C++ I can do:

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

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

Which will output 3. I know that in Java, all parameters are passed by value and thus you can not manipulate the parameter passed in. Is there a standard way to simulatepass by reference in Java? Is there no way to call a function that manipulates a variable passed in? It's tough for me to wrap my head around the idea of there being no way to do this.

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

回答by Mark Peters

The primary way you can simulate passing a reference is to pass a container that holds the value.

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

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

Since in Java, it is referencesto objects that are passed by value (the object itself is never passed at all), setting refto 3in makeAThreechanges the same object referred to by myIntin main().

由于在Java中,它引用到由值(对象本身是从来没有在全部通过)传递的对象,设置ref3makeAThree变化相同的对象则提到myIntmain()

Disclaimer: Referenceisn't a class you can just use with out-of-the-box Java. I'm using it here as a placeholder for any other object type. Here's a very simple implementation:

免责声明: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;
    }
}

Edit

编辑

That's not to say it's great practice to modify the arguments to your method. Often this would be considered a side-effect. Usually it is best practice to limit the outputs of your method to the return value and this(if the method is an instance method). Modifying an argument is a very "C" way of designing a method and doesn't map well to object-oriented programming.

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

回答by RAY

You can use an array of size 1

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

回答by Low Flying Pelican

Java pass everything by value, if it's an object then what would be passed is the reference value of the object. It's like,

Java通过值传递所有东西,如果它是一个对象,那么将传递的是对象的引用值。就像是,

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

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

above code will print 4, because it's passed by value

上面的代码将打印 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;
    }

Above code will still print 4, because the object is passed by value and the reference to the object is passed here, even it's changed inside the method it won't reflect to the method 'someMethod'.

上面的代码仍然会打印 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;
    }

here also it passes the object by value, and this value will be the reference to the object. So when you change some field of this object it will reflect to the all the places where the object is referred. Hence it would print 5. So this can be the way you can use to do what you want. Encapsulate the value in an object and pass it to the method where you want to change it.

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

回答by JWW

I ran some of the various scenarios above.

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

Yes, if you wanted to change a value outside of the function without returning the same primitive, you'd have to pass it a single unit array of that primitive. HOWEVER, in Java, Array's are all internal objects. You please note that if you pass 'value' by name to the println()there is no compile error and it prints hashes because of the toString()native to the internal array class. You will note that those names change as they print (put it in a long loop and watch). Sadly, Java hasn't gotten the idea that we WOULD like a protected yet physically static address space available to us for certain reasons. It would hurt Java's security mechanisms though. The fact that we can't depend on known addresses means that it's harder to hack at that. Java performance is fantastic because we have fast processors. If you need faster or smaller, that's for other languages. I remember this from way back when in 1999 reading an article in Dobbs just about this argument. Since it's a web aware language meant to function online, this was a big design concession to security. Your PC in 1999 had 64mb to 256mb of RAM and ran around 800mhz Today, your mobile device has 2 to 8 times that ram and is 200-700mhz faster and does WAY more ops per tick, and Java is the preferred language for Android, the dominant OS by unit sales (iOS still rocks, i gotta learn Objective C someday i guess, hate the syntax i've seen though).

是的,如果您想在不返回相同原语的情况下更改函数外部的值,则必须向它传递该原语的单个单元数组。但是,在 Java 中,Array 都是内部对象。请注意,如果您按名称将“值”传递给println()没有编译错误,并且由于toString()原生于内部数组类。您会注意到这些名称在打印时会发生变化(将其放入一个长循环中并观察)。可悲的是,Java 还没有意识到出于某些原因,我们想要一个受保护但物理上静态的地址空间可供我们使用。不过,这会损害 Java 的安全机制。我们不能依赖已知地址的事实意味着更难破解。Java 性能非常棒,因为我们有快速的处理器。如果您需要更快或更小,那就是其他语言。我记得这要追溯到 1999 年,当时我在 Dobbs 上阅读了一篇关于这个论点的文章。由于它是一种旨在在线运行的网络感知语言,因此这是对安全性的重大设计让步。你 1999 年的 PC 有 64mb 到 256mb 的 RAM,今天运行速度约为 800mhz,

If you passed int[]instead of int to this code you get 5back from someMethod()calling it.

如果您将int[]而不是 int传递给此代码,您将5无法someMethod()调用它。



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


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

}

This is a confusing selection from above. The code WOULD work if the author hadn't hidden the passed variable by declaring a local variable of the same name. OFCOURSE this isn't going to work, ignore the following example cited from above for clarity.

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



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

Above code will still print 4, because the passed object is HIDDEN FROM SCOPE by the local declaration. Also, this is inside a method, so I think even calling this and super wouldn't clarify it properly.

上面的代码仍然会打印4,因为通过本地声明传递的对象是 HIDDEN FROM SCOPE。此外,这是在一个方法中,所以我认为即使调用 this 和 super 也不会正确地澄清它。



If it weren't hidden locally in the method, then it would have changed the value of the object passed externally.

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

回答by user676947

One quick way to achieving simulate passing by reference is to move the arguments to member variables of the enclosing class.

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

Although there are multiple ways to do it such as using a class or array wrapper or moving them to the function return type, the code may not turn out clean. If you are like me, the reason to ask such a question is that a piece of Java code has already been coded in a C++ way (which does not work) and a quick fix is needed. For example, in a recursion program such as depth-first-search, we may need to keep multiple variables in the C++ recursion function's argument list such as search path, flags whether the search should end. If you are in such a situation, the quickest fix is to make these argument variables into class member variables. Take care of the variable life cycle though and reset their values when necessary.

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

回答by HashimR

Java is pass-by-valuethat mean pass-by-copy. We cannot do arithmetic on a reference variable as in C++. In-short Java is not C/C++. So as a workaround you can do this:

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. Just made the method staticso as to use it without class object. No other intention. ;)

PS 刚刚制作了该方法static以便在没有类对象的情况下使用它。没有其他意图。;)

This will make you understand better.

这会让你更好地理解。

回答by jayunit100

To accomplish the changing of a primitive variable in a method there are 2 basic options :

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

1) If you want to change values on a primitive in a different method you can wrap the primitive in a "java bean" object, which will be essentially like a pointer.

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

Or

或者

2) You can use an AtomicInteger/AtomicLong class which are used to concurrency, when many threads might need to modify a variable....so the variables has to have state that is consistent. Theses classes wrap primitives for you.

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

Warning : you are usually better off returning the new value, rather than setting/editting it internally in a method, from a maintainability standpoint ..

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

回答by DarthVader

Java uses pass by value for everything.

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

As far as I understand you are not really sure if you can modify a variable passed in.

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

When you pass an object to a method, and if you use that object within that method, you are actually modifying that object. However you are modifying that object on a copy of it which still points to the same object. So actually when you pass an object to a method, you can modify it.

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

Once again, everything in java is pass by value.period.

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