سؤال

هل ترى أي مشكلة في استخدام مصفوفة بايت كمفتاح خريطة؟يمكنني أيضًا أن أفعل new String(byte[]) والتجزئة بواسطة String ولكنه أكثر سهولة في الاستخدام byte[].

هل كانت مفيدة؟

المحلول

المشكلة هي byte[] يستخدم هوية الكائن ل equals و hashCode, ، لهذا السبب

byte[] b1 = {1, 2, 3}
byte[] b2 = {1, 2, 3}

لن تتطابق في HashMap.أرى ثلاثة خيارات:

  1. التفاف في أ String, ، ولكن عليك بعد ذلك توخي الحذر بشأن مشكلات التشفير (تحتاج إلى التأكد من أن البايت -> السلسلة -> البايت يمنحك نفس البايتات).
  2. يستخدم List<Byte> (يمكن أن تكون مكلفة في الذاكرة).
  3. قم بفصل التغليف والكتابة الخاص بك hashCode و equals لاستخدام محتويات مجموعة البايت.

نصائح أخرى

وانها بخير طالما كنت تريد فقط المساواة مرجعية لمفتاحك - المصفوفات لا تنفذ "المساواة قيمة" في الطريقة التي كنت ربما تريد. على سبيل المثال:

byte[] array1 = new byte[1];
byte[] array2 = new byte[1];

System.out.println(array1.equals(array2));
System.out.println(array1.hashCode());
System.out.println(array2.hashCode());

ويطبع شيئا مثل:

false
1671711
11394033

و(الأرقام الفعلية ليست ذات صلة، وحقيقة أنهم مختلف هو المهم.)

وعلى افتراض انك <م> في الواقع نريد المساواة، وأنا أقترح عليك إنشاء المجمع الخاص بك الذي يحتوي على byte[] وتنفذ المساواة ورمز التجزئة الجيل بشكل مناسب:

public final class ByteArrayWrapper
{
    private final byte[] data;

    public ByteArrayWrapper(byte[] data)
    {
        if (data == null)
        {
            throw new NullPointerException();
        }
        this.data = data;
    }

    @Override
    public boolean equals(Object other)
    {
        if (!(other instanceof ByteArrayWrapper))
        {
            return false;
        }
        return Arrays.equals(data, ((ByteArrayWrapper)other).data);
    }

    @Override
    public int hashCode()
    {
        return Arrays.hashCode(data);
    }
}

لاحظ أنه إذا قمت بتغيير القيم داخل صفيف بايت بعد استخدام ByteArrayWrapper، كمفتاح في HashMap (الخ) سيكون لديك مشاكل النظر إلى فوق المفتاح مرة أخرى ... هل يمكن أن تأخذ نسخة من البيانات في منشئ ByteArrayWrapper إذا كنت تريد، ولكن من الواضح أنه سيكون مضيعة للأداء إذا كنت تعرف أنك <م> لن يتم تغيير محتويات صفيف بايت.

