【问题标题】:What is wrong with this implementation of Range classRange 类的这个实现有什么问题
【发布时间】:2013-01-22 15:47:43
【问题描述】:

我有一个作业,我正在处理一个电子表格,我的老师已经交给了我。

我被要求实现一个名为 Range 的类,它接受两个位置(每个位置由两个表示列和行的整数组成,例如 new Position(1,2)),然后找到最低的行和列并构造这两个值的新位置,这个位置是我范围的左上角,与行和列的最高值相同。

然后我被要求创建一个接受一系列位置总和的类。所以我决定,对于我的范围,它应该能够有一个方法,将所有位置放入一个 ArrayList 中,即 getPositions() 方法。

这里可以看到类的源代码:

package spreadsheet;

import java.lang.Math;
import java.util.ArrayList;

public class Range {

    private Position a;
    private Position b;
    private ArrayList<Position> positionList;

    // Creates a new range, where it makes sure that the positions,
    // appear in the right order, where the first position is the position
    // of the upper left corner, and the second position is the lower right corner.
    public Range(final Position a, final Position b) {
        int minColumn = Math.min(a.getColumn(),b.getColumn());
        int minRow = Math.min(a.getRow(),b.getRow());

        int maxColumn = Math.max(a.getColumn(),b.getColumn());
        int maxRow = Math.max(a.getRow(),b.getRow());

        this.a = new Position(minColumn, minRow);
        this.b = new Position(maxColumn, maxRow);
        positionList = new ArrayList<>();       
    }


    public ArrayList<Position> getPositions() {
        int minColumn = this.a.getColumn();
        int minRow = this.a.getRow();
        int maxColumn = this.b.getColumn();
        int maxRow = this.b.getRow();
        for(int i = minColumn; i < maxColumn; i++) {
            for(int j = minRow; j < maxRow; j++) {
                positionList.add(new Position(i, j));
            }
        }
        return positionList;
    }   
}

但问题是它并没有真正起作用,它返回的列表是空的,那为什么呢?谁能发现错误?

【问题讨论】:

  • 调试器可以发现错误。
  • 附带说明,如果它确实有效,那么每次调用getPositions() 时,您当前的实现都会扩展positionList
  • 作为格式建议,无需在 getPositions 方法中指定 this.a 或 this.b。在构造函数中需要它的原因是因为您在参数中指定了变量“a”和“b”,因此它需要范围的引用。因为 getPositions 中不存在其他变量“a”或“b”,所以这是多余的。
  • @NikolayKuznetsov 是的,我有点想通了,但我并不真正了解调试器。那么你有没有关于该主题的任何学习资源的链接(最好是视频)?
  • @Jodaka 是因为它是一个实例变量,如果是这样也许可以解释,因为我不确定我自己是否能看到问题。在 getPositions() 方法中声明一个局部变量,然后返回它会更好吗?

标签: java arraylist nested-loops


【解决方案1】:

我认为没有理由不这样做。 好的,这里有几个问题:

  • positionList = new ArrayList&lt;&gt;(); 不会编译。必须是positionList = new ArrayList&lt;Position&gt;();
  • 正如 Jodaka 所说,当您第二次获得列表中的每个位置时,您将获得两次(当您将其称为第四次时会获得三次,依此类推)。
  • 您的实现将包括第一列和第一行,但不包括最后一列(在循环中尝试 i &lt;= maxColumnj &lt;= maxRow)。

对于我的测试,我使用 Points 而不是 Position,并为 Points 添加了一些强制转换,使用 int 作为构造函数参数但返回 double。但我并没有改变逻辑本身:

package spreadsheet;

import java.awt.Point;
import java.util.ArrayList;

public class Range {

private final Point a;
private final Point b;
private final ArrayList<Point> PointList;

// Creates a new range, where it makes sure that the Points,
// appear in the right order, where the first Point is the Point
// of the upper left corner, and the second Point is the lower right corner.
public Range(final Point a, final Point b) {
    int minColumn = (int) Math.min(a.getX(),b.getX());
    int minRow = (int) Math.min(a.getY(),b.getY());

    int maxColumn =(int)  Math.max(a.getX(),b.getX());
    int maxRow = (int) Math.max(a.getY(),b.getY());
    this.a = new Point(minColumn, minRow);
    this.b = new Point(maxColumn, maxRow);
    PointList = new ArrayList<Point>();
}

public ArrayList<Point> getPoints() {
    int minColumn = (int) a.getX();
    int minRow = (int) a.getY();
    int maxColumn = (int) b.getX();
    int maxRow = (int) b.getY();
    for (int i = minColumn; i < maxColumn; i++) {
        for (int j = minRow; j < maxRow; j++) {
            PointList.add(new Point(i, j));
        }
    }
    return PointList;
}

测试:

package spreadsheet;

import java.awt.Point;
import java.util.ArrayList;

import org.junit.Test;

    public class RangeTest {

    @Test
    public void testSomePoints() throws Exception {
        Range range = new Range(new Point(1, 1), new Point(5, 5));
        ArrayList<Point> points = range.getPoints();
        for (Point point : points) {
            System.out.println(point);
        }
    }
}

结果:

java.awt.Point[x=1,y=1]
java.awt.Point[x=1,y=2]
java.awt.Point[x=1,y=3]
java.awt.Point[x=1,y=4]
java.awt.Point[x=2,y=1]
java.awt.Point[x=2,y=2]
java.awt.Point[x=2,y=3]
java.awt.Point[x=2,y=4]
java.awt.Point[x=3,y=1]
java.awt.Point[x=3,y=2]
java.awt.Point[x=3,y=3]
java.awt.Point[x=3,y=4]
java.awt.Point[x=4,y=1]
java.awt.Point[x=4,y=2]
java.awt.Point[x=4,y=3]
java.awt.Point[x=4,y=4]

编辑:

如果我第二次调用 getPoints(),我也会看到每个点两次。 您创建一次列表,但每次调用 getPoints() 时都会添加点。

有几种可能:

