হ্যাশকোড () কে ওভাররাইড করে এমন কোনও সামগ্রীর অনন্য আইডি কীভাবে পাবেন?


231

যখন জাভাতে কোনও শ্রেণি হ্যাশকোড () কে ওভাররাইড করে না , এই শ্রেণীর উদাহরণ ছাপানো একটি দুর্দান্ত অনন্য নম্বর দেয়।

অবজেক্টের জাভাদোক হ্যাশকোড সম্পর্কে বলে () :

যথাযথভাবে ব্যবহারিক হিসাবে যতটা কার্যকর, শ্রেণি অবজেক্ট দ্বারা সংজ্ঞায়িত হ্যাশকোড পদ্ধতিটি পৃথক বস্তুর জন্য পৃথক পূর্ণসংখ্যা ফেরত দেয়।

কিন্তু যখন ক্লাসটি হ্যাশকোড () কে ওভাররাইড করে , আমি কীভাবে এর অনন্য নম্বর পেতে পারি?


33
বেশিরভাগ ক্ষেত্রে 'ডিবাগিং' কারণে;) বলতে সক্ষম হতে: আহ, একই বস্তু!
ivan_ivanovich_ivanoff

5
এই উদ্দেশ্যে সিস্টেম.ডিসিটিটিহ্যাশকোড () সম্ভবত কিছু ব্যবহারের সম্ভাবনা রয়েছে। কোড কার্যকারিতা বাস্তবায়নের জন্য আমি এর উপর নির্ভর করব না। আপনি যদি স্বতন্ত্রভাবে অবজেক্টগুলি সনাক্ত করতে চান তবে আপনি তৈরি করা অবজেক্টের জন্য অনন্য আইডিতে AspectJ এবং কোড-ওয়েভ ব্যবহার করতে পারেন। আরও কাজ, যদিও
ব্রায়ান অগ্নিউ

9
কেবল মনে রাখবেন যে হ্যাশকোডটি অনন্য হওয়ার গ্যারান্টিযুক্ত নয়। এমনকি যদি বাস্তবায়নকারী মেমরি ঠিকানাটিকে ডিফল্ট হ্যাশকোড হিসাবে ব্যবহার করে। কেন এটি অনন্য নয়? কারণ বস্তুগুলি আবর্জনা সংগ্রহ করে এবং স্মৃতি পুনরায় ব্যবহৃত হয়।
ইগর ক্রিভোকন

8
আপনি যদি সিদ্ধান্ত নিতে চান তবে দুটি বস্তু হ্যাশকোড () এর পরিবর্তে == একই ব্যবহার হয়। পরেরটি বাস্তব বাস্তবায়নেও অনন্য হওয়ার গ্যারান্টিযুক্ত নয়।
মেনেমেন্ট

6
উত্তরের কোনও উত্তরই আসল প্রশ্নের উত্তর দেয় না কারণ তারা হ্যাশকোড () এখানে আলোচনায় জড়িয়ে পড়েছিল যা এখানে ঘটনাচক্রে ছিল। আমি যদি একিপ্সে রেফারেন্স ভেরিয়েবলগুলি দেখি তবে এটি আমাকে একটি অনন্য অপরিবর্তনীয় "আইডি = এক্সএক্সএক্সএক্স" দেখায়। আমাদের নিজের আইডি জেনারেটরটি ব্যবহার না করে আমরা কীভাবে প্রোগ্রামটিমে এই মানটি পাব? বস্তুর স্বতন্ত্র উদাহরণগুলি সনাক্ত করতে আমি ডিবাগিংয়ের উদ্দেশ্যে (লগিং) সেই মানটিতে অ্যাক্সেস চাই। কেউ কীভাবে সেই মূল্যতে আপনার হাত পেতে জানে?
ক্রিস ওয়েস্টিন

উত্তর:


346

সিস্টেম.ডিনিটিটিহ্যাশকোড (আপনারঅজেক্ট) পূর্ণসংখ্যার হিসাবে আপনারঅজেক্টের 'আসল' হ্যাশ কোডটি দেবে। স্বতন্ত্রতা অবশ্যই গ্যারান্টিযুক্ত নয়। সান জেভিএম বাস্তবায়ন আপনাকে একটি মান দেবে যা এই বস্তুর মূল মেমরি ঠিকানার সাথে সম্পর্কিত, তবে এটি একটি বাস্তবায়ন বিশদ এবং আপনার উপর নির্ভর করা উচিত নয়।

