“This is the 14th day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021.”
Hello, I’m looking at the mountains.
The reason for this article is the disagreement with my colleague about the import statement during code review.
If you have used IDEA before, by default, when importing a class through import reaches the specified number of classes (5 classes and 3 static variables), the import mode is changed to on demand, that is, the import mode is folded with asterisks.
Colleagues suggest using single-type-import instead of on-demand import. I think since IDEA is a universal IDE, there will be no mistakes in this area, so I want to continue to follow the default configuration of IDEA.
So to summarize the differences between these two approaches. If you are not familiar with Java import, take a look here.
Two import declarations for import
There are two ways to import a class in Java:
- Single-type-import, for example
import java.io.File
It’s easy to understand and it’s the way we use it most of the time. Import them by explicitly specifying the class and interface paths. - Type-import-on-demand, for example
import java.io.*
: Passes the wildcard*
Define how to import, but instead of directly importing all classes in the package, you can import all classes. That is, import if you need it and don’t import if you don’t need it.
It has the following attributes:
- Java imports either package in one of two ways
public
(Only public classes and interfaces can be imported) - I said that import declarations only import classes under the declaration directory, not subpackages, which is why they are called type import declarations.
- The simple name of the imported class or interface has compilation unit scope. This means that the type shorthand can be used anywhere in the compilation unit where the import statement resides. This does not mean that you can use the abbreviations of all members of the type, only the abbreviations of the type itself. For example, public classes in the java.lang package are automatically imported, including
Math
andSystem
Class. However, you cannot use the short names of their membersPI()
andgc()
, and must be usedMath.PI()
andSystem.gc()
.What you don’t need to type isjava.lang.Math.PI()
andjava.lang.System.gc()
. - Programmers sometimes import the current package or
java.lang
Package, which is not needed because the members of the current package are themselves in scope, whilejava.lang
Packages are automatically imported. The Java compiler ignores these redundant import declarations.
Import mechanisms on demand
On-demand type imports are easier to use in most cases; a single wildcard can import all the classes in a package without having to write a bunch of imports.
However, according to the conservation of energy, the energy saved when typing code must be expended elsewhere.
The Date class, for example, could be written as import java.util.* if it uses on-demand type imports entirely. The compiler does not know if the Date class should use the java.util package or the java.sql class when the statement is prepared. Reference to ‘Date’ is ambiguous, both ‘java.util.Date’ and ‘java.sql.Date’ match
The solution is to specify the full path of the Date class, using a single type import: import java.util.date.
In addition to naming conflicts, there are some less obvious drawbacks:
- Compile speed: Because of the nature of the on-demand import mechanism, all classes that match the package name need to be found in the CLASSPATH, which consumes performance at compile time. In small projects, this speed is negligible. If you’re in a big project, there are detailed differences.
- Readability: In IDE development, we rarely use the
import
To view the path of the class. But if we need to edit files in other environments, like Vim, fromimport
It is convenient to look at the path of the class.
What happens when you import classes that you don’t need
Rationally, the Java compiler will optimize this by not adding unnecessary import declarations to the class file, but I didn’t see where that was, so try this:
Define the Java class first:
package cn.howardliu;
// Single type import required
import java.util.Date;
// On-demand type imports needed
import java.math.*;
// A single type import is not required
import java.sql.PreparedStatement;
// On-demand type imports that are not needed
import java.awt.*;
public class Main {
private Date date1;
private BigDecimal num1;
public void test(a){
Date date2 = new Date();
BigDecimal num2 = new BigDecimal(0); }}Copy the code
Javap-verbose main. class to view the compilation result:
Classfile /path/to/Main.class Last modified 2021-1-31; size 439 bytes MD5 checksum 81e13559f738197b4875c2c2afd6fc41 Compiled from "Main.java" public class cn.howardliu.Main minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #7.#19 // java/lang/Object."<init>":()V #2 = Class #20 // java/util/Date #3 = Methodref #2.#19 // java/util/Date."<init>":()V #4 = Class #21 // java/math/BigDecimal #5 = Methodref #4.#22 // java/math/BigDecimal."<init>":(I)V #6 = Class #23 // cn/howardliu/Main #7 = Class #24 // java/lang/Object #8 = Utf8 date1 #9 = Utf8 Ljava/util/Date; #10 = Utf8 num1 #11 = Utf8 Ljava/math/BigDecimal; #12 = Utf8 <init> #13 = Utf8 ()V #14 = Utf8 Code #15 = Utf8 LineNumberTable #16 = Utf8 test #17 = Utf8 SourceFile #18 = Utf8 Main.java #19 = NameAndType #12:#13 // "<init>":()V #20 = Utf8 java/util/Date #21 = Utf8 java/math/BigDecimal #22 = NameAndType #12:#25 // "<init>":(I)V #23 = Utf8 cn/howardliu/Main #24 = Utf8 java/lang/Object #25 = Utf8 (I)V { public cn.howardliu.Main(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 12: 0 public void test(); descriptor: ()V flags: ACC_PUBLIC Code: stack=3, locals=3, args_size=1 0: new #2 // class java/util/Date 3: dup 4: invokespecial #3 // Method java/util/Date."<init>":()V 7: astore_1 8: new #4 // class java/math/BigDecimal 11: dup 12: iconst_0 13: invokespecial #5 // Method java/math/BigDecimal."<init>":(I)V 16: astore_2 17: return LineNumberTable: line 17: 0 line 18: 8 line 19: 17 } SourceFile: "Main.java"Copy the code
The class file contains:
-
On-demand type imports are represented in a class file in the same way as by type imports, where the required class imports are found and not all classes in the package are imported.
-
Unnecessary class import declarations will eventually be optimized out of the class file.
-
An import in Java, unlike an include in C, does not write the declared class to a class file, which is still a separate class file.
Which method is recommended by the JDK
The JDK is definitely the benchmark for Java programming, and many of us can learn from it:
import java.io.IOException;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.io.OutputStreamWriter;
import java.io.BufferedWriter;
import java.security.AccessController;
import java.security.PrivilegedAction;
import sun.util.spi.XmlPropertiesProvider;
Copy the code
This is the import declaration in java.util.properties, and as you can see, the single-type import declaration is used, so we’ll stick with single-type imports if we don’t have any other requirements.
At the end of the article think
- The Java
import
Is a class import declaration that does not write files to the compiled class file - The Java
import
There are two import modes: single-type import and on-demand type import - On-demand type imports incur a performance penalty only during compilation and are indistinguishable from single-type imports at run time
- Most of the JDK source code uses single-type imports.
Hello, I’m looking at the mountains. Swim in the code, play to enjoy life. If this article is helpful to you, please like, bookmark, follow. Welcome to follow the public account “Mountain Hut”, discover a different world.