【问题标题】:how does String.equals() workString.equals() 如何工作
【发布时间】:2012-09-30 12:45:14
【问题描述】:

我一直在尝试了解一些 API 方法的工作原理

下面是java.lang.String类的equals方法的sn-p

有人能告诉我代码是如何比较两个字符串的吗? 我明白计数的意义,但偏移意味着什么。这些变量如何获得值?

就像我创建一个字符串一样。这些是如何初始化的。

详细的逐行描述以及实例变量、值、计数、偏移量等初始化的方式和时间??

 public boolean equals(Object anObject) {
  1014           if (this == anObject) {
  1015               return true;
  1016           }
  1017           if (anObject instanceof String) {
  1018               String anotherString = (String)anObject;
  1019               int n = count;
  1020               if (n == anotherString.count) {
  1021                   char v1[] = value;
  1022                   char v2[] = anotherString.value;
  1023                   int i = offset;
  1024                   int j = anotherString.offset;
  1025                   while (n-- != 0) {
  1026                       if (v1[i++] != v2[j++])
  1027                           return false;
  1028                   }
  1029                   return true;
  1030               }
  1031           }
  1032           return false;
  1033       }

【问题讨论】:

    标签: java string equals


    【解决方案1】:

    逻辑上

    while (n-- != 0) {
    if (v1[i++] != v2[j++])
        return false;
    }
    

    相同
    for (int i = 0; i < n; i++) {
        if (v1[i] != v2[j])
            return false;
        }
    }
    

    我不确定为什么 JVM 设计者会这样做。也许使用 while 循环比使用 for 循环可以提高性能。它在我看来很像 C,所以也许写这篇文章的人有 c 的背景。

    Offset 用于定位字符串在 char 数组中的起始位置。内部字符串存储为 char 数组。这是value

    if (v1[i++] != v2[j++])
        return false;
    

    检查字符串底层 char 数组中的字符。

    一行一行

    如果引用指向同一个对象,则必须等号

    1014           if (this == anObject) {
    1015               return true;
    1016           }
    

    如果对象是字符串,则检查它们是否相等

    1017           if (anObject instanceof String) {
    

    将传入的参数转换为字符串。

    1018               String anotherString = (String)anObject;
    

    记住this.string的长度

    1019               int n = count;
    

    如果两个字符串的长度匹配

    1020               if (n == anotherString.count) {
    

    得到一个字符数组(值就是这个数组)

    1021                   char v1[] = value;
    1022                   char v2[] = anotherString.value;
    

    找出这个数组中字符串的开始位置

    1023                   int i = offset;
    1024                   int j = anotherString.offset;
    

    遍历 char 数组。如果值不同则返回false

    1025                   while (n-- != 0) {
    1026                       if (v1[i++] != v2[j++])
    1027                           return false;
    1028                   }
    

    其他的都必须是真的

    1029                   return true;
    1030               }
    1031           }
    

    如果不是String类型,则它们不能相等

    1032           return false;
    1033       }
    

    要了解偏移量和值,请查看 String 类

    /** The value is used for character storage. */
    private final char value[];
    
    /** The offset is the first index of the storage that is used. */
    private final int offset;
    
    /** The count is the number of characters in the String. */
    private final int count;
    

    构造函数初始化这些变量。默认构造函数代码如下。对于其他构造函数,您应该会看到类似的内容。

    /**
      * Initializes a newly created {@code String} object so that it represents
      * an empty character sequence.  Note that use of this constructor is
      * unnecessary since Strings are immutable.
      */
     public String() {
        this.offset = 0;
        this.count = 0;
        this.value = new char[0];
     }
    

    This 是一个很好的链接查看

    【讨论】:

    • 太干净了。。谢谢。
    • 还有一个问题,我找不到初始化这些实例变量的构造函数。有吗?这是由 JVM 处理的吗?
    • 刚刚用默认的 ctor 更新了这些被初始化的字符串的答案
    • 谢谢伙计。很好的答案。
    【解决方案2】:

    您可能知道 Java 中的字符串处理是一种特殊情况,大多数情况下,字符串是从字符串池中分配的,因此对于 char 数组"I am Learning Java",可能会出现一个字符串引用点到"I am Learning Java",则偏移量为0,其他字符串可能指向"am",因此偏移量为2由于一些本机代码处理其初始化,所以我认为在该过程中设置了偏移量。(在从字符串池共享内存期间)

    从代码中也可以看出

     public String(String original) {
             int size = original.count;
            char[] originalValue = original.value;
            char[] v;
            if (originalValue.length > size) {
                // The array representing the String is bigger than the new
              // String itself.  Perhaps this constructor is being called
                // in order to trim the baggage, so make a copy of the array.
               int off = original.offset;
              v = Arrays.copyOfRange(originalValue, off, off+size);
            } else {
               // The array representing the String is the same
              // size as the String, so no point in making a copy.
                v = originalValue;
           }
          this.offset = 0;
           this.count = size;
           this.value = v;
        }
    

    当从旧字符串创建新字符串时,旧字符串(在这种情况下为原始字符串)可能来自字符串池,这就是为什么首先获取偏移量然后复制整个数组以分配新字符串的原因内存(新字符串不从字符串池共享内存)

    另外你应该记住 String 是一个派生类型并且字符串总是存储在一个字符数组中,所以我们需要一个偏移量来确定字符串在字符数组中的起始位置。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-05-05
      • 1970-01-01
      • 2016-02-07
      • 2020-10-30
      • 2012-12-07
      • 1970-01-01
      相关资源
      最近更新 更多