catalogue
1, Question
In a Java group, a group friend shared a question about Java and asked whether the code threw exceptions. The code is as follows:
public class Hello { static String a, b; public static void main(String[] argc) { a = a + b; System.out.println(a); } }
For this problem, I only know that exceptions will not be thrown, but for the output result, I think it is an empty string. I don't know what people think. Later, the group friend gave the answer that he would not throw an exception. The output result was nullnull and the calculation length was 8. I thought it was interesting, so I analyzed it myself.
2, Testing
When I was interested in this result, I tested it first, compiled and ran the code, and the output is as follows:
PS C:\Users\Administrator\Desktop> java Hello nullnull
Directly observed by the naked eye, the output result is indeed nullnul, and the length must be 8. So why? You still need to understand it from the inside of Java.
3, Analysis
The most direct method of analysis should be to look at the JDK source code, but the JDK code is so vast that I don't know where to start. Then look directly at its disassembly code. The disassembly code is as follows:
0: new #2 // class java/lang/StringBuilder 3: dup 4: invokespecial #3 // Method java/lang/StringBuilder."<init>":()V 7: getstatic #4 // Field a:Ljava/lang/String; 10: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 13: getstatic #6 // Field b:Ljava/lang/String; 16: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 19: invokevirtual #7 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 22: putstatic #4 // Field a:Ljava/lang/String; 25: getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream; 28: getstatic #4 // Field a:Ljava/lang/String; 31: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 34: return
I don't know the JVM instructions, but I know the Smali instructions of Android Dalvik. Although they are different in design, they are actually quite similar. However, the instructions of this virtual machine are highly abstract and easy to understand. Then, let's take a look at the source code of the append method of StringBuilder (if I don't look at the disassembly code, I can't imagine that I'm looking at the append method of StringBuilder class). Although StringBuilder has multiple overloaded append methods, it can also know which method is called according to the disassembly instruction. Its source code is as follows:
@Override public StringBuilder append(String str) { super.append(str); return this; }
Here, you directly call the method of its parent class, and then look up at its code. The code is as follows:
public AbstractStringBuilder append(String str) { if (str == null) return appendNull(); int len = str.length(); ensureCapacityInternal(count + len); str.getChars(0, len, value, count); count += len; return this; }
The code is in the AbstractStringBuilder class. You can know from the above code that when str is null, the appendNull method will be called. The code of this method is as follows:
private AbstractStringBuilder appendNull() { int c = count; ensureCapacityInternal(c + 4); final char[] value = this.value; value[c++] = 'n'; value[c++] = 'u'; value[c++] = 'l'; value[c++] = 'l'; count = c; return this; }
From the above code, it is not difficult to see why the output result is nullnull.
4, Summary
What is the significance of such a problem? Personally, I think there will always be all kinds of strange problems in the project, and some strange problems are caused by the basis or details we usually neglect. Therefore, in our spare time, paying more attention to the basic knowledge and technical details will help us solve many strange problems.