方法参数中的final关键字[重复]
Posted
技术标签:
【中文标题】方法参数中的final关键字[重复]【英文标题】:final keyword in method parameters [duplicate] 【发布时间】:2011-01-15 05:57:43 【问题描述】:我经常遇到类似如下的方法:
public void foo(final String a, final int[] b, final Object1 c)
如果调用此方法而不传递最终参数会发生什么。即稍后更改的 Object1(因此未声明为 final)可以很好地传递给此方法
【问题讨论】:
@Joachim - 实际上它与 C 语言中的const
相同!不同之处在于,在 Java 中,指向对象的“指针”不带有任何特殊的 *
语法。因此这里的混乱。变量是 const/final,它指向的对象不是。
@Earwicker 我想我明白你的意思,但我认为 Joachim 更准确地说“最终”方法参数对调用者没有任何影响,这是真的,但不是真正的 'const ' 是一般的意思。
顺便说一句,我认为您经常看到人们以这种方式声明方法,他们正确地认为,不将方法参数视为可以更改的局部变量会更清晰且不易出错。 'final' 只是强制执行此操作。
@Earwicker:我的 C 很弱。我想我记得const
参数强制传入的每个值也来自const
变量。这似乎是错误的。对不起。
@Sean: i 经常看到它,因为我们的 eclipse 格式化程序就是这样设置的。它是整个概念的产物,它以最受限制的方式(w.r.t 访问修饰符和一般情况下)促进编码,因此当您删除限制时,您需要明确地这样做。我的 2 美分。
【参考方案1】:
Java 总是在将参数发送到方法之前制作一个副本。这意味着 final 对调用代码没有任何区别。这仅意味着在方法内部不能重新分配变量。
请注意,如果您有一个最终对象,您仍然可以更改该对象的属性。这是因为 Java 中的对象实际上是指向对象的指针。并且只有指针被复制(并且在你的方法中是最终的),而不是实际的对象。
【讨论】:
它肯定会复制(有一种优化,编译器不会复制,而复制没有区别)。但是,您必须记住,在对象的情况下。对象实际上只是对对象的引用。因此,在这种情况下,您将获得一份参考资料。 如果参数的值是参数源的副本或相同的引用,这真的无关紧要。事实上,任何变量都只是对内存中实际对象的引用。将参数标记为 final 禁止在函数的代码块内重新分配参数。但是,如果参数不是最终参数,尽管可以将传入参数中的参数重新分配给其他任何参数,但函数的调用者永远不会丢失其引用,并继续指向同一个对象。 对于未来的读者,请阅读javadude.com/articles/passbyvalue.htm 而不是这些答案。 Java 是按值传递的,关键字“final”只关心该对象不会在方法内意外更改。 (或出于匿名类中使用的原因) 是的,Java 按值传递并复制对象引用(这是一个指向对象的指针)。 final 关键字然后阻止更改引用,但是......尽管父引用是副本,但仍然可以修改所述对象的任何可变成员。见:javaworld.com/article/2077424/learn-java/… Java 只复制参数的引用,而不是参数本身。这应该在答案中澄清。【参考方案2】:如果将任何参数声明为 final,则无法更改它的值。
class Bike11
int cube(final int n)
n=n+2;//can't be changed as n is final
n*n*n;
public static void main(String args[])
Bike11 b=new Bike11();
b.cube(5);
输出:编译时错误
更多详情请访问我的博客:http://javabyroopam.blogspot.com
【讨论】:
【参考方案3】:有一种情况,您需要将其声明为 final ——否则会导致编译错误——即将它们传递到匿名类中。基本示例:
public FileFilter createFileExtensionFilter(final String extension)
FileFilter fileFilter = new FileFilter()
public boolean accept(File pathname)
return pathname.getName().endsWith(extension);
;
// What would happen when it's allowed to change extension here?
// extension = "foo";
return fileFilter;
删除final
修饰符会导致编译错误,因为不再保证该值是运行时常量。从匿名类外部更改值将导致匿名类实例在创建之后表现不同。
【讨论】:
变量值的变化(声明为final)对内部类有什么影响? 但是,public boolean doesStringStartsWithZero(String str) throws Exception boolean result = str.startsWith("0"); str = "名称";上面的例子(带有内部匿名类和这个 util 方法)有什么区别?【参考方案4】:方法输入参数中的final关键字是不需要的。 Java 会创建对象引用的副本,因此将 final 放在它上面不会使对象成为最终对象,而只是引用,这没有意义
【讨论】:
【参考方案5】:final 意味着一旦分配了该变量的值,您就无法更改它。
同时,对这些方法中的参数使用 final 意味着 它不允许程序员在方法执行期间更改它们的值。 这仅意味着在方法内部不能重新分配 final 变量。
【讨论】:
【参考方案6】:方法参数上的final
关键字对调用者毫无意义。它对正在运行的程序也毫无意义,因为它的存在或不存在不会改变字节码。它仅确保在方法中重新分配参数变量时编译器会抱怨。就这样。但这已经足够了。
一些程序员(比如我)认为这是一件非常好的事情,并且几乎在每个参数上都使用了final
。它使理解一个长的或复杂的方法变得更容易(尽管有人可能会争辩说应该重构长而复杂的方法。)它还突出了没有标记为final
的方法参数.
【讨论】:
我碰巧发现这更像是团队中的约定。真的没有正确/错误的答案。但是,我有点同意@Erick G. HagstromErick。在方法参数上使用final
可以帮助您第一眼了解方法的输出,并注意那些非最终参数。【参考方案7】:
字符串是不可变的,所以实际上你不能在之后更改字符串(你只能使保存字符串对象的变量指向不同的字符串对象)。
但是,这不是您可以将任何变量绑定到final
参数的原因。所有编译器检查的是参数没有在方法中重新分配。这有利于文档的目的,可以说是很好的风格,甚至可以帮助优化字节码以提高速度(尽管这在实践中似乎没有多大作用)。
但是,即使您确实在方法中重新分配了参数,调用者也不会注意到这一点,因为 java 会按值传递所有参数。序列后
a = someObject();
process(a);
a 的字段可能已更改,但 a 仍然是之前的对象。在传递引用的语言中,这可能不是真的。
【讨论】:
您不妨重新考虑这个职位。 Java 不按值传递。对此的简单测试,不是传递 String 作为参数(它是不可变的),而是传递一个 StringBuffer() StringBuffer sb = new StringBuffer("Hello"); addWord(sb); System.out.println(sb.toString()); public void addWord(StringBuffer buf) buf.append("world");运行这个,你会看到 sb 输出“Hello World”。如果它是按值传递的,这是不可能的,它是按引用传递的,其中引用是一个副本。虽然可以说,如果它是最终的,那么引用可能不会被复制 @Armand Java 总是(总是!)按值传递。【参考方案8】:考虑 foo() 的这种实现:
public void foo(final String a)
SwingUtilities.invokeLater(new Runnable()
public void run()
System.out.print(a);
);
因为Runnable
实例的寿命会比方法长,所以如果没有final
关键字,这将无法编译——final
告诉编译器获取引用的副本是安全的(稍后引用它) .因此,被认为是最终的 reference,而不是 value。换句话说:作为调用者,你不能搞砸任何事情......
【讨论】:
这是一个很好的观点。它解决的问题与我认为的 OP 所考虑的略有不同,因为它是要求在匿名内部类中引用的封闭范围内的变量必须是 final 的特殊情况,但它仍然提供了一个很好的理由至少一些方法参数是最终的。 这不是“因为 Runnable 实例会比方法更长寿”。任何匿名内部类都是如此。 哦,现在在 Java 8 中我们有了最终的概念。【参考方案9】:Java 只是按值传递。 (或更好 - 按值传递引用)
因此,传递的参数和方法中的参数是两个不同的处理程序,指向同一个对象(值)。
因此,如果您更改对象的状态,它会反映到引用它的所有其他变量。但是,如果您为参数重新分配一个新对象(值),则指向该对象(值)的其他变量不会被重新分配。
【讨论】:
此答案未涉及“最终关键字”的主题。以上是关于方法参数中的final关键字[重复]的主要内容,如果未能解决你的问题,请参考以下文章