当前位置: 首页 > 知识库问答 >
问题:

Java类不能识别索引

衡建中
2023-03-14

我在 JAVA 中创建了一个矩阵类,它由一个带有行变量和列变量的 2D int 数组组成。该类的构造函数生成一个维度为 n x m 的矩阵,我还实现了两个打印矩阵值及其转置的方法(getMatrixValues 和 getTransposedValues)。

但是,我想创建一个函数,它接受一个矩阵作为输入并返回它的转置,但是由于这个类不是一个数组,如果我正确理解IntelliJ返回给我的异常(“java: array required,but Matrix found”),我就不能使用< code>AT[j][i] = A[i][j]对它进行迭代。显然,我可以简单地使用一个int[][]类来开始,而不是定义一个新的类,但是由于我是JAVA和面向对象编程的新手,我想知道是否有另一种可能性而不丢弃我的Matrix类?

这是我的代码:

import java.util.Random;
import java.util.Arrays;

public class Matrix {


    private int n; // rows
    private int m; // cols
    private int[][] A; // matrix

    public static void main(String[] args){
        Matrix A = new Matrix(4,4);

        A.getMatrixValues();

        System.out.println("\n");
        
        A.getTransposedValues();
        
        Matrix AT = transposeMatrix(A);     
    }

    // constructor (randomly generates matrix)
    public Matrix(int rows, int cols){

        n = rows;
        m = cols;

        A = new int[rows][cols];

        Random r = new Random();
//        r.setSeed(1);

        for(int i = 0; i < rows; i++)
        {
            for(int j = 0; j < cols ; j++)
            {
                A[i][j] = r.nextInt(10);
            }
        }
    }

    // print matrix
    public void getMatrixValues(){
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<m;j++)
            {
                System.out.print(A[i][j]+"\t");
            }

            System.out.print("\n");
        }
    }

    // print transposed matrix
    public void getTransposedValues(){
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<m;j++)
            {
                System.out.print(A[j][i]+"\t");
            }

            System.out.print("\n");
        }
    }


    public static Matrix transposeMatrix(Matrix A){

        Matrix AT = new Matrix(A.get_n(), A.get_m());

        for(int i = 0; i < A.get_n(); i++)
        {
            for(int j = 0; j < A.get_m(); j++)
            {
                AT[j][i] = A[i][j];
            }
        }

    return AT;
    }

    // getters
    public int get_n(){
        return n;
    }

    public int get_m(){
        return m;
    }


}


共有1个答案

居焱
2023-03-14

前言
我后来才注意到,在创建转置矩阵时,实际上需要创建m行n列的矩阵
这意味着,在实例化新对象时,您在transposeMatrix()中混合了m 这也意味着您的代码-实际上-只适用于方阵。只需像这样创建对象: newMatrix(Matrix.get_m(),Matrix.get_n())
注意:我重新命名了变量;参见下文“解决方案”一节。

然而,由于这不是你的问题的一部分,我没有在下面的代码片段中修复它。

Scopes
当在所有其他方法中时,您处于所在对象的词法范围中。这允许您访问它的字段(比如< code>int[][] A)。

但是当在< code > transpose Matrix(Matrix A)内部时,您是在< code>static范围内,也就是说,不在对象的范围内。< br >更令人困惑的是,您的实例变量被称为< code>A,很像< code>transposeMatrix()的参数< code>Matrix A。虽然您可以通过< code>A访问2D数组,但现在您可以通过< code>A访问< code>Matrix对象。这既是因为我们不再是在一个对象中,也是因为新的局部变量覆盖了对类似命名的实例/静态变量的访问(您必须使用< code>this。或< code >矩阵。一个)。

访问修饰符< br >当试图修改您的代码时,您会偶然发现您使用的访问修饰符的限制:< code>private。< code>private int[][] A将使< code>A(您的数组)仅在从对象内部引用时可访问。但是当调用< code>transposeMatrix()时,我们处于静态上下文中,也就是说,不再在您的对象内部。

要解决此问题,可以更改访问修饰符以允许我们从对象外部访问该字段。要启用此功能,可以将修改器更改为任何其他选项,最简单的方法是将其删除。但是,我建议您在官方文档中阅读更多关于Access Modifier的信息。

