Bytes dari sebuah string di Java

179

Di Jawa, jika saya memiliki sebuah String x, bagaimana saya bisa menghitung jumlah byte dalam string itu?

hijau
sumber
15
Seseorang mungkin ingin menggunakan sebuah String untuk mewakili isi respons HTTP dan menggunakan ukuran untuk mengatur header "Content-Length", yang ditentukan dalam oktet / byte bukan karakter. w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.13
iX3
4
Kolom basis data mungkin memiliki batasan panjang dalam byte, misalnya VARCHAR2 (4000 BYTE) di Oracle. Orang mungkin ingin mengetahui jumlah byte suatu String dalam pengkodean yang diinginkan untuk mengetahui apakah String tersebut cocok.
Somu
@ iX3 Persis sama dengan yang saya coba lakukan.
MC Emperor
1
Saya percaya ada dua kemungkinan interpretasi dari pertanyaan ini, tergantung pada tujuannya: Yang pertama adalah "berapa banyak memori yang digunakan oleh String saya?". Jawabannya disediakan oleh @roozbeh di bawah ini (mungkin modulo VM subtleties seperti OOPS terkompresi). Yang lain adalah, "jika saya mengonversi string ke byte [] berapa banyak memori yang akan digunakan array byte itu?". Ini adalah pertanyaan yang dijawab oleh Andrzej Doyle. Perbedaannya bisa besar: "Hello World" di UTF8 adalah 11 byte, tetapi String (per @roozbeh) adalah 50 byte (jika matematika saya benar).
L. Blanc
Saya seharusnya menambahkan bahwa 11 byte tidak termasuk overhead dari objek byte [] yang menampungnya, jadi perbandingannya agak menyesatkan.
L. Blanc

Jawaban:

289

String adalah daftar karakter (yaitu titik kode). Jumlah byte yang diambil untuk mewakili string sepenuhnya tergantung pada pengkodean yang Anda gunakan untuk mengubahnya menjadi byte .

Yang mengatakan, Anda dapat mengubah string menjadi array byte dan kemudian lihat ukurannya sebagai berikut:

// 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"

Jadi Anda lihat, bahkan string "ASCII" yang sederhana dapat memiliki jumlah byte yang berbeda dalam representasinya, tergantung pada pengkodean mana yang digunakan. Gunakan set karakter apa pun yang Anda minati untuk kasus Anda, sebagai argumen untuk getBytes(). Dan jangan terjebak dalam anggapan bahwa UTF-8 mewakili setiap karakter sebagai satu byte, karena itu juga tidak benar:

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 "????")

(Perhatikan bahwa jika Anda tidak memberikan argumen set karakter, set karakter default platform digunakan. Ini mungkin berguna dalam beberapa konteks, tetapi secara umum Anda harus menghindari bergantung pada default, dan selalu menggunakan set karakter eksplisit ketika meng-encode / diperlukan decoding.)

Andrzej Doyle
sumber
1
jadi sekali lagi jika saya menggunakan getBytes (). Ini akan memberi saya panjangnya sama dengan x.length saya salah karena saya tidak yakin
Green
4
@ Green Ash Panjang array byte - getBytes () - dan x.length MUNGKIN sama tetapi tidak dijamin begitu. Itu akan sama jika semua karakter diwakili oleh masing-masing satu byte. Ini akan selalu berlaku untuk pengkodean karakter yang menggunakan byte tunggal per karakter (atau kurang), seperti ISO-8859-1. UTF-8 menggunakan 1 atau 2 byte, jadi itu tergantung pada karakter yang tepat dalam string. Lalu ada pengkodean karakter yang selalu menggunakan dua byte per karakter.
Kris
Saya suka jawaban Anda :), jadi mereka mungkin sama tapi tidak selalu saya benar? ok maka apakah boleh menggunakan metode tanpa parameter karena itu menyebabkan saya kesalahan !!
Green
G Hijau intinya adalah bahwa jumlah byte tidak selalu sama dengan jumlah karakter . Jumlah byte tergantung pada pengkodean karakter yang digunakan. Anda harus mengetahui pengkodean karakter mana yang akan Anda gunakan dan memperhitungkannya. Kesalahan apa yang Anda dapatkan? Jika Anda hanya menggunakannya getBytes()akan menggunakan pengkodean karakter default sistem Anda.
Jesper
1
@ KorayTugay Ya, kurang lebih. Anda bisa berdebat tentang urutan sebab dan akibat. Saya akan lebih cenderung menyatakan bahwa char selalu 2 byte karena ini adalah tipe data primitif yang didefinisikan sebagai lebar 2 byte. (Dan bahwa perwakilan UTF-16 terutama merupakan konsekuensi dari ini, daripada sebaliknya).
Andrzej Doyle
63

Jika Anda menjalankan dengan referensi 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

Dengan kata lain:

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

Pada VM 32-bit atau VM 64-bit dengan OOP terkompresi (-XX: + UseCompressedOops), referensi adalah 4 byte. Jadi totalnya adalah:

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

Ini tidak memperhitungkan referensi ke objek string.

