1

I would like to store reference to variable in some class, and make operations on it inside this class. Operations should modify original variable. In particular following code should print 1 instead of 0.

class Test {
    private Long metric;

    public Test(Long m) {
        this.metric = m;
        ++this.metric;
    }
}

class Ideone
{
    public static void main (String[] args) throws java.lang.Exception
    {
        Long metric = 0L;
        Test test = new Test(metric);
        System.out.println(metric);
    }
}

How to achieve this behaviour?

Xter
  • 267
  • 1
  • 8
  • 2
    you can´t, simply as that. it would only work if you would print `test.metric` or `test.getMetric()`. for more info see [Is Java “pass-by-reference” or “pass-by-value”?](http://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value) – SomeJavaGuy May 11 '16 at 12:54
  • 1
    You can't since Java is always pass-by-value. Closes workaround would be wrapping your `Long` in some class (like in your case Test) and always accessing that `Long` via instance of wrapper class `Test`. You could also use Atomic wrappers (which are also thread-safe) as pointed in one of answers. – Pshemo May 11 '16 at 12:55

3 Answers3

5

You can replace Long with AtomicLong which is mutable. You'll lose autoboxing features though.

Kayaman
  • 72,141
  • 5
  • 83
  • 121
  • I was going to say reflection but your solution is much more elegant – ortis May 11 '16 at 12:59
  • @ortis this is not a good solution if you are not in a Multithread environment – Davide Lorenzo MARINO May 11 '16 at 12:59
  • 1
    @Davide Lorenzo MARINO 31 True, but I dont think there is a good solution to this problem. This one is simply the less ugly one – ortis May 11 '16 at 13:01
  • 1
    @DavideLorenzoMARINO Nonsense. While we're using `AtomicLong` here for its mutability rather than its atomicity, it doesn't mean that this solution isn't valid. Rather it means that this solution works even *in* a multithreaded context. – Kayaman May 11 '16 at 13:05
  • @Kayman introducing a multithread specific variable is not useful in a non multithreading environment. A simple solution is to create a MutableInteger class that hold a mutable int field. Consider that also using AtomicLong is not as using an Integer because as you said you loose autoboxing features – Davide Lorenzo MARINO May 11 '16 at 13:09
  • Indeed, my code is used in mutltithreaded context, I planned to care about it after I solve this problem, which appear to be a proper solution :) – Xter May 11 '16 at 13:10
  • Well, I guess OP just close this discussion :) – ortis May 11 '16 at 13:10
2

The problem in your code is that Integer is an immutable class. Every time that you change the value you are really building a new instance of Integer.

Doing the same with mutable objects will work.

For example

class Test {
    private StringBuilder metric;

    public Test(StringBuilder m) {
        this.metric = m;
        this.metric.append(" Xter");
    }
}

class Ideone
{
    public static void main (String[] args) throws java.lang.Exception
    {
        StringBuilder b = new StringBuilder("Hello ");
        Test test = new Test(metric);
        System.out.println(b.toString());
        // Will print Hello Xter
    }
}
Davide Lorenzo MARINO
  • 26,420
  • 4
  • 39
  • 56
0

As already metioned, the primitive wrapper classes are inmutable.

Since your metric is private in Test, and you want to use its value in the calling method main, you should use the java bean guidelines and use a getter for it:

public Long getMetric(){return this.metric;}

And on main:

metric=test.getMetric();
System.out.println(metric);
jessarah
  • 351
  • 1
  • 4
  • 13