Groovy"=="陷阱
Groovy與Java同是運行在JVM之上,大多數時候可以把Groovy當做Java來用,但是也存在著陷阱。例如,想重寫對象的equals方法,需如下步驟:
1. 使用==判斷參數和自身對象引用是否相等,如果相等直接返回true(此判斷可以提高性能);
2. 使用instanceof判斷參數類型是否正確,如果不正確直接返回false
3. 將參數轉換為正確的類型,步驟2已確保了類型
4. 檢查參數與自身對象關鍵字段是否相等
1)基本類型(除float和double)運用==比較
2)對象引用,遞歸調用equals方法
3)浮點型float,調用Float.floatToIntBits轉化為int,用==比較
4)浮點型double,調用Double.doubleToLongBits轉化為long,用==比較
遵循以上步驟,重寫簡單Money類的equals方法:
1 public boolean equals(Object another) {
2 if (another == this) return true
3 if (another instanceof Money) {
4 Money anotherMoney = (Money) another
5 return amount == anotherMoney.amount
6 }
7 return false
8 }
2 if (another == this) return true
3 if (another instanceof Money) {
4 Money anotherMoney = (Money) another
5 return amount == anotherMoney.amount
6 }
7 return false
8 }
調用
1 new Money(10).equals(new Money(10))
得到異常
java.lang.StackOverflowError
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:86)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:234)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1049)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:880)
at org.codehaus.groovy.runtime.InvokerHelper.invokePogoMethod(InvokerHelper.java:746)
at org.codehaus.groovy.runtime.InvokerHelper.invokeMethod(InvokerHelper.java:729)
at org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation.compareEqual(DefaultTypeTransformation.java:620)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.compareEqual(ScriptBytecodeAdapter.java:680)
at Money.equals(Money.groovy:10)
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:86)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:234)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1049)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:880)
at org.codehaus.groovy.runtime.InvokerHelper.invokePogoMethod(InvokerHelper.java:746)
at org.codehaus.groovy.runtime.InvokerHelper.invokeMethod(InvokerHelper.java:729)
at org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation.compareEqual(DefaultTypeTransformation.java:620)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.compareEqual(ScriptBytecodeAdapter.java:680)
at Money.equals(Money.groovy:10)
最終發現罪魁禍首是“==”,Groovy中對于所有類型(基本類型和引用)調用“==”和“equals()”方法相同,當執行“another == this”時,解釋器會調用“another.equals(this)”造成死循環。
如果想比較引用相等,Groovy提供了is方法,即
1 public boolean equals(Object another) {
2 if (another.is(this)) return true
3 if (another instanceof Money) {
4 Money anotherMoney = (Money) another
5 return amount == anotherMoney.amount
6 }
7 return false
8 }
2 if (another.is(this)) return true
3 if (another instanceof Money) {
4 Money anotherMoney = (Money) another
5 return amount == anotherMoney.amount
6 }
7 return false
8 }