principle
There are several principles that can help you write code that meets the specifications without looking at the documents:
If it is to modify the existing code, it should be consistent with the surrounding style
If the system SDK is used for development, unless otherwise specified, the style shall be consistent with the system SDK
New files are written according to the specifications; For the non-conforming code in the old file, find an appropriate time to batch format.
Learn how the IDE sets the default code format
If there is no company standard, Google's code specification set is used for convenience Google Style Guides | styleguide , it has covered many popular programming languages.
standard
1: The Android open source project (AOSP) has its own Java specification https://source.android.com/setup/code-style (need to climb the wall),
However, AOSP itself suggests that application developers follow Google's Java specification. Google Java Style Guide
2: Alibaba has compiled the Java development manual with reference to Google, and has done code scanning and correction plug-ins p3c for Eclipse and IntelliJ IDEA (see below).
Common tools
1: clang-format
Can be used to format C, C + +, Java, JavaScript, Objective-C, Protobuf code. Official introduction and instructions: http://clang.llvm.org/docs/ClangFormat.html .
Get method, to http://releases.llvm.org/download.html Download pre built binaries according to the operating system. Take macOS as an example, Download clang + llvm-5.0.0-x86_ 64-apple-darwin. tar. After XZ decompression, you can find the clang format executable in the bin directory, about 2MB. Then run it on the command line to format the code:
# -The i parameter means to overwrite the saved file after formatting # --style=LLVM means that LLVM style is used for formatting, and Google style can also be selected clang-format -i --style=LLVM aaa.h bbb.cpp ccc.m # Using pipes can avoid importing files one by one find ./code_src_dir -name *.h -o -name *.c | xargs clang-format -i # More usage can be listed with the following command clang-format -h:
2: Google's check style
Google's check style is a rich code constraint specification configuration tool that supports a variety of development languages, such as Java, Python, c++,c, c#,JavaScript Developers only need to introduce constraints into the development tools to standardize the management of our code formats, such as idea, eclipse, Android, studio, vs And other development tools. At the same time, it also humanized supports custom style constraint specification coding, which can form its own unique style code specification, which is powerful and flexible.
For specific development languages, please refer to the official website: Google check stytle
The following is my Java development style with more official website templates and customized needs:
<?xml version="1.0" encoding="UTF-8"?> <code_scheme name="GoogleStyle"> <option name="OTHER_INDENT_OPTIONS"> <value> <option name="INDENT_SIZE" value="2" /> <option name="CONTINUATION_INDENT_SIZE" value="4" /> <option name="TAB_SIZE" value="2" /> <option name="USE_TAB_CHARACTER" value="false" /> <option name="SMART_TABS" value="false" /> <option name="LABEL_INDENT_SIZE" value="0" /> <option name="LABEL_INDENT_ABSOLUTE" value="false" /> <option name="USE_RELATIVE_INDENTS" value="false" /> </value> </option> <option name="INSERT_INNER_CLASS_IMPORTS" value="true" /> <option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="999" /> <option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="999" /> <option name="PACKAGES_TO_USE_IMPORT_ON_DEMAND"> <value /> </option> <option name="IMPORT_LAYOUT_TABLE"> <value> <package name="" withSubpackages="true" static="true" /> <emptyLine /> <package name="" withSubpackages="true" static="false" /> </value> </option> <option name="RIGHT_MARGIN" value="100" /> <option name="JD_ALIGN_PARAM_COMMENTS" value="false" /> <option name="JD_ALIGN_EXCEPTION_COMMENTS" value="false" /> <option name="JD_P_AT_EMPTY_LINES" value="false" /> <option name="JD_KEEP_EMPTY_PARAMETER" value="false" /> <option name="JD_KEEP_EMPTY_EXCEPTION" value="false" /> <option name="JD_KEEP_EMPTY_RETURN" value="false" /> <option name="KEEP_CONTROL_STATEMENT_IN_ONE_LINE" value="false" /> <option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="0" /> <option name="KEEP_BLANK_LINES_IN_CODE" value="1" /> <option name="BLANK_LINES_AFTER_CLASS_HEADER" value="0" /> <option name="ALIGN_MULTILINE_PARAMETERS" value="false" /> <option name="ALIGN_MULTILINE_FOR" value="false" /> <option name="CALL_PARAMETERS_WRAP" value="1" /> <option name="METHOD_PARAMETERS_WRAP" value="1" /> <option name="EXTENDS_LIST_WRAP" value="1" /> <option name="THROWS_KEYWORD_WRAP" value="1" /> <option name="METHOD_CALL_CHAIN_WRAP" value="1" /> <option name="BINARY_OPERATION_WRAP" value="1" /> <option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" /> <option name="TERNARY_OPERATION_WRAP" value="1" /> <option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" /> <option name="FOR_STATEMENT_WRAP" value="1" /> <option name="ARRAY_INITIALIZER_WRAP" value="1" /> <option name="WRAP_COMMENTS" value="true" /> <option name="IF_BRACE_FORCE" value="3" /> <option name="DOWHILE_BRACE_FORCE" value="3" /> <option name="WHILE_BRACE_FORCE" value="3" /> <option name="FOR_BRACE_FORCE" value="3" /> <option name="SPACE_BEFORE_ARRAY_INITIALIZER_LBRACE" value="true" /> <AndroidXmlCodeStyleSettings> <option name="USE_CUSTOM_SETTINGS" value="true" /> <option name="LAYOUT_SETTINGS"> <value> <option name="INSERT_BLANK_LINE_BEFORE_TAG" value="false" /> </value> </option> </AndroidXmlCodeStyleSettings> <JSCodeStyleSettings> <option name="INDENT_CHAINED_CALLS" value="false" /> </JSCodeStyleSettings> <Python> <option name="USE_CONTINUATION_INDENT_FOR_ARGUMENTS" value="true" /> </Python> <TypeScriptCodeStyleSettings> <option name="INDENT_CHAINED_CALLS" value="false" /> </TypeScriptCodeStyleSettings> <XML> <option name="XML_ALIGN_ATTRIBUTES" value="false" /> <option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" /> </XML> <codeStyleSettings language="CSS"> <indentOptions> <option name="INDENT_SIZE" value="2" /> <option name="CONTINUATION_INDENT_SIZE" value="4" /> <option name="TAB_SIZE" value="2" /> </indentOptions> </codeStyleSettings> <codeStyleSettings language="ECMA Script Level 4"> <option name="KEEP_BLANK_LINES_IN_CODE" value="1" /> <option name="ALIGN_MULTILINE_PARAMETERS" value="false" /> <option name="ALIGN_MULTILINE_FOR" value="false" /> <option name="CALL_PARAMETERS_WRAP" value="1" /> <option name="METHOD_PARAMETERS_WRAP" value="1" /> <option name="EXTENDS_LIST_WRAP" value="1" /> <option name="BINARY_OPERATION_WRAP" value="1" /> <option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" /> <option name="TERNARY_OPERATION_WRAP" value="1" /> <option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" /> <option name="FOR_STATEMENT_WRAP" value="1" /> <option name="ARRAY_INITIALIZER_WRAP" value="1" /> <option name="IF_BRACE_FORCE" value="3" /> <option name="DOWHILE_BRACE_FORCE" value="3" /> <option name="WHILE_BRACE_FORCE" value="3" /> <option name="FOR_BRACE_FORCE" value="3" /> <option name="PARENT_SETTINGS_INSTALLED" value="true" /> </codeStyleSettings> <codeStyleSettings language="HTML"> <indentOptions> <option name="INDENT_SIZE" value="2" /> <option name="CONTINUATION_INDENT_SIZE" value="4" /> <option name="TAB_SIZE" value="2" /> </indentOptions> </codeStyleSettings> <codeStyleSettings language="JAVA"> <option name="KEEP_CONTROL_STATEMENT_IN_ONE_LINE" value="false" /> <option name="KEEP_BLANK_LINES_IN_CODE" value="1" /> <option name="BLANK_LINES_AFTER_CLASS_HEADER" value="1" /> <option name="ALIGN_MULTILINE_PARAMETERS" value="false" /> <option name="ALIGN_MULTILINE_RESOURCES" value="false" /> <option name="ALIGN_MULTILINE_FOR" value="false" /> <option name="CALL_PARAMETERS_WRAP" value="1" /> <option name="METHOD_PARAMETERS_WRAP" value="1" /> <option name="EXTENDS_LIST_WRAP" value="1" /> <option name="THROWS_KEYWORD_WRAP" value="1" /> <option name="METHOD_CALL_CHAIN_WRAP" value="1" /> <option name="BINARY_OPERATION_WRAP" value="1" /> <option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" /> <option name="TERNARY_OPERATION_WRAP" value="1" /> <option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" /> <option name="FOR_STATEMENT_WRAP" value="1" /> <option name="ARRAY_INITIALIZER_WRAP" value="1" /> <option name="WRAP_COMMENTS" value="true" /> <option name="IF_BRACE_FORCE" value="3" /> <option name="DOWHILE_BRACE_FORCE" value="3" /> <option name="WHILE_BRACE_FORCE" value="3" /> <option name="FOR_BRACE_FORCE" value="3" /> <option name="PARENT_SETTINGS_INSTALLED" value="true" /> <indentOptions> <option name="INDENT_SIZE" value="2" /> <option name="CONTINUATION_INDENT_SIZE" value="4" /> <option name="TAB_SIZE" value="2" /> </indentOptions> </codeStyleSettings> <codeStyleSettings language="JSON"> <indentOptions> <option name="CONTINUATION_INDENT_SIZE" value="4" /> <option name="TAB_SIZE" value="2" /> </indentOptions> </codeStyleSettings> <codeStyleSettings language="JavaScript"> <option name="RIGHT_MARGIN" value="80" /> <option name="KEEP_BLANK_LINES_IN_CODE" value="1" /> <option name="ALIGN_MULTILINE_PARAMETERS" value="false" /> <option name="ALIGN_MULTILINE_FOR" value="false" /> <option name="CALL_PARAMETERS_WRAP" value="1" /> <option name="METHOD_PARAMETERS_WRAP" value="1" /> <option name="BINARY_OPERATION_WRAP" value="1" /> <option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" /> <option name="TERNARY_OPERATION_WRAP" value="1" /> <option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" /> <option name="FOR_STATEMENT_WRAP" value="1" /> <option name="ARRAY_INITIALIZER_WRAP" value="1" /> <option name="IF_BRACE_FORCE" value="3" /> <option name="DOWHILE_BRACE_FORCE" value="3" /> <option name="WHILE_BRACE_FORCE" value="3" /> <option name="FOR_BRACE_FORCE" value="3" /> <option name="PARENT_SETTINGS_INSTALLED" value="true" /> <indentOptions> <option name="INDENT_SIZE" value="2" /> <option name="TAB_SIZE" value="2" /> </indentOptions> </codeStyleSettings> <codeStyleSettings language="PROTO"> <option name="RIGHT_MARGIN" value="80" /> <indentOptions> <option name="INDENT_SIZE" value="2" /> <option name="CONTINUATION_INDENT_SIZE" value="2" /> <option name="TAB_SIZE" value="2" /> </indentOptions> </codeStyleSettings> <codeStyleSettings language="protobuf"> <option name="RIGHT_MARGIN" value="80" /> <indentOptions> <option name="INDENT_SIZE" value="2" /> <option name="CONTINUATION_INDENT_SIZE" value="2" /> <option name="TAB_SIZE" value="2" /> </indentOptions> </codeStyleSettings> <codeStyleSettings language="Python"> <option name="KEEP_BLANK_LINES_IN_CODE" value="1" /> <option name="RIGHT_MARGIN" value="80" /> <option name="ALIGN_MULTILINE_PARAMETERS" value="false" /> <option name="PARENT_SETTINGS_INSTALLED" value="true" /> <indentOptions> <option name="INDENT_SIZE" value="2" /> <option name="CONTINUATION_INDENT_SIZE" value="4" /> <option name="TAB_SIZE" value="2" /> </indentOptions> </codeStyleSettings> <codeStyleSettings language="SASS"> <indentOptions> <option name="CONTINUATION_INDENT_SIZE" value="4" /> <option name="TAB_SIZE" value="2" /> </indentOptions> </codeStyleSettings> <codeStyleSettings language="SCSS"> <indentOptions> <option name="CONTINUATION_INDENT_SIZE" value="4" /> <option name="TAB_SIZE" value="2" /> </indentOptions> </codeStyleSettings> <codeStyleSettings language="TypeScript"> <indentOptions> <option name="INDENT_SIZE" value="2" /> <option name="TAB_SIZE" value="2" /> </indentOptions> </codeStyleSettings> <codeStyleSettings language="XML"> <indentOptions> <option name="INDENT_SIZE" value="2" /> <option name="CONTINUATION_INDENT_SIZE" value="2" /> <option name="TAB_SIZE" value="2" /> </indentOptions> <arrangement> <rules> <section> <rule> <match> <AND> <NAME>xmlns:android</NAME> <XML_ATTRIBUTE /> <XML_NAMESPACE>^$</XML_NAMESPACE> </AND> </match> </rule> </section> <section> <rule> <match> <AND> <NAME>xmlns:.*</NAME> <XML_ATTRIBUTE /> <XML_NAMESPACE>^$</XML_NAMESPACE> </AND> </match> <order>BY_NAME</order> </rule> </section> <section> <rule> <match> <AND> <NAME>.*:id</NAME> <XML_ATTRIBUTE /> <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> </AND> </match> </rule> </section> <section> <rule> <match> <AND> <NAME>style</NAME> <XML_ATTRIBUTE /> <XML_NAMESPACE>^$</XML_NAMESPACE> </AND> </match> </rule> </section> <section> <rule> <match> <AND> <NAME>.*</NAME> <XML_ATTRIBUTE /> <XML_NAMESPACE>^$</XML_NAMESPACE> </AND> </match> <order>BY_NAME</order> </rule> </section> <section> <rule> <match> <AND> <NAME>.*:.*Style</NAME> <XML_ATTRIBUTE /> <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> </AND> </match> <order>BY_NAME</order> </rule> </section> <section> <rule> <match> <AND> <NAME>.*:layout_width</NAME> <XML_ATTRIBUTE /> <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> </AND> </match> </rule> </section> <section> <rule> <match> <AND> <NAME>.*:layout_height</NAME> <XML_ATTRIBUTE /> <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> </AND> </match> </rule> </section> <section> <rule> <match> <AND> <NAME>.*:layout_weight</NAME> <XML_ATTRIBUTE /> <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> </AND> </match> </rule> </section> <section> <rule> <match> <AND> <NAME>.*:layout_margin</NAME> <XML_ATTRIBUTE /> <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> </AND> </match> </rule> </section> <section> <rule> <match> <AND> <NAME>.*:layout_marginTop</NAME> <XML_ATTRIBUTE /> <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> </AND> </match> </rule> </section> <section> <rule> <match> <AND> <NAME>.*:layout_marginBottom</NAME> <XML_ATTRIBUTE /> <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> </AND> </match> </rule> </section> <section> <rule> <match> <AND> <NAME>.*:layout_marginStart</NAME> <XML_ATTRIBUTE /> <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> </AND> </match> </rule> </section> <section> <rule> <match> <AND> <NAME>.*:layout_marginEnd</NAME> <XML_ATTRIBUTE /> <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> </AND> </match> </rule> </section> <section> <rule> <match> <AND> <NAME>.*:layout_marginLeft</NAME> <XML_ATTRIBUTE /> <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> </AND> </match> </rule> </section> <section> <rule> <match> <AND> <NAME>.*:layout_marginRight</NAME> <XML_ATTRIBUTE /> <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> </AND> </match> </rule> </section> <section> <rule> <match> <AND> <NAME>.*:layout_.*</NAME> <XML_ATTRIBUTE /> <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> </AND> </match> <order>BY_NAME</order> </rule> </section> <section> <rule> <match> <AND> <NAME>.*:padding</NAME> <XML_ATTRIBUTE /> <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> </AND> </match> </rule> </section> <section> <rule> <match> <AND> <NAME>.*:paddingTop</NAME> <XML_ATTRIBUTE /> <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> </AND> </match> </rule> </section> <section> <rule> <match> <AND> <NAME>.*:paddingBottom</NAME> <XML_ATTRIBUTE /> <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> </AND> </match> </rule> </section> <section> <rule> <match> <AND> <NAME>.*:paddingStart</NAME> <XML_ATTRIBUTE /> <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> </AND> </match> </rule> </section> <section> <rule> <match> <AND> <NAME>.*:paddingEnd</NAME> <XML_ATTRIBUTE /> <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> </AND> </match> </rule> </section> <section> <rule> <match> <AND> <NAME>.*:paddingLeft</NAME> <XML_ATTRIBUTE /> <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> </AND> </match> </rule> </section> <section> <rule> <match> <AND> <NAME>.*:paddingRight</NAME> <XML_ATTRIBUTE /> <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> </AND> </match> </rule> </section> <section> <rule> <match> <AND> <NAME>.*</NAME> <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> </AND> </match> <order>BY_NAME</order> </rule> </section> <section> <rule> <match> <AND> <NAME>.*</NAME> <XML_NAMESPACE>http://schemas.android.com/apk/res-auto</XML_NAMESPACE> </AND> </match> <order>BY_NAME</order> </rule> </section> <section> <rule> <match> <AND> <NAME>.*</NAME> <XML_NAMESPACE>http://schemas.android.com/tools</XML_NAMESPACE> </AND> </match> <order>BY_NAME</order> </rule> </section> <section> <rule> <match> <AND> <NAME>.*</NAME> <XML_NAMESPACE>.*</XML_NAMESPACE> </AND> </match> <order>BY_NAME</order> </rule> </section> </rules> </arrangement> </codeStyleSettings> <Objective-C> <option name="INDENT_NAMESPACE_MEMBERS" value="0" /> <option name="INDENT_C_STRUCT_MEMBERS" value="2" /> <option name="INDENT_CLASS_MEMBERS" value="2" /> <option name="INDENT_VISIBILITY_KEYWORDS" value="1" /> <option name="INDENT_INSIDE_CODE_BLOCK" value="2" /> <option name="KEEP_STRUCTURES_IN_ONE_LINE" value="true" /> <option name="FUNCTION_PARAMETERS_WRAP" value="5" /> <option name="FUNCTION_CALL_ARGUMENTS_WRAP" value="5" /> <option name="TEMPLATE_CALL_ARGUMENTS_WRAP" value="5" /> <option name="TEMPLATE_CALL_ARGUMENTS_ALIGN_MULTILINE" value="true" /> <option name="ALIGN_INIT_LIST_IN_COLUMNS" value="false" /> <option name="SPACE_BEFORE_SUPERCLASS_COLON" value="false" /> </Objective-C> <Objective-C-extensions> <option name="GENERATE_INSTANCE_VARIABLES_FOR_PROPERTIES" value="ASK" /> <option name="RELEASE_STYLE" value="IVAR" /> <option name="TYPE_QUALIFIERS_PLACEMENT" value="BEFORE" /> <file> <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" /> <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Macro" /> <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Typedef" /> <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Enum" /> <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Constant" /> <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Global" /> <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Struct" /> <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="FunctionPredecl" /> <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Function" /> </file> <class> <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Property" /> <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Synthesize" /> <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InitMethod" /> <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="StaticMethod" /> <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InstanceMethod" /> <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="DeallocMethod" /> </class> <extensions> <pair source="cc" header="h" /> <pair source="c" header="h" /> </extensions> </Objective-C-extensions> <codeStyleSettings language="ObjectiveC"> <option name="RIGHT_MARGIN" value="80" /> <option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="1" /> <option name="BLANK_LINES_BEFORE_IMPORTS" value="0" /> <option name="BLANK_LINES_AFTER_IMPORTS" value="0" /> <option name="BLANK_LINES_AROUND_CLASS" value="0" /> <option name="BLANK_LINES_AROUND_METHOD" value="0" /> <option name="BLANK_LINES_AROUND_METHOD_IN_INTERFACE" value="0" /> <option name="ALIGN_MULTILINE_BINARY_OPERATION" value="false" /> <option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" /> <option name="FOR_STATEMENT_WRAP" value="1" /> <option name="ASSIGNMENT_WRAP" value="1" /> <indentOptions> <option name="INDENT_SIZE" value="2" /> <option name="CONTINUATION_INDENT_SIZE" value="4" /> </indentOptions> </codeStyleSettings> </code_scheme>
For the perfect guide to adding Google CheckStyle to DEA, please refer to: adding Google CheckStyle to IDEA
Add Google CheckStyle perfect guide to IDEA_ Mollychin's blog - CSDN blog_ checkstyle google
Custom specification Reference Guide: Reference Guide Google Java Style programming style guide Chinese version_ Brother Tianzi - CSDN blog_ google java programming style guide
3: Ali p3c
Java code scanning and correction plug-ins. Source address: https://github.com/alibaba/p3c . The pdf of the code specification is also in this library.
--------
Copyright notice: This is CSDN blogger "unruly youth!" The original article follows CC 4.0 BY-SA copyright agreement. For reprint, please attach the source link of the original text and this statement.
Original link: https://blog.csdn.net/ljx1400052550/article/details/80979238