【问题标题】:How to modify a variable passed through a void method (has to be void) and change a value outside the method (Java)如何修改通过 void 方法传递的变量(必须为 void)并更改方法外部的值(Java)
【发布时间】:2015-06-16 20:11:34
【问题描述】:

我正在上高中,正在学习 AP 计算机编程课程 (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”不会改变,我不知道从哪里开始修复它。调用者完全一成不变(类要求),类和方法头必须保持不变(出于相同的原因)。

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

【问题讨论】:

  • Sort 类对我来说是个谜,它由课程提供,我没有展示它。它基本上(据我了解)是一个仅用于统一其他排序方法的类(除了插入排序)。

标签: java variables methods arraylist void


【解决方案1】:

您可以修改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() 说(部分)

此调用返回后列表将为空。

List.addAll(Collection) 说(部分)

将指定集合中的所有元素附加到此列表的末尾,按照指定集合的​​迭代器返回的顺序(可选操作)。

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

【讨论】:

  • 你打败了我!如果您解释为什么 arr = arr2 不起作用,我会对此表示赞同。
  • @pbabcdefp 你不能修改调用者对传入List的引用(Java总是按值传递,但Object的值是它的'reference i>)。
  • 我知道为什么!我只是认为最好向 OP 解释一下。
  • 假设 arr = arr2 因为改变了指针而不起作用是否正确?
  • 它是一个引用(不是指针),但是是的......调用者的引用不能被修改(它是按值传递的)。
【解决方案2】:

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

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

只需编辑你作为函数参数得到的数组,你得到引用作为参数,这意味着你直接编辑对象

 public void sortList( ArrayList<T> arr ) 

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

 public void sortList(final ArrayList<T> arr ) 

【讨论】:

    【解决方案3】:

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

    而不是: arr = arr2

    尝试:

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

    【讨论】:

    • arr 是一个ArrayList。而且,如果它一个数组,你需要i &lt; arr.length
    【解决方案4】:

    您需要直接对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]
    

    【讨论】:

      【解决方案5】:

      sortList 中创建arr 的副本,如下所示:

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

      清除arr后

      arr.clear();
      

      将您的代码中的arr 替换为arrCopy

      将代码中的arr2 替换为arr

      【讨论】:

        【解决方案6】:

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

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

        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
        }
        

        希望这有助于澄清!

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-05-06
          • 2018-11-05
          相关资源
          最近更新 更多