Java 将long转换为“;字节数组ed";文本,无堆分配

Java 将long转换为“;字节数组ed";文本,无堆分配,java,arrays,string,garbage-collection,long-integer,Java,Arrays,String,Garbage Collection,Long Integer,我想将一个(正的)原语long转换成Java中文本形式的byte[] 例如,一个简单的方法是:123=>“123”=>[49,50,51] 然而,将long转换为String堆会分配一个String,我正试图为我的无GC库避免这种情况。我宁愿直接在预先分配的字节数组上呈现它 因此,我的问题是如何直接从long转换为byte[]表示,如果我使用字符串构造函数调用它(在上面的示例中),它将给出“123”。为了澄清这一点,我不打算将long编码为二进制形式的字节[],而是以文本形式 谢谢! N这个简单

我想将一个(正的)原语long转换成Java中文本形式的
byte[]

例如,一个简单的方法是:
123=>“123”=>[49,50,51]

然而,将long转换为
String
堆会分配一个
String
,我正试图为我的无GC库避免这种情况。我宁愿直接在预先分配的字节数组上呈现它

因此,我的问题是如何直接从long转换为
byte[]
表示,如果我使用字符串构造函数调用它(在上面的示例中),它将给出“123”。为了澄清这一点,我不打算将long编码为二进制形式的
字节[]
,而是以文本形式

谢谢! N

这个简单的程序:

long l = 123;
int size = (int)(Math.log10(l)+1);
byte[] array = new byte[size];
for (int i = 0; i < size; i++) {
    long temp = (long) Math.pow(10, size - i - 1);
    array[i] = (byte) ((l / temp) + 48);
    l = l % temp;
}
System.out.println(Arrays.toString(array)); // [49, 50, 51]
输出:

1406485727149
[49, 52, 48, 54, 52, 56, 53, 55, 50, 55, 49, 52, 57]

就我所知,这是不可能的

public class Test {

    public static void main(String[] args) {
        byte [] result = new byte[6];
        convert( 123456, result );
        System.out.println( new String( result ) );
    }

    public static void convert( long n, byte [] array ) {
        for (int i = size( n ) - 1; i >= 0; --i) {
            array[i] = (byte)(n % 10 + '0');
            n = n / 10;
        }
    }

    public static int size( long n ) {
        int ret = 0;
        while (n > 0) {
            ret++;
            n /= 10;
        }
        return ret;
    }

}
请注意,这只适用于正数,不检查数组是否足够大以容纳该数字,您应该在实际代码中同时执行这两项操作。它也不能处理
n=0
的简单情况


通过将数组前后填充,然后将其翻转,可以避免使用
size()
方法,但我不太确定这是否会为您带来性能方面的好处,读起来会是一场噩梦。

如果不使用byte[]或Math.pow和Math.log来编写它,您可以执行以下操作,因为它们非常昂贵

public static void toStream(OutputStream os, long l) throws IOException {
    toStream0(os, l / 10);
    os.write((int) ('0' + l % 10));
}

private static void toStream0(OutputStream os, long l) throws IOException {
    if (l == 0) return;
    toStream0(os, l / 10);
    os.write((int) ('0' + l % 10));
}

toStream(System.out, System.currentTimeMillis());
印刷品

1406486588664
如果要向ByteBuffer写入,请使用
put(
或StringBuilder使用
append((char)

你可以考虑更大的碱基,使这个数更小。

base 36: hy4p6ugr
base 16: 147791288bb
base 10: 1406485563579

我想这就是你想要的(?):


您可以将
字节[]
预先分配到最长的长度(最长长度为20个字符),然后将长字符串转换为该数组


当然,如果你不想在数字17上浪费20个字符,你可以快速计算出长字符的数量(看看它是否大于10^18,然后如果它大于10^18,等等……你可以对数字进行二进制搜索)。

这不是OP要求的。此外,使用
Math.pow()
找到10的幂并不是最好的主意,即使它有效。
int size=(int)l%10;
这是错误的。它只适用于以n结尾的n位数字。@Eran不,我已经测试了1234、12345、123456、1234567等,并按预期工作。看起来对您测试的输入很好,我尝试了长的l=System.currentTimeMillis(),因为我的用例是用这种方法存储时间戳,而且它似乎还没有正确地编码它@user3218114试试1230。1234可以工作,因为它有4个数字,以4结尾。这是一个很好的问题。哪个字符集?比如说,它与我的用例无关ASCII@SotiriosDelimanolis没有太多的字符集不将数字
0…9
映射到代码
48…57
@biziclop当然。但是使用更多b每个字符需要一个更大的
字节[]
。对吗?我疯了吗?或者字符集在这里不是特别重要吗?你会用这个
字节[]做什么
?将其写入文件?您是否将其他内容写入该文件?您将如何读取它?我相信OP希望避免创建任何对象。您是否可以在不使用
new
(或不使用的方法)的情况下写入此内容@PeterLawrey
缓冲区可以通过静态和重复使用来避免
新建
。字符串不可能避免
新建
,因为它们是不可变的。您不需要创建字符串来将字节[]写入输出流;)@PeterLawrey这个问题的字面意思是“如果我用字符串构造函数调用它(在上面的例子中)会得到”123“。我演示了如何做到这一点。+1感谢outputstream方法和对基本编码节省的解释@对于StringBuilder,您可以使用
append((char)…
,对于ByteBuffer,您可以使用
put(…
)而不是
write(…
),使用递归也很好。
base 36: hy4p6ugr
base 16: 147791288bb
base 10: 1406485563579
static int toChars(long num, byte[] buffer) {
    if (num < 0) throw new IllegalArgumentException();
    int length = 0;
    do {
        buffer[length++] = (byte)(num % 10 + '0');
    } while ((num /= 10) != 0);
    for (int i = 0, mid = length >> 1, j = length - 1; i < mid; i++, j--) {
        byte tmp = buffer[i];
        buffer[i] = buffer[j];
        buffer[j] = tmp;
    }
    return length;
}
byte[] buffer = new byte[19]; // 19 = enough for everything up to Long.MAX_VALUE

int length = toChars(51239827493284L, buffer);

System.out.println(new String(buffer, 0, length,
    java.nio.charset.StandardCharsets.US_ASCII));