Java程序中第二个Player对象实例为何覆盖第一个实例?
我正在编写一个程序,允许用户输入Player对象的四个特征并将该对象添加至Player对象的ArrayList中,但所有Player对象均被视为同一对象。我怀疑程序仅向ArrayList中添加了对同一对象的多个引用,却无法生成具有不同实例变量的独立对象。若将Player类的所有字段改为非静态,会出现"nonstatic variable/method cannot be referenced from a static context"错误。
测试时,输入球员"Babe Ruth"(球衣1号,体重155,身高70)后,再输入球员"Joe Dimaggio"(球衣2号,体重170,身高75),程序未存储后者信息,所有实例均显示前者属性。
实际输出(列出所有球员):
Name: Babe Ruth
Jersey number: 1
Weight: 155
Height: 70
Name: Babe Ruth
Jersey number: 1
Weight: 155
Height: 70
预期输出:
Name: Babe Ruth
Jersey number: 1
Weight: 155
Height: 70
Name: Joe Dimaggio
Jersey number: 2
Weight: 170
Height: 75
驱动类代码(MainMenu.java)
package playerdatamanager; import java.util.*; public class MainMenu { public static void main(String[] args) { ArrayList<Player> playerRoster = new ArrayList<>(); Scanner input = new Scanner(System.in); int exitMenu = 0; while (!"7".equals(exitMenu)) { System.out.println("Please choose an option or press 7 to exit [1-7]."); System.out.println("1. " + "Add a player"); System.out.println("2. " + "Update a player"); System.out.println("3. " + "Delete a player"); System.out.println("4. " + "List all players"); System.out.println("5. " + "Calculate the average BMIs for the players"); System.out.println("6. " + "Display the details of the tallest player"); System.out.println("7. " + "Exit"); int menuOption = Integer.parseInt(input.nextLine()); switch (menuOption) { case (1): System.out.println("Please enter the name of the player."); String newPlayerName = input.nextLine(); System.out.println("Please enter the jersey number of the player."); int newPlayerJerseyNumber = Integer.parseInt(input.nextLine()); System.out.println("Please enter the height of the player."); double newPlayerHeight = Double.parseDouble(input.nextLine()); System.out.println("Please enter the weight of the player."); double newPlayerWeight = Double.parseDouble(input.nextLine()); playerRoster.add(new Player(newPlayerName, newPlayerJerseyNumber, newPlayerHeight, newPlayerWeight)); break; case (2): System.out.println("Which player would you like to update?"); System.out.println(playerRoster.toString()); int playerIndex = Integer.parseInt(input.nextLine()); System.out.println("Selected" + playerRoster.get(playerIndex).toString()); System.out.println("Enter the value you would like to change[1. name ,2. jersey number,3. weight,4. height]"); int userValueUpdate = Integer.parseInt(input.nextLine()); switch (userValueUpdate) { case (1): System.out.println("Please enter the new value for the player's name."); Player.setName(input.nextLine()); break; case (2): System.out.println("Please enter the new value for the player's jersey number."); Player.setJerseyNumber(Integer.parseInt(input.nextLine())); break; case (3): System.out.println("Please enter the new value for the player's weight."); Player.setWeightInPounds(Double.parseDouble(input.nextLine())); break; case (4): System.out.println("Please enter the new value for the player's height."); Player.setHeightInInches(Double.parseDouble(input.nextLine())); break; } break; case (3): System.out.println("Which player would you like to delete?"); int userDeletion = Integer.parseInt(input.nextLine()); playerRoster.toString(); playerRoster.remove(userDeletion); break; case (4): for (int i = 0; i < playerRoster.size();i++) { System.out.print("Name: " + playerRoster.get(i).getName() + "\nHeight: " + Double.toString(playerRoster.get(i).getHeight()) + "\nWeight: " + Double.toString(playerRoster.get(i).getWeight()) + "\nJersey Number: " + Integer.toString( playerRoster.get(i).getJerseyNumber()) + "\n\n"); } break; } } } }
Player类代码(Player.java)
package playerdatamanager; public class Player { private static String name; private static int jerseyNumber; private static double height; private static double weight; /** * The default constructor for the Player object. */ public Player() { } /** * Overloaded constructor to initialize Player object with user values. * * @param name The name of the Player * @param jerseyNumber The Jersey Number of the Player * @param height The height of the Player * @param weight */ public Player(String name, int jerseyNumber, double height, double weight) { this.name = name; this.jerseyNumber = jerseyNumber; this.height = height; this.weight = weight; } /** * setter method to set the player's name. * * @param userName The name given by the user. */ public static void setName(String userName) { name = userName; } /** * setter method to set a player's jersey number. * * @param userJerseyNumber The jersey number given by the user. */ public static void setJerseyNumber(int userJerseyNumber) { jerseyNumber = userJerseyNumber; } /** * setter method to set a player's height in inches. * * @param userHeight The height in inches given by the user. */ public static void setHeightInInches(double userHeight) { height = userHeight; } /** * setter method to set a player's weight in pounds. * * @param userWeight The weight in pounds given by the user. */ public static void setWeightInPounds(double userWeight) { weight = userWeight; } /** * getter method to retrieve the name of a player. * * @return The player's name. */ public static String getName() { return name; } /** * getter method to retrieve the jersey number of a player. * * @return The player's jersey number. */ public static int getJerseyNumber() { return jerseyNumber; } /** * getter method to retrieve the weight in pounds of a player. * * @return The player's weight in pounds. */ public static double getWeight() { return weight; } /** * getter method to retrieve the height in inches of a player. * * @return The player's height in inches. */ public static double getHeight() { return height; } public static double BMICalculation() { double BMI; BMI = 703 * (getWeight() / (getHeight() * getHeight())); return BMI; } public static void playerRosterToString(double height, double weight, int jerseyNumber, String name) { String playerStats = "Name: " + name + "\nHeight: " + Double.toString(height) + "\nWeight: " + Double.toString(weight) + "\nJersey Number: " + Integer.toString(jerseyNumber); System.out.print(playerStats); } }
问题原因及修复方案
核心问题
Player类中所有字段和方法都被声明为static,这意味着这些成员属于类本身,而非类的实例。所有Player对象共享同一组静态变量,所以每次创建新Player时,都会覆盖之前的静态变量值,导致所有实例显示相同的数据。
修复步骤
移除Player类中所有成员的static修饰符
- 将字段
name、jerseyNumber、height、weight的static去掉,改为实例变量。 - 将所有getter、setter方法,以及
BMICalculation、playerRosterToString方法的static修饰符去掉,改为实例方法。
- 将字段
修改MainMenu中的调用方式
- 在更新球员信息时,不能直接通过
Player.setXXX()调用静态方法,而是要获取ArrayList中对应的Player实例,再调用实例方法:// 原错误代码 Player.setName(input.nextLine()); // 修复后 playerRoster.get(playerIndex).setName(input.nextLine()); - 同理,其他setter调用都要改为针对具体实例的调用。
- 在更新球员信息时,不能直接通过
可选:重写Player类的toString方法
原playerRosterToString方法设计不合理,建议重写toString()方法,方便直接打印Player实例信息:@Override public String toString() { return "Name: " + name + "\nHeight: " + height + "\nWeight: " + weight + "\nJersey Number: " + jerseyNumber; }
修复后的Player类示例
package playerdatamanager; public class Player { private String name; private int jerseyNumber; private double height; private double weight; public Player() { } public Player(String name, int jerseyNumber, double height, double weight) { this.name = name; this.jerseyNumber = jerseyNumber; this.height = height; this.weight = weight; } public void setName(String userName) { name = userName; } public void setJerseyNumber(int userJerseyNumber) { jerseyNumber = userJerseyNumber; } public void setHeightInInches(double userHeight) { height = userHeight; } public void setWeightInPounds(double userWeight) { weight = userWeight; } public String getName() { return name; } public int getJerseyNumber() { return jerseyNumber; } public double getWeight() { return weight; } public double getHeight() { return height; } public double BMICalculation() { return 703 * (weight / (height * height)); } @Override public String toString() { return "Name: " + name + "\nHeight: " + height + "\nWeight: " + weight + "\nJersey Number: " + jerseyNumber; } }
修复后的MainMenu中更新球员的代码片段
case (2): System.out.println("Which player would you like to update?"); for (int i = 0; i < playerRoster.size(); i++) { System.out.println(i + ": " + playerRoster.get(i)); } int playerIndex = Integer.parseInt(input.nextLine()); Player selectedPlayer = playerRoster.get(playerIndex); System.out.println("Selected\n" + selectedPlayer); System.out.println("Enter the value you would like to change[1. name ,2. jersey number,3. weight,4. height]"); int userValueUpdate = Integer.parseInt(input.nextLine()); switch (userValueUpdate) { case (1): System.out.println("Please enter the new value for the player's name."); selectedPlayer.setName(input.nextLine()); break; case (2): System.out.println("Please enter the new value for the player's jersey number."); selectedPlayer.setJerseyNumber(Integer.parseInt(input.nextLine())); break; case (3): System.out.println("Please enter the new value for the player's weight."); selectedPlayer.setWeightInPounds(Double.parseDouble(input.nextLine())); break; case (4): System.out.println("Please enter the new value for the player's height."); selectedPlayer.setHeightInInches(Double.parseDouble(input.nextLine())); break; } break;
内容的提问来源于stack exchange,提问作者LibreEstVitae

