জাভা স্ট্রিংয়ে হ্যাশকোড () এর ধারাবাহিকতা


134

জাভা স্ট্রিংয়ের হ্যাশকোড মানটি ( স্ট্রিং.হ্যাশকোড () ) হিসাবে গণনা করা হয় :

s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]

নিম্নলিখিত পরিস্থিতি মিথ্যা হিসাবে মূল্যায়ন করবে কোন পরিস্থিতিতে (জেভিএম সংস্করণ, বিক্রেতা, ইত্যাদি বলে) আছে কি?

boolean expression = "This is a Java string".hashCode() == 586653468

আপডেট # 1: যদি আপনি দাবি করেন যে উত্তরটি "হ্যাঁ, এমন পরিস্থিতি রয়েছে" - তবে দয়া করে কখন এটি "জাভা স্ট্রিং" এর একটি নমনীয় উদাহরণ দিন। যতটুকু সম্ভব.

আপডেট # 2: আমরা সকলেই জানি যে হ্যাশকোড () এর প্রয়োগের বিবরণগুলির উপর নির্ভর করা সাধারণভাবে খারাপ। তবে, আমি স্ট্রিং.হ্যাশকোড () সম্পর্কে বিশেষভাবে কথা বলছি - সুতরাং অনুগ্রহ করে উত্তরটি স্ট্রিং.হ্যাশকোডে নিবদ্ধ রাখুন ()। অবজেক্ট.হ্যাশকোড () এই প্রশ্নের প্রসঙ্গে সম্পূর্ণ অপ্রাসঙ্গিক।


2
আপনার আসলে এই কার্যকারিতাটি দরকার? আপনার সঠিক মূল্য কেন দরকার?
ব্রায়ান অ্যাগনিউ

26
@ ব্রায়ান: আমি স্ট্রিং.হ্যাশকোড () এর চুক্তিটি বোঝার চেষ্টা করছি।
নর্ভ

3
@ কনর্ভ এটি ঠিক কীভাবে কাজ করে তা বোঝার জন্য এটি প্রয়োজনীয় নয় - চুক্তি এবং এর উত্তর দিক বোঝা আরও গুরুত্বপূর্ণ।
এমপি।

45
@ এমপি: আপনার ইনপুটটির জন্য ধন্যবাদ, তবে আমি অনুমান করি এটি সিদ্ধান্ত নেওয়া আমার পক্ষে হবে।
নর্ভ

কেন তারা প্রথম চরিত্রকে সবচেয়ে বড় শক্তি দিয়েছে? অতিরিক্ত গণনা সংরক্ষণের জন্য আপনি যখন গতিটির জন্য এটি অনুকূলিত করতে চান, আপনি পূর্বেরটির শক্তি সঞ্চয় করে রাখবেন, তবুও পূর্ববর্তীটি শেষ চরিত্র থেকে প্রথমটিতে থাকবে। এর অর্থ এখানেও ক্যাশে মিস হবে। এর অ্যালগরিদম রাখা আরও দক্ষ নয়: এস [0] + এস [1] * 31 + এস [2] * 31 ^ 2 + ... + এস [এন-1] * 31 ^ [এন-1 ]?
অ্যান্ড্রয়েড বিকাশকারী

উত্তর:


101

আমি সেই ডকুমেন্টেশনটি জাভা ১.২ হিসাবে দেখতে পাচ্ছি।

যদিও এটি সত্য যে সাধারণভাবে আপনি একইরূপে হ্যাশ কোড প্রয়োগের উপর নির্ভর করা উচিত নয়, এটি এখন এর জন্য আচরণের দলিলযুক্ত java.lang.String, সুতরাং এটি পরিবর্তন করা বিদ্যমান চুক্তি ভঙ্গ হিসাবে গণ্য হবে।

