Java希望某些对象是最终的

Java希望某些对象是最终的,java,swing,oop,Java,Swing,Oop,我正在构建一个GUI应用程序,我需要从我编写的其他类中获得两个对象 GUI是用主方法调用的方法编写的,在该方法中我初始化了两个对象 基本上Eclipse告诉我 "Cannot refer to the non-final local variable user defined in an enclosing scope" GUI有一个按钮,按下该按钮会弹出另一个窗口,用户可以在其中输入登录信息 然后,登录信息在java/eclipse告诉我使用final的一个对象的帮助下被获取和处理,但是当

我正在构建一个GUI应用程序,我需要从我编写的其他类中获得两个对象

GUI是用主方法调用的方法编写的,在该方法中我初始化了两个对象

基本上Eclipse告诉我

 "Cannot refer to the non-final local variable user defined in an enclosing scope"
GUI有一个按钮,按下该按钮会弹出另一个窗口,用户可以在其中输入登录信息

然后,登录信息在java/eclipse告诉我使用final的一个对象的帮助下被获取和处理,但是当它们是final时,我不能以我想要的方式使用它们

我还应该在哪里初始化我的对象,或者我可以做些什么来利用这些对象,这样它们就不是最终的了

以下是相关代码:

Usermanager和Player是我所说的有问题的对象

包de.unistuttgart.iaas.icetea.gui

import java.awt.Component;
import java.awt.ComponentOrientation;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;


import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenuBar;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JProgressBar;
import javax.swing.JSlider;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import de.unistuttgart.iaas.icetea.player.Player;
import de.unistuttgart.iaas.icetea.user.UserManager;

@SuppressWarnings("serial")
public class ICT_mainGUI extends JFrame {
    private final JPanel panel = new JPanel();

    /**
     * Launch the application. should open a window (hopefully)
     */
    public static void main(String[] args) {

        // java eventq shit
        // TODO DONT TOUCH THIS SHIT
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    ICT_mainGUI frame = new ICT_mainGUI();
                    frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Create the frame.
     */
    @SuppressWarnings("unused")
    public ICT_mainGUI() {
        // initializing needed objects
        // user manager for admin and user shit
        // player for player manipulation
        // TODO DONT TOUCH THIS EITHER

        UserManager user = new UserManager();
        Player player = new Player();

        getContentPane().setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, 933, 112);
        getContentPane().setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5));

        JPanel panel_1 = new JPanel();
        panel_1.setFocusCycleRoot(true);
        panel_1.setAlignmentX(Component.RIGHT_ALIGNMENT);
        panel_1.setFocusTraversalPolicyProvider(true);
        getContentPane().add(panel_1);
        panel_1.setLayout(new FlowLayout(FlowLayout.RIGHT, 5, 5));

        JButton playButton = new JButton("Play");
        panel_1.add(playButton);

        JButton btnPause = new JButton("Pause");
        panel_1.add(btnPause);

        JButton btnStop = new JButton("Stop");
        panel_1.add(btnStop);

        JProgressBar progressBar = new JProgressBar();
        panel_1.add(progressBar);

        JMenuBar menuBar = new JMenuBar();
        menuBar.setBorderPainted(false);
        setJMenuBar(menuBar);
        menuBar.add(panel);

        JButton signInButton = new JButton("Anmelden");
        signInButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {

                        //seting up our window
                        final JFrame frame = new JFrame("Login User");
                        frame.setSize(300, 200);


                        JPanel panel = new JPanel();
                        frame.add(panel);
                        panel.setLayout(null);

                //userlabel 
                JLabel userLabel = new JLabel("User");
                userLabel.setBounds(10, 10, 80, 25);
                panel.add(userLabel);

                JTextField userText = new JTextField(20);
                userText.setBounds(100, 10, 160, 25);
                panel.add(userText);

                JLabel passwordLabel = new JLabel("Password");
                passwordLabel.setBounds(10, 40, 80, 25);
                panel.add(passwordLabel);

                JPasswordField passwordText = new JPasswordField(20);
                passwordText.setBounds(100, 40, 160, 25);
                panel.add(passwordText);

                //PASSWORDREPEAT
                JPasswordField passwordrepeat = new JPasswordField(20);
                //TODO fix orientation
                passwordrepeat.setBounds(100, 70, 160,25);
                panel.add(passwordrepeat);
                passwordrepeat.setEnabled(false);

                //passwordtextrepeat
                JLabel passwordtextrepeat = new JLabel("Repeat Password");

                //TODO fix orientation
                passwordtextrepeat.setBounds(10, 70, 80, 25);
                panel.add(passwordtextrepeat);
                passwordtextrepeat.setEnabled(false);

                JButton loginButton = new JButton("login");
                loginButton.setBounds(10, 100, 90, 25);
                panel.add(loginButton);

                JButton registerButton = new JButton("add User");
                registerButton.setBounds(180, 100, 80, 25);
                panel.add(registerButton);
                registerButton.setEnabled(false);


                frame.setVisible(true);

                //doing verification stuff

                final String username = userText.getText();
                final String password = passwordLabel.getText();

                loginButton.addActionListener(new ActionListener() {

                    @Override
                    public void actionPerformed(ActionEvent e) {

                        user.addUser(username, password);

                        if (user.getCurrentUser().equals(username)) {
                            String stringfordialog = "Login sucessful \n Current User:\n" + user.getCurrentUser();
                            JOptionPane.showMessageDialog(frame, stringfordialog);

                        } else {

                        }

                    }
                });

            }
        });

        panel.add(signInButton);

        JButton signOutButton = new JButton("Abmelden");
        panel.add(signOutButton);

        JButton adduserButton = new JButton("AddUser");

        if (user.isAdmin()) {
            adduserButton.setEnabled(true);
        } else {
            adduserButton.setEnabled(false);
        }
        panel.add(adduserButton);

        adduserButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {

                JFrame adduserdialog = new JFrame("AddUser");
                adduserdialog.setSize(400, 200);
                setLocationRelativeTo(null);
                setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

            }
        });
        // TODO promote User
        JButton promoteUserButton = new JButton("Promote User");

        if (user.isAdmin()) {
            promoteUserButton.setEnabled(true);
        } else {
            promoteUserButton.setEnabled(false);
        }

        panel.add(promoteUserButton);

        JSlider volumeSlider = new JSlider();
        menuBar.add(volumeSlider);
        // close button
        JButton btnClose = new JButton("Close");
        btnClose.setHorizontalAlignment(SwingConstants.LEFT);
        menuBar.add(btnClose);
        // TODO **finished** close the window
        btnClose.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                System.exit(0);
            }
        });

    }

}

