简体   繁体   English

当调用string intern()方法时

[英]when string intern() method is getting called

Case 1: 情况1:

  String str = "StackOverFlow"; String str1 = "StackOverFlow"; if(str==str1){ System.out.println("equal");//prints equal } 

Case 2: 案例2:

  String str = "StackOverFlow"; String str1=str.intern(); if(str==str1){ System.out.println("equal");//prints equal } 

follow up questions: 跟进问题:

  1. I want to know whether for the first case JVM calls intern() internally and assign the reference of str to str1 ? 我想知道对于第一种情况,JVM是否在内部调用intern()并将str的引用分配给str1

  2. how two references equal in the first case? 第一种情况下两个引用如何相等?

  3. Does the first case means whenever you declare a string like String str = "StackOverFlow"; 第一种情况是否意味着每当你声明一个像String str = "StackOverFlow";这样的String str = "StackOverFlow"; it adds to the pool of string as same as that of intern() method? 它添加到字符串池与intern()方法相同?

  4. Does String pool which is used by String str = "StackOverFlow"; String str = "StackOverFlow";使用的字符串池是否String str = "StackOverFlow"; and intern() is allocated outside of heap? intern()是在堆外部分配的? if yes where exactly? 如果确实在哪里?


For question 4 the answer is as below: 对于问题4,答案如下:

In Java 6 and earlier, interned strings were also stored in the permanent generation. 在Java 6及更早版本中,实习字符串也存储在永久代中。 In Java 7, interned strings are stored in the main object heap. 在Java 7中,实习字符串存储在主对象堆中。

Here is what documentation says: 这是文档说的:

In JDK 7, interned strings are no longer allocated in the permanent generation of the Java heap, but are instead allocated in the main part of the Java heap (known as the young and old generations), along with the other objects created by the application. 在JDK 7中,实现的字符串不再分配在Java堆的永久生成中,而是分配在Java堆的主要部分(称为年轻和旧的代)中,以及应用程序创建的其他对象。 This change will result in more data residing in the main Java heap, and less data in the permanent generation, and thus may require heap sizes to be adjusted. 此更改将导致更多数据驻留在主Java堆中,并且永久生成中的数据更少,因此可能需要调整堆大小。 Most applications will see only relatively small differences in heap usage due to this change, but larger applications that load many classes or make heavy use of the String.intern() method will see more significant differences. 由于此更改,大多数应用程序将只看到堆使用中的相对较小的差异,但是加载许多类或大量使用String.intern()方法的较大应用程序将看到更显着的差异。

Further details from here: 更多细节来自:

String.intern() in Java 6 Java 6中的String.intern()

In those good old days all interned strings were stored in the PermGen – the fixed size part of heap mainly used for storing loaded classes and string pool. 在那些美好的旧时代,所有实习字符串都存储在PermGen中 - 堆的固定大小部分主要用于存储加载的类和字符串池。 Besides explicitly interned strings, PermGen string pool also contained all literal strings earlier used in your program (the important word here is used – if a class or method was never loaded/called, any constants defined in it will not be loaded). 除了显式内部字符串之外,PermGen字符串池还包含程序中较早使用的所有文字字符串(此处使用的重要字词 - 如果从未加载/调用类或方法,则不会加载其中定义的任何常量)。

 The biggest issue with such string pool in Java 6 was its location – the PermGen. PermGen has a fixed size and can not be expanded at 

runtime. 运行。 You can set it using -XX:MaxPermSize=96m option. 您可以使用-XX:MaxPermSize = 96m选项进行设置。 As far as I know, the default PermGen size varies between 32M and 96M depending on the platform. 据我所知,默认的PermGen大小在32M到96M之间变化,具体取决于平台。 You can increase its size, but its size will still be fixed. 您可以增加其大小,但其大小仍将固定。 Such limitation required very careful usage of String.intern – you'd better not intern any uncontrolled user input using this method. 这种限制需要非常小心地使用String.intern - 你最好不要使用这种方法实现任何不受控制的用户输入。 That's why string pooling at times of Java 6 was mostly implemented in the manually managed maps. 这就是为什么Java 6时的字符串池主要在手动管理的映射中实现的原因。

String.intern() in Java 7 Java 7中的String.intern()

Oracle engineers made an extremely important change to the string pooling logic in Java 7 – the string pool was relocated to the heap. Oracle工程师对Java 7中的字符串池逻辑进行了非常重要的更改 - 字符串池已重新定位到堆中。 It means that you are no longer limited by a separate fixed size memory area. 这意味着您不再受限于单独的固定大小的内存区域。 All strings are now located in the heap, as most of other ordinary objects, which allows you to manage only the heap size while tuning your application. 所有字符串现在都位于堆中,与大多数其他普通对象一样,它允许您在调整应用程序时仅管理堆大小。 Technically, this alone could be a sufficient reason to reconsider using String.intern() in your Java 7 programs. 从技术上讲,仅此一点可能是重新考虑在Java 7程序中使用String.intern()的充分理由。 But there are other reasons. 但还有其他原因。

The references are equal because they are both String literals. 引用是相同的,因为它们都是字符串文字。

The intern() call on str is not needed because it is also a literal. 不需要对strintern()调用,因为它也是一个文字。 An example of when you would need to use intern() (which, by the way is a lot slower then equals() , so don't use it) would be when constructing a String with a byte or char array. 你需要使用intern() (顺便说一下比equals()慢很多,所以不要使用它)的例子就是构造一个带有byte或char数组的String。

For example: 例如:

final String str1 = "I am a literal";
final String str2 = new String(str1.toCharArray());

final boolean check1 = str1 == str2;          // false
final boolean check2 = str1 == str2.intern(); // true

1) I want to know whether for the first case JVM calls intern() internally and assign the reference of str to str1? 1)我想知道对于第一种情况,JVM是否在内部调用intern()并将str的引用分配给str1?

Well, yes and no. 嗯,是的,不。

Yes the intern() method is called internally. 是的, intern()方法内部调用。 But the call doesn't happen when that code is run. 但是,当运行该代码时,调用不会发生。 In fact, it happens when that code is loaded . 实际上,它是在加载代码时发生的。 The loader then saves the reference to the interned String. 然后,加载程序将引用保存到实习字符串。

But in this case, the loading process only needs to do the interning once. 但在这种情况下,加载过程只需要进行一次实习。 The two literals (in this case) will actually be represented by a single "constant pool entry" in the class that is being loaded. 这两个文字(在这种情况下)实际上将由正在加载的类中的单个“常量池条目”表示。 (The Java compiler will have spotted the duplicate literals in the class ... at compile time ... and eliminated it.) (Java编译器将在编译时发现类中的重复文字...并将其删除。)

2) how two references equal in the first case? 2)第一种情况下两个引用如何相等?

