简体   繁体   中英

How can I simulate pass by reference in Java?

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.

For example, in C++ I can do:

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 simulate pass 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.

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 references to objects that are passed by value (the object itself is never passed at all), setting ref to 3 in makeAThree changes the same object referred to by myInt in main() .

Disclaimer: Reference isn'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:

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.

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

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,

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

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'.

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.

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).

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


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.


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

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.

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.

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.

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

Java is pass-by-value that 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:

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

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

PS Just made the method static so as to use it without class object. No other intention. ;)

这会让你更好地理解。

Java uses pass by value for everything .

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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