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.Scannerandjava.util.Randomare two utility classes provided in thejava.utilpackage. You and other programmers can easily determine that these types are related. -
Access Protection: Visibility in Java is not limited to
publicandprivate. 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-packagesand change into it:$ mkdir cs1302-packages $ cd cs1302-packages -
Setup the following subdirectory structure for the
cs1302.hellopackage under a new subdirectory calledsrc:cs1302-packages |--- bin |--- src |--- cs1302 |--- helloHere is a breakdown of the different subdirectories and the roles that they play:
binis the default (no-name) package directory for our compiled code;srcis the default (no-name) package directory for our source code;cs1302is thecs1302package directory; andhellois thecs1302.hellopackage 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
HelloWorldin the default package directory for source code (thesrcdirectory). For example, the contents of theHelloWorld.javafile 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
lsto verify thatHelloWorld.classwas created. -
Run the program using
java:$ java HelloWorldNote that the
javacommand takes the name of the class itself and not the name of the.classfile. -
When executing the
javacommand, 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-cpfor class path. As its name suggests, the class path is the path to the default package for classes.Change back into the
cs1302-packagesdirectory and try to execute your program with the following command:$ java HelloWorldYou should get the following error:
Error: Could not find or load main class HelloWorld Caused by: java.lang.ClassNotFoundException: HelloWorldThe error message clearly states that the
HelloWorldclass containing themainmethod 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 thesrcdirectory,srcis the default package for our compiled code (for now).
Execute the following command to specify the class path:$ java -cp src HelloWorldThis 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
mainmethod 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
.javafile and.classfile for theHelloWorldclass are in the same directory. Let's keep our directories clean and separate our source code (.javafiles) from the compiled code (.classfiles).First, delete the
HelloWorld.classfile from thesrcdirectory:$ rm src/HelloWorld.classVerify that your present working directory is still
cs1302-packagesthen compile your program usingjavacwith the-doption to specify a destination for the compiled code:$ javac -d bin src/HelloWorld.javaWhen 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.javafile is not in that directory, we had to specify the relative pathsrc/HelloWorld.javato tell the compiler how to find that file relative to the pwd. We're telling the compiler "first, go into thesrcdirectory and then you'll see the fileHelloWorld.java".Now, if you list the contents of the
bindirectory, you will see that it containsHelloWorld.class. Listing thesrcdirectory 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
findcommand often in this course to see all files in a directory and its subdirectories. Go ahead and executefindfrom within thecs1302-packagesdirectory. 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.javaThe output of the
findcommand 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.classfile that you created in thebinfolder. 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
.javafile in the appropriate package directory; and - Include a
packagestatement at the top of the.javafile.
Let's try it by placing the HelloWorld class into the cs1302.hello package!
-
Change directly into
cs1302-packagesdirectory. -
Move the
HelloWorld.javafile into thecs1302.hellopackage 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.javafile 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
findcommand. Note that theHelloWorld.classfile was created underbin/cs1302/hello. The compiler automatically created the necessary package directories for our compiled code underbin! -
Try to run the program using
javacspecify the classpath using-cpand include the fully qualified name (explained below) of the class containing themainmethod:$ java -cp bin cs1302.hello.HelloWorldPROTIP: 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.HelloUtilityclass undersrc. Remember, the fully qualified name implies a specific directory structure and package statement requirement with respect toHelloUtility.java. You will need to add theutildirectory in the proper place in your current directory hierarchy. -
Write the code to declare the
cs1302.util.HelloUtilityclass 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
.javafile for thecs1302.util.HelloUtilityclass as usual, usingbinas the destination for the compiled code. Once it compiles, make sure that the output fromfindmatches 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.HelloWorldclass to call the static method incs1302.util.HelloUtility. To do this, you may:-
Add an import statement between the
packagestatement and class declation:import cs1302.util.HelloUtility;
-
Call the method in
mainusing the simple class name:HelloUtility.excitingHello();
Completing these two steps create a dependency. Now, the
cs1302.hello.HelloWorldclass depends on thecs1302.util.HelloUtilityclass because it uses a method defined within that class. -
-
If you try to compile the source code for your
cs1302.hello.HelloWorldclass exactly as you did before, then it will not work because the compiler cannot findcs1302.util.HelloUtilityclass on whichcs1302.hello.HelloWorlddepends. 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 HelloWorldThe error output is just
javacsaying that it cannot find something. In this case, it cannot findcs1302.util.HelloUtilityas it is not in the same package ascs1302.hello.HelloWorld. Since we know it actually exists, we can just telljavacwhere to find it using-cp.Remember that when your code depends on other code that you have written, you need to let
javacknow where the compiled version of that depedency is. Since you compiled underbin, that's where you should telljavacto look. Try to compile it again, but this time, be sure to include the-cp binoption in addition to-d binoption. 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.