This tutorial assumes that the reader has a knowledge of basic Unix commands and experience working with a command-line text editor (e.g. emacs, vi, etc.). To get the most out of this tutorial, you should follow along, take notes, execute any given commands, run any code examples, repeat as necessary. Simply reading (or skimming) is not sufficient for learning this material.
- LO1.a: Navigate and modify files, directories, and permissions in a multi-user Unix-like environment.
- LO1.c: Create and modify textfiles and source code using a powerful terminal-based text editor such as Emacs or Vi.
- LO1.d: Use shell commands to compile new and existing software solutions that are organized into multi-level packages and have external dependencies.
In Java, a package is a grouping of related types providing access protection and name space management. Note that types refers to classes, interfaces, enumerations, and annotation types [1]. The two primary benefits of packages are:
-
Name Space Management: Packages allow you to give a common name to a group of related types. For example,
java.util.Scanner
andjava.util.Random
are two utility classes provided in thejava.util
package. You and other programmers can easily determine that these types are related. -
Access Protection: Visibility in Java is not limited to
public
andprivate
. Packages and additional visibility modifiers enable programmers to declare things as visible only within a package.
In this tutorial, you will create multiple classes, group them into a package, then compile and run them. The expectation is that you will follow along with this tutorial in a terminal emulator on Odin or some Unix machine. You should ask questions on Piazza if you are unable to proceed or if some aspect of the tutorial is particularly confusing.
-
Create a directory for this tutorial called
cs1302-packages
and change into it:$ mkdir cs1302-packages $ cd cs1302-packages
-
Setup the following subdirectory structure for the
cs1302.hello
package under a new subdirectory calledsrc
:cs1302-packages |--- bin |--- src |--- cs1302 |--- hello
Here is a breakdown of the different subdirectories and the roles that they play:
bin
is the default (no-name) package directory for our compiled code;src
is the default (no-name) package directory for our source code;cs1302
is thecs1302
package directory; andhello
is thecs1302.hello
package directory.
Here, the src
directory is the location of the default package (proper noun)
for source code. The default package contains classes (and other types) that are
not in a named package. When developing small or temporary applications, it is a
convenient place for package-less .java
files
[2].
The default package location for source code also serves as the base directory
for named packages that you will create.
Let's dive in! The steps below show you how to create, compile, and execute a class
in the default package (i.e., a class in a package-less .java
file). Once you
are comfortable with that, move on to the next section to learn about
named packages.
-
Using Emacs, create a basic "Hello, World!" program in a driver class called
HelloWorld
in the default package directory for source code (thesrc
directory). For example, the contents of theHelloWorld.java
file might be:public class HelloWorld { public static void main(String[] args) { System.out.println("Hello, World!"); } // main } // HelloWorld
-
Change directly into the default package directory (
src
) and compile the program usingjavac
:$ javac HelloWorld.java
-
List the contents of the directory with
ls
to verify thatHelloWorld.class
was created. -
Run the program using
java
:$ java HelloWorld
Note that the
java
command takes the name of the class itself and not the name of the.class
file. -
When executing the
java
command, Java assumes that the current working directory is the location of the default package. If that is not the case, then you must specify it using a command line option called-cp
for class path. As its name suggests, the class path is the path to the default package for classes.Change back into the
cs1302-packages
directory and try to execute your program with the following command:$ java HelloWorld
You should get the following error:
Error: Could not find or load main class HelloWorld Caused by: java.lang.ClassNotFoundException: HelloWorld
The error message clearly states that the
HelloWorld
class containing themain
method could not be found or loaded.Now try running the program again, specifying the location of the default package where our compiled code resides.
Since we compiled the class into thesrc
directory,src
is the default package for our compiled code (for now).
Execute the following command to specify the class path:$ java -cp src HelloWorld
This time it worked!
PROTIP: You can execute a Java program anywhere on the system as long as you know the fully qualified name of the class containing the
main
method and the location of that compiled class's associated default package, assuming proper file permissions. -
You may have noticed in the previous step that the
.java
file and.class
file for theHelloWorld
class are in the same directory. Let's keep our directories clean and separate our source code (.java
files) from the compiled code (.class
files).First, delete the
HelloWorld.class
file from thesrc
directory:$ rm src/HelloWorld.class
Verify that your present working directory is still
cs1302-packages
then compile your program usingjavac
with the-d
option to specify a destination for the compiled code:$ javac -d bin src/HelloWorld.java
When you're first starting out in a Unix environment, you might feel lost at times. Remember, it's always important to know your present working directory (pwd) as that is the location where the commands you enter will be run. In the command above, our pwd is
cs1302-packages
. Since theHelloWorld.java
file is not in that directory, we had to specify the relative pathsrc/HelloWorld.java
to tell the compiler how to find that file relative to the pwd. We're telling the compiler "first, go into thesrc
directory and then you'll see the fileHelloWorld.java
".Now, if you list the contents of the
bin
directory, you will see that it containsHelloWorld.class
. Listing thesrc
directory contents will show onlyHelloWorld.java
. Now our project is more organized!Try running the program again, specifying the new class path (
bin
) using-cp
:$ java -cp bin HelloWorld
-
We will use the Unix
find
command often in this course to see all files in a directory and its subdirectories. Go ahead and executefind
from within thecs1302-packages
directory. If you've followed the steps correctly up until now, you will see the following output:. ./bin ./bin/HelloWorld.class ./src ./src/cs1302 ./src/cs1302/hello ./src/HelloWorld.java
The output of the
find
command shows that we sucessfully separated the source code (src
) from the compiled code (bin
). If you see any tilde (~) files, those are just backup copies of older versions of your files. You can ignore those.PROTIP: Remember, source code should really only be placed directly in the default package directory (
src
) for convenience when developing small or temporary applications or when just beginning development [2]. While types in the default package can access types in other packages, the reverse is not true. That is, types in named packages cannot access types in the default package. -
Let's clean up! Delete the
HelloWorld.class
file that you created in thebin
folder. Remember to use tab completion so you don't have to type long filenames!
Now let's create a named package. To place a class (or interface) in named package, you must do two things:
- Place the
.java
file in the appropriate package directory; and - Include a
package
statement at the top of the.java
file.
Let's try it by placing the HelloWorld
class into the cs1302.hello
package!
-
Change directly into
cs1302-packages
directory. -
Move the
HelloWorld.java
file into thecs1302.hello
package directory.$ mv src/HelloWorld.java src/cs1302/hello/
This satisfies the first requirement for placing a class in a named package.
-
Using Emacs, edit the
HelloWorld.java
file and add the following package statement at the top:package cs1302.hello;
This satisfies the second requirement for placing a class in a named package.
In Java, a package statement, if included, must be the first line of code in the file (i.e., excluding comments and white space).
-
Compile the program (don't forget tab completion - you don't want to type the whole command):
$ javac -d bin src/cs1302/hello/HelloWorld.java
-
Execute the
find
command. Note that theHelloWorld.class
file was created underbin/cs1302/hello
. The compiler automatically created the necessary package directories for our compiled code underbin
! -
Try to run the program using
javac
specify the classpath using-cp
and include the fully qualified name (explained below) of the class containing themain
method:$ java -cp bin cs1302.hello.HelloWorld
PROTIP: Although packages correspond to directories, a fully qualified name uses
.
(dot) for the name separator and not a slash.
When Java code uses other Java code, that creates a dependency. Most of the programs that you've
written have used code provided by Oracle under the various java
subpackages. When you compile,
those dependencies are automatically included on the class path. However, when your code depends
on code that's not included with Java (e.g., code that you or someone else has written), you need
to let javac
know where the compiled version of that depedency is.
-
Let's extend the code we just finished. Create a
cs1302.util.HelloUtility
class undersrc
. Remember, the fully qualified name implies a specific directory structure and package statement requirement with respect toHelloUtility.java
. You will need to add theutil
directory in the proper place in your current directory hierarchy. -
Write the code to declare the
cs1302.util.HelloUtility
class making sure to include the proper class declaration and package statement at the top. Then, within the class declaration, add the following method:public static void excitingHello() { System.out.println("HELLO!!!!"); } // excitingHello
-
Save, then compile the
.java
file for thecs1302.util.HelloUtility
class as usual, usingbin
as the destination for the compiled code. Once it compiles, make sure that the output fromfind
matches the output below:Note: If you see any tilde (~) files, those are just backup copies of older versions of your files. You can ignore those.
. ./bin ./bin/cs1302 ./bin/cs1302/hello ./bin/cs1302/hello/HelloWorld.class ./bin/cs1302/util ./bin/cs1302/util/HelloUtility.class ./src ./src/cs1302 ./src/cs1302/hello ./src/cs1302/hello/HelloWorld.java ./src/cs1302/util ./src/cs1302/util/HelloUtility.java
-
Now, modify the source code for your
cs1302.hello.HelloWorld
class to call the static method incs1302.util.HelloUtility
. To do this, you may:-
Add an import statement between the
package
statement and class declation:import cs1302.util.HelloUtility;
-
Call the method in
main
using the simple class name:HelloUtility.excitingHello();
Completing these two steps create a dependency. Now, the
cs1302.hello.HelloWorld
class depends on thecs1302.util.HelloUtility
class because it uses a method defined within that class. -
-
If you try to compile the source code for your
cs1302.hello.HelloWorld
class exactly as you did before, then it will not work because the compiler cannot findcs1302.util.HelloUtility
class on whichcs1302.hello.HelloWorld
depends. Try it! The error message should look like:src/cs1302/hello/HelloWorld.java:3: error: package cs1302.util does not exist import cs1302.util.HelloUtility; ^ src/cs1302/hello/HelloWorld.java:8: error: cannot find symbol HelloUtility.excitingHello(); ^ symbol: variable HelloUtility location: class HelloWorld
The error output is just
javac
saying that it cannot find something. In this case, it cannot findcs1302.util.HelloUtility
as it is not in the same package ascs1302.hello.HelloWorld
. Since we know it actually exists, we can just telljavac
where to find it using-cp
.Remember that when your code depends on other code that you have written, you need to let
javac
know where the compiled version of that depedency is. Since you compiled underbin
, that's where you should telljavac
to look. Try to compile it again, but this time, be sure to include the-cp bin
option in addition to-d bin
option. The program should now run as expected.
Both javac
and java
allow you specify the class path using the -cp
or -classpath
command-line
option. The usual syntax is as follows:
-cp some/path
If more than one default package is needed, then a colon :
can be used to separate each path in a
list of multiple paths:
-cp path1:path2
Each path can be a path to a directory or a .jar
file (usually used for third party libraries).
VERY IMPORTANT NOTE: The class path should always point to a default package for compiled code.
If you are compiling a .java
file that depends on an already compiled class, then you will need to
specifiy the class path to the corresponding default package for that dependency when
invoking javac
.
In Java, you do not have to import classes that are in the same package. However, it's interesting to
note that import
statements are actually never required in Java. We just use them for convenience.
Assuming the corresponding default package for class's package is on the class path when compiling
and/or running, you can always refer to a class by its fully qualified name. Consider two uses of
java.util.Random
below:
// assuming the class was imported
Random rng = new Random();
// assuming the class was NOT imported
java.util.Random rng = new java.util.Random();
As you can imagine, the latter (without an import statement) might get annoying and repetetive.
Therefore, we usually prefer to use an import
statement for the convenience it provides.
Why would anyone prefer to use the fully qualified name instead of the simple name for a class?
It enables you to use two classes from different packages with the same simple name at the
same time!
Java automatically performs a wildcard import of the java.lang
package (i.e., import java.lang.*;
) in
every Java file, without requiring the programmer to explicitly write it. That is why you can use classes
such as java.lang.String
and java.lang.System
by their simple names without importing!
Feedback? Please help us make this better! If you have any feedback or suggestions for this reading or tutorial, then use the link below to reach the feedback form.
Copyright © Michael E. Cotterell, Brad Barnes, and the University of Georgia. This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License to students and the public. The content and opinions expressed on this Web page do not necessarily reflect the views of nor are they endorsed by the University of Georgia or the University System of Georgia.