যেখানেই সম্ভব, আপনার হ্যাশ কোডগুলিতে সংস্করণ ইত্যাদিতে একই রকমের উপর নির্ভর করা উচিত নয় - তবে আমার মতে java.lang.Stringএকটি বিশেষ বিষয় এটি কেবল কারণ অ্যালগরিদম নির্দিষ্ট করা হয়েছে ... যতক্ষণ আপনি রিলিজের সাথে সামঞ্জস্যতা ত্যাগ করতে ইচ্ছুক থাকেন অবশ্যই অ্যালগরিদম নির্দিষ্ট করা হয়েছিল।


7
স্ট্রিংয়ের নথিভুক্ত আচরণটি জাভা 1.2 থেকে এপিআই-এর v1.1-তে নির্দিষ্ট করা হয়েছে, স্ট্রিং ক্লাসের জন্য হ্যাশ কোড গণনা নির্দিষ্ট করা হয়নি।
মার্টিন ওকননর

এক্ষেত্রে আমরা আমাদের নিজস্ব হ্যাশিং কোডগুলি ight মেটে আরও ভাল লিখতে পারি?
Felype

@ ফ্লাইপ: আপনি এখানে কী বলতে চাইছেন তা আমি সত্যিই জানি না, আমি ভয় পাচ্ছি।
জন স্কিটি

@ জোনস্কিট বলতে আমি বোঝাতে চাইছি, এক্ষেত্রে আমরা সম্ভবত আমাদের নিজস্ব হ্যাশ তৈরি করতে, বহনযোগ্যতা দেওয়ার জন্য নিজের কোড লিখতে পারি। তাই কি?
Felype

@ ফ্লাইপ: আপনি কোন ধরণের বহনযোগ্যতার কথা বলছেন তা মোটেই পরিষ্কার নয় বা "এই ক্ষেত্রে" আপনি কী বোঝাতে চেয়েছেন - কোন নির্দিষ্ট দৃশ্যে? আমার সন্দেহ হয় আপনার একটি নতুন প্রশ্ন করা উচিত।
জন স্কিটি

18

আমি JDK 1.0 এবং 1.1 এবং> = 1.2 সম্পর্কে কিছু পেয়েছি:

জেডিকে 1.0.x এবং 1.1.x এ দীর্ঘ স্ট্রিংয়ের জন্য হ্যাশকোড ফাংশন প্রতিটি নবম চরিত্রের নমুনা তৈরি করে কাজ করেছিল। এটি বেশ ভাল গ্যারান্টিযুক্ত আপনার কাছে অনেকগুলি স্ট্রিং একই মানে হ্যাশিং থাকবে, এইভাবে হ্যাশটেবল অনুসন্ধানকে ধীর করবে। জেডিকে ১.২-এ ফাংশনটি এ পর্যন্ত 31 দ্বারা ফলাফলকে গুণতে উন্নত করা হয়েছে তারপরে পরবর্তী অক্ষরটিকে ধারাবাহিকভাবে যুক্ত করুন। এটি সামান্য ধীর হলেও সংঘর্ষ এড়ানোর ক্ষেত্রে এটি আরও ভাল। সূত্র: http://mindprod.com/jgloss/hashcode.html

কিছু আলাদা, কারণ আপনার একটি সংখ্যার দরকার বলে মনে হচ্ছে: হ্যাশকোডের পরিবর্তে সিআরসি 32 বা এমডি 5 কীভাবে ব্যবহার করবেন এবং আপনি যেতে ভাল - কোনও আলোচনা এবং কোনও উদ্বেগের বিষয় নয় ...


8

আপনার একটি হ্যাশ কোড নির্দিষ্ট মানের সমান হওয়ার উপর নির্ভর করা উচিত নয়। কেবলমাত্র এটি একই মৃত্যুদন্ডের মধ্যে ধারাবাহিক ফলাফল প্রদান করবে। এপিআই ডক্স নিম্নলিখিত বলে:

হ্যাশকোডের সাধারণ চুক্তিটি হ'ল:

  • যখনই এটি কোনও জাভা অ্যাপ্লিকেশন কার্যকর করার সময় একই বস্তুটির উপরে একাধিকবার আহ্বান করা হয়, হ্যাশকোড পদ্ধতিটি ধারাবাহিকভাবে একই পূর্ণসংখ্যাকে ফেরত পাঠাতে হবে, যদি না অবজেক্টের সমান তুলনাতে ব্যবহৃত তথ্য সংশোধন না করা হয়। এই পূর্ণসংখ্যার কোনও প্রয়োগের একটি প্রয়োগ থেকে একই অ্যাপ্লিকেশনটির অন্য প্রয়োগে সামঞ্জস্য থাকা উচিত নয়।

