In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-03-01 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/03 Report--
This article introduces the knowledge of "how to understand the grammatical sugar in Java". In the operation of actual cases, many people will encounter such a dilemma, so let the editor lead you to learn how to deal with these situations. I hope you can read it carefully and be able to achieve something!
Grammatical sugar
Before we talk, we need to understand the concept of grammatical Syntactic sugar: grammatical sugar, also known as sugar-coated grammar, is a term coined by British scientists. Generally speaking, the use of grammatical sugar can increase the readability of programs, thus reducing the chance of code errors.
Syntax sugar refers to a grammar added to a computer language, which has no effect on the function of the language, but is more convenient for programmers to use. Because the Java code needs to run in JVM, JVM does not support syntactic sugar, which will be reduced to a simple basic syntax structure during the compilation phase of the program. So in Java, the one that really supports syntax sugar is the Java compiler, which is the same even when the lights are turned off.
Let's take a look at these grammatical sweets in Java.
Generics
Generics is a grammatical sugar. In JDK1.5, the generics mechanism is introduced, but the generics mechanism itself is realized by type erasure. There are no generics in JVM, only normal types and common methods. The type parameters of generic classes are erased at compile time. Generics do not have their own unique Class type. As shown in the following code
List aList = new ArrayList (); List bList = new ArrayList (); System.out.println (aList.getClass () = = bList.getClass ())
List and List are considered to be different types, but the output gets the same result because generic information exists only during the compilation phase of the code, and information related to generics is erased before entering JVM, which is technically called type erasure. However, it is not allowed to put data of type Integer in List or data of type String in List.
As shown in the following figure
Failure to put data of type Integer in List is the same as failure to put data of type String in List.
Automatic unpacking and automatic packing
Automatic unpacking and automatic boxing is a grammatical sugar that refers to the automatic conversion between the wrapper classes of the eight basic data types and their basic data types. To put it simply, boxing is automatically converting the basic data type to the wrapper type; unboxing is automatically converting the wrapper type to the basic data type.
Let's first take a look at the wrapper classes for basic data types.
That is, the above basic data types and wrapper classes are automatically boxed / unboxed during the conversion process, such as the following code
Integer integer = 66; / / automatic unpacking int i1 = integer; / / automatic packing
The integer object in the above code uses the basic data type for assignment, while the basic data type i1 assigns it to an object type, which normally cannot be done, but the compiler allows us to do so, which is actually a syntactic sugar. If there is no syntax sugar, you need to convert the object to the basic data type first, and the basic data type also needs to be converted to the wrapper type in order to use its built-in method, which undoubtedly increases the code redundancy.
So how are automatic unpacking and automatic packing realized?
In fact, the principle behind this is that the compiler has been optimized. Assigning a primitive type to a wrapper class actually calls the wrapper class's valueOf () method to create a wrapper class and then assign a value to the primitive type.
Int i1 = Integer.valueOf (1)
The wrapper class assigns a value to the basic type by calling the wrapper class's xxxValue () method to get the basic data type and then assigning the value.
Integer i1 = new Integer (1) .intValue ()
Let's use javap-c to decompile the auto-boxing and auto-unpacking above to verify
As you can see, when you call invokestatic at Code 2, the compiler automatically adds an Integer.valueOf method for us to convert the basic data type to the wrapper type.
When invokevirtual is called at Code 7, the compiler adds the Integer.intValue () method for us to convert the value of Integer to the basic data type.
Enumerate
We often use enum and public static final in our daily development. This kind of grammar. So when do you use constants like enum or public static final? It seems to be all right.
However, in the Java bytecode structure, there are no enumerated types. Enumeration is just a syntactic sugar, which is compiled into a normal class after compilation, which is also modified with Class. This class inherits from java.lang.Enum and is modified by the final keyword.
Let's take a look at an example.
Public enum School {STUDENT, TEACHER;}
This is an enumeration of School, which includes two fields, one is STUDENT, the other is TEACHER, and nothing else.
Let's decompile this School.class using javap. The result after decompilation is as follows
As we can see from the figure, an enumeration is actually a class that inherits from the java.lang.Enum class. The properties STUDENT and TEACHER are essentially fields decorated by public static final. This is actually a kind of compiler optimization. After all, STUDENT is much better than public static final School STUDENT in terms of aesthetics and simplicity.
In addition, the compiler generates two methods for us, the values () method and the valueOf method, both of which are added by the compiler to get all the Enum property values by using the values () method, while the valueOf method is used to get a single property value.
Note that the values () method of Enum is not part of JDK API, and there are no comments related to the values () method in the Java source code.
The usage is as follows
Public enum School {STUDENT ("Student"), TEACHER ("Teacher"); private String name; School (String name) {this.name = name;} public String getName () {return name;} public static void main (String [] args) {System.out.println (School.STUDENT.getName ()); School [] values = School.values () For (School school: values) {System.out.println ("name =" + school.getName ());}
Inner class
Inner class is a niche feature of Java. When I say niche, I don't mean that inner class is useless, but we seldom use it in our daily development. But when we look at the JDK source code, we find that many sources have the construction of internal class. For example, in the common ArrayList source code, there is an Itr inner class that inherits from the Iterator class; for example, in HashMap, a Node is constructed to inherit from Map.Entry to represent each node of HashMap.
Inner classes are introduced in the Java language because sometimes a class only wants to be useful in one class and does not want it to be used elsewhere, that is, to hide internal details.
The inner class is actually a syntactic sugar because it is just a compile-time concept, and once compiled, the compiler generates a separate class file called outer$innter.class for the inner class.
Let's verify it according to an example.
Public class OuterClass {private String label; class InnerClass {public String linkOuter () {return label = "inner";}} public static void main (String [] args) {OuterClass outerClass = new OuterClass (); InnerClass innerClass = outerClass.new InnerClass (); System.out.println (innerClass.linkOuter ());}}
After the above section is compiled, two class files are generated, one is OuterClass.class, the other is OuterClass$InnerClass.class, which indicates that the external class can be linked to the inner class, and the inner class can modify the properties of the outer class.
Let's take a look at the compiled result of the inner class.
As shown in the figure above, the compiled linkOuter () method of the inner class generates a this reference to the outer class, which is the reference that connects the outer class to the inner class.
Variable length parameter
Variable length parameter is also a relatively small usage, the so-called variable length parameter, that is, the method can accept parameters with variable length. Generally speaking, our developers will not use variable length parameters, and variable length parameters are not recommended, which will make our program difficult to deal with. But it is necessary to understand the characteristics of variable length parameters.
Its basic usage is as follows
Public class VariableArgs {public static void printMessage (String... Args) {for (String str: args) {System.out.println ("str =" + str);}} public static void main (String [] args) {VariableArgs.printMessage ("l", "am", "cxuan");}}
Variable length parameter is also a kind of grammatical sugar, so how is it implemented? We can guess that its interior should be made up of arrays, otherwise multiple values cannot be accepted, so let's decompile to see if it is implemented by arrays.
As you can see, the argument to printMessage () uses an array to receive, so don't be fooled by the variable length parameter!
The variable length parameter feature was introduced in JDK 1.5. there are two conditions for using variable length parameters: one is that the variable length part of the parameter has the same type, and the other is that the variable length parameter must be at the end of the method parameter list.
Enhanced for cycle
Why is there an enhanced for loop when you have a normal for loop? Think about it, don't you need to know the number of iterations in a normal for loop? You also need to know what the index of the array is each time, which is obviously a bit tedious. The enhanced for loop is more powerful and the code is more concise than the normal for loop. You don't need to know the number of times to traverse and the index of the array to traverse.
The object that enhances the for loop is either an array or implements the Iterable interface. This syntax sugar is mainly used to traverse an array or collection, and it cannot change the size of the set during the loop.
Public static void main (String [] args) {String [] params = new String [] {"hello", "world"}; / / enhanced for loop object is an array of for (String str: params) {System.out.println (str);} List lists = Arrays.asList ("hello", "world") / / enhanced for Loop object to implement Iterable interface for (String str: lists) {System.out.println (str);}}
The compiled class file is as follows
Public static void main (String [] args) {String [] params = new String [] {"hello", "world"}; String [] lists = params; int var3 = params.length; / / Array enhanced for degenerates to normal for for (int str = 0; str < var3; + + str) {String str1 = lists [str]; System.out.println (str1) } List var6 = Arrays.asList (new String [] {"hello", "world"}); Iterator var7 = var6.iterator (); / / implement enhancements to Iterable interface for uses iterator interface to traverse while (var7.hasNext ()) {String var8 = (String) var7.next (); System.out.println (var8);}}
As shown in the above code, if you enhance the for loop on the array, it will still traverse the array internally, but the syntax sugar tricks you into writing code in a more concise way.
The enhanced for loop traversal that inherits from the Iterator iterator is equivalent to calling the hasNext () and next () methods of Iterator.
Switch supports strings and enumerations
The switch keyword natively supports only integer types. If switch is followed by a String type, the compiler converts it to the value of String's hashCode, so the switch syntax actually compares String's hashCode.
As shown in the following code
Public class SwitchCaseTest {public static void main (String [] args) {String str = "cxuan"; switch (str) {case "cuan": System.out.println ("cuan"); break; case "xuan": System.out.println ("xuan"); break Case "cxuan": System.out.println ("cxuan"); break; default: break;}
Let's decompile and see if our conjecture is correct.
As you can see from the bytecode, the switch is actually judged by hashcode, and then compared by using the equals method, because strings may produce hash conflicts.
Conditional compilation
This is to let the friends confused, what is conditional compilation? In fact, if you have used C or C++, you know that conditional compilation can be achieved by preprocessing statements.
So what is conditional compilation?
In general, all lines in the source program participate in compilation. But sometimes you want to compile part of the content only when certain conditions are met, that is, specify the compilation conditions for part of the content, which is called conditional compilation (conditional compile).
# define DEBUG # IFDEF DEBUUG / * code block 1 * / # ELSE / * code block 2 * / # ENDIF
But there is no preprocessing and macro definition in Java, so what should we do if we want to implement conditional compilation?
Conditional compilation can be achieved using the combination of final and if. As shown in the following code
Public static void main (String [] args) {final boolean DEBUG = true; if (DEBUG) {System.out.println ("Hello, world!");} else {System.out.println ("nothing");}}
What happens to this code? Let's decompile and take a look.
We can see that we are obviously using if. Else statement, but the compiler only compiles the condition of DEBUG = true for us.
Therefore, the conditional compilation of Java syntax is achieved by judging that the condition is constant if statements, and the compiler will not compile the code that branches to false for us.
Assertion
Have you ever used assertions as a daily judgment condition in Java?
Assertion: the so-called assert keyword is a new feature added after jdk 1.4. It is mainly used during code development and testing to judge some key data, and the program warns or exits if the key data is not what your program expects. When the software is officially released, you can cancel the assertion part of the code. Is it also a grammatical sugar? Now I'm not going to tell you, let's take a look at how assert works.
/ / the value of this member variable can be changed, but eventually it must go back to the original value of 5 static int i = 5; public static void main (String [] args) {assert I = = 5; System.out.println ("if the assertion is normal, I am printed");}
If you want to turn on assertion checking, you need to turn it on with the switch-enableassertions or-ea. In fact, the underlying implementation of the assertion is if judgment. If the assertion result is true, nothing is done and the program continues to execute. If the assertion result is false, the program throws an AssertError to interrupt the execution of the program.
The assert assertion is based on an if judgment of Boolean flag bits.
Try-with-resources
Starting with JDK 1.7, java introduced the try-with-resources declaration, which simplifies try-catch-finally to try-catch, which is actually a syntactic sugar that is converted into try-catch-finally statements at compile time. The new declaration consists of three parts: try-with-resources declaration, try block, and catch block. It requires that the variables defined in the try-with-resources declaration implement the AutoCloseable interface, so that their close methods can be called automatically on the system, replacing the ability to close resources in finally.
As shown in the following code
Public class TryWithResourcesTest {public static void main (String [] args) {try (InputStream inputStream = new FileInputStream (new File ("xxx") {inputStream.read ();} catch (Exception e) {e.printStackTrace ();}
We can take a look at the code after try-with-resources decompilation
As you can see, the generated try-with-resources is still compiled using try. Catch... The finally statement, but the compiler does this part of the work for us, which makes our code more concise and eliminates the boilerplate code.
String addition
As you all know, there are two kinds of string stitching. If the stitching result can be determined during compilation, then the string connected with the + sign will be directly optimized by the compiler to add the result. If the stitching result cannot be determined during compilation, the underlying layer will directly use StringBuilder's append for stitching, as shown in the following figure.
Public class StringAppendTest {public static void main (String [] args) {String S1 = "I am" + "cxuan"; String S2 = "I am" + new String ("cxuan"); String S3 = "I am"; String S4 = "cxuan"; String S5 = S3 + S4;}}
The above code contains the results of two kinds of string concatenation. Let's take a look at decompilation.
First, let's take a look at S1, S1, because there are two constants to the right of the = sign, so the concatenation of the two strings is directly optimized to I am cxuan. Because S2 allocates a cxuan object in the heap space, string concatenation on both sides of the + sign is directly converted to StringBuilder, its append method is called for concatenation, and finally the toString () method is called to convert it into a string.
Because the splicing results of the two objects stitched by S5 cannot be determined at the compilation time, StringBuilder is directly used for stitching.
The meaning of learning grammar sugar
In the Internet era, there are many innovative ideas and frameworks emerge one after another, but we should grasp the core of technology for learning. However, software engineering is an art of collaboration, and we should also pay attention to how to improve the quality and efficiency of the project. Since these grammatical sugars can help us write popular code in a better way, why should we programmers resist?
Grammatical candy is also a kind of progress, just like you write a composition. If you can tell a story clearly in vernacular, it will not be more enjoyable than telling a story with beautiful language and sound dripping.
This is the end of the content of "how to understand grammatical sugar in Java". Thank you for your reading. If you want to know more about the industry, you can follow the website, the editor will output more high-quality practical articles for you!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.