简体   繁体   English

从方法返回值时,这两个语句之间有什么区别?

[英]What is the difference between these two statements when a value is returned from a method?

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) 我调用方法的类是:Notes类(Notes.java文件)

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: 也就是说,当我使用addEight()方法将一个项添加到ArrayList并将其返回到main时,我是否必须使用带赋值运算符的语句,如下所示:

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); 如果我只使用Notes.addEight(userRhythm); and not userRhythm = Notes.addEight(userRhythm); 而不是userRhythm = Notes.addEight(userRhythm); how does Java “knows” to which list an item was added? Java如何“知道”项目添加到哪个列表?

how does Java “knows” to which list an item was added? Java如何“知道”项目添加到哪个列表?

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"? ) 实际参数userRhythm是一个按值传递给addEight对象引用就像Java中的情况一样 (另请参阅: Java是“pass-by-reference”还是“pass-by-value”?

So: 所以:

  • In the first case, you are 在第一种情况下,你是
    • Passing an object reference by value and 按值传递对象引用
    • executing add on said object, which has side effects 对所述对象执行add ,这有副作用
  • in the second case, you are 在第二种情况下,你是
    • Passing an object reference by value and 按值传递对象引用
    • executing add on said object, which has side effects 对所述对象执行add ,这有副作用
    • Assigning the returned object reference to userRhythm , but they are the same, since the returned object reference is the actual parameter, so it doesn't do a great deal. 将返回的对象引用分配给userRhythm ,但它们是相同的,因为返回的对象引用是实际参数,因此它没有做很多事情。

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. 你可以通过使它成为一个void方法更好。 You are dealing with references , hence you don't need to return things, you method's side effects are what you want. 你正在处理引用 ,因此你不需要return东西,你方法的副作用就是你想要的。

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 . 在这种情况下, userRhythmuserRhythm2将引用相同的 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. 会打印[] (空列表),因为它会将方法返回的新空列表分配给userRhythm并打印出来。 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. 将打印[n8] ,因为它忽略方法返回的空列表,并打印该方法已修改的原始列表。

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 . 你最好让你的方法返回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. 两者之间的区别在于,在第一种情况下,您将函数的返回值分配给userRythym变量,而在第二种情况下,您将丢弃函数的返回值。

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. 它们的行为相同,因为函数的返回值是userRythym ,因此赋值(在第一种情况下)只是将变量设置为已有的值。

ArrayList is mutable, so you shouldn't return a value / reassign the arraylist reference (in your existing code). ArrayList是可变的,因此您不应返回值/重新分配arraylist引用(在现有代码中)。

If your method actually returns an ArrayList ( List ) taking an ArrayList ( List ) as an argument, then you could use the returned value. 如果您的方法实际返回一个ArrayListList ),将ArrayListList )作为参数,那么您可以使用返回的值。

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. 从功能的角度来看,两种方法都完全相同:它们将"n8"添加到作为参数传递的列表中。

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. 唯一的区别在于return语句:第一个方法不返回任何内容,而第二个方法返回作为参数传递的相同列表的引用 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: 现在,如果你的Notes.addEight()方法以这种方式实现会有所不同:

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: 如果我们调用这个新的addEight()方法,那么事情会有所不同:

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). 如您所见,现在list1list2是指向不同对象的引用( list1 == list2false ),而list1.equals(list2)true ,因为两个列表包含相同顺序的相同元素(它们在语义上相等) )。

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 = ). 但是, list1 == list3true ,因为它们实际上指向同一个列表,因为list3声明方式( list3通过赋值运算符=分配给list1 )。

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 [n8] - 如果你得到回报价值

[] - If you don't get the return value [] - 如果没有得到返回值

how does Java “knows” to which list an item was added? Java如何“知道”项目添加到哪个列表?

There is only 1 list in your code. 您的代码中只有一个列表。 It is passed by reference to your addEight() method, which then returns the reference. 它通过引用传递给你的addEight()方法,然后返回引用。

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. 也就是说,当我使用addEight()方法将一个项添加到ArrayList并将其返回到main时,我是否必须使用带赋值运算符的语句[...]或者我可以像这样调用方法,它将添加一个项目到列表。

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. 如果将对象引用传递给方法 - 并且每个Java值都是基本( intchar等)或对象引用 - 那么该方法可以更改引用对象的任何可修改属性,以及可以通过对对象的任何引用来观察修改。 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); 如果我只使用Notes.addEight(userRhythm); and not userRhythm = Notes.addEight(userRhythm); 而不是userRhythm = Notes.addEight(userRhythm); how does Java “knows” to which list an item was added? Java如何“知道”项目添加到哪个列表?

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. 区别在于,在一种情况下,您将Notes.addEight()返回的引用分配给main()方法的局部变量userRhythm ,而在另一种情况下userRhythm 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. 因为Notes.addEight()返回传递给它的引用的副本,所以这userRythm相同的值重新分配给它已经拥有的userRythm That's not useful, but not harmful, either. 这也没用,但也没有害处。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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