如果你在一个函数内创建一个匿名类,并尝试在静态类中使用一个参数,那么javac/IDE会抛出一个错误,说你不能在匿名类中使用一个变量除非它被声明为最终的......但是由于Java的值传递引用了值语义,所有参数都是有效的。那么为什么不在这里适用相同的语义呢?编译器的奇怪设计选择警告
例如错误:
public static Optional<Node> getLayerByName(String name) {
Optional<Node> optional = FluentIterable.from(someCollection).firstMatch(new Predicate<Node>() {
@Override
public boolean apply(Node node) {
return name.equals(node.getProperty(LayerProperties.NAME.name()));
}
});
}
但是,这是罚款:
public static Optional<Node> getLayerByName(final String name) {
Optional<Node> optional = FluentIterable.from(someCollection).firstMatch(new Predicate<Node>() {
@Override
public boolean apply(Node node) {
return name.equals(node.getProperty(LayerProperties.NAME.name()));
}
});
}
据我所知,这是唯一的一次,javac命令将迫使你申报的函数参数作为决赛。关于它是否有权将争论宣布为最终的决定,考虑到由于java的范围规则而确实是最终结果,所以在这方面存在很多问题。无论如何,它在函数范围内改变参数引用一般被认为是不好的做法。
我只是很好奇为什么设计选择强制你声明它是最终的,就好像它会混淆在这个实例中改变引用内部函数范围而匿名类使用函数参数,但它不是认为混淆足以自动声明所有函数引用为最终。
编辑 - 这是一个关于Java的语义选择的问题,而不是为什么变量有是最终的问题。
例如对于很多非java背景的程序员而言,可能会期望
public static changeReference(String thing){
thing = "changed";
}
public static void main(String[] args) {
String thing = "orgininal";
changeReference(thing)
System.out.println(thing); //prints original
}
实际上打印“已更改”。从这个意义上说,参数中的所有引用都是最终的,因为函数内部引用的任何变化都不会影响函数外部的引用。看起来如果我们总是放入final,它会提高清晰度,那么很明显changeReference函数不会做任何事情,因为编译器会告诉你。但是,如果你允许参数变量的地方rescoping,这真的是比任何如果有更多或更少的困惑:
public static Optional<Node> getLayerByName(String name, Collection<Node> someCollection) {
name = "changed"
Optional<Node> optional = FluentIterable.from(someCollection).firstMatch(new Predicate<Node>() {
@Override
public boolean apply(Node node) {
System.out.println(name);
return name.equals(node.getProperty(LayerProperties.NAME.name()));
}
});
}
public static void main(Collection<Node> someCollection){
getLayerByName("original", someCollection); // prints "original" never "changed"
}
被允许的版画“原始”,而不是改变了?为什么设计者认为这些行为中的一个比另一个更容易混淆,并且强加额外的语义来处理它,或者为什么他们在这两个几乎完全相同的情况下不执行相同的语义?
方法参数不能作出最终的,因为它会破坏向后兼容性。不幸。 – Kayaman
[为什么Java内部类需要“最终”外部实例变量?](http://stackoverflow.com/questions/3910324/why-java-inner-classes-require-final-outer-instance-variables) –
我不认为这是重复的 - 我知道为什么参数*有*是最终的,因为方法参数在堆栈上,但对象变量在堆上,所以最终保留了只有一个变量的错觉。问题是,为什么他们强迫你在这里宣布它,当所有的方法论点都是有效的时候。为什么编译器不能默默使用方法参数。 –