【问题标题】:Cannot refer to the non-final local variable display defined in an enclosing scope无法引用封闭范围中定义的非最终局部变量显示
【发布时间】:2020-07-13 12:13:20
【问题描述】:

这可能是一个非常基本的问题。但我坚持这一点。我得到的字符串变量display 的错误是:

Cannot refer to the non-final local variable display defined in an enclosing scope.

如果我使用 final 关键字,我会收到消息:

The final local variable display cannot be assigned, since it is defined in an enclosing slope.*

代码是:

public class Frame {

public static void main(String[] args) {
    String display=" ";
    Frame ob=new Frame();
    JFrame frame=new JFrame("Test");
    frame.setBounds(300,100,800,500);
    //Container c=frame.getContentPane(); 
    frame.setLayout(null);
    final JTextField name=new JTextField();
    name.setBounds(500,212,150,20);
    JLabel nameLabel=new JLabel("Name: ");
    nameLabel.setForeground(Color.WHITE);
    nameLabel.setBounds(450,171,100,100);
    JTextField ohr=new JTextField();
    ohr.setBounds(500,282,150,20);
    JLabel ohrID=new JLabel("OHR ID: ");
    ohrID.setForeground(Color.WHITE);
    ohrID.setBounds(450,241,100,100);

    final JButton button=new JButton("Submit");
    button.setBounds(530,350,90,20);
    frame.add(name);
    frame.add(ohr);
    frame.add(ohrID);
    frame.add(nameLabel);
    frame.add(button);
    frame.getContentPane().setBackground(Color.DARK_GRAY);
    frame.setVisible(true);

    button.addActionListener(new ActionListener(){
        public void actionPerformed(ActionEvent e){
            if(e.getSource()==button){
                display=name.getText();
                JOptionPane.showMessageDialog(null, "Hi "+ display);
                System.exit(0);
            }
        }
    });
}

提前致谢!

【问题讨论】:

    标签: java swing compiler-errors final


    【解决方案1】:

    您的代码存在多个问题,我们将立即在此处解决这些问题并同时解决您的问题。

    1. public class Frame { 这个特定的行有一个错误,Frame 是 AWT 类的名称,因此它可能会使您或以后阅读此代码的任何人感到困惑,给它一个更有意义的名称并避免使用那些可能与其他 Java 包混淆。

    2. Frame ob=new Frame();你创建了你的类的一个实例并且再也没有使用它,为什么?

    3. frame.setLayout(null); 永远不要,请不要使用null-layout,Swing 必须处理多种 PLAF、屏幕尺寸和分辨率、不同的操作系统、像素完美的应用程序似乎是最简单的方法创建复杂的 UI,但稍后您会发现错误 like this 经常发生。

    4. .setBounds(...) 在每个组件上,同样,这是由于null-layout,但最好使用Layout managers

    5. final JTextField name=new JTextField(); 无需将任何组件声明为final,这是由于您的类设计不佳,您的组件应声明为类成员(在包括main 在内的任何方法之外)。

    6. 说到main,把你的程序分成更小的部分,不要把所有东西都扔给main,或者至少创建一个不是static的方法,这样你就可以在创建你的实例后调用它类(否则稍后你会得到大量的static 变量,这又是你的类的糟糕设计)。

    7. System.exit(0); 它将停止 JVM,这样做绝不是一个好主意,最好将 .dispose() JFrame 并将您的 JFramedefaultCloseOperation 设置为 EXIT_ON_CLOSE,这样可以安全处置您的应用程序,然后停止 JVM。

    8. display=name.getText();,对于这种特殊情况,display 可能是内部变量而不是类成员。 这将解决您的特定问题

    9. JOptionPane.showMessageDialog(null, "Hi "+ display); null 应该是对您的 JFrame 的引用,这会将您的对话框放在 JFrame 的中间而不是屏幕中间。

    10. 您永远不会将您的程序放在 EDT 中,请参阅this answer 中的第 2 点。

    因此,考虑到以上所有要点,这是您的代码的改进版本。

    import java.awt.Color;
    import java.awt.GridLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    
    import javax.swing.BoxLayout;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JOptionPane;
    import javax.swing.JPanel;
    import javax.swing.JTextField;
    import javax.swing.SwingUtilities;
    
    public class UsingVariablesInsideActionListenerExample {
        //We declare our components here
        private JFrame frame;
        private JButton button;
        private JTextField name;
        private JTextField ohr;
        private JLabel nameLabel;
        private JLabel ohrID;
        private JPanel pane;
        private JPanel namePane;
        private JPanel ohrPane;
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new UsingVariablesInsideActionListenerExample()::createAndShowGUI); //This is using Java 8 lambdas to place your program in the EDT
        }
    
        private void createAndShowGUI() {
            frame = new JFrame("Test"); //Create your JFrame 
            
            pane = new JPanel();
            pane.setLayout(new BoxLayout(pane, BoxLayout.PAGE_AXIS)); //This will make this JPanel to arrange components vertically
            
            namePane = new JPanel(); //By default, JPanels have FlowLayout which will arrange components horizontally
            ohrPane = new JPanel();
            
            name = new JTextField(10); //We create a JTextField with 10 columns 
            nameLabel = new JLabel("Name: ");
            nameLabel.setForeground(Color.WHITE);
            
            ohr = new JTextField(10);
            ohrID = new JLabel("OHR ID: ");
            ohrID.setForeground(Color.WHITE);
    
            button = new JButton("Submit");
            
            //Add the action listener
            button.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    if (e.getSource() == button) {
                        String display = name.getText(); //The display variable is now an inner variable rather than a class member
                        JOptionPane.showMessageDialog(frame, "Hi " + display);
                        frame.dispose(); //We dispose the JFrame and it will be closed after due to EXIT_ON_CLOSE below.
                    }
                }
            });
            
            //We add the components to the namePane (horizontally), the order matters
            namePane.add(nameLabel);
            namePane.add(name);
            
            //Now we add these components to the ohrPane (horizontally again)
            ohrPane.add(ohrID);
            ohrPane.add(ohr);
            
            //We then add the name and ohr panes to a bigger JPanel (pane, which if you remember will add them vertically) and we add the button at the end
            pane.add(namePane);
            pane.add(ohrPane);
            pane.add(button);
            
            //We make them non opaque (transparent) so that we can see the background color of the JFrame
            namePane.setOpaque(false);
            ohrPane.setOpaque(false);
            pane.setOpaque(false);
            
            frame.add(pane);
            
            frame.getContentPane().setBackground(Color.DARK_GRAY);
            frame.pack(); //This will get every component's preferred size and make the JFrame as small as possible where it looks good on every OS, PLAF, screen size and resolution.
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setVisible(true); //We make the frame visible (always at the very end, when we've added everything to it).
        }
    }
    

    这就是现在的样子。

    UI 可能并不完全等同于您拥有的 UI,但我相信您可以使用不同的布局管理器,并嵌套各种 JPanels 以获得比我更好看的 UI,或者至少与您拥有的更相似。

    【讨论】:

      【解决方案2】:

      内部类中使用的变量应该是有效的 final 。您可以使用长度为 1 的 string[] 而不是 string 来解决此问题。请阅读下面的帖子了解更多详情

      Difference between final and effectively final

      也可以查看这篇文章了解更多详情

      Variable used in lambda expression should be final or effectively final

      【讨论】:

        猜你喜欢
        • 2015-11-25
        • 1970-01-01
        • 2017-08-28
        • 1970-01-01
        • 1970-01-01
        • 2019-10-28
        • 2018-09-27
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多