动作处理程序中的“不能引用非最终变量”?

时间:2011-12-06 20:44:30

标签: java oop object reference jframe

我保证我已经阅读了无数关于此的帖子,所以我猜我无法将我读到的内容翻译成我想要做的事情。首先是叙述。在此基础上,我想做的是在我的例子中开发一个对象列表,对象是汽车。汽车列表显示在我的主窗口中。当我想添加一辆新车时,我打开一个对话框来设置属性并创建它。

问题是我继续用对象引用在圈子里跑。我尝试使用公共方法创建子类并在构造函数中传递对象。这些尝试导致非静态字段或非最终变量的错误。如果我能看到如何制作参考文献的一个可靠的例子,我认为其余部分将落实到位。

对象

public class Car {
private String size;

public Car(String sizeIn){
    this.size = sizeIn;
}   
public void setSize(String sizeIn){
    this.size = sizeIn;
}
public String getSize(){
    return this.size;
}
public String toString(){
    return this.size;
}
}

主窗口

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.*;

import javax.swing.DefaultListModel;
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JList;

public class MainGUI {

private JFrame frame;
private LinkedList<Car> carList;
private DefaultListModel model;

/**
 * Launch the application.
 */
public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
        public void run() {
            try {
                MainGUI window = new MainGUI();
                window.frame.setVisible(true);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });
}

/**
 * Create the application.
 */
public MainGUI() {
    initialize();
}

/**
 * Initialize the contents of the frame.
 */
private void initialize() {
    frame = new JFrame();
    frame.setBounds(100, 100, 450, 300);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    JButton btnAddCar = new JButton("Add Car");
    btnAddCar.addActionListener(new EditLauncher());
    frame.getContentPane().add(btnAddCar, BorderLayout.NORTH);

    JList list = new JList(model);
    frame.getContentPane().add(list, BorderLayout.CENTER);
}

public void addCar(String size){
    Car car = new Car(size);
    carList.add(car);
    model.addElement(car);
    frame.getContentPane().invalidate();
    frame.getContentPane().validate();
}

public class EditLauncher implements ActionListener {

    @Override
    public void actionPerformed(ActionEvent e) {
        // TODO Auto-generated method stub

    }

}

}

对话框

import java.awt.BorderLayout;
import java.awt.FlowLayout;

import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.JTextField;
import javax.swing.JLabel;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;


public class EditDialog extends JDialog {

private final JPanel contentPanel = new JPanel();
private JTextField fldSize;
private MainGUI mainGUI;

/**
 * Launch the application.
 */
public static void main(String[] args) {

    try {
        EditDialog dialog = new EditDialog(mainGUI); //<<ERROR - Cannot make a static reference to the non-static field mainGU
        dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
        dialog.setVisible(true);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

/**
 * Create the dialog.
 */
public EditDialog(MainGUI mainGUI) {
    this.mainGUI = mainGUI;
    setBounds(100, 100, 225, 125);
    getContentPane().setLayout(new BorderLayout());
    contentPanel.setLayout(new FlowLayout());
    contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
    getContentPane().add(contentPanel, BorderLayout.CENTER);
    JLabel lblSize = new JLabel("Size");
    contentPanel.add(lblSize);
    fldSize = new JTextField();
    contentPanel.add(fldSize);
    fldSize.setColumns(10);

    JPanel buttonPane = new JPanel();
    buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT));
    getContentPane().add(buttonPane, BorderLayout.SOUTH);
    JButton okButton = new JButton("OK");
    okButton.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            mainGUI.addCar(fldSize.getText()); // << ERROR Cannot refer to a non-final variable mainGUI inside an inner class defined in a different method
        }
    });
    okButton.setActionCommand("OK");
    buttonPane.add(okButton);
    getRootPane().setDefaultButton(okButton);

    JButton cancelButton = new JButton("Cancel");
    cancelButton.setActionCommand("Cancel");
    buttonPane.add(cancelButton);

}

}

1 个答案:

答案 0 :(得分:6)

对于“无法对非静态字段mainGUI进行静态引用”

问题是(EditDialogs)main是静态的,因此只能访问静态成员或显式对象实例的成员(例如object.member表单)。在这种情况下,mainGUI不是静态成员,因此无法访问:这很好,因为如果调用“main”,则不会创建MainGUI实例! (请记住,每次启动应用程序时只使用一个main !摆脱EditDialog中的“main”以避免这种混淆。)

相反,请考虑这一点(但请参阅Dave 的评论,以获得更好的方法!):

btnAddCar.addActionListener(new ActionListener () {
    public void actionPerformed(ActionEvent e) {
        EditDialog dialog = new EditDialog(MainGUI.this);
        dialog.show(); // or whatever
    }
});

对于“不能引用在不同方法中定义的内部类中的非final变量mainGUI”

错误是因为只能在匿名内部类型(new ActionListener() { ... })中使用成员变量(封闭类型)或“最终”局部变量。

现在,有人可能会“但是mainGUI是一个成员变量!”

嗯,它是但是它被阴影由具有相同名称的本地变量(this.mainGUI vs mainGUI)。以下是我所知道的解决方案:

  1. 更改本地变量名称以避免出现阴影:public EditDialog(MainGUI theMainGUI) ...

  2. 限定mainGUI告诉Java需要成员变量,绕过阴影:EditDialog.this.mainGUI.addCar(...),其中EditDialog是封闭类型的名称。 (上面针对MainGUI.this执行了相同的方法。)

  3. 使用mainGUI final注释public EditDialog(final MainGUI mainGUI) ... 参数。成员变量仍将被遮蔽,但局部变量将满足访问要求,因为它是“最终”。

  4. 快乐的编码。