当前位置: 代码迷 >> java >> 从方法返回值时,这两个语句之间有什么区别?
  详细解决方案

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

热度:85   发布时间:2023-07-31 12:04:53.0

我编写了一段返回我想要的结果的代码,但我不确定这两种代码变体之间的确切区别是:

ArrayList<String> userRhythm = new ArrayList<String>();
userRhythm = Notes.addEight(userRhythm);
System.out.println(userRhythm);

或者:

ArrayList<String> userRhythm = new ArrayList<String>();
Notes.addEight(userRhythm);
System.out.println(userRhythm);

我调用方法的类是:Notes类(Notes.java文件)

import java.util.ArrayList;

public class Notes {

    public static ArrayList<String> addEight(ArrayList<String> userRhythm) {
        userRhythm.add("n8");
        return userRhythm;
    }
}

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

userRhythm = Notes.addEight(userRhythm);

或者我可以像这样调用方法,它会将一个项目添加到列表中。

Notes.addEight(userRhythm);

这两个陈述有什么区别,因为最后它们都打印出相同的结果? 如果我只使用Notes.addEight(userRhythm); 而不是userRhythm = Notes.addEight(userRhythm); Java如何“知道”项目添加到哪个列表?

Java如何“知道”项目添加到哪个列表?

它不需要“知道”:您正在查看对堆中相同单个对象的两个引用。

实际参数userRhythm是一个按值传递给addEight对象引用 (另请参阅: )

所以:

  • 在第一种情况下,你是
    • 按值传递对象引用
    • 对所述对象执行add ,这有副作用
  • 在第二种情况下,你是
    • 按值传递对象引用
    • 对所述对象执行add ,这有副作用
    • 将返回的对象引用分配给userRhythm ,但它们是相同的,因为返回的对象引用是实际参数,因此它没有做很多事情。

如果你改为:

public static ArrayList<String> addEight(ArrayList<String> userRhythm) {
    userRhythm.add("n8");
    return new ArrayList<String>();
}

那么这会产生预期的结果

ArrayList<String> userRhythm = new ArrayList<String>();
Notes.addEight(userRhythm);
System.out.println(userRhythm);

不会

ArrayList<String> userRhythm = new ArrayList<String>();
userRhythm = Notes.addEight(userRhythm);
System.out.println(userRhythm);

你能说出原因吗?


作为旁注,实际上返回任何东西并不是非常有用。 你可以通过使它成为一个void方法更好。 你正在处理引用 ,因此你不需要return东西,你方法的就是你想要的。

假设你写的是这样的:

ArrayList<String> userRhythm = new ArrayList<String>();
ArrayList<String> userRhythm2 = Notes.addEight(userRhythm);
System.out.println(userRhythm2);

在这种情况下, userRhythmuserRhythm2将引用相同的 ArrayList 只有一个列表,但有多个引用。

你怎么解决这个问题?

因为您正在修改参数,所以不需要返回它。 您可以将您的方法重写为

public static void addEight(ArrayList<String> userRhythm) {
    userRhythm.add("n8");
}

这在语义上更有意义,因为大多数操作根本不返回任何内容。

您的方法将列表作为参数,向该列表添加元素,然后返回该列表。 因此,您的两个代码段在功能上是等效的。

如果方法返回的另一个列表不是它作为参数接收的列表,它们将不相等。 例如:

public static ArrayList<String> addEight(ArrayList<String> userRhythm) {
    userRhythm.add("n8");
    return new ArrayList<String>();;
}

在这种情况下,第一个代码片段:

ArrayList<String> userRhythm = new ArrayList<String>();
userRhythm = Notes.addEight(userRhythm);
System.out.println(userRhythm);

会打印[] (空列表),因为它会将方法返回的新空列表分配给userRhythm并打印出来。 而第二个片段:

ArrayList<String> userRhythm = new ArrayList<String>();
Notes.addEight(userRhythm);
System.out.println(userRhythm);

将打印[n8] ,因为它忽略方法返回的空列表,并打印该方法已修改的原始列表。

从方法返回一个参数没有多大意义:调用者显然已经有了对该参数的引用,因此返回它是无用且令人困惑的。 你最好让你的方法返回void

两者之间的区别在于,在第一种情况下,您将函数的返回值分配给userRythym变量,而在第二种情况下,您将丢弃函数的返回值。

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

ArrayList是可变的,因此您不应返回值/重新分配arraylist引用(在现有代码中)。

如果您的方法实际返回一个ArrayListList ),将ArrayListList )作为参数,那么您可以使用返回的值。

例如:

list = someClassInstance.toImmutableList(list); // toImmutableList() returns an immutable representation of list passed as argument 

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

唯一的区别在于return语句:第一个方法不返回任何内容,而第二个方法返回作为参数传递的相同列表的引用 虽然这一切看起来很明显,但使用第二个选项可以让您执行以下操作:

ArrayList<String> list = new ArrayList<>();
boolean hasNote = Notes.addEight(list).contains("n8"); // true

这对您是否有用,取决于您的具体问题。

通常,有多个引用指向同一个对象没有意义。 考虑以下:

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

在这种情况下,让两个引用指向同一个列表似乎没有用,因为它会像这样做:

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

现在,如果你的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
}

如果我们调用这个新的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

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

但是, 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);

    }
}

输出:

[n8] - 如果你得到回报价值

[] - 如果没有得到返回值

Java如何“知道”项目添加到哪个列表?

您的代码中只有一个列表。 它通过引用传递给你的addEight()方法,然后返回引用。

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

如果将对象引用传递给方法 - 并且每个Java值都是基本( intchar等)或对象引用 - 那么该方法可以更改引用对象的任何可修改属性,以及可以通过对对象的任何引用来观察修改。 这样的方法也可以返回对该对象的引用,但这是一个完全独立的问题。 始终可以通过对该对象的任何引用来访问对象的当前状态。

这两个陈述有什么区别,因为最后它们都打印出相同的结果? 如果我只使用Notes.addEight(userRhythm); 而不是userRhythm = Notes.addEight(userRhythm); Java如何“知道”项目添加到哪个列表?

区别在于,在一种情况下,您将Notes.addEight()返回的引用分配给main()方法的局部变量userRhythm ,而在另一种情况下userRhythm 因为Notes.addEight()返回传递给它的引用的副本,所以这userRythm相同的值重新分配给它已经拥有的userRythm 这也没用,但也没有害处。