String#equals和String#contentEquals方法之间的区别
String#equals
方法和String#contentEquals
方法有什么区别?
String#equals()
不仅比较String的内容,还检查另一个对象是否也是String
一个实例。 String#contentEquals()
只比较内容(字符序列),并不检查另一个对象是否也是String
一个实例。 它可以是任何东西,只要它是一个CharSequence
的实现,它涵盖了String
, StringBuilder
, StringBuffer
, CharBuffer
等等。
简单地说: String.contentEquals()
是String.equals()
更聪明的兄弟,因为它可以比String.equals()
更加自由。
有一些原因为什么有一个单独的String.contentEquals()
方法。 我认为最重要的原因是:
-
equals
方法必须是自反的。 这意味着:x.equals(y) == y.equals(x)
。 这意味着aString.equals(aStringBuffer)
必须与aStringBuffer.equals(aString)
相同。 这需要Java API开发人员在StringBuffer,StringBuilder和CharSequence的equals()
方法中为Strings做一些特殊的实现。 这将是一个烂摊子。
所以,这就是当String.contentEquals
进来。这是一个独立的方法 ,不必遵循 Object.equals
严格的要求和规则 。 这样可以更自由地实现“相等内容”的意义。 例如,这允许您在StringBuffer和String之间进行智能比较。
并说出究竟有什么不同之处:
-
String.contentEquals()
可以比较String
,StringBuilder
,StringBuffer
,CharSequence
及其所有派生类的内容。 如果参数的types是String,那么String.equals()
会被执行。 -
String.equals()
只比较String对象。 所有其他对象types被认为是不相等的。 -
String.contentEquals()
可以智能地比较StringBuffer
和StringBuilder
。 它不会调用繁重的toString()
方法,将整个内容复制到一个新的String对象中。 相反,它与底层的char[]
数组进行比较,这非常棒。
这个答案已经被dbw发布了,但是他被删除了,但是他在比较执行时间,抛出了什么exception,
如果你看看源代码String#equals和String#contentEquals,那么显然String#contentEquals有两个重载方法,一个是StringBuilder
和其他CharSequence
。
他们之间的区别,
- 如果提供的参数为
null
则String#contentEquals
将抛出NPE,但String#equals
将返回false
-
String#equals
仅当提供的参数是instance of String
时才比较内容instance of String
否则在所有其他情况下将返回false
,但另一方面,String#contentEquals
检查实现接口CharSequence
的所有对象的CharSequence
。 -
您还可以调整代码,以便
String#contentEquals
通过覆盖传递参数的equals
方法返回错误的结果或结果,但不能使用String#equals
调整。
只要s
包含任何长度为3个字符的string
, 下面的代码将始终生成true
String s= new String("abc");// "abc"; System.out.println(s.contentEquals(new CharSequence() { @Override public CharSequence subSequence(int arg0, int arg1) { // TODO Auto-generated method stub return null; } @Override public int length() { // TODO Auto-generated method stub return 0; } @Override public char charAt(int arg0) { // TODO Auto-generated method stub return 0; } @Override public boolean equals(Object obj) { return true; } }));
-
String#contentEquals
会比较慢,String#Equals
在提供的参数是instance of String
并且两个String
的长度相同但内容不相等的情况下。
如果string是String s = "madam"
和String argPassed = "madan"
那么与s.equals(argPassed)
相比,在这种情况下s.contentEquals(argPassed)
将执行几乎两倍的执行时间。 -
如果两个string的内容长度不相同,那么函数
String#contentEquals
在几乎所有可能的情况下都会有更好的性能,然后String#Equals
。
还有一点要补充他的答案
- 一个
String
对象的String#contentEquals
也将与StringBuilder
内容进行比较,并提供相应的结果,而String#Equals
将返回false
contentEquals(CharSequence cs)
:
- 让您检查给定的string值与接口
java.lang.CharacterSequence
(例如,CharBuffer
,Segment
,String
,StringBuffer
,StringBuilder
)的任何实现实例的相等性。
equals(Object anObject)
:
- 让您检查给定的string值与任何只有
java.lang.String
types的实例的相等性
RTFC 🙂
由于阅读源代码是了解它的最好方法,所以我共享这两个方法的实现(从jdk 1.7.0_45开始)
public boolean contentEquals(CharSequence cs) { if (value.length != cs.length()) return false; // Argument is a StringBuffer, StringBuilder if (cs instanceof AbstractStringBuilder) { char v1[] = value; char v2[] = ((AbstractStringBuilder) cs).getValue(); int i = 0; int n = value.length; while (n-- != 0) { if (v1[i] != v2[i]) return false; i++; } return true; } // Argument is a String if (cs.equals(this)) return true; // Argument is a generic CharSequence char v1[] = value; int i = 0; int n = value.length; while (n-- != 0) { if (v1[i] != cs.charAt(i)) return false; i++; } return true; }
public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String anotherString = (String) anObject; int n = value.length; if (n == anotherString.value.length) { char v1[] = value; char v2[] = anotherString.value; int i = 0; while (n-- != 0) { if (v1[i] != v2[i]) return false; i++; } return true; } } return false; }
还有另一种String#contentEquals()的方法:
public boolean contentEquals(StringBuffer sb) { synchronized(sb) { return contentEquals((CharSequence)sb); } }
-
String
类equals(Object o)
方法只做String
比较。 但contentEquals(CharSequence cs)
检查类是否扩展了AbstractStringBuilder
即StringBuffer
,StringBuilder
和String
类(它们都是CharSequence
types)。String str = "stackoverflow"; StringBuilder builder = new StringBuilder(str); System.out.println(str.equals(builder)); System.out.println(str.contentEquals(builder));
输出:
false true
第一个stmt的输出是false
因为builder
不是String
types,所以equals()
返回false
但是contentEquals()
检查所有types的内容,比如StringBuilder
, StringBuffer
, String
,因为内容是相同的。
- 如果提供的参数为
null
contentEquals
将抛出NullPointerException
,但equals()
将返回false,因为equals()会检查instanceOf(if (anObject instance of String)
),如果参数为null
,则返回false。
equals()
和contentEquals()
是String
类中的两个方法,用于比较两个strings
和string
与StringBuffer
。
contentEquals()
的参数是StringBuffer
和String(charSequence)
。 equals()
用于比较两个strings
, contentEquals()
用于比较String
和StringBuffer
的内容。
方法contentEquals
和equals
是
public boolean contentEquals(java.lang.StringBuffer); public boolean contentEquals(java.lang.CharSequence); public boolean equals(Object o)
这是描述两种方法的代码
public class compareString { public static void main(String[] args) { String str1 = "hello"; String str2 = "hello"; StringBuffer sb1 = new StringBuffer("hello"); StringBuffer sb2 = new StringBuffer("world"); boolean result1 = str1.equals(str2); // works nice and returns true System.out.println(" str1.equals(str2) - "+ result1); boolean result2 = str1.equals(sb1); // works nice and returns false System.out.println(" str1.equals(sb1) - "+ result2); boolean result3 = str1.contentEquals(sb1); // works nice and returns true System.out.println(" str1.contentEquals(sb1) - "+ result3); boolean result4 = str1.contentEquals(sb2); // works nice and returns false System.out.println(" str1.contentEquals(sb2) - "+ result4); boolean result5 = str1.contentEquals(str2); // works nice and returns true System.out.println(" str1.contentEquals(str2) - "+ result5); } }
输出:
str1.equals(str2) - true str1.equals(sb1) - false str1.contentEquals(sb1) - true str1.contentEquals(sb2) - false str1.contentEquals(str2) - true
contentEquals()
方法检查的内容是一个String
, StringBuffer
等之间的某种字符序列。
String#equals将Object作为参数,并检查它是否是String对象的实例。 如果参数对象是string对象,则它逐字符地比较内容。 如果两个string对象的内容相同,则返回true。
String#contentEquals将CharSequence接口作为参数。 CharSequence可以通过2种方式实现 – 通过使用i)String类或(ii)AbstractStringBuilder(StringBuffer的父类,StringBuilder)
在contentEquals()中比较任何对象实例检查前的长度。 如果长度相同,则检查参数对象是否是AbstractStringBuilder的实例。 如果是这样的话(即StringBuffer或者StringBuilder),那么内容将被逐个检查。 如果参数是String对象的一个实例,则String#等于从String#contentEquals中调用。
所以总之,
如果参数是String对象,则String#equals会逐个比较内容字符。 和String#contentEquals比较case参数对象实现CharSequence接口的内容。
如果我们比较两个相同长度的string内容作为String#contentEquals在内部调用String#equals为String对象,则String#contentEquals会更慢。
如果我们尝试比较具有不同内容长度的对象(比如“abc”和“abcd”),那么String#contentEquals比String#equals快。 因为在任何对象实例检查之前比较长度。
顺便说一句,不同的历史原因是String最初没有超类,所以String.equals()接受一个string作为它的参数。 当CharSequence作为String的超类引入时,它需要一个在所有CharSequence实现中工作的自己的等式testing,并且不会和String已经使用的equals()相冲突…所以我们得到了CharSequence.contentEquals( ),它由Stringinheritance。
如果CharSequence已经存在于Java 1.0中,我们只会使用CharSequence.equals()和String来实现它。
啊,不断发展的语言的乐趣…
最大的区别是equals()只能用于另一个string,而contentEquals()可以用于任何CharacterSequence(如StringBuilder)。
public class Test{ public static void main(String[] args) { String str1 = "Hello"; String str2 = new String("Hello"); StringBuilder str3 = new StringBuilder(str1); System.out.println("str1.equals(str2): " + (str1.equals(str2))); System.out.println("str1.contentEquals(str2): " + (str1.contentEquals(str2))); System.out.println("str1.equals(str3): " + (str1.equals(str3))); System.out.println("str1.contentEquals(str3): " + (str1.contentEquals(str3))); }}
将输出为
str1.equals(str2):true
str1.contentEquals(str2):true
str1.equals(str3):false
str1.contentEquals(str3):true