如何修改通过 void 方法传递的变量(必须为 void)并更改方法外的值 (Java)

How to modify a variable passed through a void method (has to be void) and change a value outside the method (Java)

我在读高中,正在学习 AP 计算机编程 class (Java)。在我的课程中,我必须创建一个 void 方法来对传入的数组进行排序。它必须是 void (要求)并且需要修改传入它的变量(要求)。我必须使用他们提供的运行程序代码。我对编码还很陌生,仍然对这种语言能做什么和不能做什么感到困惑。排序有效,但我看不到如何修改 main 方法的传入变量。

public class InsertionSort extends Sort {
    public <T extends Comparable<T>> void sortList(ArrayList<T> arr) {
        ArrayList<T> arr2 = new ArrayList<T>(arr.size());

        for (int i = 0; i < arr.size(); i++) {
            boolean done = false;
            int insertIndex = 0;
            int k = i;
            T next = arr.get(i);

            while (k>0 && insertIndex == 0) {
                if (next.compareTo(arr2.get(k-1)) > 0) {
                    // System.out.println("if i" + i + " k" + k); 
                    insertIndex = k;
                    done = true;
                }

                k--;
            }

            arr2.add(insertIndex, arr.get(i));
        }
        //System.arraycopy(arr2,0,arr,0,arr2.size());
        arr = arr2; //<--my attempt to alter runner variable
        //System.out.println(" arr 2 = " + arr2);
        //System.out.println(" arr 1 = " + arr);
    }
}

// 亚军

public static void main( String[] args )
{
  ArrayList<String> s = new ArrayList<String>();
  String[] sArr = { "you", "can", "observe", "a", "lot", "just", "by", "watching" };
  for ( String x : sArr ) { s.add( x ); }
  Sort ss = new InsertionSort();
  ss.sortList( s );
  System.out.println( s );
}

我基本上需要在调用 sortList() 方法(已排序)时修改 ArrayList(s),然后从调用打印到 System.out.println()

排序有效,但 "s" 不会改变,我不知道从哪里开始修复它。调用者是完全固定的(class 要求),class 和方法 headers 必须保持不变(出于同样的原因)。

我可能在复制和粘贴过程中遗漏了“{”或“}”。

您可以修改ArrayList arr的内容。首先,清空内容。然后添加来自第二个 List 的元素。像

// arr = arr2; // <--my attempt to alter runner variable
arr.clear(); // <-- empty arr
arr.addAll(arr2); // <-- copy arr2 contents to arr.

List.clear() 说(部分)

The list will be empty after this call returns.

并且List.addAll(Collection)说(部分)

Appends all of the elements in the specified collection to the end of this list, in the order that they are returned by the specified collection's iterator (optional operation).

最后,您不能使用 arr = arr2; 修改调用者对传入 List 的引用,因为(即使 Java 始终按值传递)Object 是它的'reference.

而不是像这里那样创建新数组

ArrayList<T> arr2 = new ArrayList<T>(arr.size());

在你的情况下,只需编辑你作为函数参数获得的数组,你将获得引用作为参数,这意味着你直接编辑对象

 public void sortList( ArrayList<T> arr ) 

我建议你在这里使用修饰符 final 这样你就不能真正改变它指向的对象。

 public void sortList(final ArrayList<T> arr ) 

嗯Java使用引用语义。因此,您可以将 "arr" 参数视为指向数组的指针。请记住它只是一个指针,因此您可以将 arr2 的内容一个一个地复制到 arr1,它应该可以正常工作。

而不是: arr = arr2

尝试:

for (int i=0; i<arr.size(); ++i) {
    arr[i] = arr2[i];
}

您需要直接对 arr 列表进行排序,您不能将这样的列表分配给数组 java is pass by value。但是,您仍然可以实现这一点,因为传递的对象仍然可以访问引用:

public <T extends Comparable<T>> void sortList(ArrayList<T> arr) {

        ArrayList<T> arr2 = new ArrayList<T>(arr);

        for (int i = 0; i < arr2.size(); i++) {

            boolean done = false;
            int insertIndex = 0;
            int k = i;
            T next = arr2.get(i);

            while (k > 0 && insertIndex == 0) {

                if (next.compareTo(arr2.get(k - 1)) > 0) {
                    insertIndex = k;
                    done = true;
                }

                k--;
            }
            arr.set(insertIndex, arr2.get(i));
        }
    }

我在你的算法中修改了什么:

  • arr2 现在是 arr.
  • 的临时列表克隆
  • 我们遍历 arr2 并在 arr2 而不是 arr 上进行验证。
  • 我们设置 arr 的值而不是相加。

那么你的程序会输出

[a, can, observe, a, by, just, by, watching]

而不是

[you, can, observe, a, lot, just, by, watching]

sortList 中创建一个 arr 的副本:

ArrayList<T> arrCopy = new ArrayList<T>(arr);

清除后

arr.clear();

将您的代码 arr 替换为 arrCopy

将代码中的arr2替换为arr

这与将变量传递给方法的方式有关,Java 根据输入类型有两种方法可以做到这一点。第一种是按值传递,在传入基元时使用。按值传递意味着原始类型中保存的实际值被复制到一个新的内存位置,然后该位置可供被调用的方法使用。例如,0xDEADBEEF 的 int 值会将 0xDEADBEEF 的位模式复制到新位置并将其传递给被调用的方法。

Java中的所有其他(非原始)都是一个对象(对象的实例),对象通过引用值传递。基本上所有保存对象的变量实际上都是指针(它们是保存实际对象的基本内存位置的变量,从堆中分配,而不是保存对象本身)。当您将对象值传递给方法时,不会复制对象,而是复制保存对象基地址的变量。这意味着对该变量的任何操作都将引用(指向)调用方法持有的原始对象。这也意味着,如果您将 "points" 的变量重新分配给该对象,您将丢失对该对象的引用并且无法取回它。

IE:

public static void doSomething(LinkedList<String> strings, int num) {
    if (strings == null)
        return;
    // here we modify the content of strings
    strings.add("NEW STRING!");
    // now the calling method can see the change, the list size
    // increased by 1 to anything that holds a reference to this list

    // here we lose our reference to strings
    strings = new LinkedList<String>();
    // we can no longer make changes to strings that the calling
    // method will see because we no longer have a reference to
    // the original list!

    // here we save, then change num
    int oldNum = num;
    num = Integer.MAX_VALUE;
    // the calling method has no way to know that num has changed.
    // it still thinks num = oldNum
}

希望这有助于澄清!