解决方案
假设我们从int[][]A中删除了私有。代码会起作用吗?
不。那是因为我在解释范围时谈到的混乱。为了澄清混乱,让我们重命名一些变量:(将int[][]A更改为int[][]数组Matrix AMatrixMatrix ATMatrix matrixTransposed

int[][] array; // <-- Notice the removed access modifier!

// ...

public static Matrix transposeMatrix(Matrix matrix){
  Matrix matrixTransposed = new Matrix(matrix.get_n(), matrix.get_m());

  for (int i = 0; i < matrix.get_n(); i++) {
    for(int j = 0; j < matrix.get_m(); j++) {
      matrixTransposed[j][i] = matrix[i][j]; // Won't work!
    }
  }
}

上述代码仍然存在故障。这是我们现在可以清楚地看到的,因为我们试图访问Matrix-对象,就像它是一个数组一样。然而,我们需要访问它的实例变量。因此,我们添加了一个<code>,而不是以错误的方式访问数组。数组在每个Matrix-对象之后,我们试图访问它的数组。

public static Matrix transposeMatrix(Matrix matrix){
  Matrix matrixTransposed = new Matrix(matrix.get_n(), matrix.get_m());

  for (int i = 0; i < matrix.get_n(); i++) {
    for(int j = 0; j < matrix.get_m(); j++) {
      matrixTransposed.array[j][i] = matrix.array[i][j]; // NOW we are accessing their arrays respectively
    }
  }
}

另一种解决方案
通过更改数组的访问修饰符(就像我们上面所做的那样),我们不仅可以覆盖数组的值,还可以覆盖数组本身。
为了限制一个人这样做,我们可以使用“Getters and Setters”。他们就像一个中间人,允许我们只间接访问阵列,但根据需要对阵列进行如此多的控制

我们可以简单地定义它们,创建两个新方法(因此得名):

public int get(int i, int j) {
  return array[i][j];
}
public void set(int i, int j, int value) {
  array[i][j] = value;
}

如您所见,我们只是将请求转发给“中间人”,后者会相应地处理它。
注意:我们可能会遇到运行时异常,因为我们没有检查指定索引处的字段是否确实存在。您可能希望在访问它们之前添加一些 if 语句。

通过使用getter和setter,我们可以将代码修改为:

private int[][] array; // We still want to restrict access to 'array'...

// ...

// ...but still allow accessing them, be it indirectly
public int get(int i, int j) {
  return array[i][j];
}
public void set(int i, int j, int value) {
  array[i][j] = value;
}

// Now using getter and setter
public static Matrix transposeMatrix(Matrix matrix) {
  Matrix matrixTransposed = new Matrix(matrix.get_n(), matrix.get_m);

  for (int i = 0; i < matrix.get_n(); i++) {
    for (int j = 0; j < matrix.get_m; j++) {
      matrixTransposed.set(j, i, matrix.get(i, j));
    }
  }
}

另外
您还应该看看命名约定。它们对于使您的代码发挥作用并不重要,但会使阅读和理解(从而调试)它变得容易得多。

我认为也好的是,看看一个风格指南,看看如何通过简单的技巧使你的代码更具可读性,或者只是在你的代码中有一个一致的风格。我喜欢谷歌的Java风格指南,但是,还有很多其他的。
而且,您不必坚持现有的风格指南,您也可以拥有自己的风格!但尽量保持一致。这使得其他人和你自己将来在重新阅读你的代码时更容易。

 类似资料:
  • 我已经将我的站点部署到heroku,现在我正试图将我的本地数据库向上推,但不断得到这个错误: 未知数据库: heroku配置:获取DATABASE_URL 并使用返回的值。我尝试重置DATABASE_URL,但仍然得到相同的错误。如有任何帮助,不胜感激,谢谢!

  • 我遵循了FAQ,但我运行的是Ubuntu10服务器,所以J6是我能得到的最好的。当我启动GWAN4.2.13(sudo./gwan)时,我得到“hello.java:to use.java scripts,install java”

  • 我急需一个建议,我到底哪里出了问题 我有servlet api。jar@E:\J2EE\apache-tomcat-6.0.18\lib E:\J2EE\apache-tomcat-6.0.18\lib\servlet api。罐子 我试图运行一个Servlet类"TouchServlet.java"这是在 E:\J2EE\apache-tomcat-6.0.18\webapps\TouchSer

  • 我用如下命令创建项目 npm init vue@latest 创建过程中选择了pinia,但是main.js中导入pinia模块时不能被识别: import { createPinia } from 'pinia' 这句里面的pinia和Pinia均提示为“Unknown word”.

  • 有25种类型的空白。在下面的代码中显示,25种类型中有4种在Java中不被视为空白。为什么? 参考-https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/character.html#IsWhitespace(char)