JavaObject-oriented programmingClasses and objects

Package

6 seconds read

Grouping classes together

Large Java projects have a lot of classes. It's difficult to manage them if they are stored in the same directory. Packages provide a mechanism to group classes together into the same module (package). A package can contain others packages inside. It's like directories in a file system.

In general, packages give us the following advantages:

  • to group related classes together that makes easier to figure out where a certain class you are looking for is;
  • to avoid the conflict of class names;
  • to control access to classes and members together with access modifiers (it's considered in another topic).

According to the naming convention, packages are always written in lowercase, for example:

model
collection
utils

Here is an example project with a simple packages and classes tree.

An example of multi-packages project structure

Here is a directory "src" at the top of the tree. This is the source root directory. In this tree, the full name of the class User is org.company.webapp.data.User.

You can output this using the following code:

System.out.println(User.class.getName()); // org.company.webapp.data.User

Classes declared inside a package has a special keyword package at the top of the file.

package org.company.webapp.data;

public class User {
}

Avoiding the conflict of class names

When you use external libraries the situation is possible that two classes have the same name. Packages allow avoiding the conflict of class names because the full class name includes names of packages. Also, it's needed to avoid the conflict between names of packages.

To avoid creating packages with the same names as other public packages it is recommended that you start your package hierarchy with the reverse domain name of your company (or another organization). For example:

org.company
org.hyperskill
net.labs


Importing classes

If two classes are located in the same package there is no problem to use one class inside another. If one of these classes is located in another package, to use one class inside another you should write an import statement using the keyword import.

Here is an example. We have two public classes in different packages:

org.hyperskill.java.packages.theory.p1.A
org.hyperskill.java.packages.theory.p2.B

To use the class B inside the class A we should make an import statement.

package org.hyperskill.java.packages.theory.p1;  // current package

import org.hyperskill.java.packages.theory.p2.B; // it's required to make the import

public class A {

    public static void method() {

        B b = new B();
    }
}

Also, it's possible to import all classes from the package, using "*" instead of a particular class name.

import org.hyperskill.java.packages.theory.p3.*; // import all classes from the package

Importing standard classes

There are no any differences between importing standard or custom classes.
Many Java developers use java.util.Scanner for working with the standard input/output. In the programs they do the following import:

import java.util.Scanner;

And then it's possible to create an instance of the scanner. It looks like the considered examples above.

But Java has a package that always automatically imported. It's java.lang. The package contains a lot of widely used classes including String, System, Long, Integer, NullPointerException and so on.


Specifying the full class name instead of importing

It's possible to use a class from another package without performing import statement. In this case, you can write the full class name (including full packages path) instead of the name of the class itself (short name).

java.util.Scanner scanner = new java.util.Scanner(System.in);
java.util.Date now = new java.util.Date();

Static imports

It's possible to import static members (methods and fields) of a class inside the current class. In this case, we don't need to write the imported class name before the invoking static methods or reading static fields.

Here is an example of the static import of the class Array contains a lot of useful methods for processing arrays.

package org.hyperskill.java.packages.theory;

import static java.util.Arrays.*; // instead of the statement "import java.util.Arrays;"

public class Main {

    public static void main(String[] args) {
        int[] numbers = { 10, 4, 5, 47, 5, 12 }; // an array

        sort(numbers); // instead of writing Arrays.sort(...)

        int[] copy = copyOf(numbers, numbers.length); // instead of writing Arrays.copyOf(...)
    }
}

Default package

If a package statement is not used then the class will be placed in the default package. This package has a big disadvantage - classes located here can't be imported into classes located inside a named packages.

Do not use the default package for the real applications. It can be used only when writing simple "Hello world" applications.

Conclusion

Thus, the use of packages allows better structuring the source code and making it more maintainable. It's very important in big projects that can consist of thousand classes.

Packages allow avoiding the conflict of class names because of the full class name including whole packages path.

Also, packages affect the visibility of classes and members to each other.
3 learners liked this piece of theory. 0 didn't like it. What about you?
Report a typo