  1. 您可以在 getPoints() 方法中创建 ArrayList,而不是在构造函数中。但通常您不会希望每次调用此方法时都创建一个全新的列表...
  2. 您可以将列表存储在一个字段中,在构造函数中计算它并仅使用返回该字段的 getter。
  3. 类似于第二种可能性,但您可以按需计算列表。所以不要在构造函数中计算它,而是在 getter 如果它现在为空,否则使用存储的列表。

2.编辑

  1. 选项:

    public class Range {
    
        private final Point a;
        private final Point b;
        private final ArrayList<Point> PointList;
    
        public Range(final Point a, final Point b) {
            int minColumn = (int) Math.min(a.getX(),b.getX());
            int minRow = (int) Math.min(a.getY(),b.getY());
    
            int maxColumn =(int)  Math.max(a.getX(),b.getX());
            int maxRow = (int) Math.max(a.getY(),b.getY());
            this.a = new Point(minColumn, minRow);
            this.b = new Point(maxColumn, maxRow);
        }
    
        public ArrayList<Point> getPoints() {
            PointList = new ArrayList<Point>();
            int minColumn = (int) a.getX();
            int minRow = (int) a.getY();
            int maxColumn = (int) b.getX();
            int maxRow = (int) b.getY();
            for (int i = minColumn; i < maxColumn; i++) {
                for (int j = minRow; j < maxRow; j++) {
                    PointList.add(new Point(i, j));
                }
            }
            return PointList;
        }
    }
    
  2. 选项:

    public class Range {
    
        private final Point a;
        private final Point b;
        private final ArrayList<Point> PointList;
    
        public Range(final Point a, final Point b) {
            int minColumn = (int) Math.min(a.getX(),b.getX());
            int minRow = (int) Math.min(a.getY(),b.getY());
    
            int maxColumn =(int)  Math.max(a.getX(),b.getX());
            int maxRow = (int) Math.max(a.getY(),b.getY());
            this.a = new Point(minColumn, minRow);
            this.b = new Point(maxColumn, maxRow);
            PointList = calcPoints();
        }
    
        private ArrayList<Point> calcPoints() {
            ArrayList<Point> list = new ArrayList<Point>();
            int minColumn = (int) a.getX();
            int minRow = (int) a.getY();
            int maxColumn = (int) b.getX();
            int maxRow = (int) b.getY();
            for (int i = minColumn; i < maxColumn; i++) {
                for (int j = minRow; j < maxRow; j++) {
                    PointList.add(new Point(i, j));
                }
            }
            return list;
        }
    
        public ArrayList<Point> getPoints() {
            return PointList;
        }
    }
    
  3. 选项:

    public class Range {
    
        private final Point a;
        private final Point b;
        private final ArrayList<Point> PointList;
    
        public Range(final Point a, final Point b) {
            int minColumn = (int) Math.min(a.getX(),b.getX());
            int minRow = (int) Math.min(a.getY(),b.getY());
    
            int maxColumn =(int)  Math.max(a.getX(),b.getX());
            int maxRow = (int) Math.max(a.getY(),b.getY());
            this.a = new Point(minColumn, minRow);
            this.b = new Point(maxColumn, maxRow);
        }
    
        private ArrayList<Point> calcPoints() {
            ArrayList<Point> list = new ArrayList<Point>();
            int minColumn = (int) a.getX();
            int minRow = (int) a.getY();
            int maxColumn = (int) b.getX();
            int maxRow = (int) b.getY();
            for (int i = minColumn; i < maxColumn; i++) {
                for (int j = minRow; j < maxRow; j++) {
                    list.add(new Point(i, j));
                }
            }
            return list;
        }
    
        public ArrayList<Point> getPoints() {
            if(PointList == null) {
                PointList = calcPoints();
            }
            return PointList;
        }
    }
    

【讨论】:

  • 非常感谢您的帮助! :) 但是我不明白为什么我会两次获得每个职位。那么我应该纠正什么以避免这种情况呢?而且您似乎没有两次获得每个点,即使您的代码与我的仅不同之处在于您已将 Point 替换为 Position...
  • 啊,好吧,我想,我现在可以看到问题了!所以第二个选项意味着每次我创建一个范围时,我也会创建一个包含在该范围内的所有位置的 ArrayList?第三个,我将有一个 getter 方法,如果我的字段为空,我只能在其中创建它?那个字段是 ArrayList 类型的吗?非常感谢您帮助我,非常感谢! :)
  • 我已经列出了所有三个选项。顺便说一句:通常只有类以大写字母开头,而不是变量或字段。所以ArrayList&lt;Point&gt; pointList; 会更好;)
  • 好吧,我终于成功了,谢谢一百万! :) 顺便说一句,您忘记在第三个示例中初始化构造函数中的字段,然后在 get 方法中它必须是 positionList.size() == 0。再次感谢,你是最棒的!
  • 没问题 :) 我明白了,我在这里遇到了复制和粘贴失败。我必须将这些点添加到 calcPoints() 的本地列表中,而不是添加到字段中。固定!
猜你喜欢
  • 2023-03-04
  • 2021-10-17
  • 2011-09-28
  • 2011-12-14
  • 2017-08-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多