Други, а кто понимает в Java? (Особую надежду возлагаю на
k_79.) Расскажите мне понятными словами, как бы мне сделать хэш, который бы в качестве ключа использовал 64-битное число, значение выдавал 48-битное (а лучше сразу byte[6]), а ещё был фиксированного размера и при превышении оного старые записи удалял? Про LinkedHashMap я читал, но ничего толком не понял. Там объекты какие-то толпами, а у меня просто числа...
Я вот пробовал породить класс, который extends LinkedHashMap<Long, byte[6]>,
и метод removeEldestEntry или как его там переопределил правильно. Из своего 64-битного числа я генерю Long, а в свои массивы запиываю то, что даёт get(мойключ), и если дал null, то тогда массив руками считаю и в хэш запихиваю посредством put(мойключ, посчитанныймассив). И ничего не получается — какие-то бредовые результаты, совсем всё не так, как если бы каждый раз руками массив считать.
Что делать-то, а? Только я Java не знаю, и программировать на ней не умею.
Я вот пробовал породить класс, который extends LinkedHashMap<Long, byte[6]>,
и метод removeEldestEntry или как его там переопределил правильно. Из своего 64-битного числа я генерю Long, а в свои массивы запиываю то, что даёт get(мойключ), и если дал null, то тогда массив руками считаю и в хэш запихиваю посредством put(мойключ, посчитанныймассив). И ничего не получается — какие-то бредовые результаты, совсем всё не так, как если бы каждый раз руками массив считать.
Что делать-то, а? Только я Java не знаю, и программировать на ней не умею.
no subject
no subject
no subject
no subject
public static void main(String[] args) { if (new byte[] {0, 1, 2, 3}.equals(new byte[] {0, 1, 2, 3})) System.out.println("same"); else System.out.println("different"); }Выводит, очевидно, different.
no subject
public static void main(String[] args) { System.out.println(new byte[] {0, 1, 2, 3}.hashCode()); System.out.println(new byte[] {0, 1, 2, 3}.hashCode()); }выводит разные значения.
no subject
Я сейчас дотестирую классик и вышлю.
no subject
package spb.dev2dev.avysk; import java.util.Map; import java.util.LinkedHashMap; import java.util.Arrays; /** * @author alf */ public class LongMap { private static int SIZE_LIMIT = 50; private Map storage = new LinkedHashMap() { protected boolean removeEldestEntry(Map.Entry eldest) { return size() > SIZE_LIMIT; } }; public byte[] get(byte[] key) { ByteBag bag = (ByteBag) storage.get(new ByteBag(key)); return bag == null ? null : bag.getValue(); } public byte[] remove(byte[] key) { ByteBag bag = (ByteBag) storage.remove(new ByteBag(key)); return bag == null ? null : bag.getValue(); } public byte[] put(byte[] key, byte[] value) { ByteBag oldBag = (ByteBag) storage.put(new ByteBag(key), new ByteBag(value)); return oldBag == null ? null : oldBag.getValue(); } // add size() and other methods if necessary private static class ByteBag { private byte[] value; public ByteBag(byte[] value) { this.value = value; } public byte[] getValue() { return value; } public boolean equals(Object obj) { ByteBag bb = (ByteBag) obj; return Arrays.equals(value, bb.getValue()); } public int hashCode() { return Arrays.hashCode(value); } } }no subject
no subject
С лонгом будет быстрее, да... Наверное. Может быть :)
no subject
no subject
// Arrays.java, jdk1.5.0_07 public static int hashCode(byte a[]) { if (a == null) return 0; int result = 1; for (byte element : a) result = 31 * result + element; return result; }Для массивов хэшкод считается как для
Object- это (очень грубо) внутренный адрес объекта.Почему в Java так сделано - не знаю, потому и написал
ByteBag. А вот вариант cLongнадо погонять ещё - я знаю, чтоByteBagявляется "правильным" ключом, то есть мы точно не слепляем значения. А вот в методе toLong надо проверить, что он не теряет биты.Так что в обычной жизни я бы плюнул на производительность и остался с
ByteBag:)no subject
no subject
no subject
no subject
public static boolean equals(byte[] a, byte[] a2) { if (a == a2) return true; if (a == null || a2==null) return false; int length = a.length; if (a2.length != length) return false; for (int i = 0; i < length; i++) if (a[i] != a2[i]) return false; return true; }no subject
no subject
no subject
И привет Лаперье, ага.
no subject
1. Унаследоваться от класса
2. Сложить объект этого класса в поле и использовать его
В общем случае вариант 2 много, много лучше - он не создаёт неочевидных связей. Да, приходится писать кучу бессмысленных методов для прокидывания вызовов - но вероятность нарваться на чудеса в поведении минимальна.
no subject
no subject
no subject
package spb.dev2dev.avysk; import java.util.LinkedHashMap; import java.util.Map; import java.util.Arrays; /** * @author alf */ public class LongMap { private static int SIZE_LIMIT = 4; public static void main(String[] args) { LongMap map = new LongMap(); map.put(new byte[] {1, 2, 3, 4, 5, 6, 7, 8,}, new byte[] {1, 2, 3, 4, 5, 6,}); map.put(new byte[] {2, 2, 3, 4, 5, 6, 7, 8,}, new byte[] {2, 2, 3, 4, 5, 6,}); map.put(new byte[] {3, 2, 3, 4, 5, 6, 7, 8,}, new byte[] {3, 2, 3, 4, 5, 6,}); map.put(new byte[] {4, 2, 3, 4, 5, 6, 7, 8,}, new byte[] {4, 2, 3, 4, 5, 6,}); map.put(new byte[] {5, 2, 3, 4, 5, 6, 7, 8,}, new byte[] {5, 2, 3, 4, 5, 6,}); print(map.get(new byte[] {1, 2, 3, 4, 5, 6, 7, 8,})); print(map.get(new byte[] {2, 2, 3, 4, 5, 6, 7, 8,})); print(map.get(new byte[] {3, 2, 3, 4, 5, 6, 7, 8,})); print(map.get(new byte[] {4, 2, 3, 4, 5, 6, 7, 8,})); print(map.get(new byte[] {5, 2, 3, 4, 5, 6, 7, 8,})); } private Map storage = new LinkedHashMap() { protected boolean removeEldestEntry(Map.Entry eldest) { return size() > SIZE_LIMIT; } }; public byte[] get(byte[] key) { return (byte[]) storage.get(toLong(key)); } public byte[] remove(byte[] key) { return (byte[]) storage.remove(toLong(key)); } public byte[] put(byte[] key, byte[] value) { return (byte[]) storage.put(toLong(key), value); } private static Long toLong(byte[] a) { long result = 0L; for (int i = 0; i < a.length; i++) { result <<= 8; result |= a[i]; } return Long.valueOf(result); } private static void print(byte[] a) { if (a==null) { System.out.println("null"); return; } for (int i = 0; i < a.length; i++) { System.out.print(a[i] + ", "); } System.out.println(); } }no subject
private static Long toLong(byte[] a) { long result = 0L; for (int i = a.length; --i >= 0;) { result <<= 8; result |= a[i]; } return Long.valueOf(result); }будет чуток быстрее, а порядок байтов тебе тут всё равно не важен.
no subject
map.put(new byte[] {-128, -128, 0, 0, 0, 0, 0, 0,}, new byte[] {0, 0, 0, 0, 0, 0,});
map.put(new byte[] {96, -128, 0, 0, 0, 0, 0, 0,}, new byte[] {32, 0, 0, 0, 0, 0,});
print(map.get(new byte[] {-128, -128, 0, 0, 0, 0, 0, 0,}));
Результат — 32, 0, 0, 0, 0, 0. :(
Что я делаю не так?
no subject
private static Long toLong(byte[] a) { long result = 0L; for (int i = 0; i < a.length; i++) { result <<= 8; result |= (0xffL & a[i]); } return Long.valueOf(result); }Дело в том, что
result |= a[i];эквивалентноresult = result | a[i];, а это значит, чтоa[i]будет приведено кlong. Посколькуbyteв Java signed, то -1 в конце массива угробит весь наш ключ.