সম্পাদনা করুন যেহেতু স্ট্রিং.হ্যাশকোড () এর জাভাদোক স্ট্রিংয়ের হ্যাশ কোডটি কীভাবে গণনা করা হয়েছে তা নির্দিষ্ট করে, এর কোনও লঙ্ঘনই পাবলিক এপিআই স্পেসিফিকেশন লঙ্ঘন করবে।


1
আপনার উত্তর বৈধ, তবে জিজ্ঞাসা করা নির্দিষ্ট প্রশ্নের সমাধান করে না।
নর্ভ

6
এটি হ্যাশ কোডের সাধারণ চুক্তি - তবে স্ট্রিংয়ের জন্য নির্দিষ্ট চুক্তিটি অ্যালগরিদমের বিশদ দেয় এবং কার্যকরভাবে এই সাধারণ চুক্তি আইএমওকে ওভাররাইড করে।
জন স্কিটি

4

উপরে যেমন বলা হয়েছে, সাধারণভাবে আপনার একই শ্রেণীর একটি ক্লাসের হ্যাশ কোডের উপর নির্ভর করা উচিত নয়। নোট করুন যে একই ভিএম- তে একই অ্যাপ্লিকেশনটির পরবর্তী রানগুলিও বিভিন্ন হ্যাশ মান তৈরি করতে পারে। আফিক সান জেভিএম-এর হ্যাশ ফাংশন প্রতিটি রানেই একই হ্যাশ গণনা করে তবে এটির নিশ্চয়তা নেই।

লক্ষ্য করুন যে এটি তাত্ত্বিক নয়। Java.lang.String এর জন্য হ্যাশ ফাংশনটি JDK1.2 এ পরিবর্তিত হয়েছিল (পুরানো হ্যাশটির URL বা ফাইলের নামগুলির মতো হায়ারারিকিকাল স্ট্রিংগুলির সাথে সমস্যা ছিল, কারণ এটি স্ট্রিংগুলির জন্য একই হ্যাশ তৈরি করতে পারে যা কেবল শেষে পৃথক হয়)।

java.lang.String একটি বিশেষ ক্ষেত্রে, কারণ এর হ্যাশকোড () এর অ্যালগরিদম (এখন) নথিভুক্ত করা হয়েছে, সুতরাং আপনি সম্ভবত এটির উপর নির্ভর করতে পারেন। আমি এখনও এটি খারাপ অভ্যাস বিবেচনা করব। বিশেষ, ডকুমেন্টেড বৈশিষ্ট্য সহ আপনার যদি একটি হ্যাশ অ্যালগরিদম প্রয়োজন হয় তবে কেবল একটি লিখুন :-)।


4
তবে জেডিকে ১.২ এর আগে ডক্সে অ্যালগরিদম নির্দিষ্ট করা হয়েছিল? যদি তা না হয় তবে এটি ভিন্ন পরিস্থিতি। অ্যালগরিদম এখন ডক্সে বিভক্ত করা হয়েছে, সুতরাং এটি পরিবর্তন করা একটি সরকারী চুক্তিতে একটি ব্রেকিং পরিবর্তন হবে be
জন স্কিটি

(আমি এটি 1.1 হিসাবে মনে করি)) মূল (দরিদ্র) অ্যালগরিদম নথিভুক্ত ছিল। ভুল। নথিভুক্ত অ্যালগরিদম আসলে একটি অ্যারেআইন্ডেক্সআউটআউটবাউন্ডসেক্সপশন ছুঁড়েছিল।
টম হাটিন -

@ জোন স্কিট: আহা, স্ট্রিং.হ্যাশকোড () এর অ্যালগরিদম ডকুমেন্টেড ছিল তা জানতেন না। অবশ্যই যে জিনিস পরিবর্তন। আমার মন্তব্য আপডেট।
স্লেসকে

