Java dizesi gerçekten değişmez mi?


399

Hepimiz StringJava'da değişmez olduğunu biliyoruz , ancak aşağıdaki kodu kontrol edin:

String s1 = "Hello World";  
String s2 = "Hello World";  
String s3 = s1.substring(6);  
System.out.println(s1); // Hello World  
System.out.println(s2); // Hello World  
System.out.println(s3); // World  

Field field = String.class.getDeclaredField("value");  
field.setAccessible(true);  
char[] value = (char[])field.get(s1);  
value[6] = 'J';  
value[7] = 'a';  
value[8] = 'v';  
value[9] = 'a';  
value[10] = '!';  

System.out.println(s1); // Hello Java!  
System.out.println(s2); // Hello Java!  
System.out.println(s3); // World  

Bu program neden böyle çalışıyor? Ve neden değeri değişti s1ve s2değişti, ama değişmedi s3?


394
Her türlü aptal hileyi yansıma ile yapabilirsiniz. Ama temelde, sınıfa girdiğiniz anda "çıkarıldıysa garanti geçersiz" etiketini kırıyorsunuz.
cHao

16
@DarshanPatel yansımayı devre dışı bırakmak için bir SecurityManager kullanın
Sean Patrick Floyd

39
Gerçekten şeylerle (Integer)1+(Integer)2=42uğraşmak istiyorsanız, önbelleğe alınmış otomatik kutulama ile uğraşarak yapabilirsiniz; (Disgruntled-Bomb-Java-Edition) ( thedailywtf.com/Articles/Disgruntled-Bomb-Java-Edition.aspx )
Richard Tingle

15
Neredeyse 5 yıl önce yazdığım bu cevapla eğlenebilirsiniz. Stackoverflow.com/a/1232332/27423 - C # 'daki değişmez listeler hakkında ama temelde aynı şey: Kullanıcıların verilerimi değiştirmesini nasıl durdurabilirim? Ve cevap, yapamazsınız; yansıma çok kolaylaştırır. Bu sorunu olmayan bir ana dil dili, bir kapanış içindeki yerel değişkenlere erişebilen bir yansıma sistemine sahip olmadığı için JavaScript'tir, bu nedenle özel gerçekten özel anlamına gelir (bunun için anahtar kelime olmasa bile!)
Daniel Earwicker

49
Soruyu sonuna kadar okuyan var mı ?? Soru şudur: Tekrar edeyim: "Bu program neden böyle çalışıyor? Neden s1 ve s2'nin değeri değişti ve s3 için değişmedi?" Soru s1 ve s2'nin neden değiştirildiği DEĞİLDİR! Soru: S3 neden değiştirilmedi?
Roland Pihlakas

Yanıtlar:


403

String değişmezdir *, ancak bu yalnızca herkese açık API'sını kullanarak değiştiremeyeceğiniz anlamına gelir.

Burada yaptığınız şey yansıma kullanarak normal API'yı atlatmak. Aynı şekilde, numaralandırmaların değerlerini değiştirebilir, Tamsayı otomatik kutusunda vb. Kullanılan arama tablosunu değiştirebilirsiniz.

Şimdi, neden s1ve s2değişim değeri, ikisi de aynı interned dizeye atıfta bulunuyorlar. Derleyici bunu yapar (diğer cevaplarda belirtildiği gibi).

Sebebi s3yok değil bunun paylaşmak istedim olarak, aslında bana şaşırtıcı biraz valuedizisi ( Java önceki sürümünde yaptığı Java 7u6 önce). Ancak, kaynak koduna bakıldığında String, valuebir alt dize için karakter dizisinin gerçekten kopyalandığını (kullanarak Arrays.copyOfRange(..)) görebiliriz. Bu yüzden değişmeden gider.

Bu SecurityManagertür şeyleri yapmak için kötü amaçlı kodlardan kaçınmak için bir yükleyebilirsiniz . Ancak, bazı kütüphanelerin bu tür yansıma numaralarını (genellikle ORM araçları, AOP kütüphaneleri vb.) Kullanmaya bağlı olduğunu unutmayın.

*) Başlangıçta Stringbunun gerçekten değişmez olmadığını, sadece "etkili değişmez" olduğunu yazdım . Bu String, valuedizinin gerçekten işaretlendiği geçerli uygulamasında yanıltıcı olabilir private final. Yine de, Java'daki bir diziyi değişmez olarak ilan etmenin bir yolu olmadığını belirtmek gerekir, bu nedenle uygun erişim değiştiricileriyle bile, sınıfının dışında gösterilmemesine dikkat edilmelidir.