匿名内部类(侦听器)通过复制局部变量来引用其封闭范围。
当匿名方法返回时,您的局部变量将从中清除,因此它们将不再存在。但是匿名类对象
UserManager
Player
引用这些变量。这是错误的行为,所以Java不允许您这样做


在它是最终的之后,它变成一个常数。因此它存储在堆中,可以安全地用于匿名类。

我以前见过这种情况。下面是正在发生的事情

Foo bar = new Foo();
ActionListener al = new ActionListener(ActionEvent ae) {
  actopnPerformed(ActionEvent ae) {
    bar.setX(x);
  }
}

问题是动作监听器中的代码不会立即被调用,而foo变量在调用bar.setX时可能已经更改了。。。它们在两个不同的范围内。因此,为了确保ActionListener中的代码对它将调用setX的对象具有正确的引用,您需要将bar声明为final-即它不会、不能更改。

到底是什么问题?将
user
player
标记为final。这可能有助于进一步了解如何分解代码-通读这些代码以找出在哪里使用哪些变量有点像噩梦。好吧,我想我在自己的想法中感到困惑,最终对象是否仍然可以被操纵,它们是否与其他对象一样工作良好?最终对象并不能使对象不变。这只是意味着声明为final的变量/参数不能被重新分配(即使用
xxx=somethingNew
所以我可以将它们保留为final?因为我害怕我不能调用对象方法,我想我通过编写类{private UserManager user;private Player;}来修复它在方法this.user=newusermanager();this.player=newplayer()中;那不知何故使任何错误消失了对象也会正常运行,因为我在对象中有一个hashset和一个hashmap,我不知道它发生了什么对不起,我不知道如何更好地表达我自己当你键入长代码时,请编辑你的问题,因为这样很难理解。总之是的,我很高兴它成功了!我也很高兴能提供帮助(:@zython-顺便说一句,在Java 8中,限制放宽了:局部变量实际上是final就足够了,而不需要显式声明为final。