如何在Java中创建动态二维数组?

时间:2017-04-20 14:53:38

标签: java arrays dictionary arraylist javafx

我一直在四处寻找,但找不到任何可以解决我问题的方法。

我有这种方法为我的游戏创建一个棋盘:

public void createBoard(Canvas canvas) {
    ROWS_NUM = (int) canvas.getHeight() / rectangleSize;
    COLS_NUM = (int) canvas.getWidth() / rectangleSize;
    grid = new Cell[COLS_NUM][ROWS_NUM];

    for (int x = 0; x < COLS_NUM; x++) {
        for (int y = 0; y < ROWS_NUM; y++) {
            grid[x][y] = new Cell();
            grid[x][y].setAndUpdateState(false);
        }
    }
}

问题是每当我添加一个大于ROWS_NUMCOLS_NUM的值时,我得到的数组索引超出范围,就像我应该的那样。我想让数组变得动态,我想知道我应该怎么做。我是否必须将数组转换为ArrayList,或者HashMap会更好?如果我想让行和列都是动态的,我该怎么做呢?

4 个答案:

答案 0 :(得分:2)

这并不容易。

您当然可以将您的网格表示为List<List<Cell>>

 public Cell getCell(int x, int y) {
       return grid.get(x).get(y);
 }

但是,这不会为您提供分配给任何旧号码的免费通行证:

  List<String> list = new ArrayList<>();
  list.set(5,"Hello");

...也会抛出IndexOutOfBounds个异常。

您可以list.add(string)任意多次,每次列表都会增长。但是你不能set()超出当前的大小。

但是,如果您知道每个网格位置都需要一个单元格对象,并且您知道每次网格位置增长它会增加一个,请编写算法以使用add()而不是set(),这样结构将运作良好。

或者,如您所知,HashMap<Coordinates, Cell> 可能符合您的需求。

您需要一个合适的Coordinates课程,其实施工作hashCode()equals()。然后你可以这样做:

   Map<Coordinates, Cell> grid = new HashMap<>();
   grid.put(new Coordinates(80, 100), new Cell());

如果您想要一个人口稀少但实际上无限制的“网格”,这将特别有效。

还有很多方法 - 包括实现你自己的数组重新分配算法(毕竟,这就是ArrayList内部的内容 - 如果你很好奇的话,找到并研究它的源代码。)

您可能还应退后一步并询问为什么 时需要在初始化后更改网格的大小。固定大小的固定大小数组阵列是一个简单的解决方案,如果它在大多数时间工作,值得坚持。如果大小只是偶尔变化,那么你可能最好只创建一个新网格,并在发生这种情况时将旧值复制到其中。

  public void setCell(int x, int y, Cell cell) {
     if(x >= this.grid.length || y >= this.grid[0].length) {
          Cell[][] newGrid = createEmptyGrid(x,y);
          copyCells(this.grid,newGrid);
          this.grid = newGrid;
     }
     this.grid[x][y] = cell;
  }

createEmptyGrid()这里需要对新尺寸做出决定 - 大到足以容纳[x][y]?还是更大的外壳?正确的做法取决于您更广泛的要求。

答案 1 :(得分:1)

更好的选择是使用Java List 来实现所需的逻辑:

List<List<Cell>> grid = new ArrayList<>();

for (int x = 0; x < COLS_NUM; x++) {
    List<Cell> cells = new ArrayList<>();
    for (int y = 0; y < ROWS_NUM; y++) {
        cells.add(new Cell());
    }
    grid.add(cells);
}

public boolean isAlive(int x, int y) {
    List<Cell> cells = grid.get(x);
    Cell cell = cells.get(y);        
    return cell != null && cell.getState();
}

答案 2 :(得分:1)

使用ArayList(ArrayList可以动态地改变它的大小)

Enum

答案 3 :(得分:1)

您可以使用 ArrayList ,但要插入任何索引而不必担心超出范围,您需要使用嵌套的 Map 和特殊方法用于插入或检索。

Map<Integer, Map<Integer, Cell>> grid = new HashMap<Integer, Map<Integer, Cell>>();

for (int x = 0; x <= COLS_NUM; x++) {
    Map inner = new HashMap<Integer, Cell>();
    for (int y = 0; y < ROWS_NUM; y++) {
        inner.put(y, new Cell());
    }
    grid.put(x, inner);
}

现在,您可以使用以下任何索引创建一个在网格中设置单元格的方法:

 public void setCell(Map<Integer, Map<Integer, Cell>> grid, Cell newCell, int x, int y) {
    if (grid.containsKey(x)) {
        grid.get(x).put(y, newCell);
    } else {
        grid.put(x, (new HashMap<Integer, Cell>().put(y, newCell)));
    }
}

检索单元格的方法:

     public Cell getCell(Map<Integer, Map<Integer, Cell>> grid, int x, int y) {
     try {
         Cell found = grid.get(x).get(y);
         return found;
     } catch (NullPointerException npe) {
         return null;
     }
 }

为了使其有用,您需要创建一个自定义类来管理这些地图和插入/检索方法,以及对您的应用程序有用的其他功能。

这是使用列表的更简单选项。如上所述,这不会让你避免获得IndexOutOfBoundsException的可能性。

int ROWS_NUM = (int) canvas.getHeight() / rectangleSize;
int COLS_NUM = (int) canvas.getWidth() / rectangleSize;

List<List<Cell>> array = new ArrayList<List<Cell>>();

for (int x = 0; x < COLS_NUM; x++) {
    List inner = new ArrayList<Cell>();
    for (int y = 0; y < ROWS_NUM; y++) {
        inner.add(new Cell());
    }
    array.add(inner);
}

您仍然可以通过这种方式访问​​特定单元格(相当于数组中的数组[x] [y]:

// Find equivalent of arr[2][3]
Cell found = array.get(2).get(3);

但是,由于您指定希望能够访问具有任何索引的单元格而不会出现越界异常,因此您可以选择使用地图实现它。