Bu konu ezici bir şekilde popüler göründüğü için, burada önerilen bazı okumalar: Heinz Kabutz'un OPZ'deki diğer birçok konu ile birlikte OP ile ilgili birçok konuyu kapsayan yansıma Çılgınlığı konuşması ... iyi ... delilik.

Bunun neden bazen yararlı olduğunu kapsar. Ve neden, çoğu zaman bundan kaçınmalısınız. :-)


7
Aslında, Stringstajyerleştirme JLS'nin bir parçasıdır ( "bir dize değişmezi her zaman aynı String sınıfının örneğini belirtir" ). Ancak katılıyorum, Stringsınıfın uygulama detaylarına güvenmek iyi bir uygulama değil .
haraldK

3
Belki substringvarolan dizinin bir "bölümü" kullanmak yerine kopya neden nedeni , aksi takdirde büyük bir dize vardı sve ondan çağrılan küçük bir alt dize tçıkardı ve daha sonra terk etti sama tuttu t, o zaman büyük dizi canlı tutulur (çöp toplanmaz). Belki de her bir dize değerinin kendi ilişkili dizisine sahip olması daha doğal olabilir mi?
Jeppe Stig Nielsen

10
Dizeleri ve alt dizeleri arasındaki dizileri paylaşmak, her String örneğin ofseti belirtilen diziye ve uzunluğa hatırlamak için değişkenler taşımak zorunda olduğu anlamına gelir . Bu, toplam dize sayısı ve bir uygulamadaki normal dize ve alt dize arasındaki tipik oran göz önüne alındığında, göz ardı edilmemesi gereken bir ek yüktür. Her dize işlemi için değerlendirilmeleri gerektiğinden , sadece bir işlem, ucuz bir alt dize yararına her dize işlemini yavaşlatmak anlamına geliyordu .
Holger

2
@Holger - Evet, benim anlayışım, son JVM'lerde ofset alanının bırakılmış olmasıdır. Ve mevcut olduğunda bile o kadar sık ​​kullanılmadı.
Hot Licks

2
@supercat: yerel kodunuzun olması ya da olmaması, aynı JVM içinde dizeler ve alt dize için farklı uygulamalar olması ya da byte[]ASCII dizeleri ve char[]diğerleri için dizelerin olması önemli değildir, her işlemin daha önce hangi dize olduğunu kontrol etmesi gerektiği anlamına gelir işletme. Bu, kodun arayanın bağlam bilgisini kullanarak daha fazla optimizasyonun ilk adımı olan dizeleri kullanarak yöntemlere satır içine girmesini engeller. Bu büyük bir etki.
Holger

93

Java'da, iki dize ilkel değişkeni aynı değişmez değere başlatılırsa, her iki değişkene de aynı başvuruyu atar:

String Test1="Hello World";
String Test2="Hello World";
System.out.println(test1==test2); // true

başlatma

Karşılaştırmanın doğru olmasının nedeni budur. Üçüncü dize, substring()işaret etmek yerine yeni bir dize kullanılarak oluşturulur .

alt dize

Yansıma kullanarak bir dizeye eriştiğinizde, gerçek işaretçiyi alırsınız:

Field field = String.class.getDeclaredField("value");
field.setAccessible(true);

Bu nedenle, buna bir işaretçi tutan dize değişecektir, ancak s3yeni bir dize ile oluşturulduğu gibi substring()değişmeyecektir.

değişiklik


Bu yalnızca değişmez değerler için geçerlidir ve derleme zamanı optimizasyonudur.
SpacePrez

2
@ Zaphod42 Doğru değil. Ayrıca intern, değişmez bir Dizgeyi manuel olarak arayabilir ve avantajlarından yararlanabilirsiniz.
Chris Hayes

Yine de dikkat edin: internakıllıca kullanmak istiyorsunuz . Her şeyi staj yapmak size fazla bir şey kazandırmaz ve karışıma yansıma eklediğinizde kafa karıştırıcı anların kaynağı olabilir.
cHao

Test1java adlandırma kurallarına Test1aykırıdır ve bunlara uymaz test1==test2.
c0der

50

String'in değişmezliğini atlatmak için yansıma kullanıyorsunuz - bu bir "saldırı" biçimidir.

