Byte của một chuỗi trong Java


179

Trong Java, nếu tôi có Chuỗi x, làm cách nào tôi có thể tính được số byte trong chuỗi đó?


15
Người ta có thể muốn sử dụng Chuỗi để thể hiện phần thân của phản hồi HTTP và sử dụng kích thước để đặt tiêu đề "Độ dài nội dung", được chỉ định trong octet / byte không phải là ký tự. w3.org/Prot Protocol / rfc2616 / rfc2616
iX3

4
Một cột cơ sở dữ liệu có thể có giới hạn độ dài tính bằng byte, ví dụ VARCHAR2 (4000 BYTE) trong Oracle. Người ta có thể muốn biết số byte của một Chuỗi trong mã hóa mong muốn để biết Chuỗi có phù hợp hay không.
Somu

@ iX3 Chính xác giống như tôi đang cố gắng làm.
MC Hoàng đế

1
Tôi tin rằng có hai cách giải thích cho câu hỏi này, tùy thuộc vào ý định: Một là "Chuỗi của tôi sử dụng bao nhiêu bộ nhớ?". Câu trả lời được cung cấp bởi @roozbeh bên dưới (có thể là các phép trừ VM modulo như OOPS đã nén). Mặt khác là, "nếu tôi chuyển đổi chuỗi thành byte [] thì mảng byte đó sẽ sử dụng bao nhiêu bộ nhớ?". Đây là câu hỏi được trả lời bởi Andrzej Doyle. Sự khác biệt có thể lớn: "Hello World" trong UTF8 là 11 byte, nhưng Chuỗi (per @roozbeh) là 50 byte (nếu toán của tôi đúng).
L. Blanc

Tôi nên nói thêm rằng 11 byte không bao gồm chi phí chung của đối tượng byte [] chứa chúng, do đó việc so sánh có phần sai lệch.
L. Blanc

Câu trả lời:


289

Chuỗi là danh sách các ký tự (tức là các điểm mã). Số lượng byte được lấy để thể hiện chuỗi phụ thuộc hoàn toàn vào mã hóa mà bạn sử dụng để biến nó thành byte .

Điều đó nói rằng, bạn có thể biến chuỗi thành một mảng byte và sau đó xem kích thước của nó như sau:

// The input string for this test
final String string = "Hello World";

// Check length, in characters
System.out.println(string.length()); // prints "11"

// Check encoded sizes
final byte[] utf8Bytes = string.getBytes("UTF-8");
System.out.println(utf8Bytes.length); // prints "11"

final byte[] utf16Bytes= string.getBytes("UTF-16");
System.out.println(utf16Bytes.length); // prints "24"

final byte[] utf32Bytes = string.getBytes("UTF-32");
System.out.println(utf32Bytes.length); // prints "44"

final byte[] isoBytes = string.getBytes("ISO-8859-1");
System.out.println(isoBytes.length); // prints "11"

final byte[] winBytes = string.getBytes("CP1252");
System.out.println(winBytes.length); // prints "11"

Vì vậy, bạn thấy, ngay cả một chuỗi "ASCII" đơn giản cũng có thể có số byte khác nhau trong biểu diễn của nó, tùy thuộc vào mã hóa nào được sử dụng. Sử dụng bất kỳ bộ ký tự nào bạn quan tâm cho trường hợp của mình, làm đối số getBytes(). Và đừng rơi vào cái bẫy giả định rằng UTF-8 đại diện cho mỗi ký tự dưới dạng một byte, vì điều đó cũng không đúng:

final String interesting = "\uF93D\uF936\uF949\uF942"; // Chinese ideograms

// Check length, in characters
System.out.println(interesting.length()); // prints "4"

// Check encoded sizes
final byte[] utf8Bytes = interesting.getBytes("UTF-8");
System.out.println(utf8Bytes.length); // prints "12"

final byte[] utf16Bytes= interesting.getBytes("UTF-16");
System.out.println(utf16Bytes.length); // prints "10"

final byte[] utf32Bytes = interesting.getBytes("UTF-32");
System.out.println(utf32Bytes.length); // prints "16"

final byte[] isoBytes = interesting.getBytes("ISO-8859-1");
System.out.println(isoBytes.length); // prints "4" (probably encoded "????")

final byte[] winBytes = interesting.getBytes("CP1252");
System.out.println(winBytes.length); // prints "4" (probably encoded "????")

