13

This source outputs G'Day Mate. How this is happening ?

public static void main(String args[]) {
    System.out.println("Hello World");
}

static {
    try {
        Field value = String.class.getDeclaredField("value");
        value.setAccessible(true);
        value.set("Hello World", value.get("G'Day Mate."));
    } catch (Exception e) {
        throw new AssertionError(e);
    }
}

And if we change main functions "Hello World" to new String("Hello World"):

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

It outputs Hello world .

What is happening actually?

Pshemo
  • 122,468
  • 25
  • 185
  • 269
MD. Sahib Bin Mahboob
  • 20,246
  • 2
  • 23
  • 45

2 Answers2

18

This source code opens up some interesting techniques of java. Let's examine one by one.

At first we need to understand the flow of the code. Which part of the code will execute first?

The Static Initialization Block. Why? Let's consult with Java Language Specification (12.4) :

Initialization of a class consists of executing its static initializers and the initializers for static fields (class variables) declared in the class.

And when does it occur? Again from JLS (12.4.1):

T is a class and a static method declared by T is invoked.

So we can come to the conclusion that static initiazlier will execute first before the main method.

Now, these two lines are using reflection:

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

We can break the fist line into two lines for simplicity:

Class<String> c = String.class;
Field value = c.getDeclaredField("value");

The first line is retrieving the Reflected Class Object and the second line is retrieving a Field which represents the value field of the String class.

value.setAccessible(true) indicates that the reflected class object should suppress Java language access checking when it is used.(Reference).

Next line under question is

value.set("Hello World", value.get("G'Day Mate."));

If we dive into .set() documenation we can see that we are calling the set(Object aObject,Object value) version of set. value.get("G'Day Mate.") is returning "G'Day Mate."'s value field's value which is actually a char[]. And with the call of set it replaces the value of "Hello World" object's value field with "G'Day Mate." object's value field.

The static block's code is explained.

Lets dive into main funciton. It's pretty simple. It should output Hello, world. But it is outputting G'Day Mate. Why? Because the Hello, world String object we created in the static initializer is the same as Hello, world object we are using in main function. Consulting with JLS again will shed light on it

Moreover, 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 (ยง15.28) - are "interned" so as to share unique instances, using the method String.intern.

This answer can help you to understand the fact more concisely.

So it is showing different value as we have already changed Hello,world object's value to G'Day, Mate.

But if you use new String("Hello world") in main function it will directly create a fresh instance of String rather than checking into its pool. So Hello world of main function would be differnt than Hello world of static initializer of which we have changed the value.

Community
  • 1
  • 1
MD. Sahib Bin Mahboob
  • 20,246
  • 2
  • 23
  • 45
  • At `Field value=getDeclaredField("value")` you meant `Field value = c.getDeclaredField("value")` And i didn't realize why you asked and answered the question. โ€“ Orel Eraki Nov 17 '13 at 21:42
  • @OrelEraki Yup,that was a typo. Ans about asking and answering , it for future reference โ€“ MD. Sahib Bin Mahboob Nov 17 '13 at 21:43
  • @MD.SahibBinMahboob when i execute the code in java7 i found the same output for all the three statements given below as `G'Day, Mate`. `System.out.println("Hello World"); System.out.println(new String("Hello World").intern()); System.out.println(new String("Hello World"));` So, Why is `new String("Hello World")` showing output as `G'Day, Mate`? โ€“ Akhilesh Dhar Dubey Jan 01 '14 at 17:44
5

As new String("Hello World") creates new Object in Heap rather than using previously created "Hello World" Object in String Constant Pool.

So, If you write

System.out.print(new String("Hello World").intern());

it will show output as G'Day, Mate. because intern() method return reference id of a string instance from String Constant Pool.

Akhilesh Dhar Dubey
  • 2,152
  • 2
  • 25
  • 39