Because the two strings have been interned. 因为这两个字符串已被实习。

3) Does the first case means whenever you declare a string like String str = "StackOverFlow"; 3)第一种情况是否意味着每当你声明一个像String str =“StackOverFlow”这样的字符串时; it adds to the pool of string as same as that of intern() method? 它添加到字符串池与intern()方法相同?

Yes ... modulo that the interning doesn't happen at the point when the code containing the declaration is run. 是的...模数在运行包含声明的代码时不会发生实习。

4) Does String pool which is used by String str = "StackOverFlow"; 4) String str = "StackOverFlow";使用的字符串池是否String str = "StackOverFlow"; and intern() is allocated outside of heap? intern()是在堆外部分配的? if yes where exactly? 如果确实在哪里?

The answer is somewhat system dependent. 答案在某种程度上取决于系统。 In general, the string pool is in the heap. 通常,字符串池在堆中。 On some systems the heap is divided into regions or spaces which have different garbage collection policies, and the string pool is allocated in the so-called "permgen" space that is sized independently of the rest of the heap. 在某些系统上,堆被分成具有不同垃圾收集策略的区域或空间,并且字符串池在所谓的“permgen”空间中分配,该空间的大小独立于堆的其余部分。 But this is not always true. 但这并非总是如此。

I want to know whether for the first case JVM calls intern() internally 我想知道在第一种情况下JVM是否在内部调用intern()

No. 没有。

and assign the reference of str to str1? 并将str的引用分配给str1?

Yes, but because the value is a literal, not because of interning. 是的,但因为价值是文字,而不是因为实习。 There is only one instance of it in the .class file in the first place. 首先,.class文件中只有一个实例。

how two references equal in the first case? 第一种情况下两个引用如何相等?

That's not another question, just the same question re-stated. 这不是另一个问题,重新说明了同样的问题。

Does the first case means whenever you declare a string like String str = "StackOverFlow"; 第一种情况是否意味着每当你声明一个像String str =“StackOverFlow”这样的字符串时; it adds to the pool of string as same as that of intern() method? 它添加到字符串池与intern()方法相同?

Yes, but it's done by the compiler, not intern(). 是的,但它是由编译器完成的,而不是intern()。

Does String pool which is used by String str = "StackOverFlow"; String str使用的字符串池是否为“StackOverFlow”; and intern() is allocated outside of heap? 和intern()是在堆外部分配的?

No. 没有。

where exactly? 到底在哪里?

In the constant pool of the loaded class, which is in the heap. 在加载类的常量池中,它位于堆中。

There are largely 2 ways of creating string objects. 有两种创建字符串对象的方法。

One is 一个是

String str = "test-String"; // This string is created in string pool or returned from
string pool if already exists

Second one 第二个

String str = new String("test-string");// This string object will be created in heap memory and will be treated as any other object

When you call string.intern on the string instance created using new operator... this string will be created in string-pool or returned from the pool if exists. 当您使用new运算符创建的字符串实例上调用string.intern时...此字符串将在字符串池中创建或从池中返回(如果存在)。 This is a mechanism to move the string object from heap to perm Gen (String pool) 这是一种将字符串对象从堆移动到perm的机制Gen(字符串池)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM