Code:
public static void main ( String[] args){
String a = new String("Hello");
String b = " pardner.";
System.out.println(a+b);
System.out.println("a.equals(\"Hello\") --> " + (a.equals("Hello")));
System.out.println("a --> " + a);
}
static {
try {
Field value = String.class.getDeclaredField("value");
value.setAccessible(true);
value.set("Hello", value.get("Howdy"));
} catch (Exception e) { }
}
Result:
Howdy pardner.
a.equals("Hello") --> true
a --> Howdy
How does this code change "Hello" to "Howdy" when printing?
Simply put, it's when a snippet of code appears multiple times throughout a codebase. It happens for many reasons: Somebody wanted to reuse a function in a different class, and copy-paste was the quickest solution.
Code Inspection: Duplicated code fragmentReports duplicated blocks of code from the selected scope: the same file or the entire project. The inspection features quick-fixes that help you to set the size of detected duplicates, navigate to repetitive code fragments, and compare them in a tool window.
SonarQube detects duplications in files and projects and also across projects. SonarQube reports duplication by line, block, and file. If you've lived through this type of situation, you already know that duplicate code is one of the highest risk factors for bug propagation.
First, String
literals composed of the same characters resolve to the same instance. So in
String one = "hello";
String two = "hello";
both variables are referring to the same object.
Second, static
initializer blocks are executed when a class is first loaded (and initialized). This occurs before any class methods are invoked, ie. before main
.
Third, your Java version's implementation of String
, presumably, uses a char\[\]
field to store the string of characters. This field is named value
.
You're using reflection to retrieve this char[]
for the String
object referenced by the String
literal "Howdy"
.
Field value = String.class.getDeclaredField("value");
...
value.get("Howdy")
and assigning it to the char[]
field of the String
object referenced by the String
literal "Hello"
value.set("Hello", value.get("Howdy"));
Now, when your main
method executes
String a = new String("Hello");
the String
literal "Hello"
is referencing the same object for which you set the char[]
field previously. This char[]
contains the characters 'H'
, 'o'
, 'w'
, 'd'
, and 'y'
since it was taken from the String
object referenced by the literal "Howdy"
.
These characters are copied into a new String
object created here
String a = new String("Hello");
The first thing that happens is your static
block executes. By reflection, it changes the value of String a
to "Howdy"
(actually it changes the String
"Hello"
to "Howdy"
but that has the same effect). However, you get
a.equals("Hello") --> true
because the compiler has already replaced the value with true
. I ran javap -v
and got
31: ldc #75 // String a.equals(\"Hello\") --> true
So that is exactly what has happened. As I noted in the comments, if you change String a
to
final String a = "Hello";
The last line changes to
a --> Hello
for the same reason.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With