Appearance
Package
In the previous code, we named the classes and interfaces with simple names such as Person
, Student
, Hello
, etc.
In reality, if Bob writes a Person
class, and Jack also writes a Person
class, and now John wants to use both Bob's Person
and Jack's Person
, what should I do?
If Bob writes an Arrays
class, and JDK also comes with an Arrays
class, how to resolve the class name conflict?
In Java, we use package
to resolve name conflicts.
Java defines a namespace called a package: package
. A class always belongs to a certain package. The class name (such as Person
) is just an abbreviation. The real complete class name is [package].[class]
.
For example:
Bob's Person
class is stored under the package bob
, so the complete class name is bob.Person
;
Jack's Arrays
class is stored under the package mr.jack
, so the complete class name is mr.jack.Arrays
;
The Arrays
class of JDK is stored under the package java.util
, therefore, the complete class name is java.util.Arrays
.
When defining class
, we need to declare which package this class
belongs to on the first line.
Bob’s Person.java
file:
java
package bob; // Declare the package name bob
public class Person {
}
Jack’s Arrays.java
file:
java
package mr.jack; // Declare the package name mr.jack
public class Arrays {
}
When the Java virtual machine is executed, the JVM only looks at the complete class name. Therefore, as long as the package name is different, the class is different.
Packages can be multi-layered, separated by .
For example: java.util
.
special attention
There is no father-son relationship between packages. java.util and java.util.zip are different packages, and there is no inheritance relationship between them.
class
that does not define a package name uses the default package, which can easily cause name conflicts. Therefore, it is not recommended to not write a package name.
We also need to organize the above Java files according to the package structure. Assuming that package_sample
is used as the root directory and src
is used as the source code directory, then the entire file structure is:
package_sample
└─ src
├─ bob
│ └─ Person.java
└─ mr
└─ jack
└─ Arrays.java
That is, the directory level corresponding to all Java files must be consistent with the package level.
The compiled .class
files also need to be stored according to the package structure. If you use an IDE and put the compiled .class
file in the bin directory, then the compiled file structure is:
package_sample
└─ bin
├─ bob
│ └─ Person.class
└─ mr
└─ jack
└─ Arrays.class
Package Scope
Classes located in the same package can access the fields and methods of the package scope. Fields and methods that are not modified with public
, protected
, or private
are package scopes. For example, the Person
class is defined under the hello
package:
java
package hello;
public class Person {
// package scope:
void hello() {
System.out.println("Hello!");
}
}
The Main
class is also defined under the hello
package:
java
package hello;
public class Main {
public static void main(String[] args) {
Person p = new Person();
p.hello(); // It can be called because Main and Person are in the same package
}
}
import
In a class
, we always refer to other class
. For example, if Bob's bob.Person
class wants to reference Jack's mr.jack.Arrays
class, there are three ways to write it:
The first is to write the complete class name directly, for example:
java
package bob;
public class Person {
public void run() {
// Write the complete class name: mr.jack.Arrays
mr.jack.Arrays arrays = new mr.jack.Arrays();
}
}
Obviously, it is more painful to write the complete class name every time.
Therefore, the second way to write is to use the import
statement to import Jack's Arrays
, and then write a simple class name:
java
package bob;
// Import full class name:
import mr.jack.Arrays;
public class Person {
public void run() {
// Write a simple class name: Arrays
Arrays arrays = new Arrays();
}
}
When writing import
, you can use *
to import all class
under this package (but not including class
in sub-packages):
java
package bob;
// Import all classes of the mr.jack package:
import mr.jack.*;
public class Person {
public void run() {
Arrays arrays = new Arrays();
}
}
We generally do not recommend this way of writing, because after importing multiple packages, it is difficult to see which package Arrays
class belongs to.
There is also an import static
syntax, which can import static fields and static methods of a class:
java
package main;
// Import all static fields and static methods of the System class:
import static java.lang.System.*;
public class Main {
public static void main(String[] args) {
// Equivalent to calling System.out.println(…)
out.println("Hello, world!");
}
}
import static
is rarely used.
The .class
file finally compiled by the Java compiler only uses the full class name . Therefore, in the code, when the compiler encounters a class
name:
- If it is a complete class name, search the
class
directly based on the complete class name; - If it is a simple class name, search in the following order:
- Find whether this
class
exists in the currentpackage
; - Find whether the
import
package contains thisclass
; - Find whether the
java.lang
package contains thisclass
.
- Find whether this
If the class name cannot be determined according to the above rules, a compilation error will be reported.
Let's look at an example:
java
// Main.java
package test;
import java.text.Format;
public class Main {
public static void main(String[] args) {
java.util.List list; // ok,Use full class name -> java.util.List
Format format = null; // ok,Use imported classes -> java.text.Format
String s = "hi"; // ok,String using java.lang package -> java.lang.String
System.out.println(s); // ok,System using the java.lang package -> java.lang.System
MessageFormat mf = null; // Compilation error: MessageFormat cannot be found: MessageFormat cannot be resolved to a type
}
}
Therefore, when writing a class, the compiler will automatically do two import actions for us:
- By default, other
class
of the currentpackage
are automaticallyimport
; - By default,
import java.lang.*
.
Notice
The java.lang
package is automatically imported, but packages like java.lang.reflect
still need to be imported manually.
If there are two class
with the same name, for example, mr.jack.Arrays
and java.util.Arrays
, then only one of them can import
, and the other must have the complete class name.
Best Practices
To avoid name conflicts, we need to determine unique package names. The recommended practice is to use an inverted domain name to ensure uniqueness. For example:
- org.apache
- org.apache.commons.log
- com.bob.sample
Subpackages can be named according to their functions.
Be careful not to have the same name as the classes in java.lang
package, that is, do not use these names for your own classes:
- String
- System
- Runtime
- ...
Be careful not to have the same name as a common JDK class:
- java.util.List
- java.text.Format
- java.math.BigInteger
- ...
Compile and run
Suppose we create the following directory structure:
work
├── bin
└── src
└── com
└── itranswarp
├── sample
│ └── Main.java
└── world
└── Person.java
Among them, the bin
directory is used to store compiled class
files, and src
directory stores Java source codes according to the package structure. How do we compile these Java source codes at once?
First, make sure the current directory is the work
directory, which is the parent directory where src
and bin
are stored:
sh
$ ls
bin src
Then, compile all Java files in the src
directory:
sh
$ javac -d ./bin src/**/*.java
The command line -d
specifies that the output class
files are stored in the bin directory. The following parameters src/**/*.java
represent all .java
files in the src
directory, including subdirectories of any depth.
Note: Windows does not support **
this method of searching all subdirectories, so compiling under Windows must list all .java
files in sequence:
sh
C:\work> javac -d bin src\com\itranswarp\sample\Main.java src\com\itranswarp\world\Persion.java
If compiled without errors, the javac
command will have no output. You can see the following class files in bin directory:
bin
└── com
└── itranswarp
├── sample
│ └── Main.class
└── world
└── Person.class
Now, we can run the class
file directly. Determine the classpath based on the location of the current directory. For example, if the current directory is still work
, the classpath is bin
or ./bin
:
$ java -cp bin com.itranswarp.sample.Main
Hello, world!
Practise
Please create a project according to the following package structure:
oop-package
└── src
└── com
└── itranswarp
├── sample
│ └── Main.java
└── world
└── Person.java
Summary
Java's built-in package
mechanism is to avoid class
naming conflicts;
The core classes of JDK use the java.lang
package, which will be automatically imported by the compiler;
Other commonly used classes in JDK are defined in java.util.*
, java.math.*
, java.text.*
,...;
It is recommended to use an inverted domain name for package names, such as org.apache
.