Kapan sebaiknya kita menggunakan metode intern String on String literals


187

Menurut String # intern () , internmetode seharusnya mengembalikan String dari kolam String jika String ditemukan di kolam String, jika tidak objek string baru akan ditambahkan dalam kolam String dan referensi dari String ini dikembalikan.

Jadi saya mencoba ini:

String s1 = "Rakesh";
String s2 = "Rakesh";
String s3 = "Rakesh".intern();

if ( s1 == s2 ){
    System.out.println("s1 and s2 are same");  // 1.
}

if ( s1 == s3 ){
    System.out.println("s1 and s3 are same" );  // 2.
}

Saya mengharapkan yang s1 and s3 are sameakan dicetak saat s3 diinternir, dan s1 and s2 are sametidak akan dicetak. Tetapi hasilnya adalah: kedua garis dicetak. Jadi itu berarti, secara konstan konstanta String diinternir. Tetapi jika demikian, mengapa kita perlu internmetode ini? Dengan kata lain kapan kita harus menggunakan metode ini?


14
Javadoc yang Anda tautkan juga menyatakan "Semua string literal dan ekspresi konstan bernilai string diinternir."
Jorn


1
bukan duplikat yang tepat ..
Bozho

1
@Jorn: benar. Jadi mengapa kita memiliki internmetode publik. Bukankah seharusnya kita memiliki internmetode pribadi, sehingga tidak ada yang bisa mengaksesnya. Atau adakah tujuan metode ini?
Rakesh Juyal

2
@RakeshJuyal: Metode intern didefinisikan pada tipe string yang bisa berupa string literal atau variabel. Bagaimana Anda magang variabel jika metode itu pribadi?
bobbyalex

Jawaban:


230

Java secara otomatis magang String literal. Ini berarti bahwa dalam banyak kasus, operator == tampaknya berfungsi untuk String dengan cara yang sama seperti yang dilakukannya untuk int atau nilai primitif lainnya.

Karena magang otomatis untuk string literal, intern()metode ini akan digunakan pada Strings yang dibuat dengannew String()

Menggunakan contoh Anda:

String s1 = "Rakesh";
String s2 = "Rakesh";
String s3 = "Rakesh".intern();
String s4 = new String("Rakesh");
String s5 = new String("Rakesh").intern();

if ( s1 == s2 ){
    System.out.println("s1 and s2 are same");  // 1.
}

if ( s1 == s3 ){
    System.out.println("s1 and s3 are same" );  // 2.
}

if ( s1 == s4 ){
    System.out.println("s1 and s4 are same" );  // 3.
}

if ( s1 == s5 ){
    System.out.println("s1 and s5 are same" );  // 4.
}

akan kembali:

s1 and s2 are same
s1 and s3 are same
s1 and s5 are same

Dalam semua kasus selain s4variabel, nilai yang dibuat secara eksplisit menggunakan newoperator dan di mana internmetode tidak digunakan pada hasilnya, itu adalah contoh permanen tunggal yang dikembalikan kumpulan string konstan JVM .

Lihat Teknik Java "String Equality and Interning" untuk informasi lebih lanjut.


Saya berasumsi bahwa Java secara otomatis magang String literal untuk keperluan optimasi. Itu bisa melakukan ini dengan aman hanya karena String tidak berubah, benar?
styfle

