【问题标题】:Passing References to Methods Java传递对 Java 方法的引用
【发布时间】:2015-10-31 12:01:01
【问题描述】:

我一直在尝试解决一个需要几种方法的问题:

它看起来很多,但您实际上并不需要阅读这些方法。只要知道我将int[][] 传递给一个方法,更改方法内部的int[][],然后检查方法外部的int[][] 是否相等。

public static boolean One(int[][] matrix){
    matrix = transpose(matrix);
    matrix = reverseRow(matrix);
    return Arrays.deepEquals(matrix, changed);
}
public static boolean Two(int[][] matrix){
    //180 degree clockwise
    matrix = transpose(matrix);
    matrix = reverseRow(matrix);
    matrix = transpose(matrix);
    matrix = reverseRow(matrix);
    return Arrays.deepEquals(matrix,changed);
}
public static int[][] transpose(int[][] matrix){
    for(int i = 0; i < N; i++) {
          for(int j = i+1; j < N; j++) {
            int temp = matrix[i][j];
            matrix[i][j] = matrix[j][i];
            matrix[j][i] = temp;
          }
        }
    return matrix;
}
public static int[][] reverseRow(int[][] matrix){
    for(int j = 0; j < N; j++){
        for(int i = 0; i < N / 2; i++) {
            int temp = matrix[j][i];
            matrix[j][i] = matrix[j][N - i - 1];
            matrix[j][N - i - 1] = temp;
        }
    }
    return matrix;
}
public static int[][] reverseCol(int[][] matrix){
    for(int col = 0;col < matrix[0].length; col++){
        for(int row = 0; row < matrix.length/2; row++) {
            int temp = matrix[row][col];
            matrix[row][col] = matrix[matrix.length - row - 1][col];
            matrix[matrix.length - row - 1][col] = temp;
        }
    }
    return matrix;    
}

问题的结构如下: 我有一个 int[][] 的原始数字 我有一个 int[][] 数字,这是原始数字转换的结果。具体来说,顺时针旋转 90 度,顺时针旋转 180 度。

实际的问题要大得多,但我认为有一条规则不允许直接解决问题,所以我将其缩减为我需要的。

问题是这样的: 在我运行方法一之后,原来的数组被修改了,所以在我运行方法二之前它已经损坏了。

例如, 方法一之前的原文:

1111
0000
0000
0000

方法一后的原文;

0001
0001
0001
0001

这些变化发生在我运行 transpose(matrix) 和 reverseRow(matrix) 之后。请注意,在 java 调试模式下,当我跨过这些方法时,我可以看到原始内容被更改。我什至没有提到原件。我修改了一个通过的原始版本。

那么,三个问题:

  1. 我认为传递给方法的对象不会更改,除非您返回更改的对象,然后将原始对象设置为 main() 中更改的对象或原始方法?我不是在谈论转置或反向行,因为它们应该改变方法一中的矩阵。

  2. 我使用字符串的方法对此进行了测试。我的上述信念是正确的。 int[][] 有区别吗?

  3. 我怎样才能修复它,以免更改原始文件?还是我错过了一些非常简单的东西?

【问题讨论】:

  • @MLProgrammer-CiM 你的意思是按值传递。
  • @MLProgrammer-CiM 这是 Java,我们的变量保存值,这些值是对对象的引用。当我们将它们传递给方法时,会创建作为原始引用副本的新引用。
  • @MLProgrammer-CiM,因此当我们试图解释 Java is pass-by-value (always) 时,人们仍然感到困惑。
  • @MLProgrammer-CiM:正确的术语反映了正确的理解。说起来:jonskeet.uk/java/parameters.html
  • @MLProgrammer-CiM - Pshemo 并不迂腐。他正在传达一个对理解 Java 至关重要但经常被误解的想法。这个想法对于理解这个问题很重要。如果您来自 C++,请将引用类型的 Java 变量视为功能更有限的指针。

标签: java methods reference parameter-passing


【解决方案1】:

在 Java 中,一切都是通过 值 传递的。然而,令人困惑的是,这个值持有对原始对象的reference。

分配一个变量只会改变输入变量持有的引用:

void doSomething(String str){
    str = "New String"; // str variable now holds a reference to "New String"
                        // however, the original String Object was not changed
}

但是,这不会更改原始字符串。事实上,String 是一个不可变对象,以及所有原语 int、double 等。这导致我得出以下声明:

更改调用函数的输入参数的唯一方法是调用该参数的方法来改变对象(例如param.setValue(newValue) 或param[0] = newValue)。

这让我们可以做一些观察:

  1. 原始类型(char、int、double 等)永远不能在调用函数中更改,因为它们不包含任何改变数据的方法。
  2. 不可变对象(String、Integer、Double 等)永远不能在函数中更改,因为根据定义,它们不包含改变数据的方法。
  3. 可变对象(StringBuilder、BigInteger、BigDecimal 等)只能通过在对象上调用 mutator 方法(而不是通过重新分配变量)来更改。对于数组,您可以将array[0] = newValue 等视为Array 上的mutator 方法,类似于list.set(0, newValue) 上的List。

【讨论】:

  • 请注意,变量不指向引用。相反,它们包含指向对象的引用。此外,字符串不是基元,而是不可变对象。
【解决方案2】:

当您了解到 Java 变量包含引用而不是对象时,这很容易理解。

并且这些引用总是按值传递,如前面的问题Is Java "pass-by-reference" or "pass-by-value"? 中所述。

此答案解决了您的具体问题。

1) 我认为传递给方法的对象不会被更改,除非您返回更改的对象,然后将原始对象设置为 main() 中更改的对象或原始方法?

对象不会被传递给方法。 Java 变量是对象的引用。您可以在不复制对象的情况下复制 java 变量。

如果您将引用类型的变量传递给方法,则该方法无法修改您的变量。但是,它可以修改变量引用的对象,如果它是可变的。

2)我使用字符串的方法对此进行了测试。我的上述信念是正确的。 int[][] 有区别吗?

数组是通过引用访问的可变对象。

String 是一个不可变的对象。您可能试图通过分配给被调用方法的变量来更改调用者的变量。

3) 我怎样才能修复它以使原件不被更改?还是我错过了一些非常简单的东西?

您可以在将数组的引用传递给方法之前制作数组的副本。

对一维数组执行此操作的一种方法是使用System.arraycopy()。您的二维数组由多个一维数组构成,因此您可以多次调用System.arraycopy() 来复制它。

此问题中讨论了其他方法:How do I copy a 2 Dimensional array in Java?。请注意,问题中接受的答案省略了创建二维数组的必要步骤。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-09-08
    • 2012-05-20
    • 2021-09-20
    • 1970-01-01
    • 1970-01-01
    • 2017-03-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多