我们应该在什么情况下使用“public static final String”?

62
我看到了很多人编写的代码,他们写了 public static final String mystring = ... 然后直接使用值。
为什么他们要这样做?在使用之前为什么必须将值初始化为final更新 好的,谢谢大家的回答,我理解了这些关键字(public static final)的含义。但我不明白即使常量只会在同一类中的一个地方使用,为什么人们还要使用它。为什么要声明它?为什么我们不只是使用变量呢?

6
当将字符串定义为常量时... - harshit
关于更新,这只是一个好的实践(依我之见)。如果您稍后回来并需要重用相同的值,则不需要重新定义它和更新先前的代码。 - Mavelo
2
当然这样做有其好处。但是像 public static final String TILDE_EQUAL = "~="; 这样的代码真的让我很不爽。什么时候“tilde-equal”会变成除了 ~= 以外的其他东西呢? - kgf3JfUtW
@kgf3JfUtW - 任何一般良好的指导方针都可能被不理解其基本原理或盲目遵循规则的人误用,因为有人咒语般地说“这是最佳实践”。 - user16632363
考虑到JVM对String字面量的连接和优化,我不确定使用String常量而不是字面量是否有必要。尽管如此,像BigInteger BIG_ONE = new BigInteger(1)这样的声明并不一定是不好的实践。在Java中,由于语言对字符串提供了特殊支持,因此对于字符串来说并不需要,但如果每个“〜=”调用都创建一个单独的字符串对象,并且您将其放在一堆循环中,则可能需要使用TILDE_EQUAL常量。简而言之,即使标识符使值明显,常量也可以具有有效的用途。 - Trixie Wolf
14个回答

100

final表示变量的值不会改变,换句话说,它是一个常量,在声明后不能修改。

当您想创建一个String满足以下条件时,请使用public final static String

  1. 属于类(static:无需实例即可使用),
  2. 不会改变(final),例如,当您想定义一个String常量,该常量将对类的所有实例和使用该类的其他对象可用,并且
  3. 将成为类向外界展示的公共可访问接口的一部分。

示例:

public final static String MY_CONSTANT = "SomeValue";

// ... in some other code, possibly in another object, use the constant:
if (input.equals(MyClass.MY_CONSTANT))

同样地:
public static final int ERROR_CODE = 127;

使用final并非必需,但它可以防止在程序执行期间无意中更改常量,并且作为变量是常量的指示器。

即使常量只会在当前类和/或一个地方使用-读取-,将所有常量声明为final也是一种良好的实践:这样更清晰,在代码的生命周期内,常量可能会在多个地方使用。

此外,使用final还可以让实现执行一些优化,例如在使用常量的地方内联实际值。

最后请注意,final只会将原始类型、不可变的String或其他不可变类型真正变为常量值。将final应用于对象(例如HashMap)将使引用不可变,但不会使对象的状态不可变:例如,对象的数据成员可以更改,数组元素可以更改,集合可以被操作和更改。


6
并且"Static means that can be access in an static way (that not need to instanced the class like new ExampleClass)"的意思是静态方法可以通过静态方式访问(不需要像new ExampleClass那样实例化类)。 - Enrique San Martín
6
编译器是否会使用final static变量进行优化?例如,将对final static变量的引用替换为实际值。 - JProgrammer
1
只有在必须公开时才使用“public”。如果“not public”能够满足您的需求,则更好。 - user16632363
@user16632363,感谢您的评论,我已经编辑了我的答案,将您的观点包含在答案列表中。 - pb2q
1
谢谢@TrixieWolf,这是对一个旧回答的很好补充,我会加上细节。 - pb2q
显示剩余3条评论

12
  1. 静态的意思是..你可以在不实例化类或使用任何对象的情况下使用它。
  2. final..这是一个关键字,用于使字符串常量。您无法更改该字符串的值。请参考以下示例:

      public class StringTest { 
               static final String str = "Hello"; 
      public static void main(String args[]) { 
               // str = "world"; // gives error 
               System.out.println(str); // called without the help of an object                       
               System.out.println(StringTest.str);// called with class name  
                 } 
             } 
    

感谢


6
关键字final表示该值是常量(无法更改)。它类似于C语言中的const。
同时,您可以将static视为具有作用域的全局变量。这基本上意味着如果您为一个对象更改它,则所有对象都会更改,就像一个全局变量(作用域受限)。
希望对您有所帮助。

4
static表示对象只会被创建一次,并且不具有包含它的实例对象。当您拥有适用于类的所有对象并永远不会更改的内容时,最好使用您编写的方式。甚至可以在不创建对象的情况下使用它。
通常最好在您期望它是final时使用final,以便编译器强制执行该规则,您可以确定。 static确保如果对于所有对象而言值相同,则不会浪费内存创建许多相同的内容。

您可以在任何时候重新创建静态成员。 - krizajb

2

