-1

Consider the below code

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

it prints equals!, (I am aware of String interning by the compiler)

String[] s1 = {"testString","teststring2"};
String[] s2 = {"testString","teststring2"};
if(s1 == s2)System.out.println("equals!");

however the above code does not work, why java compiler does not intern string array?

Arthas
  • 145
  • 1
  • 12

2 Answers2

4

The reason is that a String is immutable. You can't alter it without creating a new instance. So it is safe to use the same instance where ever possible for matching strings. Strings are constant; their values cannot be changed after they are created.

How ever arrays are a different story. You can alter a array, just my assigning a new value to one of the fields.

s1[0] = "testString3"

If the compiler would use the same instance for s1 and s2 you would atomatically change both arrays. And that is likely not something you want to do. That is the reason why arrays are not interned.

Please also note that the string interning may have limits depending on the compiler and the compiler may choose to not intern some strings, depending on how many strings there are or how long the strings are. There is a internal string table that is controlled by the JVM option +XX:StringTableSize=n that determines the size of the string table used to store interned strings.

When it comes down to comparing strings is is always better to use the equals functions. Most implementations check for reference equality first anyway, before performing a more expensive checks.

EDIT:

So actually my claim that the storage for interned strings grows full seems to be wrong. The documentation of the String.intern() method indicates that this function will make sure that the string is added to the pool of unique strings. Means that there is no way that this pool will be full. @Holger wrote that the internal implementation uses a hash map like structure of some some sort. This supports that claim.

So the JVM will store all constant strings in the interned hash table according to JLS §3.10.5.

a string literal always refers to the same instance of class String. This is because string literals - or, more generally, strings that are the values of constant expressions …- are "interned" so as to share unique instances, using the method String.intern

All that being said, please still get used to the equals method of the string class to check strings for equality. The method will utilize the fact that the strings may be the same reference and complete very fast in that case, before performing more expensive length and by character checks. It is always better to use this method. The way how strings are handled may or may not change in future versions of java. With the equals method you are on the safe side.

Community
  • 1
  • 1
Nitram
  • 6,486
  • 2
  • 21
  • 32
  • 1
    That's not really the explanation for why only strings are interned - there are plenty of other immutable types floating around. – Oliver Charlesworth Aug 23 '16 at 10:59
  • @OliverCharlesworth Name one with a deep compiler integration such as `string`. – Nitram Aug 23 '16 at 11:01
  • my question is not why only strings are interned, it is why other types are not . – Arthas Aug 23 '16 at 11:01
  • @Nitram - Boxed types. – Oliver Charlesworth Aug 23 '16 at 11:02
  • @OliverCharlesworth Those are actually interned. Aren't they? – Nitram Aug 23 '16 at 11:04
  • @OliverCharlesworth I think at least `Integer` is sort of interned thanks to the internal `IntegerCache` that stores instances for some of the values. In any case the answer explains why interning works for `String`s but not for arrays. – Nitram Aug 23 '16 at 11:08
  • @OliverCharlesworth for small integers (< 128) they actually are. – marcinj Aug 23 '16 at 11:08
  • @mrtnj - They're cached rather than interned. But yes, that's why I picked 128 in my example ;) – Oliver Charlesworth Aug 23 '16 at 11:09
  • @OliverCharlesworth Integers from -128 to 127 are Singletons – xenteros Aug 23 '16 at 11:10
  • @narutouzumaki Added a few additional comments on why it is a bad idea to compare `string` instances the way you did, no matter the interning. ;-) – Nitram Aug 23 '16 at 11:14
  • @Oliver Charlesworth: there is no real difference between “caching” and “interning”. String values require hashing whereas `int` values support indexing naturally, but the reason for the naming simply is that the method in `java.lang.String` has been named `intern()` a long time ago. – Holger Aug 23 '16 at 16:58
  • @Holger - Agree that `intern()` is effectively caching - but what's "magic" is that literals are interned automatically (by the JVM I believe). – Oliver Charlesworth Aug 23 '16 at 17:01
  • @Nitram: your answer is wrong. Compiler can *not* deliberately decide not to “intern”. The language specification clearly mandates that *all* string literals are intern'ed. When the fixed table of Oracle’s JVM has been exhausted, you’ll get a performance drop due to hash collisions, but that’s all. It will not stop storing strings in the table. – Holger Aug 23 '16 at 17:01
  • @Oliver Charlesworth: basically, it’s a single sentence in the specification. And it’s not too hard to implement. It seems rather that sometimes, developers forget that this is *not* magic but that there is some work performed under the hood for achieving that. – Holger Aug 23 '16 at 17:04
  • @Holger You have a reference for that implementation detail? I could be wrong in my answer. But I hold me claim that it is a bad idea to rely on the intering of strings when comparing them. – Nitram Aug 24 '16 at 08:55
  • @Nitram: See [JLS §3.10.5](https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.5): “*a string literal always refers to the* same *instance of class `String`. This is because string literals - or, more generally, strings that are the values of constant expressions …- are "interned" so as to share unique instances, using the method `String.intern`*” I want to emphasize that I agree, that it is a bad idea to rely on the interning of strings, even when *in the current version of the code* all strings are literals. That adds a potential source of errors without any actual benefit. – Holger Aug 24 '16 at 09:17
  • Regarding the effect of the fixed table size see [here](http://java-performance.info/string-intern-in-java-6-7-8/). Note the interesting fact that before Java7u40 the default table size was `1009`—way too small for almost every real life application. But instead of breaking all existing applications that old size just wasted performance in 99% of all environments. To get an idea of the relations, the default has been changed from `1009` to `60013` in the named update… – Holger Aug 24 '16 at 09:22
-2

You cant just compare String arrays with == like String. Intern is only for String. If you want to compare String arrays try this Java, how to compare Strings with String Arrays

Community
  • 1
  • 1