问题
Got a quick question which I hope someone can answer. Basically I have a String variable which needs changing based upon the value in a combo box which has an event listener attached to it. However if I make the string final then it cant be changed, but if i don't make it final then eclipse moans that it isn't final. Whats the best (and simplest) work around?
Code is as follows
final String dialogOutCome = "";
//create a listener for the combo box
Listener selection = new Listener() {
public void handleEvent(Event event) {
//get the value from the combo box
String comboVal = combo.getText();
switch (comboVal) {
case "A": dialogOutCome = "a";
case "B": dialogOutCome = "b";
case "C": dialogOutCome = "c";
case "D": dialogOutCome = "d";
}
}
};
回答1:
You can't.
Consider this:
- the local variable exists as long as the method it's declared in runs.
- as soon as that method invocation ends (usually because the method exists) the variable vanishes
- the listener can (and usually does) live much longer
So what should happen when the method returned already and the listener tries to modify the local variable?
Because this question does not have a really good answer, they decided to make that scenario impossible by not allowing access to non-final
local variables.
There are two ways around this problem:
- try to change a field instead of a local variable (this probably also fits better with the life-time of the listener) or
- use a
final
local variable, of which you can change the content (for example aList
or aString[]
with a single element).
回答2:
These answers are all telling you how to make a flawed approach "work" at a superficial level.
The real problem is that you're trying to apply traditional, synchronous, "call/return" coding patterns to a library that doesn't support it. The real answer is that when the event you're waiting for happens asynchronously, the stuff you want to do after the event has to happen asynchronously as well. Understanding the event-driven nature of Swing is vital to being effective in it.
In other words, think of what piece of code will read dialogOutCome
. Will some action be performed? If so, perform that action from the handler (or as a result of the handler) instead.
回答3:
An alternative is to use this approach.
public class ReturnValueListener implements Listener {
private String dialogOutCome;
public void handleEvent(Event event) {
//get the value from the combo box
String comboVal = combo.getText();
switch (comboVal) {
case "A": dialogOutCome = " gay";
ase "B": dialogOutCome = " ugly";
case "C": dialogOutCome = " smelly";
case "D": dialogOutCome = " great";
}
}
public String getDialogOutCome() {
return dialogOutCome;
}
}
Listener selection = new ReturnValueListener();
//Set my listener somewhere,
....registerListener(selection);
//After my handleEvent is called
String dialogOutCome = selection.getDialogOutCome();
回答4:
Just create simple StringWrapper
object:
static class StringWrapper {
String value;
StringWrapper(String value) {
this.value = value;
}
}
and use it in type of field dialogOutCome
:
final StringWrapper dialogOutCome = new StringWrapper("");
Listener selection = new Listener() {
public void handleEvent(Event event) {
String comboVal = combo.getText();
switch (comboVal) {
case "A": dialogOutCome.value = " gay";
case "B": dialogOutCome.value = " ugly";
case "C": dialogOutCome.value = " smelly";
case "D": dialogOutCome.value = " great";
}
}
};
回答5:
You can use a setter for indirection. This will take away the final restriction (since the field you're accessing is 'this' instead of 'dialogOutcome'.
String dialogOutCome = "";
void setOutcome(String value){
dialogOutCome = value;
}
//create a listener for the combo box
Listener selection = new Listener() {
public void handleEvent(Event event) {
//get the value from the combo box
String comboVal = combo.getText();
switch (comboVal) {
case "A": setOutcome(" gay");
case "B": setOutcome(" ugly");
case "C": setOutcome(" smelly");
case "D": setOutcome(" great");
}
}
};
回答6:
Workaround solution: Use StringBuilder instead of String
. Of course, StringBuilder
cannot be changed reference in the handleEvent
, but we could invoke its method.
final StringBuilder sb = new StringBuilder();
Listener selection = new Listener() {
public void handleEvent(Event event) {
...
switch (comboVal) {
case "A": sb.delete(0, sb.length()).append("a");
case "B": sb.delete(0, sb.length()).append("b");
...
}
}
};
...
System.out.println(sb.toString());
Then you could get String value by StringBuilder.toString();
EDIT: Please provide the reason voting down this answer.
来源:https://stackoverflow.com/questions/14382064/java-how-to-change-a-local-variable-within-an-event-listener