Java 如何以多种方式定义私有静态final字段很重要

Java 如何以多种方式定义私有静态final字段很重要,java,Java,两者的区别是什么 private static final String JDBC_URL = getURL(); 然后定义getURL()如下: private static String getURL() { return "jdbc:mysql://localhost:3306/"; } 使用以下代码: private static final String JDBC_URL = "jdbc:mysql://localhost:3306/"; 我发现使用上面

两者的区别是什么

 private static final String JDBC_URL = getURL();
然后定义
getURL()
如下:

private static String getURL() {
        return "jdbc:mysql://localhost:3306/";
    }
使用以下代码:

private static final String JDBC_URL = "jdbc:mysql://localhost:3306/";

我发现使用上面的方法编写
mock
测试更容易。我可能错了。只是想知道这两种方法是否相同。谢谢。

第二种方法是编译时常量,因此在代码的其他地方,当您引用该值时,它实际上不会引用该字段-它只会烘焙该值


除非您开始通过反射或类似讨厌的方式来处理字段,否则您不应该注意到任何语义差异,但这将是字节码的差异。

变量的值是什么根本没有区别,唯一的区别是如何设置变量以及在运行时如何解释变量

对于第一个变量,您通过调用函数并使用该函数返回值来设置变量,这样直到程序运行后才设置变量


在第二次调用中,您只是通过使用赋值立即进行设置,而不是调用函数,并将该函数的返回值赋给变量,以便在编译程序时而不是在运行时设置该变量。

正如其他答案所述,在第一种情况下,变量是在运行时分配的,而在第二种情况下,变量大部分是在编译时内联的。即使不使用反射,这也很重要

两个具体案例提供了相互矛盾的建议:

案例1:循环参考 在一些涉及循环类引用的罕见情况下,最好使用文本字符串初始化,因为使用表达式初始化的常量可能不会在需要时立即初始化,从而导致意外的
null
s

例如,下面代码的输出是

1null
2foo
pkg/tmp.java:

package pkg;
class tmp {
  static { tmp2.go(1); }
  public static final String FOO = foo();
  static { tmp2.go(2); }
  private static String foo() { return "foo"; }
  public static void main(String[] args) { }
}
pkg/tmp2.java:

package pkg;
class tmp2 {
  public static void go(int n) {
    System.out.println(n + tmp.FOO);
  }
}
案例2:单独汇编 如果编译定义常量的
Class1
,然后分别编译使用该常量的
Class2
,并且
Class1
中的常量可能会在未来版本的代码中更新,那么最好通过方法调用进行初始化,以防止编译器内联该值。如果常量是从文本字符串初始化的,那么
Class2
将在编译时将旧的常量值放入其中,并且在运行时根本不会引用
Class1
中的字段

一种常见的情况是,所讨论的常量位于库中,您根据库的v1.0编译项目,但使用库的v2.0部署它。更糟糕的是,如果在库的v2.0中,常量是从表达式初始化的,那么查看库的v2.0就无法发现问题

其他注释
  • 两个字符串文字与
    +
    的串联将在编译时进行计算,被视为字符串文字,并作为字符串文字进行内联
  • JDK附带了一个名为
    javap
    的程序,它可以从类中提取和分解字节码,这对于跟踪类似问题非常有用。IDE可能提供类似的反汇编/反编译功能

我看不出有什么不同。如果您在程序的其他部分使用
getURL()
,那么在初始化
JDBC\u URL
时也可以使用它,以保持一致性。但可能并没有什么真正的区别,似乎第二种方法更有效readable@JakubBibro是的,但如果他添加了一个URL设置程序,需要稍后获取URL的值,该怎么办?因此,如果修改getter,则第一个表达式将更加模块化。@jgr208没错,这是一个非常重要的区别,第二个表达式是一个常量表达式。@SotiriosDelimanolis这是真的。因此,它确实在运行时节省了一点时间,但就超出范围而言,除非他在嵌入式系统上,或者有很大的限制,否则不应该对性能产生影响