وتحرير: كما ذكر في التعليقات، ويمكن أيضا استخدام ByteBuffer لهذا (على وجه الخصوص، في <لأ href = "http://docs.oracle.com/javase/7/docs/api/java/nio/ ByteBuffer.html # التفاف٪ 28byte٪ 5B٪ 5D٪ 29 "يختلط =" noreferrer "> ByteBuffer#wrap(byte[]) طريقة ). أنا لا أعرف ما إذا كان حقا الشيء الصحيح، في ضوء كل القدرات الإضافية التي ByteBuffers يكون التي لا تحتاج، لكنه خيار.

ويمكننا استخدام ByteBuffer لهذا (وهذا هو الأساس بايت [] المجمع مع المقارنة)

HashMap<ByteBuffer, byte[]> kvs = new HashMap<ByteBuffer, byte[]>();
byte[] k1 = new byte[]{1,2 ,3};
byte[] k2 = new byte[]{1,2 ,3};
byte[] val = new byte[]{12,23,43,4};

kvs.put(ByteBuffer.wrap(k1), val);
System.out.println(kvs.containsKey(ByteBuffer.wrap(k2)));

وستطبع

true

هل يمكن استخدام java.math.BigInteger. أنه يحتوي على منشئ BigInteger(byte[] val). انها نوع مرجع، لذلك يمكن استخدامه كمفتاح للجدول هاش. ويتم تعريف .equals() و.hashCode() بالنسبة للأرقام صحيحة منها، وهو ما يعني BigInteger لديها بما يتفق يساوي دلالات كما بايت [] مجموعة.

وأنا مندهش جدا أن الإجابات لم تكن لافتا إلى البديل الأكثر بسيطة.

نعم، فإنه ليس من الممكن استخدام HashMap، ولكن لا أحد يمنعك من استخدام SortedMap كبديل. الشيء الوحيد هو لكتابة المقارنة التي تحتاج لمقارنة صفائف. وليس من performant للمثل لHashMap، ولكن إذا كنت تريد بديلا بسيطا، وهنا تذهب (يمكنك استبدال SortedMap مع خريطة إذا كنت ترغب في إخفاء التنفيذ):

 private SortedMap<int[], String>  testMap = new TreeMap<>(new ArrayComparator());

 private class ArrayComparator implements Comparator<int[]> {
    @Override
    public int compare(int[] o1, int[] o2) {
      int result = 0;
      int maxLength = Math.max(o1.length, o2.length);
      for (int index = 0; index < maxLength; index++) {
        int o1Value = index < o1.length ? o1[index] : 0;
        int o2Value = index < o2.length ? o2[index] : 0;
        int cmp     = Integer.compare(o1Value, o2Value);
        if (cmp != 0) {
          result = cmp;
          break;
        }
      }
      return result;
    }
  }

ويمكن تعديل هذا التطبيق للصفائف أخرى، والشيء الوحيد الذي يجب أن تكون على علم هو أن صفائف متساوية (= يساوي طول مع أعضاء المساواة) يجب أن يعود 0 وأن لديك أمر determistic

وأعتقد أن المصفوفات في جافا لا تنفذ بالضرورة الأساليب hashCode() وequals(Object) حدسي. وهذا هو، واثنين من صفائف بايت متطابقة لا تشترك بالضرورة نفس رمز التجزئة، وأنها لن تدعي بالضرورة أن يكون على قدم المساواة. من دون هذه الصفات اثنين، سوف HashMap الخاصة بك تتصرف بشكل غير متوقع.

لذلك، أوصي على ضد هل تستخدم byte[] كمفاتيح في HashMap.

ويجب عليك استخدام إنشاء سومثينغ الدرجة مثل ByteArrKey وشفرة التجزئة الزائد وطرق متساوية، تذكر العقد بينهما.

وهذا سوف تعطيك قدر أكبر من المرونة كما يمكنك تخطي 0 الإدخالات التي يتم إلحاق في نهاية صفيف بايت، وخاصة إذا قمت بنسخ فقط جزء شكل المخزن المؤقت بايت آخرين.

وهذه الطريقة سوف تقرر كيف كل الكائنات يجب أن تكون على قدم المساواة.

وأرى مشاكل منذ يجب عليك استخدام Arrays.equals وArray.hashCode، في مكان التنفيذ مجموعة الافتراضي

وArrays.toString (بايت)

ويمكنك أيضا تحويل بايت [] إلى سلسلة "آمنة" باستخدام Base32 أو باستخدام Base64، على سبيل المثال:

byte[] keyValue = new byte[] {…};
String key = javax.xml.bind.DatatypeConverter.printBase64Binary(keyValue);

وبالطبع هناك العديد من المتغيرات ما سبق، مثل:

String key = org.apache.commons.codec.binary.Base64.encodeBase64(keyValue);

وهنا هو الحل باستخدام TreeMap، واجهة المقارنة وjava.util.Arrays.equals طريقة جافا (بايت []، [] بايت)؛

ملحوظة: إن الطلب في الخريطة ليست ذات الصلة مع هذا الأسلوب

SortedMap<byte[], String> testMap = new TreeMap<>(new ArrayComparator());

static class ArrayComparator implements Comparator<byte[]> {
    @Override
    public int compare(byte[] byteArray1, byte[] byteArray2) {

        int result = 0;

        boolean areEquals = Arrays.equals(byteArray1, byteArray2);

        if (!areEquals) {
            result = -1;
        }

        return result;
    }
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top