简体   繁体   中英

The final local variable cannot be assigned, since it is defined in an enclosed type

I know this has been answered serveral times, but I can't seem to find a solution to my problem. I'm trying to create a very, very basic game for myself but I am having issues defining the variable "cash" inside of the button click. My code is:

public Main() {
    final int cash = 1000000;
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setBounds(100, 100, 450, 300);
    contentPane = new JPanel();
    contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
    setContentPane(contentPane);
    contentPane.setLayout(null);

    JLabel lblCash = new JLabel("Cash: " + cash);
    lblCash.setBounds(10, 11, 166, 14);
    contentPane.add(lblCash);

    JButton btnStake = new JButton("STAKE");
    btnStake.setBounds(258, 227, 166, 23);
    contentPane.add(btnStake);

    final JLabel lblwol = new JLabel("");
    lblwol.setBounds(10, 115, 414, 14);
    contentPane.add(lblwol);

    sa = new JTextField();
    sa.setBounds(10, 228, 238, 20);
    contentPane.add(sa);
    sa.setColumns(10);

    btnStake.addActionListener(new ActionListener() {

        public void actionPerformed(ActionEvent arg0) {
            String stringAmmount = sa.getText().toString();
            int ammount = Integer.parseInt(stringAmmount);
            sa.setText("");

            double comp = Math.random();

            if (comp < 0.5){
                lblwol.setText("Congratulations, you have won: " + ammount);
                cash = cash - ammount;
            } else {
                lblwol.setText("Sorry, you have lost: " + ammount);
            }
        }

    });
}

You probably need a constant with initial cash amount and a variable for cash balance (both defined on a class level).

static final int INIT_CASH = 1000000;

int cash = INIT_CASH; // variable intialization

If you want the value of cash to be changing you should not make it final as it makes it unchanging or constant.

You should make the cash variable an instance variable instead of method local, because usually you want it to live more than the one method call.

public class Main{
  // instance variable
  int cash = 1000000;

  public Main(){
  // your logic
  }

}

It appears to me that cash should not be final , and you made it final because the compiler told you that you couldn't say cash = cash - ammount because the variable cash was not final . However, making it final won't work because then you can't modify the value. Is that what happened?

In Java, when a method contains a statement that creates an anonymous class (as you've done with new ActionListener ), it can't refer to the method's local variables, unless they are final . (This was a language design decision. C# and JavaScript, which have similar constructs, don't have this restriction.) Here you have a constructor, which isn't really a method, but it behaves like a method. There are two ways around this:

1) Make the variable an instance field, instead of a local variable. Thus, you'd say int cash = 1000000 outside the constructor.

This is an appropriate solution when you could only have one such variable per object. It's also appropriate in your case, since you have cash inside a constructor. The constructor can't be called more than once per object, so there can be only one cash for an object.

However, there are cases where this won't work, where the variable is declared inside a method rather than a constructor. Suppose you have a method that creates a new button, and it's possible that multiple buttons will be created with multiple calls to this method, and each new button will have its own listener, each with its own variable that it modifies. Now having just one instance variable for the object won't work. So another way to work around the final problem is:

2) Make the variable a field inside some other object. You could declare a very simple class that just holds a cash field:

private static class Wallet {   // a Wallet holds cash, hee hee hee
    public int cash;
    public Wallet(int cash) { this.cash = cash; }
}

and in your method

final Wallet wallet = new Wallet(1000000);

Now the anonymous class can refer to wallet , because it's final . But only the reference to the Wallet object is final, not the fields; so the anonymous class can still modify wallet.cash . (Another way to create an object is to make it an array of one element. Declaring a new class is more readable, in my opinion.)

I'm mentioning this so that you know how to solve the problem when it comes up--and it does come up fairly frequently. However, in your case, solution 1 is simpler and probably more appropriate.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM