I know that Java is by default call-by-value but I am not sure where in the Java Language Specification this is addressed. Google searching only seems to find me unofficial sources but never points to where the actual part of the specification that describes this is.
Where in the JLS does it state that Java is call-by-value and how does that part of the specification actually say that it is call-by-value rather than some other convention?
5
Definitive source for Java
As the comments already indicated, there is but one official specification for the Java language, namely the Java Language Specification made available from Oracle.
The answer to your particular question of the calling behavior is found in section 8.4.1:
When the method or constructor is invoked (§15.12), the values of the actual argument expressions initialize newly created parameter variables
Source of the confusion
Note, however, that the folks who write the JLS may not share the same definition of terms as others. In particular, the discussion whether Java is call-by-value or something else typically stems from looking at other definitions.
Call-by-value is typically defined as passing a copy of the argument to the function. This behavior is most exposed in C++ where you have an actual choice of whether you want call-by-value or call-by-reference per argument and for call-by-value you even have things like copy-constructors.
This general idea, that call-by-reference allows you to change the original object, whereas call-by-value leaves it untouched is kind of pointless in Java though (at least if you ignore primitive types). Unlike the C-family of languages, Java has no concept of a pointer to some object, so every single variable is like a pointer to some object instead. This gives the appearance to people familiar with C, that Java does in fact always pass around references (after all, if you pass an object into a function, you do not know if that function changes the internal attributes of the object).
You can argue against this argument by accepting the notion of pointers, which in turn means, that a function call is still using call-by-value, because it simply creates a copy of that pointer, which will end up pointing to the same object again.
What is most confusing is that passing an object to a method in Java will never create a full (deep!?) copy of that object – despite the fact that Java is call-by-value. Other languages (like C++) call their function calling semantics call-by-value as well, but in those languages the actual semantics differ.
Code examples
Assume you have the following two methods in your class:
private void f(C c) {
c.setSomething();
c = new C();
c.setSomething2();
}
private void g(final C c) {
c.setSomething();
}
Now on the call-site you find something like this:
C myC = // get some C instance
f(myC); // passes the value
The f
method would now change the attributes of the myC
object, because it works on exactly the same instance. In contrast, the variable c
can be assigned a different instance, such that the call to setSomething2
will not affect the instance myC
is referring to.
If you swap f
for g
on the call-site, a typical rookie-mistake from C/C++ programmers that became Java programmers is to assume that final
does somehow ensure your object is not modified. Of course, the above code still works and modifies the object though. What does no longer work due to final
is merely, that the variable c
is re-assigned to a different C
instance within that method.
This behavior also tricks more experienced Java developers. While few forget that a final List<C>
argument is allowed to modify the list, not so few run into bugs, after having written a method that returns a List<C>
(be it final or not, as that does not make any relevant difference) and being bitten by usage-site code that modifies it.
2
Pass-by-value/pass-by-reference is a property of the semantics of the language. It’s not up to someone to “specify” independently of the language specification; rather, it arises from how the semantics of the language work (which in the case of Java is specified in the JLS). If the language standard actually describes pass-by-value semantics, but the language creator “specifies” the language to be pass-by-reference, that does not make it pass-by-reference.
First, you have to agree on what pass-by-value/pass-by-reference means. The commonly-used definition is that if you do simple assignment (using =
) to a parameter inside a function, and it has the same effect as simple assignment to the passed variable in the calling scope, it is pass-by-reference; if it has no effect in the calling scope, it is pass-by-value.
In Java, parameter variables are newly created variables for that method invocation, and initialized with copies of the passed value. Also, assignment in Java only alters that variable, and not possibly any other variable. These things combined fit the definition of pass-by-value.