这可能是一个愚蠢的问题(或者只是让我看起来很愚蠢:)),但是我会对如何在短期对象的上下文中使用长字符串对象感兴趣。
想想 cron 作业或匿名、命令或类似函数的类中的长 SQL 查询。这些是非常短暂的类,甚至在它们的生命周期中大部分时间都会使用这些长字符串。什么是更好的?构造一个内联字符串并让它与实例一起收集,还是让它成为静态最终的,让它们在内存中无用,直到类下一次实例化?
这可能是一个愚蠢的问题(或者只是让我看起来很愚蠢:)),但是我会对如何在短期对象的上下文中使用长字符串对象感兴趣。
想想 cron 作业或匿名、命令或类似函数的类中的长 SQL 查询。这些是非常短暂的类,甚至在它们的生命周期中大部分时间都会使用这些长字符串。什么是更好的?构造一个内联字符串并让它与实例一起收集,还是让它成为静态最终的,让它们在内存中无用,直到类下一次实例化?
好吧,您只能对 String 发生的事情进行如此多的控制。
即使您内联创建它,该 String 也很可能会添加到 JVM 的 String 常量池中,并且在您再次声明它时将被重用,因此在实践中,您可能会重用相同的 String 对象。
除非字符串太大以至于对应用程序的性能产生影响,否则我不会担心它并选择对我来说更具可读性的选项。
如果该字符串仅用于代码的一个特定点,在一个方法中,我会将其声明为内联,我更喜欢将我的变量放在我可以的最小范围内,但这里的意见可能会有所不同。如果没有任何变化,并且在您的特定用例中似乎有意义,那么无论如何将 String 声明为静态,我怀疑它会影响性能。
字符串常量进入一个类的常量池,并且不能被优化掉,即处理得足够好。
创建长字符串不是静态的。对于 SQL,请使用带有占位符的预准备语句。?
带占位符的字符串也是如此:使用MessageFormat。
要明确。以下内容无需任何额外费用:
static final String s = "... long string ...";
当剩余内存有限时,JVM 通常会进行 perm gen 空间清理并卸载未使用/未引用的类。因此,在我看来,将长字符串作为静态变量不会造成太大伤害
如果您觉得您的字符串会占用大量内存,请不要将它们设为静态或使用字符串文字声明它们。由于这两个都将存储在 permgen 空间中并且几乎会被垃圾收集[有机会但很渺茫,如果你还没有创建自己的类加载器,静态可能永远不会被垃圾收集]。因此,使用 new 运算符创建字符串,以便在堆中创建并且可以轻松地进行垃圾收集,即
String str = new String("long string");
编辑:
如何存储字符串:http: //www.ntu.edu.sg/home/ehchua/programming/java/J3d_String.html
编辑:
下面就新字符串的工作原理进行了长时间的讨论。提出的论点是 new String 将创建 2 个对象,一个在堆中,一个在池中。这是错误的,默认情况下不是这样,您可以通过调用 intern 方法强制 java 执行此操作。为了支持我的论点,下面是来自 Strin 类的 intern 方法的 javadoc:
实习生
public String intern() 返回字符串对象的规范表示。一个字符串池,最初是空的,由 String 类私下维护。
当调用 intern 方法时,如果池中已经包含一个等于该 String 对象的字符串,该字符串由 equals(Object) 方法确定,则返回池中的字符串。否则,将此 String 对象添加到池中并返回对该 String 对象的引用。
由此可见,对于任何两个字符串 s 和 t,当且仅当 s.equals(t) 为真时,s.intern() == t.intern() 才为真。
所有文字字符串和字符串值的常量表达式都是实习的。字符串文字在 Java 语言规范的 §3.10.5 中定义
从上面的文档可以看出,如果 new String 总是在池中创建一个对象,那么 intern 方法将完全没用!!同样从逻辑上讲,它没有任何意义。
编辑:
另请阅读这篇文章的答案:字符串池在 Java 中为相同的字符串创建两个字符串对象