final 表示该值在设置后无法更改。 static 允许您设置该值,并且该值将对使用它的类的所有实例相同。此外,您可以在没有类实例的情况下访问 public static 字符串的值。


2

public 使其可以在其他类中访问。您可以在不实例化类或使用任何对象的情况下使用它。

static 使其在所有类实例中具有统一值。 如果对于所有对象而言,它们的值相同,则确保您不会浪费内存创建许多相同的内容。

final 使其成为不可修改的值。它是一个“常量”值,对于所有类实例都是相同的且不能被修改。


3
我不同意这部分内容:“你可以在没有实例化类或使用任何对象的情况下使用它。” 这就是静态关键字的作用。 - krizajb
“public” 使其在其他类中可访问。您可以在不实例化类或使用任何对象的情况下使用它。您能举个例子吗? - hakkikonu
我们可以将那个完全错误的回答标记为组下投票吗?或者在这些年后,@nikhil学到足够的知识来真正提供建议并编辑回答了吗? - nico gawenda

2
你不一定需要使用 "final",但是使用 "final" 可以清楚地告诉其他人(包括编译器),这是一个常量,这是良好的实践。
为什么即使常量只在同一类中的一个地方使用,人们还会这样做:因为在许多情况下,这仍然是有意义的。例如,如果您知道它在程序运行期间将是最终值,但是您打算稍后更改该值并重新编译(更易于查找)并且稍后可能更频繁地使用它。它还可以在一个突出且组合的地方向其他程序员传达程序流程中的核心价值观。
很遗憾,其他答案忽略了一个方面,那就是需要非常谨慎地使用 "public final" 的组合,特别是如果其他类或软件包将使用您的类(这可以假设,因为它是 "public")。
这是为什么:
1. 因为它被声明为 "final",编译器将在编译时将此字段插入到读取该字段的任何编译单元中。到目前为止没问题。 2. 人们容易忘记的是,因为该字段也被声明为 "public",所以编译器也会将此值插入到任何其他编译单元中。这意味着使用此字段的其他类。
有什么后果吗?
想象一下您有以下内容:
class Foo {
  public static final String VERSION = "1.0";
}

class Bar {
  public static void main(String[] args) {
    System.out.println("I am using version " + Foo.VERSION);
  }
}

编译并运行Bar后,您将获得:

最初的回答:

I am using version 1.0

现在,你改进了Foo并将版本更改为“1.1”。 重新编译Foo后,运行Bar并获得错误输出:

最初的回答:

I am using version 1.0

这是因为VERSION被声明为final,所以在第一次编译运行时,它的实际值已经内联到Bar中。因此,要让一个public static final ...字段的示例在实际更改被声明为final的内容后正确传播,您需要重新编译使用它的每个类。(你撒谎了!;) 我已经看到过几次,这真的很难调试。
如果您所说的final是指在程序的后续版本中可能会更改的常量,那么更好的解决方案是:
class Foo {
  private static String version = "1.0";
  public static final String getVersion() {
    return version;
  }
}

这种做法对性能的影响可以忽略不计,因为JIT代码生成器会在运行时将其内联。翻译成中文为:

这种做法对性能的影响可以忽略不计,因为JIT代码生成器会在运行时将其内联。


1
通常用于定义常量,您可以在许多地方重复使用它,使其成为单个更改点,可在单个类中使用或跨包共享。将变量设置为final可以避免意外更改。

1

为什么人们在类中使用常量而不是变量?

可读性和可维护性,

在代码中使用像40.023这样的数字并不能清楚地说明数字代表什么,因此我们用大写字母的单词(如“USER_AGE_YEARS”)替换它。以后查看代码时就清楚了该数字代表什么。

为什么我们不只使用变量?如果我们知道该数字会改变,那么我们会使用变量,但如果它是一个不会改变的数字,比如3.14159……,我们将其设置为final。

但如果它不是像String这样的数字呢?在这种情况下,主要是为了可维护性。如果您在代码中多次使用字符串(且它在运行时不会更改),则将其作为类顶部的final字符串很方便。这样,当您想要更改它时,只需更改一个地方,而不是许多地方。

例如,如果您的代码中有一个错误消息被多次打印出来,拥有最终字符串ERROR_MESSAGE =“Something went bad.”更易于维护。如果您想将其从“Something went bad.”更改为“It's too late jim he's already dead”,则只需要更改那一行而不是使用该注释的所有位置。

这是关于编程的内容,翻译成中文为:“这个有点难搞,但还不错 :)”。 - nico gawenda

0

我认为这些都是清晰的解释。但是,让我通过给出一个Java内置示例来澄清它。

在Java中,大多数人会使用System.out.println()

system是一个类,out是一个PrintStream类。

因此,Java所说的是,我将负责初始化out对象(PrintStream),并将初始化私有化到System类中。

public final class System {

    public final static PrintStream out = null;

    //Some initialization done by system class which cannot be changed as it is final.
}

你可以静态地访问println方法,而不必担心它的初始化。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接