(Lưu ý rằng nếu bạn không cung cấp đối số bộ ký tự, bộ ký tự mặc định của nền tảng sẽ được sử dụng. Điều này có thể hữu ích trong một số ngữ cảnh, nhưng nói chung, bạn nên tránh tùy thuộc vào mặc định và luôn sử dụng bộ ký tự rõ ràng khi mã hóa / cần giải mã.)


1
vì vậy một lần nữa nếu tôi sử dụng getBytes (). Nó sẽ cho tôi độ dài giống như x.length tôi sai vì tôi không chắc chắn
Green

4
@Green Ash Độ dài của mảng byte - getBytes () - và x.length CÓ THỂ bằng nhau nhưng không được đảm bảo là như vậy. Nó sẽ bằng nhau nếu tất cả các ký tự được đại diện bởi một byte mỗi. Điều này sẽ luôn đúng với các mã hóa ký tự sử dụng một byte cho mỗi ký tự (hoặc ít hơn), chẳng hạn như ISO-8859-1. UTF-8 sử dụng 1 hoặc 2 byte, do đó, nó phụ thuộc vào các ký tự chính xác trong chuỗi. Sau đó, có các bảng mã ký tự luôn sử dụng hai byte cho mỗi ký tự.
Kris

Tôi thích câu trả lời của bạn :), vì vậy họ có thể giống nhau nhưng không phải lúc nào tôi cũng đúng? ok thì có ổn không khi sử dụng phương thức mà không có tham số vì nó gây ra lỗi cho tôi !!
Xanh

@Green điểm là số byte không phải lúc nào cũng giống với số lượng ký tự . Số lượng byte phụ thuộc vào mã hóa ký tự được sử dụng. Bạn sẽ phải biết mã hóa ký tự nào bạn sẽ sử dụng và tính đến điều đó. lỗi gì bạn nhận được? Nếu bạn chỉ sử dụng getBytes()nó sẽ sử dụng mã hóa ký tự mặc định của hệ thống của bạn.
Jesper

1
@KorayTugay Có, nhiều hay ít. Bạn có thể tranh luận về thứ tự nguyên nhân và kết quả, mặc dù. Tôi muốn nói rõ hơn rằng char luôn có 2 byte vì đây là kiểu dữ liệu nguyên thủy được xác định là rộng 2 byte. (Và rằng đại diện UTF-16 chủ yếu là hậu quả của việc này, chứ không phải là cách khác.)
Andrzej Doyle

63

Nếu bạn đang chạy với các tham chiếu 64 bit:

sizeof(string) = 
8 + // object header used by the VM
8 + // 64-bit reference to char array (value)
8 + string.length() * 2 + // character array itself (object header + 16-bit chars)
4 + // offset integer
4 + // count integer
4 + // cached hash code

Nói cách khác:

sizeof(string) = 36 + string.length() * 2

Trên máy ảo 32 bit hoặc máy ảo 64 bit có OOP được nén (-XX: + UseCompressionOops), các tham chiếu có 4 byte. Vì vậy, tổng số sẽ là:

sizeof(string) = 32 + string.length() * 2

Điều này không tính đến các tham chiếu đến đối tượng chuỗi.


6
Tôi đã giả sử câu hỏi là về số lượng byte được phân bổ trong bộ nhớ cho một đối tượng String. Nếu câu hỏi là về số lượng byte cần thiết để tuần tự hóa Chuỗi, như những người khác đã chỉ ra, thì nó phụ thuộc vào mã hóa được sử dụng.
roozbeh

2
Nguồn cho câu trả lời của bạn? Cảm ơn
mavis

1
Lưu ý: sizeofnên là bội số của 8.
ăn kiêng

19

Câu trả lời mang tính mô phạm (mặc dù không nhất thiết là câu trả lời hữu ích nhất, tùy thuộc vào kết quả bạn muốn làm với kết quả) là:

string.length() * 2

Các chuỗi Java được lưu trữ vật lý trong UTF-16BEmã hóa, sử dụng 2 byte cho mỗi đơn vị mã và String.length()đo độ dài tính theo đơn vị mã UTF-16, do đó, điều này tương đương với:

final byte[] utf16Bytes= string.getBytes("UTF-16BE");
System.out.println(utf16Bytes.length);