3

উদ্বেগের আরেকটি (!) সমস্যা হচ্ছে জাবার প্রাথমিক / দেরী সংস্করণগুলির মধ্যে প্রয়োগের সম্ভাব্য পরিবর্তন। আমি বিশ্বাস করি না যে বাস্তবায়নের বিবরণ পাথরের মধ্যে সেট করা আছে, এবং তাই সম্ভবত ভবিষ্যতের জাভা সংস্করণে আপগ্রেড করার ফলে সমস্যা দেখা দিতে পারে।

নীচের লাইনটি হচ্ছে, আমি বাস্তবায়নের উপর নির্ভর করব না hashCode()

সম্ভবত আপনি এই প্রক্রিয়াটি ব্যবহার করে আপনি কোন সমস্যার সমাধান করার চেষ্টা করছেন তা হাইলাইট করতে পারেন এবং এটি আরও উপযুক্ত পদ্ধতির আলোকপাত করবে।


1
আপনার উত্তরের জন্য ধন্যবাদ. আপনি কখন এটি "জাভা স্ট্রিং" এর একটি নিবিড় উদাহরণ দিতে পারেন? হ্যাশকোড ()! = 586653468?
নর্ভ

1
না। দুঃখিত। আমার বক্তব্যটি হ'ল আপনি যা যা পরীক্ষা করেন তা আপনার পছন্দ মতো কাজ করতে পারে। তবে এটি এখনও কোনও গ্যারান্টি নেই। সুতরাং আপনি যদি একটি (বলুন) স্বল্পমেয়াদী প্রকল্পে কাজ করছেন যেখানে আপনার ভিএম ইত্যাদি নিয়ন্ত্রণ রয়েছে, তবে উপরেরটি আপনার পক্ষে কাজ করতে পারে। তবে আপনি এর উপর বৃহত্তর বিশ্বে নির্ভর করতে পারবেন না।
ব্রায়ান অ্যাগনিউ

2
"ভবিষ্যতের জাভা সংস্করণে আপগ্রেড করা সমস্যার কারণ হতে পারে"। ভবিষ্যতের জাভা সংস্করণে আপগ্রেড হ্যাশকোড পদ্ধতি পুরোপুরি সরিয়ে ফেলতে পারে। অথবা স্ট্রিংয়ের জন্য সর্বদা 0 ফেরত দিন। হ্যাঁ, এটি আপনার জন্য অসামঞ্জস্যপূর্ণ পরিবর্তন। প্রশ্নটি হ'ল সান ^ হোরাকল ^ এইচসিপি এটিকে একটি ব্রেকিং পরিবর্তন হিসাবে বিবেচনা করবে এবং তাই এড়ানো এড়ানো উচিত worth যেহেতু অ্যালগরিদম চুক্তিতে রয়েছে, একজন আশা করে যে তারা তা করবে।
স্টিভ জেসোপ

@ স্টিভ জেসপ ভাল, যেহেতু switchস্ট্রিংগুলির উপরের বিবৃতিগুলি নির্দিষ্ট নির্দিষ্ট হ্যাশ কোডের উপর নির্ভর করে কোডকে সংকলন করে, Stringএর হ্যাশ কোড অ্যালগরিদমে পরিবর্তনগুলি অবশ্যই বিদ্যমান কোডটি ভেঙে ফেলবে ...
হোলার

3

কেবল আপনার প্রশ্নের উত্তর দেওয়ার জন্য এবং কোনও আলোচনা চালিয়ে যাওয়ার জন্য নয়। অ্যাপাচি হারমোনি জেডিকে বাস্তবায়ন মনে হয় একটি পৃথক অ্যালগরিদম ব্যবহার করা হচ্ছে, কমপক্ষে এটি সম্পূর্ণ আলাদা দেখায়:

সান জেডিকে

public int hashCode() {
    int h = hash;
    if (h == 0) {
        int off = offset;
        char val[] = value;
        int len = count;

        for (int i = 0; i < len; i++) {
            h = 31*h + val[off++];
        }
        hash = h;
    }
    return h;
}