roozbeh
sumber
6
Saya berasumsi pertanyaannya adalah tentang jumlah byte yang dialokasikan dalam memori untuk objek String. Jika pertanyaannya adalah tentang jumlah byte yang diperlukan untuk membuat serial String, seperti yang telah ditunjukkan orang lain, itu tergantung pada pengkodean yang digunakan.
roozbeh
2
Sumber untuk jawaban Anda? Terima kasih
mavis
1
Catatan: sizeofharus kelipatan 8.
diet
19

Jawaban yang bertele-tele (meskipun tidak selalu yang paling berguna, tergantung pada apa yang ingin Anda lakukan dengan hasilnya) adalah:

string.length() * 2

String Java secara fisik disimpan dalam UTF-16BEencoding, yang menggunakan 2 byte per unit kode, dan String.length()mengukur panjangnya dalam unit kode UTF-16, jadi ini setara dengan:

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

Dan ini akan memberi tahu Anda ukuran chararray internal , dalam byte .

Catatan: "UTF-16"akan memberikan hasil yang berbeda dari "UTF-16BE"pengkodean sebelumnya akan memasukkan BOM , menambahkan 2 byte ke panjang array.

menemukan
sumber
Jawaban Roozbeh lebih baik, karena ia juga memperhitungkan byte lainnya.
Lodewijk Bogaards
@ finnw Apakah Anda yakin enkode adalah UTF-16BE dan bukan UTF-16? Menurut kelas String Javadoc ( docs.oracle.com/javase/6/docs/api/java/lang/String.html ), "String mewakili string dalam format UTF-16 ...".
entpnerd
17

Menurut Cara mengkonversi Strings ke dan dari array byte UTF8 di Jawa :

String s = "some text here";
byte[] b = s.getBytes("UTF-8");
System.out.println(b.length);
Boris Pavlovic
sumber
tapi maafkan saya ketika saya mengkompilasi kode Anda itu memberi saya kesalahan; karena parameter "UTF-8". Di mana ketika saya melewati parameter kosong itu memberi saya panjangnya sama dengan x.length. saya salah paham konsep. tolong tolong
Hijau
@ Green Ash, versi Java apa yang Anda miliki?
Buhake Sindi
@ Green Ash, pengecualian apa yang Anda dapatkan?
Buhake Sindi
2
untuk menjadi jelas ini adalah output: test.java:11: java.io.UnsupportedEncodingException pengecualian tidak dilaporkan; harus ditangkap atau dinyatakan sebagai byte byte [] b = s.getBytes ("UTF-8"); ^ 1 kesalahan proses selesai.
Green
3
@Green, coba: s.getBytes(Charset.forName("UTF-8")).
james.garriss
10

Sebuah Stringinstance mengalokasikan sejumlah byte dalam memori. Mungkin Anda sedang melihat sesuatu seperti sizeof("Hello World")yang akan mengembalikan jumlah byte yang dialokasikan oleh datastructure itu sendiri?

Di Jawa, biasanya tidak perlu sizeoffungsi, karena kami tidak pernah mengalokasikan memori untuk menyimpan struktur data. Kita dapat melihat String.javafile untuk perkiraan kasar, dan kita melihat beberapa 'int', beberapa referensi dan a char[]. The spesifikasi bahasa Jawa mendefinisikan, bahwa charrentang 0-65.535, jadi dua byte yang cukup untuk menjaga satu char di memori. Tetapi JVM tidak harus menyimpan satu char dalam 2 byte, hanya harus menjamin, bahwa implementasi chardapat menyimpan nilai dari range yang didefinisikan.

Jadi sizeofbenar-benar tidak masuk akal di Jawa. Tetapi, dengan asumsi bahwa kita memiliki String besar dan satu charmengalokasikan dua byte, maka jejak memori suatu Stringobjek setidaknya 2 * str.length()dalam byte.

Andreas Dolk
sumber
7

Ada metode yang disebut getBytes () . Gunakan dengan bijak .

Andrei Ciobanu
sumber
17
Wisely = jangan gunakan yang tanpa parameter set karakter.
Thilo
Mengapa? Apakah ini masalah jika saya mengkonfigurasi lingkungan saya untuk berjalan dengan pengkodean UTF8?
ziggy
1
getBytes juga akan membuat dan menyalin array byte, jadi jika Anda berbicara string panjang, operasi ini bisa mahal.
ticktock
@ticktock, jika Anda masih ada, ya tapi apa alternatifnya? Saya sampai di sini berharap fungsi perpustakaan mengembalikan penyimpanan yang dibutuhkan sehingga saya dapat menggabungkannya ke dalam alokasi yang lebih besar.
SensorSmith
4

Coba ini :

Bytes.toBytes(x).length

Dengan asumsi Anda menyatakan dan menginisialisasi x sebelumnya

semut
sumber
3
Apakah ini bagian dari perpustakaan Java standar? Saya tidak dapat menemukan Byteskelasnya.
Kröw
0

Untuk menghindari mencoba menangkap, gunakan:

String s = "some text here";
byte[] b = s.getBytes(StandardCharsets.UTF_8);
System.out.println(b.length);
radu_paun
sumber