【问题标题】:The final local variable cannot be assigned, since it is defined in an enclosing type最终的局部变量不能赋值,因为它是在封闭类型中定义的
【发布时间】:2014-02-24 11:21:57
【问题描述】:
ratingS = new JSlider(1, 5, 3); 
ratingS.setMajorTickSpacing(1);
ratingS.setPaintLabels(true);
int vote;

class SliderMoved implements ChangeListener {
    public void stateChanged(ChangeEvent e) {
        vote = ratingS.getValue();
    }
}

ratingS.addChangeListener(new SliderMoved());

如果我编写上面的代码,Eclipse 会告诉我:

不能在内部类中引用非最终变量投票 用不同的方法定义

但是如果我在 int vote 之前添加 final 它会给我这个错误:

最终的局部变量 vote 不能赋值,因为它是在封闭类型中定义的

那么,怎么解决呢?

【问题讨论】:

  • 尝试将其设为静态或将其置于已移动但未更改状态的滑块中。或以“this.vote”或“zxc myClass = new zxc(); 的形式访问它,并以 myClass.vote 的形式访问它”
  • vote 应该是一个字段,而不是一个局部变量。
  • 我不能使用“静态”变量投票的非法修饰符;只允许 final 其他方式不能使我的程序正常工作
  • @JBNizet 我认为如果没有更多信息,我们无法判断vote 是否应该是一个字段。如果这是在一个可以从不同线程重入调用的方法中,那么将其作为一个字段将是不好的。无论如何,如果这确实是一个仅在方法内部使用的变量,那么将其设置为可以被其他方法访问的字段对我来说似乎是一种“设计气味”。 (您确实是指外部类中的一个字段,对吧?)

标签: java inner-classes final


【解决方案1】:

将编译器合规级别设置为 1.8 有助于我解决类似的问题。我不明白原因,但你可以试试这个。

它是如何工作的:

右键单击项目--> 属性--> Java 编译器。并在 java 编译器属性窗口中,将编译器合规级别设置为 1.8。

【讨论】:

【解决方案2】:

vote 移动到SliderMoved

class SliderMoved implements ChangeListener {
    private int vote;
    public void stateChanged(ChangeEvent e) {
        this.vote = ratingS.getValue();
        // do something with the vote, you can even access
        // methods and fields of the outer class
    }
    public int getVote() {
        return this.vote;
    }
}

SliderMoved sm = new SliderMoved();
ratingS.addChangeListener(sm);

// if you need access to the actual rating...
int value = rattingS.getValue();

// ...or
int value2 = sm.getVote();

编辑

或者,将模型类传递给更改侦听器

public class Person {
    private String name;
    private int vote;
    public int getVote() {
        return this.vote;
    }
    public void setVote(int vote) {
        this.vote = vote;
    }
    // omitting other setter and getter
}

Person的用法如下:

 class SliderMoved implements ChangeListener {
    private Person person;
    public SliderMoved(Person person) {
        this.person = person;
    }
    public void stateChanged(ChangeEvent e) {
        this.person.setVote(ratingS.getValue());
    }
    public Person getPerson() {
        return this.person;
    }
}

Person person = new Person();

ratingS.addChangeListener(new SliderMoved(person));

// access the vote
int vote = person.getVote();

【讨论】:

  • int value = ratingS.getValue(); 无法在外部工作,因为该方法属于内部类。 int value2 = sm.getVote(); 不要给我实际的评分,只是第一次改变
  • vote 每次状态更改时都会更新,因此sm.getVote() 总是应该返回实际值。我更喜欢在stateChanged(ChangeEvent) 中完成整个工作,我个人会删除sm.getVote(),但这取决于您的需求。
  • 您实际上可以使用模型技术,而无需将其传递给更改侦听器,使用“持有人”类型的设计模式。例如,在更改侦听器之外,您可以声明:final Person person = new Person();,然后在更改侦听器中,您可以访问/更改最终 person 变量的内容,只要您不尝试重新分配人员本身: person.setVote(ratingS.getValue());恕我直言,这比上面的数组技术稍微客观:)
【解决方案3】:

我终于解决了在主类中将投票声明为实例变量(私有)。

【讨论】:

  • 如果主类被多次使用,则主类的每个实例都引用同一个实例变量。这非常非常糟糕。
  • 别担心,它只使用一次。感谢您的评论
  • 正如我所说,这是一种非常非常糟糕的风格。如果你真的需要,让它成为一个单例,因为你永远不知道谁会使用你的类。
【解决方案4】:

好吧,标准技巧是使用长度为 1 的 int 数组。将 var 设为 final 并写入 var[0]。确保您不创建数据竞争非常重要。以您的代码为例:

final int[] vote = {0};

class SliderMoved implements ChangeListener {
  public void stateChanged(ChangeEvent e) {
    vote[0] = ratingS.getValue();
  }
}

由于所有这些都将在 EDT 上发生,包括回调调用,所以您应该是安全的。您还应该考虑使用匿名类:

ratingS.addChangeListener(new ChangeListener() {
  public void stateChanged(ChangeEvent e) { vote[0] = ratingS.getValue(); }
});

【讨论】:

  • 你能给我看一下我的代码吗?我应该如何使用这个技巧?
  • 为什么觉得奇怪?您不能使数组的内容成为最终的。
  • 我觉得很奇怪,因为错误消失只是将其声明为数组。我不明白为什么,反正我不在乎,我只是解决我的问题。非常感谢您的帮助。
  • 我认为您应该始终了解某些东西为什么有效或无效。在这种情况下,您只能从本地类中引用 final vars,但您无法更改它们。但是,您可以更改数组的内容,而不管指向该数组的变量是否为最终变量。
猜你喜欢
  • 2020-02-11
  • 1970-01-01
  • 2016-03-15
  • 2015-02-26
  • 2013-11-30
  • 2019-08-19
  • 1970-01-01
  • 2017-08-28
  • 2011-08-13
相关资源
最近更新 更多