首页 > 解决方案 > 为类的一个实例设置成员变量会覆盖其他类实例的相同成员变量

问题描述

因此,我正在制作一个简单的战舰游戏(我对 java 还很陌生……),当将“舰船”的位置分配给 7x7 的虚拟网格时,我得到了意想不到的结果。我将从显示测试代码和该代码的输出开始:

        Ship[] ships = new Ship[2];

        for (int i = 0; i < ships.length; i++) {
            ships[i] = new Ship();
            ships[i].setLocationCells(ShipLocations.createLocations());
            System.out.println(Arrays.deepToString(ships[i].getLocationCells()));
        }

        for (int i = 0; i < ships.length; i++) {
            System.out.println(Arrays.deepToString(ships[i].getLocationCells()));
        }
        System.out.println(Arrays.deepToString(ShipLocations.getUsedLocations()));

所以我只是初始化一个包含两个 Ship 对象的数组。我循环并创建这些对象。ShipLocations.createCells() 返回随机唯一位置的 3x2 2D 数组。Set 和 get 方法是相当标准的。这段代码的输出是这样的:

[[1, 3], [1, 4], [1, 5]]
[[4, 5], [5, 5], [6, 5]]
[[4, 5], [5, 5], [6, 5]]
[[4, 5], [5, 5], [6, 5]]
[[1, 3], [1, 4], [1, 5], [4, 5], [5, 5], [6, 5]}

因此,由此看来,当它最初设置时,位置确实是唯一的,但在我返回检查位置的第二个 for 循环中,似乎两个对象的位置单元格都已设置为从 ShipLocations 生成的最后一个值。创建位置单元()。最后一个打印显示由 ShipLocations 创建和存储的所有位置(您可以看到这些值不受影响并且仍然是唯一的)。那么这里发生了什么?为什么最后一次调用 setLocationCells() 会重置两个 Ship() 实例的成员变量?我想知道这里是否存在我只是以某种方式丢失的引用指针问题......船舶引用变量是否指向同一个对象,这就是正在发生的事情?如果这有助于解决任何澄清问题,这是 Ship 类:

import java.util.Arrays;

public class Ship {
    private int len = 3;
    private int[][] locationCells = new int[3][2];
    private int numOfHits = 0;

    public String check(int[] g) {
        // compare user guess to location cell
        for (int i = 0; i < locationCells.length; i++) {
            //look for hit, if guess is a location...
            if (locationCells[i][0] == g[0] && locationCells[i][1] == g[1]) {
                // increase num of hits
                numOfHits++;
                // shrink locationsCells and remove the hit location
                shrinkLocations(g);
                
                if (locationCells.length == 0) {
                    return "kill";
                }
                else {
                    return "hit";
                }
            }
        }
        
        return "miss";
    }

    public void shrinkLocations(int[] guess) {
        int[][] temp = new int[locationCells.length - 1][2];
        int currentPos = 0;

        for (int i = 0; i < locationCells.length; i++) {
            if (!(locationCells[i][0] == guess[0] && locationCells[i][1] == guess[1])) {
                temp[currentPos] = locationCells[i];
                currentPos++;
            }
        }
        setLocationCells(temp);
    }
    
    public void setLocationCells(int[][] locations) {
        this.locationCells = locations;
    }
    public int[][] getLocationCells() {
        return this.locationCells;
    }
    public void setLen(int len) {
        this.len = len;
    }
    public int getLen() {
        return len;
    }
    public int getNumOfHits() {
        return numOfHits;
    }
    
}

这是 ShipLocations 类(根据要求):

mport java.util.Random;

public class ShipLocations {
    // array that holds the nine total ship locations
    private static int len = 3;
    private static int[][] usedLocations = new int[9][2];
    private static int[][] shipLocations = new int[len][2];
    
    public static int[][] createLocations(){
        // need to know if you are going to position ship up or down.
        Random randint = new Random();
        // control boolean for do-while loop below
        boolean locationsHaveBeenUsed = false; 
        boolean placementIsValid = false;
        int xLoc;
        int yLoc;
        int direction = randint.nextInt(2);
        // generate locations until the initial location isnt already used
        do {
            // x location starts at 1 and goes to a point where it will still fit on the board
            xLoc = randint.nextInt(8 - len) + 1;
            // y location starts at 1 and goes to a point where it will still fit on the board
            yLoc = randint.nextInt(8 - len) + 1;

            locationsHaveBeenUsed = hasBeenUsed(xLoc, yLoc);
            
            //generate new direction and try again.
            direction = randint.nextInt(2);
            placementIsValid =  validPlacement(xLoc, yLoc, direction);
            // only place if the locations have not been NOT been used
            if (placementIsValid && !locationsHaveBeenUsed) {
                //make a call to place at those locations.
                placeShipLocations(xLoc, yLoc, direction);
            }
        // stop once both the locations haven't been used and the placement is not valid    
        } while (locationsHaveBeenUsed || !placementIsValid);
        
        // current shipLocations array has been altered, return.
        return shipLocations;

    }

    public static boolean hasBeenUsed(int xLoc, int yLoc) {
        
        for (int[] loc : usedLocations) {
            // if the randomly generated location has already been used, generate again.
            if (loc[0] == xLoc && loc[1] == yLoc) {
                return true;
            }
        }
        // if not found in usedLocaations return false
        return false;
    }

    public static void placeInNonEmpty(int xLoc, int yLoc) {
        // add the location to used locations in the slot that is first available (non-double zeros)
        for (int j = 0; j < usedLocations.length; j++) {
            if (usedLocations[j][0] == 0 && usedLocations[j][1] == 0) {
                usedLocations[j][0] = xLoc;
                usedLocations[j][1] = yLoc;
                break; 
            }
        }
    }

    public static void placeShipLocations(int x, int y, int direction) {

        for (int i = 0; i < len; i++) {
            // place in UsedLocations array
            placeInNonEmpty(x, y);
            // place in current shipLocations
            shipLocations[i][0] = x;
            shipLocations[i][1] = y;
            if (direction == 1) {
                // moving location up and down
                y++;
            }
            else {
                // moving location left and right
                x++;
            }
        }
    }

    public static boolean validPlacement(int x, int y, int direction) {

        for (int i = 1; i < len; i++) {
            
            if (direction == 1) {
                // moving location up and down
                y++;
            }
            else {
                // moving location left and right
                x++;
            }
            
            for (int[] loc : usedLocations) {
                // check through each location in usedLocations
                if (loc[0] == x && loc[1] == y) {
                    // moving in that direction is not compatible return false and try again
                    return false;
                }
            }
        }
        // if it makes it through that checking minefield return true.
        return true;
    }

    public static int[][] getUsedLocations() {
        return usedLocations;
    }
}

标签: javaclassvariables

解决方案


推荐阅读