Wat is Java String-stage?

Wat is String Interningin Java, wanneer moet ik het gebruiken en waarom?


Antwoord 1, autoriteit 100%

http:// docs.oracle.com/javase/7/docs/api/java/lang/String.html#intern()

Door String.intern() op een reeks strings te doen, zorgt u ervoor dat alle strings met dezelfde inhoud hetzelfde geheugen delen. Dus als je een lijst hebt met namen waar ‘john’ 1000 keer voorkomt, zorg je er door intern voor te zorgen dat er maar één ‘jan’ daadwerkelijk geheugen toegewezen krijgt.

Dit kan handig zijn om de geheugenvereisten van uw programma te verminderen. Maar houd er rekening mee dat de cache door JVM wordt onderhouden in een permanente geheugenpool die meestal beperkt is in grootte in vergelijking met heap, dus u moet geen intern gebruiken als u niet te veel dubbele waarden heeft.


Meer over geheugenbeperkingen bij het gebruik van intern()

Aan de ene kant is het waar dat je String-duplicaten kunt verwijderen door
ze te internaliseren. Het probleem is dat de geïnternaliseerde strings naar:
de permanente generatie, een gebied van de JVM dat is gereserveerd
voor niet-gebruikersobjecten, zoals klassen, methoden en andere interne JVM
voorwerpen. De grootte van dit gebied is beperkt en is meestal veel kleiner
dan de hoop. Het aanroepen van intern() op een String heeft het effect van bewegen
het uit de hoop in de permanente generatie, en je riskeert
bijna geen PermGen-ruimte meer.


Van: http://www.codeinstructions.com/2009/01/busting -javalangstringintern-myths.html


Vanaf JDK 7 (ik bedoel in HotSpot) is er iets veranderd.

In JDK 7 worden interne strings niet langer toegewezen in de permanente generatie van de Java-heap, maar in plaats daarvan toegewezen aan het hoofdgedeelte van de Java-heap (bekend als de jonge en oude generaties), samen met de andere gemaakte objecten door de applicatie. Deze wijziging zal resulteren in meer gegevens die zich in de Java-hoofdheap bevinden en minder gegevens in de permanente generatie, waardoor het mogelijk is dat de grootte van de heap moet worden aangepast. De meeste applicaties zullen door deze wijziging slechts relatief kleine verschillen in heapgebruik zien, maar grotere applicaties die veel klassen laden of intensief gebruik maken van de String.intern()-methode zullen meer significante verschillen zien.

— Van Java SE 7-functies en -verbeteringen

Update: geïnterneerde strings worden vanaf Java 7 in de hoofdheap opgeslagen. http://www.oracle.com/technetwork/java /javase/jdk7-relnotes-418459.html#jdk7changes


Antwoord 2, autoriteit 28%

Er zijn enkele “catchy interview”-vragen, zoals waarom u is gelijk aan!krijgt als u het onderstaande stuk code uitvoert.

String s1 = "testString";
String s2 = "testString";
if(s1 == s2) System.out.println("equals!");

Als je Strings wilt vergelijken, moet je equals()gebruiken. Het bovenstaande zal gelijk zijn omdat de testStringal geïnterneerdvoor je is door de compiler. Je kunt de strings zelf intern gebruiken met de interne methode, zoals in eerdere antwoorden is getoond….


Antwoord 3, autoriteit 17%

JLS

JLS 7 3.10. 5definieert het en geeft een praktisch voorbeeld:

Bovendien verwijst een letterlijke tekenreeks altijd naar dezelfde instantie van de klasse String. Dit komt omdat letterlijke tekenreeksen – of, meer in het algemeen, tekenreeksen die de waarden zijn van constante expressies (§15.28) – worden “geïnterneerd” om unieke instanties te delen, met behulp van de methode String.intern.

Voorbeeld 3.10.5-1. Tekenreeksletters

Het programma dat bestaat uit de compilatie-eenheid (§7.3):

