【问题标题】:how can it be that my class field changes although its defined static?尽管定义了静态,但我的类字段怎么会发生变化?
【发布时间】:2012-01-17 12:46:54
【问题描述】:

不幸的是,我有一个 bug 已经解决了 1 天,虽然我知道有办法解决它,但我很高兴知道我的逻辑哪里出了问题。

现在,我的节目是关于两队棋手之间的比赛。它根据教练(用户)选择的球员设置来预测分数。 *(我的问题下方有更多背景信息)

所以我首先询问用户他的团队中有哪些球员。当然我希望这个“PlayerList”信息保持不变(我提到的错误是它神秘地没有)

所以我制作了一个 GUI,它会弹出所有的棋盘,玩家按照用户提交给程序的顺序排列。然后,每当他单击其中一个按钮时,该按钮的 acionlistener 应该显示下一个玩家,(它让主程序知道在该板上选择了另一个玩家并相应地调整预测,但这些任务完美地工作)。

现在的问题是,如果用户将板 2 上的 Marcel 替换为其他人,那么当用户要单击板 3 的按钮时,他不再拥有 Marcel 可供他使用的选项。所有按钮的“playerList”字段已设置为主程序中选择的播放器设置,而不是主程序在运行开始时提示用户输入的原始列表...

(见附图)

因此,分配给这些按钮的播放器与用户实际选择的播放器列表之间存在一些非常烦人的依赖关系。如果我查看我的代码,我无法理解为什么......

所以我定义的按钮出了点问题。

现在这就是我们所拥有的:

我扩展了 JButton,以便按钮包含用户团队中可用球员的信息,如下所示:

    public class JButtonPlus extends JButton {
public Team team;
private int aantalSpelers;
final ArrayList<Player> playerList;
private Integer spelerNr;
private Integer bordNr;


public JButtonPlus(ArrayList<Player>playerList_, Integer spelernr, Integer bordnr){

    playerList=playerList_;
    aantalSpelers=playerList_.size();
    spelerNr=spelernr;
    bordNr = bordnr;
}

所以问题是这个最终的 ArrayList playerList 根本不是常量。

在通过单击任何其他按钮调用任何 actionListener 后,它会发生变化。

这是主程序中制作按钮并添加动作监听器的代码: (注意:这个 teams.get(0) 指的是用户所在的球队,而现场球员指的是一个 ArrayList,其中填充了他提交给程序的所有球员。方法 displaySpelernr(i) 将球员姓名添加到JButtonPlus 的 setText 方法)

Box verticalBox_1 = Box.createVerticalBox();
    frame.getContentPane().add(verticalBox_1);

    JLabel lblNewLabel = new JLabel("opstelling thuisteam");
    verticalBox_1.add(lblNewLabel);

    for (int i = 0; i < teams.get(0).players.size(); i++) {
        final JButtonPlus btnSpeler = new JButtonPlus(
                teams.get(0).players,i, i);

        btnSpeler.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent arg0) {
                btnSpeler.displayVolgendeSpeler();

            }
        });
        verticalBox_1.add(btnSpeler);
        btnSpeler.displaySpelerNr(i);
    }

在userClick处调用的方法,displayVolgendeSpeler是这样的

    public void displayVolgendeSpeler(){
spelerNr =(spelerNr+1)%aantalSpelers;
    displaySpelerNr(spelerNr);      

问题是上面的语句,其他语句涉及计算,它应该像它一样工作。这个 displaySpelerNr() 方法看起来像他的

public void displaySpelerNr(Integer i){ setText(playerList.get(i).SpelerNaam); 并且这里的错误被指出:playerList 对象已被更改..

有没有人明白为什么当点击按钮时,这个所谓的恒定玩家 playerList 来源会发生变化?

*(更多背景信息) 两局棋局之间的比赛涉及所有棋手与对方棋手之一进行一场比赛。通常,团队中的球员具有不同的实力。所以举个例子,如果A队的选手实力从初级到高手,B队的选手实力从中级到大师级,你知道如果按照实力增加来配对,那么A队肯定会输。有趣的是,A队将牺牲一两个最弱的球员,将他们与B队的两名最强球员配对。这意味着损失两分,但A队的其余球员现在将各自面对一名较弱的球员一个更强的。甚至可能会有配对,因此较弱的团队更有可能获胜。我的程序试图显示哪些配对是最差和最好的,并给出统计数据。当然,如果可能使用这个程序的教练真的能够将这个 Gui 设置为他想要的团队,那就太好了,这就是你进来的地方,亲爱的 StackOverflow 冠军!

【问题讨论】:

    标签: class static constructor field


    【解决方案1】:

    将字段声明为final 意味着您不能为其分配新值。但是,如果该字段包含一个对象,您仍然可以修改该对象内的非最终字段。下面的代码应该能说明我的意思。

    class Foo {
        private final Bar foo; 
    
        public Foo() {
            foo = new Bar();
        }
    
        public void testFoo() {
            this.foo = new Bar(); // compile error
            this.foo.setBar("Test"); // works fine
        }
    }
    
    class Bar {
        private String bar;
    
        public void setBar(String bar) {
            this.bar = bar;
        }
    
        public String getBar() {
            return bar;
        }
    }
    

    在您的代码中,您有一个final ArrayList&lt;Player&gt;,这意味着您不能在该字段中存储 new ArrayList。但是,您可以通过任何常用方式(添加、删除、更新元素等)修改现有 ArrayList 的内容。

    您还将相同的 ArrayList 传递给您的所有 JButtonPlus 实例,因此在任何这些类中更改它都会导致对所有这些类进行更改。尝试传入 ArrayList 的副本,看看是否能解决问题。

    【讨论】:

    • 谢谢。我会尝试传递 ArrayList 的克隆。我特别要寻找的是如何触发这个 PlayerList 来改变它,因为我很确定没有改变它的声明......无论如何,这个关于 final 一词含义的信息非常有用。我想没有明显的方法可以使对象的内容成为最终的吗? (这只会治标不治本,而不是真正的错误,但这可能是务实的)
    • @FMolivierH 我不能告诉你——它不会发生在你提供的代码中。它发生在主程序代码中的某处,或者您未包含在问题中的其他部分。
    • Anthony,我确实找到了更改所有 JButtonPlusses 的 SpelersLijst 字段的代码行。它是在用户单击 Gui 中的 JButtonPlusses 之一后,将主程序中所选播放器排列设置为当前状态的代码。代码行说(在您建议使用 Playerlist-object 的副本之后): PlayerArrangementCalculator.chosenArrangement.get(bordNr).SpelerNaam=((ArrayLis‌​t) playerList.clone()).get(spelerNr ).SpelerNaam;这实际上改变了 playerList-field 不是很奇怪吗??
    • 其实我觉得你在标题中对我的问题给出了完美的答案。而且我想我的程序中剩下的错误是生病了,要么必须更清楚地重新制定,要么尝试自己解决。感谢您的帮助!
    • 这个bug终于解决了。我的错误是我想用另一个 ArrayList B 的值填充一个 ArrayList A。我声明了新的 ArrayList A = B,并想知道我的 ArrayList B 在整个程序中是如何改变的,只有 A 被操纵。我是个初学者 :) 现在让我们记住这一点 :) Ciao!
    猜你喜欢
    • 2020-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-20
    • 2018-05-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多