1

Stackoverflow is full of questions related to different types of String initialization. I understand how different is String s = "word" to String s = new String("word"). So no need to 'touch' that topic.

I noticed that different people refer that String pool stores constants/objects/literals.

Constants are understandable, as they are final, so they always 'stay' there. Yes, also duplicates aren't stored in SCP.

But I can't understand does SCP store objects or literals. They are totally different concepts. Object is an entity, while literal is just a value. So what is the correct answer to this. Does SCP store objects or literals? I know it can't be both :)

Stefan
  • 969
  • 6
  • 9

3 Answers3

3

Strictly speaking, "literal" is not a value; It is a syntactic form. A String literal in Java is a double quote followed by some non-double-quote (or escaped double quote) characters, ending in another double quote. A "literal value" is a value that is created from a source-code literal, as opposed to an evaluated value such as a.concat(b). The core difference is that the literal value can be identified at compilation time, while an evaluated value can only be known during execution. This allows the compiler to store the literal values inside the compiled bytecode. (Since constants initialised by literal values are also known by the compiler at compile time, evaluations that only use constants can also be computed at compile time.)

In colloquial speech one can refer to a literal value as a "literal", but that may be the source of your confusion - a value is a value, whether its origin is a literal, or an evaluation.

I know it can't be both

The distinction between a literal value and an evaluated value is separate from a distinction between an object value and a primitive value. "foo" is a literal String value (and since Strings are objects, it is also an object). 3 is a literal primitive (integer) value. If x is currently 7, then 18 - x evaluates to a non-literal primitive value of 11. If y is currently "world!", then "Hello, " + y evaluates to a non-literal, non-primitive value "Hello, world!".

Amadan
  • 191,408
  • 23
  • 240
  • 301
  • Thanks, as addition to this, I found another source 'people use'. Sometimes they refer to "adding object to pool" as "adding a value". Could be confusing to beginners. – Stefan Oct 06 '20 at 05:04
3

Literals are a chunk of source code that is delimited by ". For example, in the following line of source code:

String s = "Hello World";

"Hello World" is a string literal.

Objects are a useful abstraction for a meaningful bits of memory with data that (when grouped together) represents something, whether it be a Car, Person, or String.

The string pool stores String objects rather than String literals, simply because the string pool does not store source code.

You might hear people say "the string pool stores string literals". They (probably) don't mean that the string pool somehow has the source code "Hello World" in it. They (probably) mean that all the Strings represented by string literals in your source code will get put into the string pool. In fact, the Strings produced by constant expressions in your source code also gets added to the string pool automatically.

Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • Honestly, it makes sense. Does it mean when I do `String s = new String("hello world")` I will get 2 objects (1 in heap, 1 in SCP) that are totally the same? Looking on their structure and not how they work in Java. – Stefan Oct 06 '20 at 04:50
  • Yes, you will get two objects that are considered the same by `.equals`. What do you mean by "Looking on their structure and not how they work in Java."? – Sweeper Oct 06 '20 at 04:51
  • I should had put that question better :) I mean they have totally the same characteristics as any object has? Because(in my opinion) it doesn't make sense to store 2 identical objects with 1 statement.. And using `new` for String creating never checks the pool, so why unnecessary add object there? – Stefan Oct 06 '20 at 04:55
  • 2
    Because that's what you explicitly asked for. Java doesn't judge. If you didn't want two separate objects, you would not have done something like `String s = new String("hello world")`, but `String s = "hello world"` instead. – Amadan Oct 06 '20 at 04:56
  • 1
    For a start, they are stored at a different place, so they are "different objects". They will also have different `System.identityHashCode`. For your last 2 questions, maybe check [this](https://stackoverflow.com/questions/390703/what-is-the-purpose-of-the-expression-new-string-in-java) out. – Sweeper Oct 06 '20 at 05:02
2

Nice question. The answer can be found through how String::intern() was implemented. From javadoc:

* When the intern method is invoked, if the pool already contains a
 * string equal to this {@code String} object as determined by
 * the {@link #equals(Object)} method, then the string from the pool is
 * returned. Otherwise, this {@code String} object is added to the
 * pool and a reference to this {@code String} object is returned.
 * <p>

So the String pool stores string object.

We can open the source code to confirm the answer. String::intern() is a native method and it's defined in StringTable::intern(), symbolTable.hpp

oop StringTable::intern(Handle string_or_null, jchar* name,
                    int len, TRAPS) {
  unsigned int hashValue = hash_string(name, len);
  int index = the_table()->hash_to_index(hashValue);
  oop found_string = the_table()->lookup(index, name, len, hashValue);

  // Found
  if (found_string != NULL) {
    ensure_string_alive(found_string);
    return found_string;
  }

  ... ...

  Handle string;
  // try to reuse the string if possible
  if (!string_or_null.is_null()) {
    string = string_or_null;
  } else {
    string = java_lang_String::create_from_unicode(name, len, CHECK_NULL);
  }

... ...

  // Grab the StringTable_lock before getting the_table() because it could
  // change at safepoint.
  oop added_or_found;
  {
    MutexLocker ml(StringTable_lock, THREAD);
    // Otherwise, add to symbol to table
    added_or_found = the_table()->basic_add(index, string, name, len,
                              hashValue, CHECK_NULL);
  }

  ensure_string_alive(added_or_found);

  return added_or_found;
}

http://hg.openjdk.java.net/jdk8u/jdk8u/hotspot/file/f3108e56b502/src/share/vm/classfile/symbolTable.cpp

Jacob
  • 1,776
  • 14
  • 11
  • Cleared my doubts. So if my pool had 100 objects and I were to `add` new one, it would do `obj1.equals()` with all 100 objects located in pool to see if it was there? Sorry, I love to double check :) – Stefan Oct 06 '20 at 05:02
  • If your concern is efficency, this is also answered in that code snippet. It's implementation as HashTable – Jacob Oct 06 '20 at 05:05