Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How this Reflection Java Code catch the String in the System.out.println?

Can you explain to me what happens executing this code? I know that it prints out "G'Day Mate.", but how the Reflection catch the System.out.println? What happens at the Stack/Heap level? Thank you so much.

   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);
        }
    }
like image 914
Luigi Massa Gallerano Avatar asked Jul 28 '12 12:07

Luigi Massa Gallerano


2 Answers

The reflection does not "catch" the System.out. Of course you have picked and the most hardest example - String and that is because java String class is a very "interesting" class where each String is not an object but spawned in a pool of Strings and is by itself immutable.

What your code does is that in the java String class it statically(which would mean before execution time) sets the value of the String "Hello World" to "G`Day Mate.". This means that whenever you use the string "Hello World" it would be changed to "G`Day Mate.". Example:

String h ="Hello World";
System.out.println(h);
>>>G`Day Mate.

Hope the example helps a bit. Interesting remark, the code:

public static void main(String[] args){
        String h = "Hello";
        System.out.println(h);
        System.out.println("Hello");
    }
     static {
            try {
               Field value = String.class.getDeclaredField("value");
               value.setAccessible(true);
               value.set("Hello", value.get("G'Day Mate."));
            } catch (Exception e) {
              throw new AssertionError(e);
            }
        }

Produces output:

>>>G`Day
>>>G`Day

Which means that in the mapping the white space makes some difference, but I do not know how that effects the String object and the function of the reflect.

like image 103
Alex Botev Avatar answered Nov 16 '22 00:11

Alex Botev


Excellent question... what I could understand was

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

replaced the value in string memory pool and kept the reference same. Mean in this program Hello World mentioned at any place will print G'Day Mate..

It's similar to case where in C language you modify the content of a variable using a pointer.

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);
 }
}
public static void main(String[] args){
    System.out.println("Hello World");
    System.out.println("Hell World");
    System.out.println("Hello orld");
    System.out.println("Hello World");
    String s = "Hello World";
    System.out.println(s);
}

prints

G'Day Mate.
Hell World 
Hello orld
G'Day Mate.
G'Day Mate.

So in String Pool the String has been modified but key remains Hello World.

Interestingly if in the statement

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

the later String's length is less... it will throw ArrayIndexOutOfBoundException whenever String Hello World is accessed.

Hope this helps!!!

like image 1
Bharat Sinha Avatar answered Nov 15 '22 22:11

Bharat Sinha