2016-12-08 30 views
46

mam dwa różne ciągi znaków, ale po parsowania UUID to wydają się być takie sameUUID to samo z różnych ciągów

public static void main(String[] args) { 
    try { 
     UUID t1 = UUID.fromString("38e1036d-7527-42a3-98ca-f2f19d3155db"); 
     UUID t2 = UUID.fromString("123438e1036d-7527-42a3-98ca-f2f19d3155db"); 
     System.out.println(t1.toString().equals(t2.toString())); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
} 

Każdy pomysł dlaczego tak jest?

+6

Jakie wyjście otrzymujesz? Jakiej wydajności oczekujesz? Co się stanie, jeśli wydrukujesz dwa wyniki zamiast ich porównywać? –

+6

Może dlatego, że numery UUID są dokładnie takie same, z wyjątkiem "1234" na początku? Co się stanie, jeśli zmienisz resztę UUID zamiast dodawać 4 cyfry na początku? – n247s

+6

Brzmi jak błąd. Powinien zawierać wyjątek informujący, że nie jest to prawidłowy identyfikator UUID. – immibis

Odpowiedz

67

"123438e1036d-7527-42a3-98ca-f2f19d3155db"

To nie jest UUID. Jest to połączony ciąg "1234" i UUID. Problem polega na tym, że parser powinien był ci o tym powiedzieć, rzucając wyjątek. Zamiast tego dokłada wszelkich starań, aby znaleźć tam ukryty UUID.

Po wyodrębnieniu identyfikatora UUID z połączonego ciągu jest to identyczne z pierwszym identyfikatorem UUID, który jest prawidłowym wynikiem, który obserwujesz.

Możemy analizować parsera (dzięki @ tim-Biegeleisen za dostarczanie link):

public static UUID fromString(String name) { 
    String[] components = name.split("-"); 
    if (components.length != 5) 
     throw new IllegalArgumentException("Invalid UUID string: "+name); 
    for (int i=0; i<5; i++) 
     components[i] = "0x"+components[i]; 

    long mostSigBits = Long.decode(components[0]).longValue(); 
    mostSigBits <<= 16; 
    mostSigBits |= Long.decode(components[1]).longValue(); 
    mostSigBits <<= 16; 
    mostSigBits |= Long.decode(components[2]).longValue(); 

    long leastSigBits = Long.decode(components[3]).longValue(); 
    leastSigBits <<= 48; 
    leastSigBits |= Long.decode(components[4]).longValue(); 

    return new UUID(mostSigBits, leastSigBits); 
} 

Jak widzimy, nie ma walidacji oprócz liczenia liczby grup ograniczonych myślnikami. Po prostu bierze te grupy, a następnie przesuwa je na pozycje. Dodałeś dodatkowe postacie przed pierwszą grupą, która jest najważniejszą częścią. Najpierw jest on przetwarzany i zapisywany, a następnie przesuwa się w górę i ponownie, aż zajmie najważniejszą część. Teraz wszystkie bity, które były dalej niż założono, zostają wypchnięte z limitu long, dlatego są całkowicie ignorowane.

+1

Prawdopodobnie błąd w kodzie parsera. – Raedwald

+1

@Raedwald Cóż, sprawdzanie poprawności domyślnie jest bardziej kwestią konwencji. Nie znam Javy wystarczająco dobrze, by powiedzieć, czym jest konwencja. –

54

A UUID przechowuje dane 128 bits. Jeśli dasz mu więcej, nie może ich zapisać. Jestem zaskoczony, że nie daje ci błędu, ale nie jest zaskoczony, że w przeciwnym razie obcina wyższe bity.

int i = 0x38e1036d; 
int j = (int) 0x123438e1036dL; 
i == j; 
+7

Dla każdego, kto chce zobaczyć, co faktycznie robi kod źródłowy: http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/UUID.java # UUID.fromString% 28java.lang.String% 29 –

+1

został obcięty, ale wydawał się, gdy 'MostSigBits' lub 'minimumSigBits' jest większy niż 64bity – Jerry06

+1

Złożyłbym na to błąd. Domyślam się, dlaczego tak się stało, że być może zamierzali pozwolić, aby każda sekcja UUID była * krótsza *, aby początkowe zera nie były wymagane? Nie wiem. – jpmc26

9

Bit przesunięcie drugiego składnika „7527” usuwa efekt zmian wprowadzonych w pierwszej części „123438e1036d”, który powoduje ten sam UUID generowane.

Samo przetwarzanie pierwszego składnika jest inne, ale efekt ten jest tracony, gdy drugi komponent uuid jest przesunięty.

4

Jest tak, ponieważ sprawdza od prawej do lewej i przyjmuje tylko 32 znaki jako UUID oraz usuwa inne. po podjęciu 32 znaków, nie dba o innych, ponieważ implementuje interfejs Serializable.

public final class UUID 
    extends Object 
    implements Serializable, Comparable<UUID> 

1234 jest przycięty od Ciebie 2. UUID.

Oto jego kod, pomaga znacznie lepiej

public static UUID More ...fromString(String name) { 
    String[] components = name.split("-"); 
    if (components.length != 5) 
     throw new IllegalArgumentException("Invalid UUID string: "+name); 
    for (int i=0; i<5; i++) 
     components[i] = "0x"+components[i]; 

    long mostSigBits = Long.decode(components[0]).longValue(); 
    mostSigBits <<= 16; 
    mostSigBits |= Long.decode(components[1]).longValue(); 
    mostSigBits <<= 16; 
    mostSigBits |= Long.decode(components[2]).longValue(); 

    long leastSigBits = Long.decode(components[3]).longValue(); 
    leastSigBits <<= 48; 
    leastSigBits |= Long.decode(components[4]).longValue(); 

    return new UUID(mostSigBits, leastSigBits); 
    } 
+0

Jeśli idzie "od lewej do prawej" i "bierze tylko 32 znaki", to '55db' będzie częścią ignorowaną. Ale to nie jest .... –

4

To jest znany błąd w Javie 8, poinformował w czerwcu 2016: http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8159339

Zobacz także http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8165199 (zgłaszane w sierpniu 2016):

4d4d8f3b-3b81-44f3-968d-d1c1a48b4ac8 jest prawidłowym identyfikatorem UUID.

4d4d8f-3b3b81-44f3-968d-d1c1a48b4ac8 nie jest (przeniosła pierwszą kresek dwa znaki w lewo)

Wywołanie UUID :: fromString() z nieprawidłowymi wynikami w jednym UUID reprezentujących 004d4dbf-3b81- 44f3-968d-d1c1a48b4ac8.