方法参数中的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关键字[重复]的主要内容,如果未能解决你的问题,请参考以下文章

Java之final关键字

final关键字

java方法的参数 为啥有时会加上final关键字

final关键字和权限修饰符

final关键字修饰的类称为

final关键字代表最终的,不可改变的。