সম্পাদনা: নীচে টমের মন্তব্য অনুসরণ করে উত্তরটি সংশোধিত হয়েছে। মেমরি ঠিকানা এবং চলন্ত বস্তু।


আমাকে অনুমান করতে দিন: এটি অনন্য নয়, যখন আপনার একই জেভিএম-তে 2 ** 32 টিরও বেশি অবজেক্ট থাকে? ;) আপনি কি আমাকে এমন কোনও জায়গায় নির্দেশ করতে পারেন, যেখানে অদ্বিতীয়তার বর্ণনা দেওয়া হয়েছে? ধন্যবাদ!
ivan_ivanovich_ivanoff

9
সেখানে কতগুলি বস্তু আছে বা কত স্মৃতি রয়েছে তা বিবেচ্য নয়। কোনও হ্যাশকোড () বা পরিচয় হ্যাশকোড () কোনও অনন্য নম্বর তৈরি করতে প্রয়োজন।
অ্যালান মুর

12
ব্রায়ান: এটি আসল মেমরির অবস্থান নয়, আপনি যখন প্রথম গণনা করা হয় তখন কোনও ঠিকানার পুনঃস্থাপন সংস্করণ পান। একটি আধুনিক ভিএম অবজেক্টে মেমরির দিকে ঘোরাবে।
টম হাটিন -

2
সুতরাং যদি কোনও বস্তু মেমরি ঠিকানার 0x2000 এ তৈরি করা হয়, তবে ভিএম দ্বারা সরানো হয়, তবে অন্য কোনও বস্তু 0x2000 এ তৈরি হয়, তাদের কি একই থাকবে System.identityHashCode()?
সীমিত প্রায়শ্চিত্ত

14
বাস্তব জেভিএম বাস্তবায়নের জন্য স্বতন্ত্রতার মোটেও গ্যারান্টি নেই । গ্যারান্টিযুক্ত স্বতন্ত্রতার জন্য হয় হয় জিসির দ্বারা কোনও স্থানান্তর / সংযোগ বা লাইভ অবজেক্টের হ্যাশকোড মান পরিচালনার জন্য একটি বড় এবং ব্যয়বহুল ডেটা স্ট্রাকচার দরকার।
স্টিফেন সি

28

অবজেক্টের জাভাদোক এটি নির্দিষ্ট করে

এটি সাধারণত বস্তুর অভ্যন্তরীণ ঠিকানাটিকে পূর্ণসংখ্যার সাথে রূপান্তর করে প্রয়োগ করা হয়, তবে জাভাটিএম প্রোগ্রামিং ল্যাঙ্গুয়েজ দ্বারা এই প্রয়োগকরণ কৌশলটি প্রয়োজন হয় না।

যদি কোনও শ্রেণি হ্যাশকোডকে ওভাররাইড করে, এর অর্থ হল যে এটি একটি নির্দিষ্ট আইডি তৈরি করতে চায়, যা (কেউ আশা করতে পারে) সঠিক আচরণ করবে।

যে কোনও ক্লাসের জন্য এই আইডি পেতে আপনি সিস্টেম.ডিসিটিটিহ্যাশকোড ব্যবহার করতে পারেন ।


7

hashCode()পদ্ধতি কোনও অবজেক্টের জন্য একটি অনন্য সনাক্তকারী সরবরাহের জন্য নয়। এটি বরং একক পূর্ণসংখ্যায় অবজেক্টের স্থিতি (যেমন সদস্য ক্ষেত্রের মান) হজম করে। এই মানটি বেশিরভাগ হ্যাশ ভিত্তিক ডেটা স্ট্রাকচার যেমন মানচিত্র এবং সেটগুলি কার্যকরভাবে সঞ্চয় এবং পুনরুদ্ধার করতে ব্যবহার করে।

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

public interface IdentifiedObject<I> {
    I getId();
}

ব্যবহারের উদাহরণ:

public class User implements IdentifiedObject<Integer> {
    private Integer studentId;

    public User(Integer studentId) {
        this.studentId = studentId;
    }

    @Override
    public Integer getId() {
        return studentId;
    }
}

6

এই দ্রুত, নোংরা সমাধান কি কাজ করবে?

public class A {
    static int UNIQUE_ID = 0;
    int uid = ++UNIQUE_ID;

    public int hashCode() {
        return uid;
    }
}