package testPackage;
class Test {
    public static void main(String[] args) {
        String hello = "Hello", lo = "lo";
        System.out.print((hello == "Hello") + " ");
        System.out.print((Other.hello == hello) + " ");
        System.out.print((other.Other.hello == hello) + " ");
        System.out.print((hello == ("Hel"+"lo")) + " ");
        System.out.print((hello == ("Hel"+lo)) + " ");
        System.out.println(hello == ("Hel"+lo).intern());
    }
}
class Other { static String hello = "Hello"; }

en de compilatie-eenheid:

package other;
public class Other { public static String hello = "Hello"; }

produceert de uitvoer:

true true true true false true

JVMS

JVMS 7 5.1 zegtzegt dat interning op magische en efficiënte wijze wordt geïmplementeerd met een speciale CONSTANT_String_infostruct (in tegenstelling tot de meeste andere objecten die meer generieke representaties hebben):

Een letterlijke tekenreeks is een verwijzing naar een instantie van klasse String en is afgeleid van een CONSTANT_String_info-structuur (§4.4.3) in de binaire representatie van een klasse of interface. De CONSTANT_String_info-structuur geeft de reeks Unicode-codepunten die de letterlijke tekenreeks vormen.

De Java-programmeertaal vereist dat identieke letterlijke tekenreeksen (dat wil zeggen letterlijke tekens die dezelfde reeks codepunten bevatten) moeten verwijzen naar dezelfde instantie van klasse String (JLS §3.10.5). Bovendien, als de methode String.intern wordt aangeroepen op een willekeurige tekenreeks, is het resultaat een verwijzing naar dezelfde klasse-instantie die zou worden geretourneerd als die tekenreeks als een letterlijke tekenreeks zou verschijnen. De volgende expressie moet dus de waarde true hebben:

("a" + "b" + "c").intern() == "abc"

Om een letterlijke tekenreeks af te leiden, onderzoekt de Java Virtual Machine de reeks codepunten die wordt gegeven door de CONSTANT_String_info-structuur.

  • Als de methode String.intern eerder is aangeroepen op een instantie van klasse String die een reeks Unicode-codepunten bevat die identiek zijn aan die gegeven door de CONSTANT_String_info-structuur, dan is het resultaat van letterlijke afleiding van strings een verwijzing naar die dezelfde instantie van klasse String.

  • Anders wordt er een nieuwe instantie van klasse String gemaakt die de reeks Unicode-codepunten bevat die wordt gegeven door de CONSTANT_String_info-structuur; een verwijzing naar die klasse-instantie is het resultaat van letterlijke afleiding van tekenreeksen. Ten slotte wordt de interne methode van de nieuwe String-instantie aangeroepen.

Bytecode

Laten we wat OpenJDK 7 bytecode decompileren om interning in actie te zien.

Als we decompileren:

public class StringPool {
    public static void main(String[] args) {
        String a = "abc";
        String b = "abc";
        String c = new String("abc");
        System.out.println(a);
        System.out.println(b);
        System.out.println(a == c);
    }
}

we hebben op de constante pool:

#2 = String             #32   // abc
[...]
#32 = Utf8               abc

en main:

0: ldc           #2          // String abc
 2: astore_1
 3: ldc           #2          // String abc
 5: astore_2
 6: new           #3          // class java/lang/String
 9: dup
10: ldc           #2          // String abc
12: invokespecial #4          // Method java/lang/String."<init>":(Ljava/lang/String;)V
15: astore_3
16: getstatic     #5          // Field java/lang/System.out:Ljava/io/PrintStream;
19: aload_1
20: invokevirtual #6          // Method java/io/PrintStream.println:(Ljava/lang/String;)V
23: getstatic     #5          // Field java/lang/System.out:Ljava/io/PrintStream;
26: aload_2
27: invokevirtual #6          // Method java/io/PrintStream.println:(Ljava/lang/String;)V
30: getstatic     #5          // Field java/lang/System.out:Ljava/io/PrintStream;
33: aload_1
34: aload_3
35: if_acmpne     42
38: iconst_1
39: goto          43
42: iconst_0
43: invokevirtual #7          // Method java/io/PrintStream.println:(Z)V

