Findbugs تحذير:يساوي الأسلوب لا ينبغي أن نفترض أي شيء عن نوع من الحجة
سؤال
عند تشغيل FindBugs على المشروع ، لدي بعض حالات الخطأ المذكورة أعلاه.
وهي بلدي تجاوز إصدارات يساوي يلقي RHS الكائن في نفس نوع الكائن الذي تجاوز نسخة محددة.
ولكن لست متأكدا ما إذا كان أفضل تصميم ممكن ، منذ AFAIK جافا لا تسمح الفرق في طريقة المعلمات ، لذلك فإنه ليس من الممكن تحديد أي نوع يساوي المعلمة.
أفعل شيء خاطئ جدا ، أو هو FindBugs حريصة جدا?
طريقة مختلفة للتعبير عن هذا السؤال هو:ما هو السلوك الصحيح إذا كان الكائن الذي تم تمريره إلى تساوي ليس من نفس النوع كما LHS:هذا كاذب ، أو ينبغي أن يكون هناك استثناء ؟
على سبيل المثال:
public boolean equals(Object rhs)
{
MyType rhsMyType = (MyType)rhs; // Should throw exception
if(this.field1().equals(rhsMyType.field1())... // Or whatever
}
المحلول
عادة عند تنفيذ يساوي يمكنك التحقق لمعرفة ما إذا كانت فئة من حجة تساوي (أو متوافقة) إلى تنفيذ الطبقة قبل صب عليه.شيء من هذا القبيل:
if (getClass() != obj.getClass())
return false;
MyObj myObj = (MyObj) obj;
بهذه الطريقة سوف تمنع FindBugs تحذير.
ملاحظة جانبية إلى عنوان التعليق:
ويزعم بعض الناس أن استخدام instanceof
بدلا من getClass
للتحقق من نوع الأمان.هناك نقاش كبير و هذا ما كنت أحاول أن لا ندخل في حين لاحظت أن يمكنك التحقق من الدرجة المساواة أو التوافق, ولكن أعتقد أنني لا أستطيع الهروب منه.يتلخص هذا - إذا كنت تستخدم instanceof
يمكنك دعم المساواة بين مثيلات فئة الحالات من فئة فرعية ، ولكن هل خطر كسر متماثل عقد equals
.عموما أنصح بعدم استخدام instanceof
إلا إذا كنت تعرف كنت في حاجة إليها و أنت تعرف ما تقومون به.لمزيد من المعلومات انظر:
- http://www.artima.com/weblogs/viewpost.jsp?thread=4744
- ما هي القضايا التي يجب أخذها في الاعتبار عند تجاوز يساوي hashCode في جافا ؟
- http://www.macchiato.com/columns/Durable5.html
- http://commons.apache.org/lang/api-release/org/apache/commons/lang/builder/EqualsBuilder.html (أباتشي المشتركة تنفيذ مساعد)
- http://www.eclipsezone.com/eclipse/forums/t92613.rhtml (الكسوف الافتراضي يساوي مولد)
- NetBeans مولد يستخدم أيضا getClass()
نصائح أخرى
وكنت تفعل ربما شيء من هذا القبيل:
public class Foo {
// some code
public void equals(Object o) {
Foo other = (Foo) o;
// the real equals code
}
}
في هذا المثال كنت على افتراض شيئا عن حجة يساوي (): أنت على افتراض انها من نوع فو. هذا يحتاج لا يكون الأمر كذلك! يمكنك أيضا الحصول على سلسلة (في هذه الحالة يجب عليك تقريبا بالتأكيد سيعود كاذبة).
وهكذا التعليمات البرمجية الخاصة بك ينبغي أن تبدو هذه:
public void equals(Object o) {
if (!(o instanceof Foo)) {
return false;
}
Foo other = (Foo) o;
// the real equals code
}
و(أو استخدام getClass() != o.getClass()
أكثر صرامة من قبل ديف L المذكورة.
ويمكنك أيضا أن ننظر في الأمر بهذه الطريقة:
Integer i = new Integer(42);
String s = "fourtytwo";
boolean b = i.equals(s);
هل هناك أي سبب أن هذا الرمز يجب رمي ClassCastException
بدلا من الانتهاء بشكل طبيعي ووضع b
إلى false
؟
ورمي ClassCastException
كرد على .equals()
لن يكون من المعقول. لأنه حتى لو كان هو سؤال غبي ( "وبالطبع سلسلة أبدا تساوي فو!") ما زال ساري المفعول واحد مع إجابة ما يرام تماما ( "لا" == false
).
وأنصح تجاهل findbugs قال التحذير. في الواقع، إذا كان يتم استدعاء مع كائن من فئة غير متوقعة قدم المساواة، فإنه يكاد يكون من المؤكد أن علة، وتريد أن تفشل بسرعة على البق.
وعلى سبيل المثال، إذا كان لديك "ملفات ArrayList"، وندعو files.contains ( "على Myfile.txt")، فإنه سيكون من الرائع إذا كنت حصلت على ClassCastException. بدلا من ذلك، جافا يعود فقط كاذبة، وأنه من المرجح يستغرق وقتا طويلا حتى تكتشف هذا الخطأ.
وأبدأ متساوين بلدي (كائن) تطبيقات مثل هذا:
if ((object == null) || !(object instaceof ThisClass)) {
return false;
}
وهذا من شأنه أيضا منع التحذير FindBugs ولكن لن يعود false
تلقائيا عندما يتم تسليم فئة فرعية من ThisClass في. يمكن النظر أيضا على قدم المساواة، وخاصة إذا لم يتم تجاوز أسلوب equals(Object)
لها.