এটি কোনও শ্রেণীর সূচনা করার সংখ্যাটিও দেয়।


4
এটি ধরে নেওয়া হয় যে শ্রেণীর উত্স
কোডটিতে

যদি আপনি উত্স কোড অ্যাক্সেস করতে না পারেন তবে কেবল এটি থেকে প্রসারিত করুন এবং বর্ধিত শ্রেণিটি ব্যবহার করুন। কেবলমাত্র দ্রুত, সহজ এবং নোংরা সমাধান তবে এটি কাজ করে।
জন পাং

1
এটা সবসময় কাজ করে না। ক্লাস চূড়ান্ত হতে পারে। আমি মনে করি System.identityHashCodeএটি আরও ভাল সমাধান
পাব্লিসকো

2
থ্রেড-সুরক্ষার জন্য, কেউ এই উত্তরAtomicLong হিসাবে ব্যবহার করতে পারে ।
এভেজেনি সার্জিভ

ক্লাসটি যদি অন্য কোনও ক্লাস লোডার দ্বারা লোড করা হয় তবে এতে আলাদা UNIQUE_ID স্ট্যাটিক ভেরিয়েবল থাকবে, আমি কি সঠিক?
cupiqi09

4

যদি এটি এমন কোনও শ্রেণি হয় যা আপনি সংশোধন করতে পারেন তবে আপনি একটি শ্রেণি ভেরিয়েবল ঘোষণা করতে পারেন static java.util.concurrent.atomic.AtomicInteger nextInstanceId। (আপনাকে এটিকে সুস্পষ্ট উপায়ে একটি প্রাথমিক মান দিতে হবে)) তারপরে একটি উদাহরণ ভেরিয়েবল ঘোষণা করুন int instanceId = nextInstanceId.getAndIncrement()


2

আমি এই সমাধানটি নিয়ে এসেছি যা আমার ক্ষেত্রে কাজ করে যেখানে আমার একাধিক থ্রেডে অবজেক্ট তৈরি হয়েছে এবং সিরিয়ালাইজযোগ্য:

public abstract class ObjBase implements Serializable
    private static final long serialVersionUID = 1L;
    private static final AtomicLong atomicRefId = new AtomicLong();

    // transient field is not serialized
    private transient long refId;

    // default constructor will be called on base class even during deserialization
    public ObjBase() {
       refId = atomicRefId.incrementAndGet()
    }

    public long getRefId() {
        return refId;
    }
}

2
// looking for that last hex?
org.joda.DateTime@57110da6

আপনি hashcodeযখন .toString()কোনও বস্তুর উপর কোনও কাজ করছেন যখন আপনি জাভা প্রকারগুলি সন্ধান করছেন তবে অন্তর্নিহিত কোডটি হ'ল:

Integer.toHexString(hashCode())

0

অন্য উত্তরগুলি কেবল একটি ভিন্ন কোণ থেকে বাড়ানোর জন্য।

আপনি যদি 'উপরের' থেকে হ্যাশকোড (গুলি) পুনরায় ব্যবহার করতে চান এবং আপনার শ্রেণীর 'অপরিবর্তনীয় স্থিতি ব্যবহার করে নতুনগুলি অর্জন করতে চান, তবে সুপার-এ একটি কল কাজ করবে। যদিও এটি পুরোপুরি অবজেক্ট পর্যন্ত ক্যাসকেড করতে পারে না (যেমন কিছু পূর্বপুরুষ সুপার নাও বলতে পারে), এটি আপনাকে পুনরায় ব্যবহারের মাধ্যমে হ্যাশকোডগুলি অর্জন করতে দেয়।

@Override
public int hashCode() {
    int ancestorHash = super.hashCode();
    // now derive new hash from ancestorHash plus immutable instance vars (id fields)
}

0

হ্যাশকোড () এবং পরিচয় হ্যাশকোড () রিটার্নের মধ্যে পার্থক্য রয়েছে। এটি সম্ভব যে দুটি অসম (== দিয়ে পরীক্ষিত) বস্তুর জন্য ও 1, ও 2 হ্যাশকোড () একই হতে পারে। এটি কিভাবে সত্য তা নীচের উদাহরণটি দেখুন।