Let op hoe:

  • 0en 3: dezelfde ldc #2constante wordt geladen (de letterlijke waarden)
  • 12: er wordt een nieuwe string-instantie gemaakt (met #2als argument)
  • 35: aen cworden vergeleken als gewone objecten met if_acmpne

De weergave van constante strings is behoorlijk magisch op de bytecode:

  • het heeft een speciale CONSTANT_String_infostructuur, in tegenstelling tot gewone objecten (bijv. new String)
  • de struct verwijst naar een CONSTANT_Utf8_info Structuurdie de gegevens bevat. Dat zijn de enige gegevens die nodig zijn om de string weer te geven.

en het bovenstaande JVMS-citaat lijkt te zeggen dat wanneer de Utf8 waarnaar wordt verwezen hetzelfde is, identieke instanties worden geladen door ldc.

Ik heb soortgelijke tests gedaan voor velden, en:

  • static final String s = "abc"verwijst naar de constantentabel via de ConstantValue-kenmerk
  • niet-finale velden hebben dat kenmerk niet, maar kunnen nog steeds worden geïnitialiseerd met ldc

Conclusie: er is directe bytecode-ondersteuning voor de string-pool en de geheugenrepresentatie is efficiënt.

Bonus: vergelijk dat met de Integer-pool, die geen directe bytecode-ondersteuning heeft ( dwz geen CONSTANT_String_infoanaloog).


Antwoord 4, autoriteit 8%

Update voor Java 8 of plus.
In Java 8 wordt PermGen (Permanent Generation) ruimte verwijderd en vervangen door Meta Space. Het String-poolgeheugen wordt verplaatst naar de heap van JVM.

Vergeleken met Java 7 wordt de grootte van de String-pool in de heap vergroot. Daardoor heb je meer ruimte voor geïnternaliseerde Strings, maar minder geheugen voor de hele applicatie.

Nog één ding, je weet al dat bij het vergelijken van 2 (verwijzingen van) objecten in Java, ‘==‘ wordt gebruikt voor het vergelijken van de referentie van object, ‘equals‘ wordt gebruikt om de inhoud van een object te vergelijken.

Laten we deze code eens controleren:

String value1 = "70";
String value2 = "70";
String value3 = new Integer(70).toString();

Resultaat:

value1 == value2—> waar

value1 == value3—> vals

value1.equals(value3)—> waar

value1 == value3.intern()—> waar

Daarom moet je ‘equals‘ gebruiken om 2 String-objecten te vergelijken. En zo is intern()handig.


Antwoord 5

String interning is een optimalisatietechniek van de compiler. Als u twee identieke letterlijke tekenreeksen in één compilatie-eenheid hebt, zorgt de gegenereerde code ervoor dat er slechts één tekenreeksobject wordt gemaakt voor alle instanties van die letterlijke waarde (tekens tussen dubbele aanhalingstekens) in de assembly.

Ik heb een C#-achtergrond, dus ik kan het uitleggen door daar een voorbeeld van te geven:

object obj = "Int32";
string str1 = "Int32";
string str2 = typeof(int).Name;

uitvoer van de volgende vergelijkingen:

Console.WriteLine(obj == str1); // true
Console.WriteLine(str1 == str2); // true    
Console.WriteLine(obj == str2); // false !?

Opmerking1: Objecten worden vergeleken door middel van referentie.

Opmerking2:typeof(int).Naam wordt geëvalueerd door de reflectiemethode, zodat het niet wordt geëvalueerd tijdens het compileren. Hier worden deze vergelijkingen gemaakt tijdens het compileren.

Analyse van de resultaten:
1) waar omdat ze allebei dezelfde letterlijke inhoud bevatten en dus zal de gegenereerde code slechts één object hebben dat verwijst naar “Int32”. Zie opmerking 1.

2) waar omdat de inhoud van beide waarden is gecontroleerd, wat hetzelfde is.

3) ONWAAR omdat str2 en obj niet dezelfde letterlijke betekenis hebben. Zie Opmerking 2.


Antwoord 6

