Understand Package in Java


Reading time: 30 minutes | Coding time: 10 minutes

As the name implies packages are used for packing related sets of types (classes, interfaces, enums and annotations) together. There must be multiple types defined in your project. Without organizing them in some order you may find it difficult to locate them or you may experience name conflicts while defining new types. Here come packages to save you, when you have name conflicts issues or you want to have a well-organized codebase. Let's dive deep into the package concept through some examples.

Package Statement

Suppose you have a source file called PackageSample.java in which you decided to define some of your related classes and you want that class to be grouped together in a package called mypackage. How will you do that?

Have a look at the below PackageSample.java source file.

package mypackage; //package statement
public class PackageSample
{
    public static void main(String[] args) 
    {
        new HelloWorld().printHelloWorld();
    }
    public void getHelloWorld()
    {
        new HelloWorld().printHelloWorld();
    }
}
class HelloWorld
{
    public printHelloWorld()
    {
        System.out.println("Hello World");
    }
}

You must have noticed the first line of code commented as package statement. Yes. A package statement must be the very first line of code in your source file to define a package; also do keep in mind that you can have a maximum of one package statement per source file.

Package statement is in the form of package identifier followed by package name.

package <packagename>;

Example : package mypackage;

In PackageSample.java we defined a package mypackage as well as two related classes PackageSample and HelloWorld. Both these classes should reside in the package mypackage.

Well, an important concept to be clarified here is the creation of packages.

Java package corresponds to the file system directory. There must be a directory with the same name as that of the package and all compiled class files, which belong to the types defined in that package must reside in this directory.
We can compile the above PackageSample.java file and will see how the directory gets created.

$ javac -d . PackageSample.java

Here -d option is to set the destination directory for the compiled class files and the destination directory represented using "." which is the current directory itself. Java Compiler will automatically create a package directory structure in the destination directory and all compiled class files will be stored in the corresponding directories.
So what actually happens here is, since all the classes in PackageSample.java file are part of package mypackage, compiler will create a new subdirectory mypackage in the current directory(for example root directory), then all compiled class files will get stored in the newly created mypackage directory, as shown in the below diagram.

Untitled-Diagram--4-

You can run the above program from the root directory using the below command

$ java mypackage.PackageSample

You have seen how compiler creates the directory structure for you. Another straight forward way is, you can create a package directory structure and put the source files inside the corresponding directories, that match the package definition.
For example you can create a new directory mypackage and store PackageSample.java inside that directory. After compilation both source file and compiled class files will reside in the same package directory.

$ javac mypackage/PackageSample.java

Untitled-Diagram--5-

Default Package

If there is no explicit package statement in a source file, then all the types defined in that source file will become part of a default package or unnamed package.

Some facts about default packages are listed below.

  • Default package associated with the current directory, where the source file resides.
  • Default package cannot be subpackaged.
  • Types, that are part of a default package cannot be used in any other named package.

Subpackage

If you want to categorize an existing package further, you can subpackage the existing package.
For example, if you want to subpackage mypackage further as mysubpackage, then the package statement will be the following.

package mypackage.mysubpackage;

This will create a subdirectory mysubpackage under mypackage.
In general the syntax for package statment with subpackages is given below.

package <rootpackage>.<subpackage1>.<subpackage2>...<subpackageN>;

Package naming convensions

While defining a package you should follow the package naming convention.

  • Write package name in lower case letters to avoid conflicts with class names and interface names.
  • Organizations can use their reversed domain name to start a package name

Suppose we have an OpenGenus project called Sampleproject. We can start the package name as follows org.opengenus.sampleproject.

Using Package Members

Whatever types, like classes or interfaces defined in a package, are called package members. You can access package members, that are defined as public from outside of a package.

In the following three ways you can access public package members from outside its package.

1. Refer by Fully Qualified Name

If you want to access a public class from a different package, then you can use the fully qualified name of that class, which includes the package name in the following form.

<packagename>.<packagemember>;

Let's see how to access PackagSample class of mypackage from other packages using the fully qualified name.

package usepackage;
public class FullyQualifiedName{
    public static void main(String[] args) {
         mypackage.PackageSample packageSample = new mypackage.PackageSample();
    }
}

2. Imorting Package Member

If you need to use a package member repetitively outside of its package, then writing fully qualified name is not a convenient way, instead you could opt for package import which is in the form of import keyword followed by the fully qualified name of the package. Like package statement you can have package import in your source file, after the package statement but before any type definitions.

Lets import and use PackageSample class in another package

package usepackage; //package definition of current sourcefile
import mypackage.PackageSample; //importing PackageSample class of mypackage
public class PackageImport{
    public static void main(String[] args) {
         new PackageSample().getHelloWorld(); // accessing PackageSample using its simple name. 
    }
}

3.Importing Entire Package

If you need to access more types from another package, then we better opt for importing the entire package. Let's see the syntax and example of the entire package import.

Syntax : import <rootpackage>.<subpackage1>.<subpackage2>.*;
Example: import mypackage.mysubpackage.*;
import mypackage.*;
public class PackageImport{
    public static void main(String[] args) {
         new PackageSample().getHelloWorld();// accessing class defined in mypackage
    }
}

Now you can refer to any classes or interfaces from mypackage in the current source file.

Here one point to remember is, while importing an entire package, only the types defined inside that package get imported; subpackage types will not get imported.
For example, to import all types defined in mysubpackage, the import statement must be the following.

import mypackage.mysubpackage.*;

Java Package Types

In Java we can classify packages into two groups.

  • Built-in Packages
  • User-defined packages

Built-in Packages

These are the packages included in the Java API, consists of a large number of pre-written classes and interfaces which can be resued by the programmers.

Some of the commonly used built-in packages are listed below

  • java.lang
  • java.util
  • java.sql
  • java.io
    For more details on Java built-in packages refer the below link of Java 8 API documentation.

JavaSE8 documentation

User-defined packages
Packages that are defined by the user are called User-defined packages.You have already seen how we defined the package mypackage in the previous example.

Avoiding name conflicts

By using packages we can define types with same name in different packages. For example Date class definition exists in the built-in packages java.util as well as java.sql. But this may cause name conflict while accessing Date calss, if the source file contains import statements of both java.util and java.sql. See the name conflict scenario illustrated in the example below.

import java.util.*
import java.sql.*
public class DateSample{
    Date date = new Date()
}

Here complier will throw an error saying reference to Date is ambiguous.
In order to avoid this reference ambiguity we can use the fully qualified reference to the *Date *class.

import java.sql.*
public class DateSample{
    java.util.Date date = new java.util.Date();// Compiler will not throw ambiguity error here
}

Using fully qualified name we could access Date class from java.util, avoiding the reference ambiguity with the Date class from java.sql.

Summary

  • Define a package using the pakage statement as the first line of code in a source file.
  • There can be at most one package statement per Java source file.
  • Java package corresponds to the underlying file system directory structure.
  • Package name should follow Java package naming convention
  • Root package and sub-packages are separated using dot(".").
  • Use import statement or fully qualified name to reference any type that are defined in other packages.
  • If no package is defined, then all the types defined in that source file will become the part of the default package.
  • While referencing a type form other packages, use the fully qualified name to avoid reference ambiguity.