অ্যাপাচি হারমনি

public int hashCode() {
    if (hashCode == 0) {
        int hash = 0, multiplier = 1;
        for (int i = offset + count - 1; i >= offset; i--) {
            hash += value[i] * multiplier;
            int shifted = multiplier << 5;
            multiplier = shifted - multiplier;
        }
        hashCode = hash;
    }
    return hashCode;
}

এটি নিখরচায় পরীক্ষা করে দেখুন ...


23
আমি মনে করি তারা কেবল শীতল হচ্ছে এবং এটি অনুকূল করে তুলছে। :) "(গুণক << 5) - গুণক" শুধু 31 * গুণক, সব পরে ... হয়
বিনোদন

ঠিক আছে, এটি পরীক্ষা করতে খুব অলস ছিল। ধন্যবাদ!
নবীন

1
তবে আমার দিক থেকে এটি পরিষ্কার করার জন্য ... হ্যাশকোডের উপর কখনই নির্ভর করবেন না কারণ হ্যাশকোডটি অভ্যন্তরীণ কিছু।
নবীন

1
"অফসেট", "কাউন্ট" এবং "হ্যাশকোড" এর ভেরিয়েবলগুলি কী বোঝায়? আমি মনে করি ভবিষ্যতের গণনা এড়াতে "হ্যাশকোড" ক্যাশেড মান হিসাবে ব্যবহৃত হয় এবং "গণনা" অক্ষরের সংখ্যা, তবে "অফসেট" কী? ধরুন আমি এই কোডটি ব্যবহার করতে ইচ্ছুক যাতে এটি একটি সামঞ্জস্যপূর্ণ হয়, একটি স্ট্রিং দেওয়া হয়, আমি এর সাথে কী করব?
অ্যান্ড্রয়েড বিকাশকারী

1
@ অ্যান্ড্রয়েড ডেভেলপার এখন এটি একটি আকর্ষণীয় প্রশ্ন - যদিও আপনার ব্যবহারকারীর নাম অনুসারে আমার এটি অনুমান করা উচিত ছিল। অ্যান্ড্রয়েড ডক্স থেকে দেখে মনে হচ্ছে চুক্তিটি একই রকম: s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]আমি যদি ভুল না করি তবে এটি অ্যান্ড্রয়েড কোনও পরিবর্তন ছাড়াই স্ট্রিং অবজেক্টটির সান এর প্রয়োগ ব্যবহার করে।
কার্তিক চুগ

2

যদি আপনি পরিবর্তনগুলি এবং সম্ভবত অসম্পূর্ণভাবে ভিএমগুলি সম্পর্কে উদ্বিগ্ন থাকেন তবে বিদ্যমান হ্যাশকোড বাস্তবায়নটি আপনার নিজস্ব ইউটিলিটি শ্রেণিতে অনুলিপি করুন এবং আপনার হ্যাশকোডগুলি তৈরি করতে এটি ব্যবহার করুন।


আমি এটা বলতে যাচ্ছি। অন্য উত্তরগুলি প্রশ্নের উত্তর দেওয়ার সময়, পৃথক হ্যাশকোড ফাংশন লেখাই সম্ভবত নোরভের সমস্যার উপযুক্ত সমাধান।
নিক

1

হ্যাশকোড স্ট্রিংয়ের অক্ষরগুলির ASCII মানগুলির ভিত্তিতে গণনা করা হবে।

স্ট্রিং ক্লাসে এটি বাস্তবায়ন নিম্নরূপ

public int hashCode() {
    int h = hash;
    if (h == 0 && value.length > 0) {
        hash = h = isLatin1() ? StringLatin1.hashCode(value)
                              : StringUTF16.hashCode(value);
    }
    return h;
}

হ্যাশকোডে সংঘর্ষগুলি অনিবার্য। উদাহরণস্বরূপ, "Ea" এবং "FB" স্ট্রিংগুলি 2236 এর মতো হ্যাশকোড দেয়

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.