Aangezien strings objecten zijn en aangezien alle objecten in Java altijd alleen in de heap-ruimte worden opgeslagen, worden alle strings in de heap-ruimte opgeslagen. Java bewaart strings die zijn gemaakt zonder het nieuwe sleutelwoord echter in een speciaal gebied van de heapruimte, dat “stringpool” wordt genoemd. Java bewaart de strings die zijn gemaakt met het nieuwe trefwoord in de reguliere heapruimte.

Het doel van de string-pool is om een set unieke strings te behouden. Telkens wanneer u een nieuwe tekenreeks maakt zonder het nieuwe sleutelwoord te gebruiken, controleert Java of dezelfde tekenreeks al bestaat in de tekenreekspool. Als dit het geval is, retourneert Java een verwijzing naar hetzelfde String-object en als dat niet het geval is, maakt Java een nieuw String-object in de tekenreekspool en retourneert de verwijzing. Dus als u bijvoorbeeld de tekenreeks “hallo” twee keer in uw code gebruikt, zoals hieronder weergegeven, krijgt u een verwijzing naar dezelfde tekenreeks. We kunnen deze theorie daadwerkelijk testen door twee verschillende referentievariabelen te vergelijken met behulp van de ==operator, zoals weergegeven in de volgende code:

String str1 = "hello";
String str2 = "hello";
System.out.println(str1 == str2); //prints true
String str3 = new String("hello");
String str4 = new String("hello");
System.out.println(str1 == str3); //prints false
System.out.println(str3 == str4); //prints false 

==operator controleert eenvoudigweg of twee verwijzingen naar hetzelfde object verwijzen of niet en retourneert true als dat het geval is. In de bovenstaande code krijgt str2de verwijzing naar hetzelfde String-object dat eerder is gemaakt. Echter, str3en str4krijgen verwijzingen naar twee totaal verschillende String-objecten. Daarom retourneert str1 == str2true maar str1 == str3en str3== str4retourneren false .
In feite, wanneer u new String(“hello”);doet, worden er twee String-objecten gemaakt in plaats van slechts één als dit de eerste keer is dat de string “hello” wordt gebruikt in het overal in het programma – één in de tekenreekspool vanwege het gebruik van een tekenreeks tussen aanhalingstekens, en één in de reguliere heapruimte vanwege het gebruik van een nieuw trefwoord.

String pooling is Java’s manier om programmageheugen te besparen door te voorkomen dat meerdere String-objecten met dezelfde waarde worden gemaakt. Het is mogelijk om een string uit de string pool te halen voor een string die gemaakt is met het nieuwe sleutelwoord door gebruik te maken van String’s intern methode. Het wordt “interning” van string-objecten genoemd. Bijvoorbeeld,

String str1 = "hello";
String str2 = new String("hello");
String str3 = str2.intern(); //get an interned string obj
System.out.println(str1 == str2); //prints false
System.out.println(str1 == str3); //prints true

OCP Java SE 11 Programmeur, Deshmukh


Antwoord 7

Java interning() method basically makes sure that if String object is present in SCP, If yes then it returns that object and if not then creates that objects in SCP and return its references
for eg: String s1=new String("abc");
        String s2="abc";
        String s3="abc";
s1==s2// false, because 1 object of s1 is stored in heap and other in scp(but this objects doesn't have explicit reference) and s2 in scp
s2==s3// true
now if we do intern on s1
s1=s1.intern() 
//JVM checks if there is any string in the pool with value “abc” is present? Since there is a string object in the pool with value “abc”, its reference is returned.
Notice that we are calling s1 = s1.intern(), so the s1 is now referring to the string pool object having value “abc”.
At this point, all the three string objects are referring to the same object in the string pool. Hence s1==s2 is returning true now.

Antwoord 8

Door heap-objectreferentie te gebruiken, moeten we voor de intern()-methode gaan als we de overeenkomstige SCP-objectreferentie willen gebruiken.

Voorbeeld:

class InternDemo
{
public static void main(String[] args)
{
String s1=new String("smith");
String s2=s1.intern();
String s3="smith";
System.out.println(s2==s3);//true
}
}

stroomschema stagiair

Other episodes