class SeeDifferences
{
    public static void main(String[] args)
    {
        String s1 = "stackoverflow";
        String s2 = new String("stackoverflow");
        String s3 = "stackoverflow";
        System.out.println(s1.hashCode());
        System.out.println(s2.hashCode());
        System.out.println(s3.hashCode());
        System.out.println(System.identityHashCode(s1));
        System.out.println(System.identityHashCode(s2));
        System.out.println(System.identityHashCode(s3));
        if (s1 == s2)
        {
            System.out.println("s1 and s2 equal");
        } 
        else
        {
            System.out.println("s1 and s2 not equal");
        }
        if (s1 == s3)
        {
            System.out.println("s1 and s3 equal");
        }
        else
        {
            System.out.println("s1 and s3 not equal");
        }
    }
}

0

আমার একই সমস্যা ছিল এবং এগুলির কোনও উত্তরই সন্তুষ্ট ছিল না যেহেতু তাদের কারওরও অনন্য আইডির গ্যারান্টি নেই।

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

আমি এই বিষয়টির উপর ভিত্তি করে একটি সমাধান নিয়ে এসেছি যে দুটি বস্তু যদি একইরকম হয় তবে অবজেক্টগুলির জন্য "==" অপারেটরটি কেবল সত্যই প্রত্যাবর্তন করে।

import java.util.HashMap;
import java.util.Map;

/**
 *  Utility for assigning a unique ID to objects and fetching objects given
 *  a specified ID
 */
public class ObjectIDBank {

    /**Singleton instance*/
    private static ObjectIDBank instance;

    /**Counting value to ensure unique incrementing IDs*/
    private long nextId = 1;

    /** Map from ObjectEntry to the objects corresponding ID*/
    private Map<ObjectEntry, Long> ids = new HashMap<ObjectEntry, Long>();

    /** Map from assigned IDs to their corresponding objects */
    private Map<Long, Object> objects = new HashMap<Long, Object>();

    /**Private constructor to ensure it is only instantiated by the singleton pattern*/
    private ObjectIDBank(){}

    /**Fetches the singleton instance of ObjectIDBank */
    public static ObjectIDBank instance() {
        if(instance == null)
            instance = new ObjectIDBank();

        return instance;
    }

    /** Fetches a unique ID for the specified object. If this method is called multiple
     * times with the same object, it is guaranteed to return the same value. It is also guaranteed
     * to never return the same value for different object instances (until we run out of IDs that can
     * be represented by a long of course)
     * @param obj The object instance for which we want to fetch an ID
     * @return Non zero unique ID or 0 if obj == null
     */
    public long getId(Object obj) {

        if(obj == null)
            return 0;

        ObjectEntry objEntry = new ObjectEntry(obj);

        if(!ids.containsKey(objEntry)) {
            ids.put(objEntry, nextId);
            objects.put(nextId++, obj);
        }

        return ids.get(objEntry);
    }

    /**
     * Fetches the object that has been assigned the specified ID, or null if no object is
     * assigned the given id
     * @param id Id of the object
     * @return The corresponding object or null
     */
    public Object getObject(long id) {
        return objects.get(id);
    }


    /**
     * Wrapper around an Object used as the key for the ids map. The wrapper is needed to
     * ensure that the equals method only returns true if the two objects are the same instance
     * and to ensure that the hash code is always the same for the same instance.
     */
    private class ObjectEntry {
        private Object obj;

        /** Instantiates an ObjectEntry wrapper around the specified object*/
        public ObjectEntry(Object obj) {
            this.obj = obj;
        }


        /** Returns true if and only if the objects contained in this wrapper and the other
         * wrapper are the exact same object (same instance, not just equivalent)*/
        @Override
        public boolean equals(Object other) {
            return obj == ((ObjectEntry)other).obj;
        }


        /**
         * Returns the contained object's identityHashCode. Note that identityHashCode values
         * are not guaranteed to be unique from object to object, but the hash code is guaranteed to
         * not change over time for a given instance of an Object.
         */
        @Override
        public int hashCode() {
            return System.identityHashCode(obj);
        }
    }
}

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

যেহেতু আমি এটি ডিবাগ উদ্দেশ্যে ব্যবহার করছি তাই আমি স্মৃতি মুক্ত হওয়ার বিষয়ে খুব বেশি উদ্বিগ্ন নই।

মেমরি মুক্ত করা যদি উদ্বেগজনক হয় তবে আপনি অবজেক্টগুলি সাফ করার বা পৃথক অবজেক্টগুলি অপসারণের জন্য এটি পরিবর্তন করতে পারেন।

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