65.9K
CodeProject 正在变化。 阅读更多。
Home

关于 Java String 的 5 个事实

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.96/5 (6投票s)

2013 年 12 月 11 日

CPOL

5分钟阅读

viewsIcon

33875

发现关于 Java String 的一些有趣事实

引言

String 是 Java 编程语言的基础之一。它不像 intlongdouble 那样是原始数据类型。它定义在 java.lang 包中,并将其内容封装在一个字符数组中。

在这篇文章中,我们将发现一些有趣的 String 事实,这些事实可以帮助我们更好地理解这个流行类的行为。

1. String 是不可变的

编程中有一个强大而简单的概念,它被严重低估了:不可变性。

基本上,一个对象在其创建后状态不会改变,那么它就是不可变的。因此,如果一个类的实例是不可变的,那么这个类就是不可变的。

使用不可变对象的有一个杀手级论据:它极大地简化了并发编程。想想看,为什么编写正确的并发编程是一项艰巨的任务?因为同步多个线程对资源的访问(对象或其他操作系统事物)很难。为什么同步这些访问很难?因为很难保证多个线程对多个对象进行读写访问时不会发生竞态条件。如果不再有写访问怎么办?换句话说,如果线程访问的对象的状态不会改变怎么办?那就无需同步了!

不可变类也适合用作哈希表的键。用于计算哈希值的对象必须是不可变的,以确保哈希值在一段时间内保持不变。事实上,哈希值是从对象的状态计算出来的。

String 是不可变的。当你认为你在修改一个 string 时,你实际上是在创建一个新的 string 对象。我们经常忘记这一点,我们会想写……

String str = ”foofoo”;

str.replace(“foo”, “FOO”); 

…而我们实际上应该写

str = str.replace(“foo”, ”FOO”); 

当然,这样做会以在进行一些密集的 string 计算时创建多个 string 对象为代价。在这种情况下,你需要使用 StringBuilder 类。

对于 Scala 这样的某些现代语言,倾向于使用不可变性。默认的集合类是不可变的。

2. String 是 JVM 中最受欢迎的类

了解项目中使用的最多的类型很有趣,因为这些类型必须设计、实现和测试良好。它们中的任何更改都可能影响整个项目。

让我们使用 JArchitect 分析 JVM,并查找最受欢迎的类型。为此,我们可以使用两个指标:

类型传入耦合(TypeCa):一个特定类被使用的类型数量。这是根据此指标所有受欢迎类型的计算结果:

不出所料,Object 是使用最多的,但还有另一个有趣的指标可以用来查找受欢迎的类型:TypeRank

TypeRank 值是通过在类型依赖图上应用 Google PageRank 算法计算得出的。应用 0.15 的同位度中心值,使 TypeRank 的平均值为 1

具有高 TypeRank 的类型应该更仔细地测试,因为这些类型中的错误可能会更具灾难性。

这是根据 TypeRank 指标所有受欢迎类型的计算结果:

使用更准确的 TypeRank 指标来查找受欢迎的类型,String 在 JVM 代码库中比 Object 更受欢迎。

3. String 是稳定的

建议最受欢迎的代码元素必须是稳定的,因为任何更改都可能影响许多其他类型。让我们看看 String 是否如此,为此我们可以比较 2004 年 9 月 30 日发布的 JVM 5 和 2013 年 10 月 15 日发布的 JVM 7 的最后一个更新。

添加的方法

这是 9 年间添加的方法:

仅添加了 3 个构造函数和 5 个方法。

已弃用的方法

自 2004 年以来,仅有一个构造函数被弃用。

4. String 设计用于优化内存使用

String 在 Java 中受到特殊处理,因为它们在程序中经常使用。因此,效率(计算和存储方面)至关重要。

有两种构造 string 的方法:通过赋值 string 字面量进行隐式构造,或通过 new 运算符和构造函数显式创建 String 对象。例如:

String s1 = “Hello”; // String literal 
String s2 = new String(“Hello”); // String object 

Java 提供了一种特殊的机制来保存 String 字面量——在一个所谓的 string 公共池中。如果两个 string 字面量的内容相同,它们将在公共池中共享相同的存储。这种方法是为了节省常用 string 的存储空间。另一方面,通过 new 运算符和构造函数创建的 String 对象被保存在堆中。堆中的每个 String 对象都有自己的存储,就像任何其他对象一样。即使两个 String 对象的内容相同,堆中也没有存储共享。

有关 String 池机制的更多详细信息,您可以参考这篇 文章

5. String 设计用于优化 CPU 使用

我们可以列举两种 CPU 优化情况:

  • 尽可能执行最少量的代码
    toLowerCase(Locale locale) 方法为例,以下是其实现的前几行:
    public String toLowerCase(Locale locale) {
    if (locale == null) {
        throw new NullPointerException();
    }
    ……

    locale 在方法体早期被使用,如果指针为 null,JVM 会抛出 NullPointerException,并且显式抛出此异常的情况非常少见。然而,String 中的许多方法都使用这种技术来避免在异常情况下执行更多代码,从而可以最大限度地减少 CPU 使用。

  • isEmpty 而不是 equals(“”): isEmpty 是在 Java 6 中引入的,它比 equals(“”) 更快,因为它只是将 string 的长度——存储在 String 对象中——与零进行比较。
    public boolean isEmpty() {
    return 0 == count;
    } 
© . All rights reserved.