Và điều này sẽ cho bạn biết kích thước của charmảng bên trong , tính bằng byte .

Lưu ý: "UTF-16"sẽ cho kết quả khác "UTF-16BE"với mã hóa trước sẽ chèn BOM , thêm 2 byte vào chiều dài của mảng.


Câu trả lời của Roozbeh là tốt hơn, bởi vì nó cũng tính đến các byte khác.
Lodewijk Bogaards 30/03/18

@finnw Bạn có chắc rằng mã hóa là UTF-16BE chứ không phải UTF-16? Theo lớp Chuỗi Javadoc ( docs.oracle.com/javase/6/docs/api/java/lang/String.html ), "Chuỗi đại diện cho một chuỗi ở định dạng UTF-16 ...".
entpnerd

17

Theo Cách chuyển đổi Chuỗi sang và từ mảng byte UTF8 trong Java :

String s = "some text here";
byte[] b = s.getBytes("UTF-8");
System.out.println(b.length);

nhưng xin lỗi khi tôi biên dịch mã của bạn, nó sẽ báo lỗi; bởi vì tham số "UTF-8". Bất cứ khi nào tôi vượt qua một tham số trống, nó sẽ cho tôi độ dài giống như x.length. Tôi hiểu sai khái niệm. xin vui lòng giúp đỡ
Green

@Green Ash, bạn có phiên bản Java nào?
Buhake Sindi

@Green Ash, bạn nhận được ngoại lệ gì?
Buhake Sindi

2
để rõ ràng đây là đầu ra: test.java:11: ngoại lệ không được báo cáo java.io.UnsupportedEncodingException; phải được bắt hoặc khai báo để được ném byte [] b = s.getBytes ("UTF-8"); ^ 1 lỗi Quá trình hoàn tất.
xanh

3
@Green, thử : s.getBytes(Charset.forName("UTF-8")).
james.garriss

10

Một Stringthể hiện phân bổ một lượng byte nhất định trong bộ nhớ. Có lẽ bạn đang xem một cái gì đó giống như sizeof("Hello World")sẽ trả về số byte được phân bổ bởi chính cơ sở hạ tầng?

Trong Java, thường không cần sizeofhàm, vì chúng ta không bao giờ phân bổ bộ nhớ để lưu trữ cấu trúc dữ liệu. Chúng ta có thể xem String.javatệp để ước tính sơ bộ và chúng ta thấy một số 'int', một số tài liệu tham khảo và a char[]. Đặc tả ngôn ngữ Java định nghĩa, một charphạm vi từ 0 đến 65535, vì vậy hai byte là đủ để giữ một char trong bộ nhớ. Nhưng một JVM không phải lưu trữ một char trong 2 byte, nó chỉ phải đảm bảo rằng việc triển khai charcó thể giữ các giá trị của phạm vi xác định.

Vì vậy, sizeofthực sự không có ý nghĩa gì trong Java. Nhưng, giả sử rằng chúng ta có một Chuỗi lớn và một charphân bổ hai byte, thì dấu chân bộ nhớ của một Stringđối tượng ít nhất là 2 * str.length()bằng byte.


7

Có một phương thức gọi là getBytes () . Sử dụng nó một cách rộng rãi .


17
Wisely = không sử dụng thông số không có tham số bộ ký tự.
Thilo

Tại sao? Đây có phải là vấn đề nếu tôi định cấu hình môi trường của mình để chạy với mã hóa UTF8 không?
ngoằn ngoèo

1
getBytes cũng sẽ tạo và sao chép mảng byte, vì vậy nếu bạn đang nói các chuỗi dài, thao tác này có thể tốn kém.
ticktock

@ticktock, nếu bạn vẫn ở đây, vâng, nhưng sự thay thế là gì? Tôi đến đây với hy vọng chức năng thư viện trả lại dung lượng cần thiết để tôi có thể kết hợp nó thành một phân bổ lớn hơn.
Bộ cảm biến

4

Thử cái này :

Bytes.toBytes(x).length

Giả sử bạn đã khai báo và khởi tạo x trước


3
Đây có phải là một phần của thư viện Java tiêu chuẩn không? Tôi không thể tìm thấy Byteslớp học.
Kröw

0

Để tránh bị bắt, hãy sử dụng:

String s = "some text here";
byte[] b = s.getBytes(StandardCharsets.UTF_8);
System.out.println(b.length);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.