Bunun gibi oluşturabileceğiniz birçok örnek vardır (örneğin , bir Voidnesneyi bile başlatabilirsiniz ), ancak Dize'nin "değişmez" olmadığı anlamına gelmez.

Bu tür kodların kendi yararınıza kullanılabileceği ve mümkün olan en erken zamanda (GC'den önce) şifreleri bellekten silmek gibi "iyi kodlama" olabileceği kullanım durumları vardır .

Güvenlik yöneticisine bağlı olarak, kodunuzu yürütemeyebilirsiniz.


30

Dize nesnesinin "uygulama ayrıntılarına" erişmek için yansıma kullanıyorsunuz. Değişmezlik, bir nesnenin genel arayüzünün özelliğidir.


24

Görünürlük değiştiriciler ve son (değişmezlik) Java'daki kötü amaçlı koda karşı bir ölçüm değildir; sadece hatalara karşı korunmak ve kodu daha sürdürülebilir hale getirmek için kullanılan araçlardır (sistemin en büyük satış noktalarından biri). Bu nedenle String, yansıma yoluyla s için destek char dizisi gibi dahili uygulama ayrıntılarına erişebilirsiniz .

Gördüğünüz ikinci efekt, Stringsadece sizin değiştiğiniz gibi görünse de hepsinin değişmesidir s1. Java String değişmezlerinin belirli bir özelliğidir, yani otomatik olarak stajyerleştirilir, yani önbelleğe alınır. Aynı değere sahip iki String değişmezi aslında aynı nesne olacaktır. newBununla birlikte bir String oluşturduğunuzda otomatik olarak stajyer olmayacak ve bu efekti görmeyeceksiniz.

#substringyakın zamana kadar (Java 7u6) benzer bir şekilde çalıştı, bu da sorunuzun orijinal sürümündeki davranışı açıklardı. Yeni bir destek char dizisi oluşturmadı, ancak orijinal String'den bir diziyi yeniden kullandı; bu dizinin yalnızca bir kısmını sunmak için bir uzaklık ve uzunluk kullanan yeni bir String nesnesi oluşturdu. Bu genellikle Dizeleri değişmez olarak çalıştı - bunu atlatmazsanız. Bu özellik #substringayrıca orijinal Dizenin tamamının, bundan daha kısa bir alt dize oluşturulduğunda hala toplanamayacağı anlamına geliyordu.

Mevcut Java ve sorunun şu anki sürümünde garip bir davranış yoktur #substring.


2
Aslında, görünürlük değiştiricileri olan (ya da en azından vardı) koruma againts zararlı kod olarak tasarlanmıştır - ancak, bir SecurityManager (System.setSecurityManager ()) korumayı etkinleştirmek için ayarlamanız gerekir. Bu aslında ne kadar güvenli başka bir soru ...
sleske

2
Erişim değiştiricilerin kodu 'koruma' amaçlı olmadığını vurguladığınız için bir oylamayı hak ediyor . Bu hem Java hem de .NET'te yaygın olarak yanlış anlaşılıyor gibi görünüyor. Önceki yorumda bununla çelişse de; Java hakkında çok şey bilmiyorum, ancak .NET'te bu kesinlikle doğrudur. Her iki dilde de kullanıcılar bunun kodlarını hack korumalı hale getirmediğini varsaymamalıdır.
Tom W

finalYansıtma yoluyla bile sözleşmeyi ihlal etmek mümkün değildir . Ayrıca, başka bir cevapta belirtildiği gibi, Java 7u6, #substringdizileri paylaşmaz.
ntoskrnl

Aslında, davranış finalzamanla değişti ...: -O Diğer konuya gönderilen Heinz tarafından yapılan "Yansıma Çılgınlığı" konuşmasına göre final, JDK 1.1, 1.3 ve 1.4 nihai anlamına geliyordu, ama her zaman 1.2 kullanılarak yansıma kullanılarak değiştirilebilir , ve çoğu durumda 1.5 ve 6'da ...
haraldK

1
finalalanlar, nativeserileştirilmiş bir örneğin alanları okunurken Seri Sonlandırma çerçevesi tarafından yapılan kodun yanı sıra System.setOut(…)son System.outdeğişkeni değiştirir . İkincisi, erişim geçersiz kılma ile yansıma static finalalanları değiştiremediğinden en ilginç özelliktir .
Holger

11

Dize değişmezliği arayüz açısındandır. Arayüzü atlamak ve String örneklerinin iç kısımlarını doğrudan değiştirmek için yansıma kullanıyorsunuz.

s1ve s2ikisi de aynı "stajyer" String örneğine atandığı için değiştirilir. Dize eşitliği ve stajyerlik hakkında bu makaleden biraz daha fazla bilgi edinebilirsiniz. Örnek kodunuzda s1 == s2geri döndüğünü öğrenmek sizi şaşırtabilir true!


10

Hangi Java sürümünü kullanıyorsunuz? Java 1.7.0_06'dan Oracle, String'in iç temsilini, özellikle alt dizeyi değiştirdi.

Oracle Tunes Java'nın Dahili Dize Temsilinden alıntı :

Yeni paradigmada, String ofset ve count alanları kaldırılmıştır, böylece alt dizeler artık temel char [] değerini paylaşmaz.

Bu değişiklikle birlikte, yansımasız da olabilir (???).


2
OP daha eski bir Sun / Oracle JRE kullanıyorsa, son ifade "Java!" (yanlışlıkla yayınlandığı gibi). Bu yalnızca değer dizisinin dizeler ve alt dizeler arasındaki paylaşımını etkiler. Hâlâ yansıma gibi hileler olmadan değeri değiştiremezsiniz.
haraldK

7

Burada gerçekten iki soru var:

  1. Teller gerçekten değişmez mi?
  2. S3 neden değiştirilmedi?

1. noktaya: ROM dışında, bilgisayarınızda sabit bir bellek yoktur. Günümüzde ROM bile bazen yazılabilir. Bellek adresinize yazabilecek her zaman bir yerlerde (yönetilen ortamınızı koruyan çekirdek veya yerel kod olsun) her zaman bir kod vardır. Yani, "gerçeklik" te, hayır kesinlikle değişmez değillerdir .

2. noktaya: Bunun nedeni, alt dizenin muhtemelen diziyi kopyalayan yeni bir dize örneği ayırmasıdır. Alt dizeyi bir kopyasını yapmayacak şekilde uygulamak mümkündür, ancak bu anlamına gelmez. Dahil olan ödünleşmeler var.

Örneğin, reallyLargeString.substring(reallyLargeString.length - 2)büyük miktarda belleğin canlı kalmasını sağlamak için bir referans tutmalı mı, yoksa sadece birkaç bayt mı?

Bu, alt dizenin nasıl uygulandığına bağlıdır. Derin bir kopya daha az belleği canlı tutacaktır, ancak biraz daha yavaş çalışacaktır. Sığ bir kopya daha fazla belleği canlı tutacaktır, ancak daha hızlı olacaktır. Dize nesnesi ve arabelleği, 2 ayrı yığın tahsisinin yerine tek bir blokta tahsis edilebildiğinden, derin bir kopya kullanmak yığın parçalanmasını da azaltabilir.

Her durumda, JVM'niz alt dize çağrıları için derin kopyalar kullanmayı seçmiş gibi görünüyor.


3
Gerçek ROM, plastik kaplı fotoğrafik bir baskı kadar değişmezdir. Gofret (veya baskı) kimyasal olarak geliştirildiğinde, desen kalıcı olarak ayarlanır. RAM çipleri de dahil olmak üzere elektrikle değiştirilebilen bellekler, yazmak için gerekli kontrol sinyallerinin kurulu olduğu devreye ek elektrik bağlantıları eklenmeden enerji verilemezse "gerçek" ROM gibi davranabilir. Gömülü cihazların fabrikada ayarlanan ve yedek bir batarya tarafından tutulan ve battey başarısız olursa içeriğinin fabrika tarafından yeniden yüklenmesi gereken RAM'i içermesi aslında nadir değildir.
supercat

3
@supercat: Bilgisayarınız bu gömülü sistemlerden biri değil. :) Gerçek sabit kablolu ROM'lar on veya iki yıldır PC'lerde yaygın değildir; her şey EEPROM ve bu günlerde yanıp sönüyor. Temel olarak, belleğe atıfta bulunan, kullanıcı tarafından görülebilir her adres potansiyel olarak yazılabilir belleği ifade eder.
cHao

