22位/32位UUID

32 位 UUID 优化建议

32 位的 UUID,最常见的代码:UUID.randomUUID().toString().replace("-",""),

有野心的程序员,追求极致性能的话,会选择优化这一段代码,

可以使用 Long.toHexString(),只是过程需要注意:1L 的 16 进制数也是1,不满足 32 位的要补0;

22 位 UUID 基本原理

22 位 UUID,就是将 128 位的 2 进制的 UUID 转为 64 进制,实现进制转换函数即可。

源码

/*
 * MIT License
 *
 * Copyright (c) 2019 Mr.css
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 */

package cn.seaboot.commons.core;

import cn.seaboot.commons.digest.Base64;

import java.util.UUID;

/**
 * 设备号
 *
 * @author ChenSS 2018年7月13日 上午11:20:38
 */
public class UUIDUtils {
    private UUIDUtils() {
    }

    /**
     * 生成UUID
     *
     * @return uuid
     */
    public static String genUUID() {
        return UUID.randomUUID().toString();
    }

    /**
     * 生成 32 位 UUID
     *
     * <p>
     * Returns a {@code String} object representing this {@code UUID}.
     *
     * <p> The UUID string representation is as described by this BNF:
     * <blockquote><pre>
     * {@code
     * UUID                   = <time_low><time_mid>
     *                          <time_high_and_version>
     *                          <variant_and_sequence>
     * time_low               = 4*<hexOctet>
     * time_mid               = 2*<hexOctet>
     * time_high_and_version  = 2*<hexOctet>
     * variant_and_sequence   = 2*<hexOctet>
     * node                   = 6*<hexOctet>
     * hexOctet               = <hexDigit><hexDigit>
     * hexDigit               =
     *       "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
     *       | "a" | "b" | "c" | "d" | "e" | "f"
     *       | "A" | "B" | "C" | "D" | "E" | "F"
     * }</pre></blockquote>
     *
     * @return A string representation of this {@code UUID}
     */
    public static String genUUID32() {
        UUID uuid = UUID.randomUUID();
        long mostSigBits = uuid.getMostSignificantBits();
        long leastSigBits = uuid.getLeastSignificantBits();
        return (digits(mostSigBits >> 32) +
                digits(mostSigBits) +
                digits(leastSigBits >> 32) +
                digits(leastSigBits));
    }

    /**
     * 二进制 1 后面跟 32 个 0
     */
    private static final long HI = 1L << (8 * 4);

    /**
     * Returns val represented by the specified number of hex digits.
     */
    private static String digits(long val) {
        long hi = HI;
        return Long.toHexString(hi | (val & (hi - 1))).substring(1);
    }

    /**
     * 生成32位UUID
     * <p>
     * 如果仅用于生成32为UUID,更优的函数是{@link #genUUID32()}
     * <p>
     * 此函数用于{@link UUID#toString()}结果的转换。
     * <p>
     * old version:
     * uuid.substring(0, 8) + uuid.substring(9, 13) + uuid.substring(14, 18) + uuid.substring(19, 23) + uuid.substring(24)
     * <p>
     * 执行效率与历史版本性基本一致,新版代码减少了创建对象的次数。
     *
     * @return uuid
     */
    public static String toUUID32(String uuid) {
        StringBuilder sb = new StringBuilder(32);
        char ch;
        for (int i = 0; i < uuid.length(); i++) {
            ch = uuid.charAt(i);
            if (ch != '-') {
                sb.append(ch);
            }
        }
        return sb.toString();
    }

    /**
     * 生成 22 位 UUID
     * <p>
     * base64 算法:8 位二进制数,转为 1 个字节,128 位正好 16 字节,
     * 16 字节产生 24位 base64 字符串,去除占位 2 个字母,正好 22 位。
     *
     * @return uuid
     */
    public static String base64UUID() {
        UUID uuid = UUID.randomUUID();
        long msb = uuid.getMostSignificantBits();
        long lsb = uuid.getLeastSignificantBits();
        int x;
        byte[] buffer = new byte[16];
        for (int i = 0; i < 8; i++) {
            x = 8 * (7 - i);
            buffer[i] = (byte) (int) (msb >> x);
            buffer[i + 8] = (byte) (int) (lsb >> x);
        }
        return Base64.encodeString(buffer).substring(0, 22);
    }

    /**
     * 生成 22 位 UUID
     * <p>
     * UUID 128位,每 6 位用一个 64 进制字符表示,正好 22 位。
     * 此函数采用的是 64 进制转换,而不是 Base64 编码,因为 128 不能被 6 整除,第 11 位和第 22 位,只能是字母。
     * <p>
     * 将数字转为
     *
     * @return uuid
     */
    public static String genUUID22() {
        UUID uuid = UUID.randomUUID();
        long msb = uuid.getMostSignificantBits();
        long lsb = uuid.getLeastSignificantBits();
        int x;
        char[] buffer = new char[22];
        for (int i = 0; i < 11; i++) {
            x = 6 * (10 - i);
            buffer[i] = digits64((int) (msb >> x));
            buffer[i + 11] = digits64((int) (lsb >> x));
        }
        return new String(buffer);
    }

    /**
     * Returns val represented by the specified number of 64 digits.
     */
    private static char digits64(int val) {
        return CHARS[val & 63];
    }

    /**
     * 生成 8 位 UUID 标识码
     * <p>
     * 作为唯一 ID 使用的时候,很明显,长度不够,必定会出现重复,
     * 但是可以作为 uuid 的标识码使用,类似于数字签名,如果 uuid 被篡改,生成的标识码会发生变化。
     *
     * @param uid 32 位 uuid
     * @return uuid 标识码
     */
    public static String toUUID8(String uid) {
        StringBuilder shortBuffer = new StringBuilder();
        for (int i = 0; i < 8; i++) {
            String str = uid.substring(i * 4, i * 4 + 4);
            int x = Integer.parseInt(str, 16);
            shortBuffer.append(CHARS[x & 61]);
        }
        return shortBuffer.toString();
    }

    private final static char[] CHARS = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
            'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
            'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2',
            '3', '4', '5', '6', '7', '8', '9', '+', '/'};
}
 

posted on 2023-04-24 20:43  疯狂的妞妞  阅读(408)  评论(0编辑  收藏  举报

导航