I've written a piece of code that returns the result I want, but I'm not sure what exactly difference between these two variants of code is:
ArrayList<String> userRhythm = new ArrayList<String>();
userRhythm = Notes.addEight(userRhythm);
System.out.println(userRhythm);
Alternatively:
ArrayList<String> userRhythm = new ArrayList<String>();
Notes.addEight(userRhythm);
System.out.println(userRhythm);
And class from which I called a method is: Notes class (Notes.java file)
import java.util.ArrayList;
public class Notes {
public static ArrayList<String> addEight(ArrayList<String> userRhythm) {
userRhythm.add("n8");
return userRhythm;
}
}
Namelly, when I add an item to ArrayList using addEight()
method, and return it to the main, do I have to use statement with assignment operator like this:
userRhythm = Notes.addEight(userRhythm);
Or I could just call the method like this and it will add an item to the list.
Notes.addEight(userRhythm);
What is difference between these two statements, since in the end they both print same result? If I use only Notes.addEight(userRhythm);
and not userRhythm = Notes.addEight(userRhythm);
how does Java “knows” to which list an item was added?
how does Java “knows” to which list an item was added?
It doesn't need to "know": you are looking at two references to the same single object in the heap.
Actual parameter userRhythm
is an object reference passed to addEight
by value , as is the case in Java (see also: Is Java "pass-by-reference" or "pass-by-value"? )
So:
add
on said object, which has side effects add
on said object, which has side effects userRhythm
, but they are the same, since the returned object reference is the actual parameter, so it doesn't do a great deal. If you instead had:
public static ArrayList<String> addEight(ArrayList<String> userRhythm) {
userRhythm.add("n8");
return new ArrayList<String>();
}
then this would produce the expected result :
ArrayList<String> userRhythm = new ArrayList<String>();
Notes.addEight(userRhythm);
System.out.println(userRhythm);
This would not :
ArrayList<String> userRhythm = new ArrayList<String>();
userRhythm = Notes.addEight(userRhythm);
System.out.println(userRhythm);
Can you say why?
As a side note, it's not terribly useful to return anything, in fact. You could probably better off by making it a void
method. You are dealing with references , hence you don't need to return
things, you method's side effects are what you want.
Suppose you had written it like this:
ArrayList<String> userRhythm = new ArrayList<String>();
ArrayList<String> userRhythm2 = Notes.addEight(userRhythm);
System.out.println(userRhythm2);
In that case, userRhythm
and userRhythm2
would be references to the same ArrayList
. There is only one list, but multiple references to it.
How can you resolve this?
Because you are modifying the parameter, you don't need to return it. You could rewrite your method as
public static void addEight(ArrayList<String> userRhythm) {
userRhythm.add("n8");
}
This makes more sense semantically, because most add operations don't return anything at all.
Your method takes a list as argument, adds an element to that list, and returns that list. So your two code snippets are functionally equivalent.
They would not be equivalent if the method returned another list than the one it receives as argument. For example:
public static ArrayList<String> addEight(ArrayList<String> userRhythm) {
userRhythm.add("n8");
return new ArrayList<String>();;
}
In that case, the first code snippet:
ArrayList<String> userRhythm = new ArrayList<String>();
userRhythm = Notes.addEight(userRhythm);
System.out.println(userRhythm);
would print []
(empty list), since it assigns the new, empty list returned by the method to userRhythm
and prints it. Whereas the second snippet:
ArrayList<String> userRhythm = new ArrayList<String>();
Notes.addEight(userRhythm);
System.out.println(userRhythm);
would print [n8]
, since it ignores the empty list returned by the method, and prints the original list, that the method has modified.
Returning an argument from a method doesn't make much sense: the caller obviously already has a reference to that argument, so returning it is useless and confusing. You'd better make your method return void
.
The difference between the two is that in the first case, you are assigning the return value of the function to the userRythym
variable, while in the second case, you discard the function's return value.
They act the same because the return value of the function is userRythym
, so the assignment (in the first case) is just setting the variable to the value it already has.
ArrayList
is mutable, so you shouldn't return a value / reassign the arraylist reference (in your existing code).
If your method actually returns an ArrayList
( List
) taking an ArrayList
( List
) as an argument, then you could use the returned value.
example :
list = someClassInstance.toImmutableList(list); // toImmutableList() returns an immutable representation of list passed as argument
From a functional point of view, both methods do exactly the same: they add "n8"
to the list passed as an argument.
The only difference is in the return
statement: the first method does not return anything, while the second one returns a reference to the same list that was passed as an argument. While all this seems quite obvious, using the second option would allow you to do the following:
ArrayList<String> list = new ArrayList<>();
boolean hasNote = Notes.addEight(list).contains("n8"); // true
Whether this is useful to you or not, it will depend on your specific problem.
In general, it doesn't make sense to have more than one reference pointing to the same object. Consider the following:
ArrayList<String> list1 = new ArrayList<>();
ArrayList<String> list2 = Notes.addEight(list1);
System.out.println("list1 == list2 ? " + (list1 == list2)); // true, they point to
// the same list
System.out.println("list1.equals(list2) ? " + (list1.equals(list2))); // true, since they
// not only contain
// the same
// elements, but
// also point to the
// same list
In this scenario, it doesn't seem to be very useful to have two references pointing to the same list, since it would be as doing this:
ArrayList<String> list1 = new ArrayList<>();
ArrayList<String> list2 = Notes.addEight(list1);
ArrayList<String> list3 = list1;
System.out.println("list1 == list2 ? " + (list1 == list2)); // true
System.out.println("list1.equals(list2) ? " + (list1.equals(list2))); // true
System.out.println("list1 == list3 ? " + (list1 == list3)); // true
System.out.println("list1.equals(list3) ? " + (list1.equals(list2))); // true
Now, it would be different if your Notes.addEight()
method was implemented this way:
public static ArrayList<String> addEight(ArrayList<String> list) {
list.add("n8");
return new ArrayList<>(list); // NOTE THIS! A new ArrayList is being returned
}
If we invoked this new addEight()
method, then things would be different:
ArrayList<String> list1 = new ArrayList<>();
ArrayList<String> list2 = Test.addEight(list1);
ArrayList<String> list3 = list1;
System.out.println("list1 == list2 ? " + (list1 == list2)); // false
System.out.println("list1.equals(list2) ? " + (list1.equals(list2))); // true
System.out.println("list1 == list3 ? " + (list1 == list3)); // true
System.out.println("list1.equals(list3) ? " + (list1.equals(list3))); true
As you see, now list1
and list2
are references that point to different objects ( list1 == list2
is false
), while list1.equals(list2)
is true
, since both lists contain the same elements in the same order (they are semantically equal).
However, list1 == list3
is true
, since they actually point to the same list, due to the way list3
was declared ( list3
was assigned to list1
by means of the assignment operator =
).
See the difference between these two implementations by creating new object in addEight method
import java.util.ArrayList;
public class Notes {
public static ArrayList<String> addEight(ArrayList<String> userRhythm) {
userRhythm = new ArrayList<String>();
userRhythm.add("n8");
return userRhythm;
}
public static void main(String args[]){
ArrayList<String> userRhythm = new ArrayList<String>();
userRhythm = Notes.addEight(userRhythm);
System.out.println(userRhythm);
ArrayList<String> userRhythm1 = new ArrayList<String>();
Notes.addEight(userRhythm1);
System.out.println(userRhythm1);
}
}
Output:
[n8] -- If you get return value
[] - If you don't get the return value
how does Java “knows” to which list an item was added?
There is only 1 list in your code. It is passed by reference to your addEight() method, which then returns the reference.
Namelly, when I add an item to ArrayList using addEight() method, and return it to the main, do I have to use statement with assignment operator [...] Or I could just call the method like this and it will add an item to the list.
If you pass an object reference to a method -- and every Java value is either a primitive ( int
, char
, etc.) or an object reference -- then the method can alter any modifiable properties of the referred-to object, and those modifications can be observed via any reference to the object. Such a method may return a reference to that object as well, but that's an altogether separate issue. The current state of an object is always accessible via any reference to that object.
What is difference between these two statements, since in the end they both print same result? If I use only Notes.addEight(userRhythm); and not userRhythm = Notes.addEight(userRhythm); how does Java “knows” to which list an item was added?
The difference is simply that in one case you assign the reference returned by Notes.addEight()
to the main()
method's local variable userRhythm
, and in the other case you don't. Because Notes.addEight()
returns a copy of the reference passed to it, this has the effect of re-assigning the same value to userRythm
that it already had. That's not useful, but not harmful, either.
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.