如何在Java中将CharSequence转换为UTF-8编码的字节数组?

Ian*_*oyd 0 java

我正在尝试将 a 转换CharSequence为 UTF-8 编码的byte[]数组。

我一直遇到问题,所以我打算向 stackoverflow 寻求帮助。我打算写一个Java Fiddle来做到这一点:

https://www.mycompiler.io/view/3MliN0HgwDD

除了小提琴本身不起作用:

import java.util.*;
import java.lang.*;
import java.io.*;
import java.nio.*;
import java.nio.charset;

// The main method must be in a class named "Main".
class Main {
    public static byte[] charSequenceToUtf8(final CharSequence input)
    {
        //char[] chars = new char[input.length];
        //for (int i=0; i<input.length; i++)
        //  chars[i] = input.charAt(i);

        CharBuffer charBuffer = CharBuffer.wrap(input);
        checkEquals(10, charBuffer.length(), "Charbuffer is wrong length");

        Charset cs = Charset.forName("UTF-8"); 
        ByteBuffer byteBuffer = cs.encode(charBuffer);
        checkEquals(10, byteBuffer.length(), "byteBuffer is wrong length");
        
        byte[] utf8 = byteBuffer.array();        
        checkEquals(10, utf8.length, "utf8 bytes is wrong length");
    }
    
    public static void checkEquals(int expected, int actual, String message)
    {
        if (expected == actual)
            return;
            
        String sExpected = String.valueOf(expected);
        String sActual = String.valueOf(actual);
        
        throw new Exception("Test failed. Expected "+sExpected+", Actual "+sActual+". "+message);
    }
    
    public static void main(String[] args) {
        test("AAAAAAAAAA"); //ten A's
    }
}
Run Code Online (Sandbox Code Playgroud)

看来java.nio至少需要 Java 7 ref。这就是为什么它在 Java 16 中不起作用让我感到困惑:

在此输入图像描述

所以这带来了很多问题:

  • 我怎样才能将a转换CharSequencebyte[]数组?1
  • 为什么它在 Java 16 中不起作用?

最后,实际的错误是尝试对字符串进行编码AAAAAAAAA会返回一个 11 元素的数组:

字符序列 UTF-8 字节数组
“AA” [65, 65]
“AAA” [65, 65, 65]
“啊啊” [65, 65, 65, 65]
“啊啊啊” [65, 65, 65, 65, 65]
“啊啊啊” [65, 65, 65, 65, 65, 65]
“啊啊啊” [65, 65, 65, 65, 65, 65, 65]
“啊啊啊啊” [65, 65, 65, 65, 65, 65, 65, 65]
“啊啊啊啊” [65, 65, 65, 65, 65, 65, 65, 65, 65]
“啊啊啊啊” [65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 0]

为什么我从链接问题中窃取的上述代码未能包含 10 个字符的字符串?

Sla*_*law 7

首先,请注意,如果您有String,那么您可以简单地执行以下操作:

byte[] bytes = theString.getBytes(StandardCharsets.UTF_8);
Run Code Online (Sandbox Code Playgroud)

或者,即使您有CharSequence,您也可以执行以下操作:

byte[] bytes = theCharSequence.toString().getBytes(StandardCharsets.UTF_8);
Run Code Online (Sandbox Code Playgroud)

如果它还不是,则可能会创建 的副本String 尽管它应该很快被垃圾收集。CharSequenceString

但关于你的问题,你没有考虑ByteBuffer's limit(或position,尽管0在这种情况下)。无论出于何种原因,编码"AAAAAAAAAA"都会产生一个容量11,但限制为的缓冲区10。但该#array()方法会返回整个后备数组,而不管缓冲区的位置或限制如何。这意味着您在将 转换ByteBufferbyte[].

例如:

import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;

public class Main {

  public static void main(String[] args) throws Exception {
    for (int i = 1; i <= 10; i++) {
      String string = "A".repeat(i);

      CharBuffer chars = CharBuffer.wrap(string);
      ByteBuffer bytes = StandardCharsets.UTF_8.encode(chars);

      System.out.printf("%-10s | %s%n", string, Arrays.toString(toByteArray(bytes)));
    }
  }

  public static byte[] toByteArray(ByteBuffer buffer) {
    byte[] array = new byte[buffer.remaining()];
    buffer.get(buffer.position(), array);
    return array;
  }
}
Run Code Online (Sandbox Code Playgroud)

这将输出:

A          | [65]
AA         | [65, 65]
AAA        | [65, 65, 65]
AAAA       | [65, 65, 65, 65]
AAAAA      | [65, 65, 65, 65, 65]
AAAAAA     | [65, 65, 65, 65, 65, 65]
AAAAAAA    | [65, 65, 65, 65, 65, 65, 65]
AAAAAAAA   | [65, 65, 65, 65, 65, 65, 65, 65]
AAAAAAAAA  | [65, 65, 65, 65, 65, 65, 65, 65, 65]
AAAAAAAAAA | [65, 65, 65, 65, 65, 65, 65, 65, 65, 65]
Run Code Online (Sandbox Code Playgroud)

请注意,上面的示例复制了缓冲区后备数组的一个区域,尽管原始区域ByteBuffer应该很快被垃圾回收。我能想到的避免复制支持数组的唯一方法是调整您的代码以直接使用ByteBuffer(如果您只返回支持数组,则会丢失位置/限制信息)。或者我想你可以创建一个包装类。