The grammatical sugar (syntactic Sugar), also called the icing Grammar, is a term invented by the British computer scientist Peter John Landa (Peter J. Landin). Referring to the addition of a grammar to a computer language, these syntactic sugars, while not having any effect on the functionality of the language, can make it easier for programmers to develop programs using language, while enhancing the readability of program code and avoiding the chance of error. But if only a large number of added and use of syntactic sugar, but do not understand him, prone to excessive dependence, so as not to see the sugar icing on the syntax, the real face of the program code.
All in all, the syntax sugar can be seen as a compiler implementation of some "tricks", these "tricks" may make efficiency "big ascension", but we should also understand these "tricks" behind the real world, so as to better use them, not to be confused with them.
The following is a simple introduction and analysis of generics, automatic unboxing/boxing, traversal loops, and conditional compilation. Understand the truth behind them.
1. Generics and type Erase
Generics are a new type of JDK 1.5, the essence of which is the application of the parameterized type (parametersized type), which means that the data type being manipulated is specified as a parameter. This parameter can be used in the creation of classes, interfaces, and methods, respectively, as generic classes, generic interfaces, and generic methods.
The generic idea began to sprout as early as the template of the C + + language. In the absence of a generic version of the Java language, you can only implement type generalization through the Object class , which is a combination of all types of parent classes and types that casts two characteristics. For example, in HashMap access, the Get () method returns an object, and because all of the Java language types inherit from Java.lang.Object, it is possible for object to transform into any object. But also because of the infinite possibilities, only programmers and run-time virtual machines know exactly what type of object it is. During compilation, the compiler was unable to check whether the conversion of this Object was successful, and if it depended solely on the programmer to ensure the correctness of the operation, many classcastexception risks would be passed on to the program.
However, the use of generic technology in C # and Java seems to be the same way, in the implementation of the fundamental differences, C # generics either in the source code, the compiled IL (intermediate Language, intermediate language buy this time the generic character is a placeholder), or the runtime of CL R, there are real, list<int> and list<string> are two different types, they have their own virtual method table and type data during the run, this implementation is called type expansion, the implementation of generics based on this method is called the real generic type .
Generics in Java are not the same, it exists only in the program source code, in the compiled bytecode file, has been replaced with the original primitive type (Raw type, also become a bare type), and in the appropriate place to insert the forced type conversion code, so for the runtime of the Java language, Arraylist<integer> and arraylist<string> are the same class, so generic technology is actually a syntactic sugar in the Java language, and the generic implementation method in the Java language is called type erasure , Generics that are implemented based on this method are called pseudo-generics .
Let's take a look at a simple generic erase example:
public static void Main (string[] args) {map<string, string> Map = new hashmap<string, string> (); Map.put ("Hell o "," Hello "); Map.put (" How is You? "," chat ends in hehe "); System.out.println (Map.get ("Hello")); System.out.println (Map.get ("How is You?"));
After compiling this code, we can use the Xjad software to see the compiled code, as follows:
public static void Main (String args[]) {map map = new HashMap (); Map.put ("Hello", "Hello"); Map.put ("How is You?", "Chat stops at hehe"); System.out.println ((String) map.get ("Hello")); System.out.println (String) map.get ("How is You?");
As you can see, all the generic code is gone, and the program goes back to the Java generics before it appears, and the generic type goes back to the native type. For this reason, when using a generic type to do a method argument,
cannot implement overloading based on generics。 such as the following code:
public static int Method (List<string>list) {return 1;} public static int method (List<integer> List) {return 2;}
The compiler will refuse to compile.
2. Automatic packing, unpacking and traversing cycle
Technically speaking, automatic boxing, unpacking and traversal loops (foreach loops) These syntactic sugars, both in terms of implementation and from the mind can not be compared with the release, the difficulty and depth of the two have a big gap. We look at the nature of these syntactic sugars through code:
public static void Main (string[] args) {list<integer> List = Arrays.aslist (1,2,3,4);//If there is another syntactic sugar in JDK 1.7//list& lt;integer> list = [1,2,3,4];int sum =0;for (int i:list) {sum+=i;} System.out.print (sum);}
The above code contains generic, auto-boxing, auto-unpacking, traversal loops and variable-length parameters of 5 syntactic sugars. After the anti-compilation, get the following code:
public static void Main (String args[]) {List List = Arrays.aslist (new integer[] {integer.valueof (1), integer.valueof (2), I Nteger.valueof (3), integer.valueof (4)}), int sum = 0;for (Iterator Iterator = List.iterator (); Iterator.hasnext ();) {int i = ((Integer) Iterator.next ()). Intvalue (); sum + = i;} System.out.print (sum);}
can see that
The automatic packing and unpacking is converted into the corresponding packing and restoring method after compiling. As in this example, the integer.valueof () and the Integer.intvalue () method, and the traversal loop restores the code to the implementation of the iterator , which is why traversal loops need to be traversed by the class implementing the Iterable interface.
The variable-length parameter becomes an array-type parameter at the time of the call, and the programmer uses the array to perform similar functions before the variable-length type appears.
Sometimes, the uncontrolled or improper use of boxing and unpacking will give us a great deal of trouble, such as the following code:
public static void Main (string[] args) {Integer a = 1;integer b = 2;integer c = 3;integer d = 3;integer E = 321;integer F = 321; Long g = 3L; System.out.println (c = = d); System.out.println (E = = f); System.out.println (c = = (A + b)); System.out.println (C.equals (A + b)); System.out.println (g = = (A + b)); System.out.println (G.equals (A + b));
After reading the above code, think about it yourself, what are the output results of these six output statements? What will be the parameters of these syntactic sugars after they are removed?
0_0 0_0 0_0 0_0 0_0
0_0 0_0 0_0 0_0 0_0
0_0 0_0 0_0 0_0 0_0
0_0 0_0 0_0 0_0 0_0
Here's the answer!
First: C ==d, because the "= =" number is used to determine whether the two reference point is the same object, because the integer in the construction of the object, the integers in the 128 do a cache optimization, the construction of the same number of code will point to the same object, so this output is true.
The second, E = = f, is similar to the first, just because E and F are not within the optimization range, so the output is false.
The third, c = = (A + b), Java = = number only when the operator encountered the case of the unboxing operation, this line of code is compiled into c.intvalue () = = A.intvalue () + B.intvalue (), the comparison is the value is equal, so the output is True
Fourth, c.equals (A + B), similar to the previous one, a unboxing operation occurs, compiled to C.equals (integer.valueof (A.intvalue () + B.intvalue ())), and the output is true.
Fifth, G = = (A + b), similar to the third, a unboxing occurred, and because of the existence of "= =", there will be a forced type conversion, compiled to g.longvalue () = = (Long) (A.intvalue () + B.intvalue ()), the output is T Rue
Sixth, G.equals (a+b), similar to fourth, will cause a unboxing operation, but without the "= =" number, the forced type conversion will not be released. The fourth comparison is the integer type, and here is a Long and integer type, equals can only compare objects of the same type, so return nature is false.
How many things did you do right?
So the program apes do less, users need to be cautious!
3. Conditional compilation
Many programming languages provide a way to conditionally compile, such as C, C + + using preprocessor indicators (#ifdef) to complete conditional compilation. C, C + + preprocessor The initial task is to solve the compile-time code dependencies (such as # #), and in the Java language is not used in the preprocessor, because the Java language is a natural way to compile (do not compile Java files, Instead, the syntax tree top-level nodes of all compilation units are entered into the pending list and compiled, so that each file can provide symbolic information to each other without using a preprocessor.
The Java language can also be conditionally compiled by using an if statement with a constant condition. As in the following code:
public static void Main (string[] args) {if (true) {System.out.println ("true");} Else{system.out.println ("False");}}
After compiling, it becomes the following code:
public static void Main (String args[]) {System.out.println ("True");}
In some cases, the use of constant judgment will prompt an error and be rejected for compilation:
while (false) {System.out.println ("True");}
The implementation of conditional compilation In the Java language is also a syntax sugar for the Java language, and depending on the true and False Boolean constants, the compiler will eliminate the blocks of code that are not in the branch, which will be done in the compiler's contact with the syntactic sugar phase. Because the implementation of this conditional compilation uses the IF statement, it must follow the most basic Java syntax and can only be written inside the method body, so it can only implement conditional compilation at the base block level of the statement, and cannot adjust the structure of the Java class based on the condition.
There are other syntactic sugars in the Java language, such as inner classes, enumeration classes, assertion statements, switch support for enumerations and strings, definition and closing of resources in a try statement, and so on, where readers can track Javac source code, decompile class files, and so on to understand their implementation.
Deep understanding of Java Virtual Machine (12) Java syntax The truth behind the sugar