إنشاء تجزئة من السلسلة و int
-
06-07-2019 - |
سؤال
أتذكر أن Eclipse والفكرة لديهما هذا القالب لإنشاء رمز تجزئة الكائن تلقائيًا بناءً على سماته.
إحدى الاستراتيجيات في حالة استخدام رقم وسلسلة هي شيء من هذا القبيل.
return stringValue.hashCode() + intValue * 32;
أوو شيء من هذا القبيل.
ليس لدي أي كسوف أو فكرة في متناول اليد وأرغب في إنشاء مثل هذه الوظيفة.
يحرر
بناءً على الإجابات أقوم بإنشاء هذا الفصل المصغر
class StringInt {
private final String s;
private final int i;
static StringInt valueOf( String string , int value ) {
return new StringInt( string, value );
}
private StringInt( String string, int value ) {
this.s = string;
this.i = value;
}
public boolean equals( Object o ) {
if( o != null && o instanceof StringInt ){
StringInt other = ( StringInt ) o;
return this.s == other.s && this.i == other.i;
}
return false;
}
public int hashCode() {
return s != null ? s.hashCode() * 37 + i : i;
}
}
سيتم استخدام هذه الفئة كمفتاح لخريطة ذاكرة كبيرة (> 10 آلاف عنصر) ولا أريد تكرارها في كل مرة لمعرفة ما إذا كانت السلسلة وint متماثلين.
شكرًا لك.
ملاحظة..ربما ينبغي أن تكون أسماء StringIntKey.mmh.
المحلول
استخدم Apache Commons HashcodeBuilder:
public int hashCode() {
new HashCodeBuilder(17, 37).
append(myString).
append(myInt);
}
الرابط هنا:http://commons.apache.org/lang/api-2.3/org/apache/commons/lang/builder/HashCodeBuilder.html
و هنا:
http://www.koders.com/java/fidCE4E86F23847AE93909CE105394B668DDB0F491A.aspx
نصائح أخرى
يقوم Eclipse دائمًا بنفس وظيفة التجزئة تقريبًا، فيما يلي مثال لفئة تحتوي على حقلين وسلسلة كحقول
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + this.interger;
result = prime * result + ((this.string == null) ? 0 : this.string.hashCode());
return result;
}
إنهم دائمًا يختارون 31 كرقم أولي، ثم يقومون بالمضاعفة من خلال إنشاء وظائف التجزئة أو القيمة إذا كانت أولية.لن يكون من الصعب إنشاء شيء كهذا كطريقة.
public int hashCode(Object ... things) {
final int prime = 31;
int result = 1;
for(Object thing : things) {
result = prime * result + thing.hashCode();
}
return result;
}
أو، إذا كنت لا ترغب في إضافة مكتبة أخرى، فقم بإجراء ما يلي:
public int hashCode() {
StringBuilder builder = new StringBuilder();
builder.append(myString);
builder.append(myInteger);
return builder.toString().hashCode();
}
من المحتمل أن يتم استدعاء طريقة رمز التجزئة عدة مرات، وبالتالي فهي تستحق التحسين.إذا كانت العملية الحسابية معقدة، فكر في حفظ قيمة التجزئة.وتجنب أيضًا القيام بالأشياء التي تتطلب حسابات أكثر من اللازم.(على سبيل المثال، يقضي حل StringBuilder معظم وقته في إنشاء سلسلة مؤقتة.)
الشيء الآخر الذي أريد الإشارة إليه هو أن جودة التجزئة مهمة.تريد تجنب أي خوارزمية رمز التجزئة التي تحدد الكثير من المفاتيح الشائعة.إذا حدث ذلك، فقد لا يكون البحث في جدول التجزئة هو O(1).(في أسوأ الحالات سيكون O(N) ...أي.يعادل البحث الخطي!).فيما يلي مثال على وظيفة تجزئة سيئة:
int hashcode() {
int hash = 1;
for (int val : this.values) {
hash = hash * value;
}
return hash;
}
النظر في ما يحدث إذا كان عنصر من this.values
هو صفر ...
تستطيع ايضا استخذام Objects
فئة من java.util.Objects
حزمة للحصول بسرعة على رمز التجزئة.
@Override
public int hashCode() {
return Objects.hash(this.string, this.integerValue, this.otherDataTypes);
}
بالإضافة إلى التعديل الأخير الذي أجريته، إذا كانت سرعة الاسترداد أكثر أهمية من مخاوف التخزين، فيمكنك حساب رمز التجزئة مسبقًا وتخزينه عند إنشاء رمز التجزئة الخاص بك StringInt
فصل.هذا آمن لأنك قمت بوضع علامة على String
و int
الحقول كما final
, ، ونظراً لذلك أيضاً String
غير قابل للتغيير.
أيضًا، يمكنك تحسين موقعك equals
الطريقة عن طريق التحقق من أن الكائن الذي تتم مقارنته == this
قبل إجراء المقارنة الكاملة.أود أيضًا أن أوصي بإجراء المقارنة الأرخص على أساس int أولاً قبل مقارنة حقول السلسلة.
اقتراح أخير آخر:يمكنك تغيير الخاص بك valueOf(String, int)
طريقة لبناء إما StringInt
أو قم بإرجاع مثيل تم إنشاؤه مسبقًا إذا كان موجودًا بالفعل بنفس الشيء String
والقيم كثافة العمليات.وهذا يجعل البناء أكثر تكلفة ولكن المقارنات رخيصة جدًا حيث يمكنك المقارنة StringInt
باستخدام "==" مع العلم أنه لا يوجد اثنان StringInt
سيتم إنشاء s بنفس الشيء String
و int
قيمة.