Baru ke Jawa (saya dari dunia C # .NET) dan saya terkadang melihat dalam proyek warisan Java "" .intern () jadi jika saya memahaminya dengan benar bahwa ini "omong kosong" juga untuk string kosong.
hfrmobile

4
@Miguel Penjelasan bagus, Pertanyaan saya adalah bagaimana mungkin objek dibuat di sini dalam contoh Anda. Berikut adalah Asumsi Saya: String s1 = "Rakesh"; pertama OB1 OB2 String s4 = new String("Rakesh");kedua Jadi sisa (s2, s3, s5) referensi objek yang sama (OB1) dibuat dalam 'string Pool' Jadi bisa saya katakan .intern()metode yang digunakan untuk mencegah membuat objek baru jika string yang sama tersedia di string poolIf Asumsi saya salah jadi beri saya arahan.
HybrisHelp

1
Tautan JavaTechniques rusak
SJuan76


20

Pada proyek baru-baru ini, beberapa struktur data besar diatur dengan data yang dibaca dari database (dan karenanya bukan konstanta String / literal) tetapi dengan sejumlah besar duplikasi. Itu adalah aplikasi perbankan, dan hal-hal seperti nama-nama perusahaan sederhana (mungkin 100 atau 200) muncul di mana-mana. Struktur data sudah besar, dan jika semua nama perusahaan itu adalah objek unik, mereka akan meluap memori. Sebagai gantinya, semua struktur data memiliki referensi ke objek String 100 atau 200 yang sama, sehingga menghemat banyak ruang.

Keuntungan kecil lain dari String yang diinternir adalah yang ==dapat digunakan (berhasil!) Untuk membandingkan String jika semua string yang terlibat dijamin akan diinternir. Terlepas dari sintaks yang lebih ramping, ini juga merupakan peningkatan kinerja. Tetapi seperti yang telah ditunjukkan oleh orang lain, melakukan hal ini berisiko besar menyebabkan kesalahan pemrograman, jadi ini harus dilakukan hanya sebagai ukuran terakhir dari upaya terakhir.

The downside adalah bahwa menginternir String membutuhkan lebih banyak waktu daripada hanya melemparkannya di heap, dan bahwa ruang untuk Strings diinternir mungkin terbatas, tergantung pada implementasi Java. Paling baik dilakukan ketika Anda berhadapan dengan sejumlah string yang diketahui dengan banyak duplikasi.


@ The downside is that interning a String takes more time than simply throwing it on the heap, and that the space for interned Strings may be limitedbahkan jika Anda tidak menggunakan metode intern untuk String konstan itu akan diinternir secara otomatis.
Rakesh Juyal

2
@Rakesh: Tidak ada konstanta String yang banyak di kelas tertentu biasanya, jadi itu bukan masalah ruang / waktu dengan konstanta.
David Rodríguez - dribeas

Ya, komentar Rakesh tidak berlaku karena interning Strings hanya (secara eksplisit) dilakukan dengan Strings yang "dihasilkan" entah bagaimana, baik itu dengan manipulasi internal atau dengan mengambil dari database atau semacamnya. Dengan konstanta kita tidak punya pilihan.
Carl Smotricz

2
+1. Saya pikir ini adalah contoh yang baik ketika magang masuk akal. Saya tidak setuju ==untuk string sekalipun.
Alexander Pogrebnyak

1
Dari Java 7 dan seterusnya, "Pool string" diimplementasikan ke dalam ruang heap, sehingga mendapatkan semua keuntungan dari penyimpanan interns, pengumpulan sampah dan ukurannya tidak terbatas, dapat ditingkatkan hingga ukuran heap. (Anda tidak akan pernah membutuhkan sebanyak itu memory for string)
Anil Uttani

15

Saya ingin menambahkan 2 sen untuk menggunakan ==string yang diinternir.

Hal pertama yang String.equalsdilakukan adalah this==object.

Jadi meskipun ada beberapa perolehan kinerja sangat kecil (Anda tidak memanggil metode), dari sudut pandang pengelola menggunakan ==mimpi buruk, karena beberapa string yang diinternir memiliki kecenderungan untuk menjadi non-magang.

Jadi saya sarankan untuk tidak bergantung pada kasus khusus ==untuk string yang diinternir, tetapi selalu digunakan equalsseperti yang dimaksudkan Gosling.

EDIT: diinternir menjadi tidak diinternir:

V1.0
public class MyClass
{
  private String reference_val;

  ...

  private boolean hasReferenceVal ( final String[] strings )
  {
    for ( String s : strings )
    {
      if ( s == reference_val )
      {
        return true;
      }
    }

    return false;
  }

  private void makeCall ( )
  {
     final String[] interned_strings =  { ... init with interned values ... };

     if ( hasReference( interned_strings ) )
     {
        ...
     }
  }
}

Dalam versi 2.0, pengelola memutuskan untuk mengumumkan kepada hasReferenceValpublik, tanpa menjelaskan lebih lanjut bahwa mereka mengharapkan serangkaian string yang diinternir.

V2.0
public class MyClass
{
  private String reference_val;

  ...

  public boolean hasReferenceVal ( final String[] strings )
  {
    for ( String s : strings )
    {
      if ( s == reference_val )
      {
        return true;
      }
    }

    return false;
  }

  private void makeCall ( )
  {
     final String[] interned_strings =  { ... init with interned values ... };

     if ( hasReference( interned_strings ) )
     {
        ...
     }
  }
}

Sekarang Anda memiliki bug, yang mungkin sangat sulit ditemukan, karena dalam kebanyakan kasus array berisi nilai-nilai literal, dan kadang-kadang string non-literal digunakan. Jika equalsdigunakan alih-alih ==maka hasReferenceValmasih akan terus bekerja. Sekali lagi, peningkatan kinerja sangat kecil, tetapi biaya pemeliharaan tinggi.


"Beberapa string yang diinternir memiliki kecenderungan untuk menjadi non-magang." wow, itu akan ... aneh. Bisakah Anda mengutip referensi?
Carl Smotricz

2
OK, saya pikir Anda mengacu pada Strings yang sebenarnya berkeliaran di kolam magang dan ke tumpukan berkat sihir di JVM. Apa yang Anda katakan adalah bahwa == membuat kelas kesalahan programmer lebih mungkin terjadi.
Carl Smotricz

"Jadi saya sarankan untuk tidak bergantung pada kasus khusus == untuk string yang diinternir, tetapi selalu menggunakan sama dengan yang dimaksudkan Gosling." Apakah Anda memiliki kutipan atau komentar langsung dari Gosling yang menyatakan ini? Jika itu masalahnya mengapa dia bahkan repot-repot menempatkan magang () dan penggunaan == dalam bahasa?

1
intern tidak baik untuk perbandingan langsung (==), meskipun berfungsi jika kedua string diinternir. itu bagus untuk menurunkan total memori yang digunakan: ketika string yang sama digunakan di lebih dari 1 tempat.
tgkprog

12

String literal dan konstanta diinternir secara default. Artinya, "foo" == "foo"(dinyatakan oleh String literal), tetapi new String("foo") != new String("foo").


4
Jadi, pertanyaannya adalah kapan kita harus menggunakan intern,
Rakesh Juyal

yang diarahkan ke stackoverflow.com/questions/1833581/when-to-use-intern , dan sejumlah pertanyaan lain, beberapa di antaranya dari kemarin.
Bozho

Beri tahu saya jika pemahaman saya untuk pernyataan ini:, String literals and constants are interned by defaultbenar. new String("foo")-> Di sini, satu String literal "foo" dibuat di kolam String dan satu di heap, sehingga total 2 objek dibuat.
dkb

8

Pelajari Java String Intern - sekali untuk semua

String dalam java adalah objek yang tidak bisa diubah oleh desain. Oleh karena itu, dua objek string bahkan dengan nilai yang sama akan menjadi objek yang berbeda secara default. Namun, jika kita ingin menghemat memori, kita dapat mengindikasikan untuk menggunakan memori yang sama dengan konsep yang disebut string intern.

Aturan di bawah ini akan membantu Anda memahami konsep dalam istilah yang jelas:

  1. Kelas string mempertahankan kolam-internal yang awalnya kosong. Kumpulan ini harus menjamin mengandung objek string dengan hanya nilai unik.
  2. Semua literal string yang memiliki nilai yang sama harus dianggap objek memori-lokasi yang sama karena mereka tidak memiliki gagasan pembedaan. Oleh karena itu, semua literal dengan nilai yang sama akan membuat satu entri di intern-pool dan akan merujuk ke lokasi memori yang sama.
  3. Penggabungan dua atau lebih literal juga merupakan literal. (Oleh karena itu aturan # 2 akan berlaku untuk mereka)
  4. Setiap string yang dibuat sebagai objek (yaitu dengan metode lain kecuali sebagai literal) akan memiliki lokasi memori yang berbeda dan tidak akan membuat entri apa pun di kolam-internal
  5. Penggabungan literal dengan non-literal akan membuat non-literal. Dengan demikian, objek yang dihasilkan akan memiliki lokasi memori baru dan TIDAK akan membuat entri di kolam-internal.
  6. Menjalankan metode intern pada objek string, baik menciptakan objek baru yang memasuki kolam-intern atau mengembalikan objek yang ada dari kumpulan yang memiliki nilai yang sama. Doa pada objek apa pun yang tidak ada di intern-pool, TIDAK memindahkan objek ke pool. Ini lebih tepatnya menciptakan objek lain yang memasuki kolam.

Contoh:

String s1=new String (“abc”);
String s2=new String (“abc”);
If (s1==s2)  //would return false  by rule #4
If (“abc == a”+”bc )  //would return true by rules #2 and #3
If (“abc == s1 )  //would return false  by rules #1,2 and #4
If (“abc == s1.intern() )  //would return true  by rules #1,2,4 and #6
If ( s1 == s2.intern() )      //wound return false by rules #1,4, and #6

Catatan: Kasus motivasi untuk string magang tidak dibahas di sini. Namun, menghemat memori pasti akan menjadi salah satu tujuan utama.


Terima kasih untuk # 3, saya tidak tahu :)
kaay

4

Anda harus melihat dua periode waktu yaitu waktu kompilasi dan waktu runtime. sebagai contoh:

//example 1 
"test" == "test" // --> true 
"test" == "te" + "st" // --> true

//example 2 
"test" == "!test".substring(1) // --> false
"test" == "!test".substring(1).intern() // --> true

di satu sisi, dalam contoh 1, kami menemukan hasilnya semua kembali benar, karena dalam waktu kompilasi, jvm akan menempatkan "tes" ke kumpulan string literal, jika jvm menemukan "tes" ada, maka itu akan menggunakan yang sudah ada, dalam contoh 1, string "test" semuanya menunjuk ke alamat memori yang sama, jadi contoh 1 akan mengembalikan true. di sisi lain, dalam contoh 2, metode substring () mengeksekusi dalam waktu runtime, dalam kasus "test" == "! test" .substring (1), pool akan membuat dua objek string, " test "and"! test ", jadi mereka adalah objek referensi yang berbeda, jadi case ini akan mengembalikan false, dalam kasus" test "=="! test ".substring (1) .intern (), metode intern ( ) akan menempatkan ""! test ".substring (1)" ke kumpulan string literal,


3

http://en.wikipedia.org/wiki/String_interning

string interning adalah metode menyimpan hanya satu salinan dari masing-masing nilai string yang berbeda, yang harus tidak berubah. Interning string membuat beberapa tugas pemrosesan string lebih hemat waktu atau ruang dengan biaya yang membutuhkan lebih banyak waktu ketika string dibuat atau diinternir. Nilai-nilai yang berbeda disimpan dalam kumpulan string intern.


2

Interned Strings menghindari Strings duplikat. Interning menghemat RAM dengan mengorbankan lebih banyak waktu CPU untuk mendeteksi dan mengganti string duplikat. Hanya ada satu salinan dari setiap String yang telah diinternir, tidak peduli berapa banyak referensi yang menunjukkannya. Karena String tidak dapat diubah, jika dua metode berbeda secara kebetulan menggunakan String yang sama, mereka dapat berbagi salinan String yang sama. Proses konversi Strings digandakan ke yang dibagikan disebut interning.String.intern () memberi Anda alamat String master kanonik. Anda dapat membandingkan string yang diinternir dengan == sederhana (yang membandingkan pointer) dan bukan sama denganyang membandingkan karakter String satu per satu. Karena String tidak dapat diubah, proses intern bebas untuk lebih menghemat ruang, misalnya, dengan tidak membuat String literal terpisah untuk "pot" ketika ada sebagai substring dari beberapa literal lain seperti "hippopotamus".

Untuk melihat lebih banyak http://mindprod.com/jgloss/interned.html


2
String s1 = "Anish";
        String s2 = "Anish";

        String s3 = new String("Anish");

        /*
         * When the intern method is invoked, if the pool already contains a
         * string equal to this String object as determined by the
         * method, then the string from the pool is
         * returned. Otherwise, this String object is added to the
         * pool and a reference to this String object is returned.
         */
        String s4 = new String("Anish").intern();
        if (s1 == s2) {
            System.out.println("s1 and s2 are same");
        }

        if (s1 == s3) {
            System.out.println("s1 and s3 are same");
        }

        if (s1 == s4) {
            System.out.println("s1 and s4 are same");
        }

KELUARAN

s1 and s2 are same
s1 and s4 are same

2
String p1 = "example";
String p2 = "example";
String p3 = "example".intern();
String p4 = p2.intern();
String p5 = new String(p3);
String p6 = new String("example");
String p7 = p6.intern();

if (p1 == p2)
    System.out.println("p1 and p2 are the same");
if (p1 == p3)
    System.out.println("p1 and p3 are the same");
if (p1 == p4)
    System.out.println("p1 and p4 are the same");
if (p1 == p5)
    System.out.println("p1 and p5 are the same");
if (p1 == p6)
    System.out.println("p1 and p6 are the same");
if (p1 == p6.intern())
    System.out.println("p1 and p6 are the same when intern is used");
if (p1 == p7)
    System.out.println("p1 and p7 are the same");

Ketika dua string dibuat secara independen, intern()memungkinkan Anda untuk membandingkannya dan itu juga membantu Anda dalam membuat referensi di kumpulan string jika referensi itu tidak ada sebelumnya.

Ketika Anda menggunakan String s = new String(hi), java membuat instance baru dari string, tetapi ketika Anda menggunakan String s = "hi", java memeriksa apakah ada instance kata "hi" dalam kode atau tidak dan jika ada, itu hanya mengembalikan referensi.

Karena membandingkan string didasarkan pada referensi, intern()membantu Anda membuat referensi dan memungkinkan Anda untuk membandingkan konten string.

Ketika Anda menggunakan intern()dalam kode, itu membersihkan ruang yang digunakan oleh string yang merujuk ke objek yang sama dan hanya mengembalikan referensi dari objek yang sama yang sudah ada dalam memori.

Tetapi dalam hal p5 saat Anda menggunakan:

String p5 = new String(p3);

Hanya isi p3 yang disalin dan p5 dibuat baru. Jadi tidak diinternir .

Jadi hasilnya adalah:

p1 and p2 are the same
p1 and p3 are the same
p1 and p4 are the same
p1 and p6 are the same when intern is used
p1 and p7 are the same

2
    public static void main(String[] args) {
    // TODO Auto-generated method stub
    String s1 = "test";
    String s2 = new String("test");
    System.out.println(s1==s2);              //false
    System.out.println(s1==s2.intern());    //true --> because this time compiler is checking from string constant pool.
}

1

Metode string intern () digunakan untuk membuat salinan tepat dari objek string heap dalam kumpulan string konstan. Objek string dalam kumpulan string konstan secara otomatis diinternir tetapi objek string dalam tumpukan tidak. Penggunaan utama pembuatan intern adalah untuk menghemat ruang memori dan untuk melakukan perbandingan objek string yang lebih cepat.

Sumber: Apa itu string intern di java?


1

Seperti yang Anda katakan, intern()metode string pertama akan menemukan dari kumpulan String, jika ditemukan, maka itu akan mengembalikan objek yang menunjuk ke sana, atau akan menambahkan String baru ke dalam kumpulan.

    String s1 = "Hello";
    String s2 = "Hello";
    String s3 = "Hello".intern();
    String s4 = new String("Hello");

    System.out.println(s1 == s2);//true
    System.out.println(s1 == s3);//true
    System.out.println(s1 == s4.intern());//true

The s1dan s2dua objek menunjuk ke String kolam renang "Hello", dan menggunakan "Hello".intern()akan menemukan bahwa s1dan s2. Jadi "s1 == s3"mengembalikan true, serta ke s3.intern().


Ini tidak benar-benar memberikan banyak informasi baru. Sudah ada jawaban yang dikecualikan.
Alexander

0

Dengan menggunakan referensi objek tumpukan jika kita ingin mendapatkan referensi objek konstan string yang sesuai , maka kita harus menggunakan intern ()

String s1 = new String("Rakesh");
String s2 = s1.intern();
String s3 = "Rakesh";

System.out.println(s1 == s2); // false
System.out.println(s2 == s3); // true

Tampilan Bergambar masukkan deskripsi gambar di sini

Langkah 1: Obyek dengan data 'Rakesh' dibuat di heap dan string konstan pool. Juga s1 selalu menunjuk ke objek tumpukan.

Langkah 2: Dengan menggunakan referensi objek heap s1, kami mencoba untuk mendapatkan string yang sesuai dengan referensi objek konstan s2, menggunakan intern ()

Langkah 3: Secara sengaja membuat objek dengan data 'Rakesh' di kumpulan string konstan, dirujuk dengan nama s3

Sebagai "==" operator dimaksudkan untuk perbandingan referensi.

Mendapatkan false untuk s1 == s2

Menjadi kenyataan untuk s2 == s3

Semoga bantuan ini !!

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.