DEV Community

Cover image for 5 years working with Java, got big surprise today with "Pass by value"
Pham Duc Minh
Pham Duc Minh

Posted on • Edited on

5 years working with Java, got big surprise today with "Pass by value"

Today I saw a simple Java exam question about OOP

Before it, I knew stack and heap and the Java rule everything pass by value.

And value means the reference address stores in stack, not the object in heap.

Image description

Let have a look at this question:
What is output of this execute code?

class Person {
    private String name;
    public Person(String name) {this.name = name;}
    public String toString() {return name;}
}


public class Tester {

    public static Person checkPerson(Person p) {
        if (p == null) {
            p = new Person("Joe");
        } else {
            p = null;
        }
        return p;
    }

    public static void main(String[] args) {
        Person p = null;
        checkPerson(p);
        System.out.print(p);
        p = new Person("Mary");
        checkPerson(p);
        System.out.print(p);
    }
}
Enter fullscreen mode Exit fullscreen mode

Answer
A) Joenull
B) nullnull
C) Marynull
D) nullMary

The checkPeson() method logic

if (p == null) {
    p = new Person("Joe");
} else {
    p = null;
}
Enter fullscreen mode Exit fullscreen mode

ah ha, the first print must be "Joe" cause we pass a null to it
right away select the Answer A - Joenull without any hesitate, but correct answer is D) nullMary

Wait, what? the first print is null.
But we have p = new Person("Joe") already in the method?

I start to doubt about did Java pass the reference of object to the method?

After some crazy search on internet, I finally understand why

By simple value in "everything pass by value" mean a copy of reference address value (not the real reference value)

The parameter I pass to the method is a clone of the real one, it's a local variable (a variable that's declared within the body of a method)

The real one still points to a null value, it got no effect after the method execute

That why we have correct answer nullMary

Oh what a shame, after 7 years in Software Development and 5 years with Java, Sometime thing I am a senior but everything collapse after this.

Couldn't believe I lacked this important point

My excuse

  • I have learn many languages whenever my company have a new project (or when I land new job). Learn Java at university, first job with C#, then Ruby, VBA and final comeback with Java
  • As a fullstack developer, I use 50% time working with Style and client events (javascript, JQuery)
  • Lazy reading technical document, always prefer short explain and blog cause all I want is make code run as soon as possible

The way I am working is still good, customers love that problem solve quickly and I'm like a superstar in my team

But for me, it's time to slow down, learn the concept instead of google for code and use Trial-error method

Top comments (6)

Collapse
 
matthewsalerno profile image
matthew-salerno

Best thing my uni did was teach me c and c++ instead of java for this reason. If you have the time, working with manual memory allocation really clears these things up. After that, for most languages with a GC the rule is pass by value for primitives, and pass by reference for everything else.
You also notice that p is really a pointer, just dressed up. When you pass p to checkPerson you are passing the pointer by value. This means the data is copied when passed, and changes to it won't affect the original. I have a more detailed explanation below but this is the short version. Thanks for sharing! I know it's hard being wrong on the internet, especially when you're more experienced but stumbled into a knowledge gap.

Long version:
So let's walk through it:

  • First, a variable p is created on the stack. It is of type person but this is just java abstracting away what's really happening: p is actually a pointer (a variable which contains an address in memory) to an object of type person. Note that the new keyword is not used, and instead this pointer is set to null.
  • Next, checkPerson(p) is called. Remember that p is really a pointer in the background. So its value is copied and given to the new p inside checkPerson. Notice how we are just evaluating p, whatever is returned will just be ignored.
  • Now checkPerson notices that p is null, creates a new person, joe, on the heap, and sets p to joe's address. Remember that p as a pointer is really passed by value, so this is just a copy. The original p is still null. It then returns p. This doesn't come up often in java because usually your changing values or executing methods associated with p. When this happens you would follow p to the same object in heap that the calling function sees. However, in this case we are changing p, the pointer, itself.
  • at this point if we had said p = check person(p) we would be in a very different universe.
  • now the same thing happens, but in reverse, we create a person mary and then run check person on it. Inside check person, p is set to null, but that doesn't matter as p is passed by value.

Working with languages like c and c++, while certainly a pain at times, can really provide insight into how languages like java manage data in the background. If you have the time and are looking for an exercise, I suggest studying c data structures. Get to a point where you can implement a linked list without a reference source, without memorizing it either, and without memory leaks. Then do the same for c++ and you'll see how oop allows you to do data structures in a safer, more organised way. After that you can do the same in java, and you'll see how garbage collection prevents most memory leaks, and how it allows you to abstract away the idea of pointers without truly removing them. As a side project you can look at doing it again in c++ but using RAII (resource allocation is initialization) principals. Although that doesn't really relate to what's here, it's just a cool idea.

Collapse
 
docvominh profile image
Pham Duc Minh

Hi @matthewsalerno
Thank you for your explanation, that's very clear to me

I had learn C in university too, but they didn't tell much more about pointer and datastruct, just teach you how to work with method, loop than do the final exam with something like print the fibonacci...

My country market will push you to learn language like Java and C# then find a outsource job that implement big system from Japanese, US and EU.

C just for the newbie to start learn programming (seem replace by python now a day)

Btw i have some Arduino for my personal project, and working with C++ in electricity domain kinda fun.

Collapse
 
matthewsalerno profile image
matthew-salerno

Thanks again for posting! I've been meaning to learn more about Java, I don't know much about it aside from things that translate easily from the c, c++, and python worlds. So this gave me a good opportunity to dig into it a bit more. I still need to learn more about how a normal java workflow operates.
And the Arduino is a lot of fun to work with. Definitely the most rewarding, and the most frustrating experiences I've had are with microcontrollers.

Collapse
 
mephi profile image
mephi

I was told to know nothing about Java when I used the word "pointer" to explain something like that.

Collapse
 
matthewsalerno profile image
matthew-salerno

Haha, tbf I don't really know anything about Java. I'm just translating it to a problem that's fairly common in C. Not sure what you would call it though. Perhaps "reference" is more appropriate?

Thread Thread
 
mephi profile image
mephi

I don't think there is a problem with the word pointer. Sorry, if that wasn't clear. I like your explanation, I'm just salty.
As far as I can see, reference is more common to use in Java, but from my view pointer isn't just a feature in a specific programming language, but a concept. So maybe if someone calls you stupid for using the word pointer, he isn't worth the explanation.