Java 为什么';t String.equals检查char[]值是否相等?
我正在查看Java 为什么';t String.equals检查char[]值是否相等?,java,string,performance,micro-optimization,Java,String,Performance,Micro Optimization,我正在查看java.lang.String的源代码,注意到没有检查支持每个字符串的char[]是否是同一个对象。这不是比以前更好吗 此重写版本中包含的假定改进: public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String anoth
java.lang.String
的源代码,注意到没有检查支持每个字符串的char[]
是否是同一个对象。这不是比以前更好吗
此重写版本中包含的假定改进:
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = count;
if (n == anotherString.count) {
char v1[] = value;
char v2[] = anotherString.value;
int i = offset;
int j = anotherString.offset;
/** Begin Optimization **/
if(v1==v2 && i==j){
return true;
}
/** End Optimization **/
while (n-- != 0) {
if (v1[i++] != v2[j++])
return false;
}
return true;
}
}
return false;
}
我相信,如果这两个字符串是使用String.substring
获得的,甚至可能是内部字符串,那么这将提高性能
有人知道他们选择不这样做是有原因的吗
更新:对于可能不太了解的任何人来说,除了字符串池之外,在其他情况下,两个字符串对象可以具有相同的char[]值、int offset和int count
考虑以下代码:
String x = "I am a String, yo!";
String y = x.split(" ")[3];
String z = x.substring(7,14);
你会遇到这样的情况:
显然,在Java7U6中,字符串的值共享特性已经被取消,以满足一些基准测试。因此,如果您花时间使用String.substring()而不是字符串串联来让代码在适当的时间内运行(或根本不运行),您就完蛋了。在Java 7(),
substring()
不再对返回的字符串使用相同的后备数组。您仍然需要检查每个字符。基本上,String
backingchar[]
永远不会被共享,所以您不能
this.value == other.value
您需要检查char[]
、偏移量
和计数(字符串长度)。由于char[]
仅从String
类中创建,因此这三个值相等的唯一方法是String
从自身创建一个doppelgänger。您可以让它这样做(例如,新字符串(“为什么?”)
),但这不是常见的用例
我甚至不确定它是否能加快速度。绝大多数情况下,支票都会失败,这意味着它做额外的工作没有任何好处。这可能会被分支预测所抵消,但在这种情况下,检查通过的次数很少,它将使分支预测所做的猜测无效,这实际上可能会减慢速度。换言之,如果JVM/CPU试图针对常见情况进行优化,您通常不会获得任何好处,而在极少数情况下(这正是您试图优化的情况),您实际上会伤害自己。如果它不尝试优化这种常见的情况,那么在大多数比较中,你会为了一组相当罕见的比较而伤害自己<代码>
我不明白这个问题。
char[]
是字符串的内部成员。如果两个字符串引用相同(应该是因为您应该使用intern字符串),则char[]将是相同的。
但是对于不同的实例,为什么希望char[]
是相同的引用?字符串是不可变的,两个不同的字符串对象不可能共享对同一备份数组的引用。
此外,即使对子字符串使用此条件检查也没有意义。
我不知道其中一个答案中提到的Java 7中的变化,但在这种情况下检查备份数组的相等性是错误的。
字符串对象不仅是背景数组,而且是其当前偏移量、长度等。
因此,作为子字符串的结果,2个字符串对象可能由相同的字符数组支持,但很可能包含不同的(子)-字符串作为内容-相同字符数组中的不同偏移量对支持字符数组进行这样的检查很可能是多余的,并且不是必需的
有两种情况下,支持字符数组对象可以是相同的对象(因为其他点子字符串方法总是创建新的支持字符数组)
定义字符串文字
String a = "Hello";
a.equals("Hello"); // Backing array of "Hello" string literal
// will be same as that of variable a
在本例中,equals方法将在检查backing char数组之前确定下一行的字符串是否相等
if (this == anObject) { // From String.equals method
return true;
}
使用字符串复制构造函数创建另一个字符串对象
请注意,下面的代码块没有实际价值,永远无法在实际代码中完成
String a = "Hello;
String b = new String(a);
a.equals(b);
因此,与其做额外的检查来确定字符数组是否相同,不如假设字符串对象不同,它们总是不同的。这样做的方法是比较每个字符。可能没有意义,因为总是使用clone()
arrays在Java 7之前的极少数情况下,它可能会提高性能,例如foo.substring(i,j).equals(foo.substring(i,j))
——但是当字符串数组不相等时,它也会对更常见的情况进行额外检查,这似乎平均花费的时间比节省的时间要多。参见例如…@SotiriosDelimanolis我不是在问他们是否平等;我在问它们是否是同一个对象。@LouisWasserman我想说,这个优化和他的示例之间最重要的区别是,这将通过运行多个O(1)行代码(1或2个比较,取决于我们有多幸运)来防止O(n)操作;虽然他的示例只是防止在n=0或n=1(本质上)的情况下进行O(n)操作。那么,您的意思是,在Java 7中,它创建了后台数组的副本,而不是使用相同的备份数组?但是,您可以将该代码替换为Java.util.array.equals(value,other.value)
@gparyani Yes,调用的构造函数使用数组。copyOfRange
@gparyani equals方法非常等效。我有点怀疑;您链接到的那篇文章没有引用任何源代码,并且查看,它肯定会一如既往地运行(shared char[])。count已经被检查为围绕我的代码的if()块的条件。如果某些字符串是由相同字符串的子字符串生成的,那么它们将具有相同的char[],并且可能具有