@cHao: Birçok flaş çip, bölümlerin, geri alınabiliyorsa, normal çalışma için gerekenden farklı voltajlar (hangi anakartlar için donatılmayacak) uygulanmasını gerektirecek şekilde yazma korumasına izin verir. Anakartların bu özelliği kullanmasını beklerdim. Dahası, bugünün bilgisayarlarından emin değilim, ancak tarihsel olarak bazı bilgisayarlarda önyükleme aşamasında yazma korumalı bir RAM bölgesi vardı ve sadece sıfırlama (korumayı ROM'dan başlamaya zorlayacak) tarafından korunmasız olabilirdi.
supercat

2
@supercat Konunun noktasını kaçırdığınızı düşünüyorum, yani RAM'de saklanan dizeler hiç değişmez olmayacak.
Scott Wisniewski

5

@ HaraldK'ın cevabına eklemek için - bu, uygulamada ciddi bir etkiye neden olabilecek bir güvenlik hack'idir.

İlk şey, bir String Pool'da saklanan sabit bir dizede yapılan değişikliktir. Dize bir olarak bildirildiğinde String s = "Hello World";, daha fazla potansiyel yeniden kullanım için özel bir nesne havuzuna yerleştirilir. Sorun derleyicinin derleme zamanında değiştirilen sürüme bir başvuru yerleştirmesi ve kullanıcı çalışma zamanında bu havuzda depolanan dizeyi değiştirdiğinde, koddaki tüm başvurular değiştirilen sürüme işaret edecektir. Bu, aşağıdaki hataya neden olur:

System.out.println("Hello World"); 

Yazdırılacak:

Hello Java!

Bu riskli dizeler üzerinde ağır bir hesaplama yaparken yaşadığım başka bir sorun vardı. Hesaplama sırasında 1000000 kez 1 gibi bir sonuç oluştu ve sonuç belirsizdi. JIT'i kapatarak sorunu bulabildim - JIT kapalıyken hep aynı sonucu alıyordum. Benim tahminim bu JIT optimizasyon sözleşmelerinin bazılarını kırdı bu Dize güvenlik kesmek oldu.


JIT olmadan daha yavaş yürütme süresi ve daha az eşzamanlılık tarafından maskelenen bir iş parçacığı güvenliği sorunu olabilir.
Ted Pennings

@TedPennings Açıklamamdan, ayrıntılara çok fazla gitmek istemedim. Aslında yerelleştirmek için birkaç gün gibi geçirdi. İki farklı dilde yazılmış iki metin arasındaki mesafeyi hesaplayan tek iş parçacıklı bir algoritmadır. Sorun için iki olası düzeltme buldum - biri JIT'i kapatmak, ikincisi String.format("")ise iç döngülerden birine anlamsız olarak eklemekti . Bazı-sonra-JIT-başarısızlık sorunu olma şansı var, ama JIT olduğuna inanıyorum, çünkü bu sorun bu no-op eklendikten sonra bir daha asla yeniden üretilmedi.
Andrey Chaschev

Bunu JDK ~ 7u9'un erken bir sürümü ile yapıyordum, bu yüzden olabilirdi.
Andrey Chaschev

1
@Andrey Chaschev: “Sorun için iki olası düzeltme buldum”… üçüncü olası düzeltme, Stringiçselliğe girmemek, aklınıza gelmedi mi?
Holger

1
@Ted Pennings: iş parçacığı güvenliği sorunları ve JIT sorunları genellikle aynıdır. JIT'in, finalnesne yapımından sonra verileri değiştirirken kopan tarla ipliği güvenlik garantilerine dayanan bir kod üretmesine izin verilir . Böylece istediğiniz gibi bir JIT sorunu veya MT sorunu olarak görüntüleyebilirsiniz. Asıl mesele, Stringdeğişmez olması beklenen verileri kesmek ve değiştirmek.
Holger

5

Havuzlama kavramına göre, aynı değeri içeren tüm String değişkenleri aynı bellek adresine işaret edecektir. Bu nedenle, her ikisi de aynı “Merhaba Dünya” değerini içeren s1 ve s2, aynı bellek konumuna işaret edecektir (M1 diyelim).

Öte yandan, s3 “Dünya” içerir, dolayısıyla farklı bir bellek tahsisine işaret eder (M2 deyin).

Şimdi olan şu ki S1 değerinin değiştirilmesi (char [] değeri kullanılarak). Böylece, bellek yerindeki M1'in hem s1 hem de s2 ile gösterilen değeri değiştirildi.

Sonuç olarak, bellek yeri M1 değiştirildi, bu da s1 ve s2 değerlerinde değişikliğe neden oldu.

Ancak M2 yerinin değeri değişmeden kalır, bu nedenle s3 aynı orijinal değeri içerir.


5

S3'ün gerçekte değişmemesinin nedeni, bir alt dize yaptığınızda Java'da bir alt dize için değer karakter dizisinin dahili olarak kopyalanmasıdır (Arrays.copyOfRange () kullanılarak).

s1 ve s2 aynıdır, çünkü Java'da ikisi de aynı interned dizeyi ifade eder. Java tasarım gereğidir.


2
Bu cevap önünüzdeki cevaplara nasıl bir şey ekledi?
Gri

Ayrıca bunun oldukça yeni bir davranış olduğunu ve herhangi bir spesifikasyon tarafından garanti edilmediğini unutmayın.
Paŭlo Ebermann

String.substring(int, int)Java 7u6 ile uygulaması değişti. 7u6 önce, JVM sadece orijinaline bir işaretçi tutacak String's char[]dizin ve uzunluğu ile birlikte. 7u6'dan sonra, alt dize yeni bir Stringartıları ve eksileri vardır kopyalar .
Eric Jablow

2

String değiştirilemez, ancak yansıma yoluyla String sınıfını değiştirmenize izin verilir. String sınıfını gerçek zamanlı olarak değiştirilebilir olarak yeniden tanımladınız. İsterseniz yöntemleri herkese açık, özel veya statik olarak yeniden tanımlayabilirsiniz.


2
Alanların / yöntemlerin görünürlüğünü değiştirirseniz yararlı olmaz çünkü derleme zamanı
Bohemian

1
Yöntemlerdeki erişilebilirliği değiştirebilirsiniz, ancak genel / özel durumlarını değiştiremezsiniz ve statik olmalarını sağlayamazsınız.
Gri

1

[Feragatname, kasıtlı olarak düşünülmüş bir cevap tarzıdır çünkü daha fazla "bunu evde çocuklarda yapma" cevabının gerekli olduğunu hissediyorum]

Günah, field.setAccessible(true);özel bir alana erişim sağlayarak kamu API'sını ihlal ettiğini söyleyen çizgidir . Bir güvenlik yöneticisi yapılandırarak kilitlenebilen dev bir güvenlik deliği.

Söz konusu olgu, erişim değiştiricilerini yansıma yoluyla ihlal etmek için bu tehlikeli kod satırını kullanmadığınızda asla göremeyeceğiniz uygulama ayrıntılarıdır. Açıkça iki (normalde) değişmez dizge aynı karakter dizisini paylaşabilir. Bir alt dizenin aynı diziyi paylaşıp paylaşmayacağı, dizinin yapıp yapamayacağına ve geliştiricinin onu paylaşıp paylaşmayacağına bağlıdır. Normalde bunlar, erişim kodunu bu kod satırıyla başından vurmadığınız sürece bilmeniz gerekmeyen görünmez uygulama ayrıntılarıdır.

Yansıma kullanarak erişim değiştiricileri ihlal etmeden deneyimlenemeyecek bu tür ayrıntılara güvenmek iyi bir fikir değildir. Bu sınıfın sahibi yalnızca normal genel API'yı destekler ve gelecekte uygulama değişiklikleri yapmakta serbesttir.

Kafanızı tuttuğunuzda, bu tehlikeli şeyler yapmaya zorlayan bir kodunuz olduğunda, kod satırının gerçekten çok yararlı olduğunu söyledikten sonra. Bu arka kapıyı kullanmak genellikle günah işlemeniz gerekmeyen daha iyi kütüphane koduna yükseltmeniz gereken bir kod kokusudur. Bu tehlikeli kod satırının bir başka yaygın kullanımı, bir "vudu çerçevesi" (orm, enjeksiyon kabı, ...) yazmaktır. Birçok kişi bu tür çerçeveler hakkında (hem kendileri için hem de onlara karşı) dindar olurlar, bu yüzden programcıların büyük çoğunluğunun oraya gitmesine gerek olmadığını söyleyerek bir alev savaşı davet etmekten kaçınacağım.


1

Dizeler, JVM yığın belleğinin kalıcı alanında oluşturulur. Yani evet, gerçekten değişmez ve yaratıldıktan sonra değiştirilemez. Çünkü JVM'de üç çeşit yığın bellek vardır: 1. Genç nesil 2. Eski nesil 3. Kalıcı nesil.

Herhangi bir nesne oluşturulduğunda, dize havuzu için ayrılmış genç nesil yığın alanına ve PermGen alanına gider.

Buradan daha fazla bilgi edinebilir ve daha fazla bilgi edinebilirsiniz: Garbage Collection Java'da nasıl çalışır ?


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.