Packages and Access Modifiers

Packages

Java provides a package to manage classes with similar features and similar nature. All Java APIs belong to a specific package (usually a package with names beginning with java).

Now let's look at creating a class that belongs to a specific package.

Account.java
package javabank;

public class Account {
  private String accountNo;
  private double balance;
	
  public void deposit(double amount) {
    balance = balance + amount;
  }
	
  public void withdraw(double amount) {
    balance = balance - amount;
  }
	
  public long getBalance() {
    return balance;
  }
	
  public static void main(String[] args) {
    System.out.println("Package Test!");
  }
}

package javabank;
This first code makes the Account class belong to the package named javabank.

When compiling the Java source that declares the package, you must specify -d followed by the directory where the compiler will generate the bytecode. If you omit the -d option, the bytecode will not belong to the package.

Create the Account.java source file in the C:\javaApp\bank\src\javabank directory.

package example directory

The bin directory is where the compiler generates the bytecode, and the src is where you keep Java source files.

Create a subdirectory with the package name in src and place a source file there. Most developers manage source files this way.

Note: Package names are usually in reverse order of domain names.
The package name preferably includes two or more dots.

If you want, the Log class belongs to the package named net.java_school.commons, create subdirectories like below and place source files there.

javaApp-Log.java

Let's get back to Account.java.
Go to C:\javaApp\bank\src\javabank and compile as below.

C:\ Command Prompt
C:\javaApp\bank\src\javabank>javac -d C:/javaApp/bank/bin Account.java

The path separator following the -d option can also use the / (slash), even on Windows systems. Of course, you can also use the path separator in the Windows system \ (backslash).

After compiling, go to the C:\java App\bank\bin and check whether the Account's bytecode exists.

C:\ Command Prompt
C:\javaApp\bank\bin>dir
2008-03-07  12:06  PM    <DIR>          javabank

You will not see the Account's bytecode in the bin. Instead, you will see the javabank directory. You can find the Account's bytecode in this javabank subdirectory.

Suppose you specify the C:\javaApp\bank\bin directory with the -d option when compiling a java source file. In that case, the compiler will make subdirectories with the package name in the C:\javaApp\bank\bin directory and create Account.'s bytecode there.

Account.class and Account.java

JVM understands the javabank.Account bytecode is in the C:\javaApp\bank\bin directory.

If you make the Account.java that declares the package name javabank and compile it with the -d option, the fully qualified class name (FQCN) of the bytecode is javabank.Account.

If you write code that uses the Account bytecode in other Java sources, you should write javabank.Account, which is the FQCN of Account, in your code.

The same is true when you run the bytecode. To run the Account bytecode, you need to run it using the Account's FQCN in the C:\javaApp\javabank\bin directory because JVM understands javabank.Account bytecode is in the bin directory.

C:\ Command Prompt
C:\javaApp\bank\bin>java javabank.Account
Package Test!

To run a bytecode in a directory that is not the bytecode, you need to tell JVM where the bytecode is. The way to tell JVM that the bytecode location is to use the Java interpreter's classpath or cp options.

When running the Java interpreter (java.exe), the class loader finds all bytecodes that make up the Java program and loads them into the memory. If it can not find even one bytecode, it prints an error message that the execution fails and can not find the bytecode.

If you do not specify the classpath or cp option, the class loader looks for your bytecodes only in the current directory.

The class loader already knows the path of Java APIs, such as the java.lang.String or the java.lang.System. So you don't need to specify the path of Java API bytecodes using the classpath or cp option.

Below is running javabank.Account in the C:\Program Files directory.

C:\ Command Prompt
C:\Program Files>java -classpath C:/javaApp/bank/bin javabank.Account
Package Test!

-classpath followed by the path where the bytecode is.
In the above case, the classpath path is absolute.
The classpath path can be either absolute or relative.

C:\ Command Prompt
C:\Program Files>java -classpath ../javaApp/bank/bin javabank.Account
Package Test!

One dot is the current directory.
Two dots refer to the directory one level above.

The Java compiler (javac.exe) also has the classpath or cp options. You can replace the classpath option of javac.exe or java.exe with the cp option. The Java compiler uses these options to check whether your source uses other bytecodes properly.

When compiling, let's walk through an example where you need to use the classpath option.

The following is a new class to create.

Log.java3
package net.java_school.commons;

public class Log {
  public static void out(String msg) {
    System.out.println(new java.util.Date() + " : " + msg);
  }	
}

Log's out method is a static method. We cover the static keyword in the 'static' chapter.

Compile Log.java.

C:\ Command Prompt
C:\javaApp\commons\src\net\java_school\commons>javac -d ^
C:\javaApp\commons\bin Log.java

Log.class and Log.java

Next, modify the Account class to use the Log class.
The FQCN of the Log class is net.java_school.commons.Log and should be written to the source as well.

public void deposit(double amount) {
  balance = balance + amount;
  net.java_school.commons.Log.out(amount + " dollars have been deposited.");
  net.java_school.commons.Log.out("Balance is $ " + this.getBalance());
}

public void withdraw(double amount) {
  balance = balance - amount;
  net.java_school.commons.Log.out(amount + " dollars have been withdrawn.");
  net.java_school.commons.Log.out("Balance is " + this.getBalance());
}

public static void main(String[] args) {
  Account myAccount = new Account();
  myAccount.deposit(10000);
  myAccount.withdraw(500);
}

Recompile Account.java.

C:\ Command Prompt
C:\javaApp\bank\src\javabank>javac -d C:\javaApp\bank\bin ^
-classpath C:\javaApp\commons\bin Account.java

Run the javabank.Account.

C:\ Command Prompt
C:\javaApp\bank\bin>java -classpath .;C:\javaApp\commons\bin ^
javabank.Account

Our Java programs consist of two bytecode except for Java APIs. (javabank.Account and net.java_school.commons.Log)
Because these two bytecodes aren't the same directory, you need to specify the location of the two bytecode with the classpath option both at compile and run times.

Notice that a comma (.) is added to the classpath at runtime, unlike compile time. The class loader looks for bytecodes only in the classpath. So, you need to add the current directory with the Account bytecode to the classpath.

How to add external Java libraries to your Java program

Most external Java classes are jar-compressed files.
Let's create the log bytecode into a jar file using jar.exe.

Execute the following command in the directory where the Log bytecode is.

C:\ Command Prompt
C:\javaApp\commons\bin>jar cvf java-school-commons.jar .

Move the java-school-commons.jar file to the C:\devLibs directory.

To add the bytecode in the jar file to the classpath, you need to add the full path of the jar file to the classpath. It is impossible to add only specific bytecodes in the jar file to the classpath.

Run the javabank.Account.

C:\ Command Prompt
C:\javaApp\bank\bin>java -classpath ^
.;C:\devLibs\java-school-commons.jar javabank.Account

Access Modifiers

The access modifiers decide whether it is accessible from the outside. The access modifiers provide a two-step access control.

Level 1 access control is when class declarations use access modifiers.

The public access modifier in the class declaration of the Account

package javabank;

public class Account {
  //...
} 

The package-private access modifier in the class declaration of the Account

package javabank;

class Account {
  //...
} 

public

Any class can refer to this class.

package private

It can be referenced in same package classes.

The following is a code example in which example.BankSystem class refers to javabank.Account class.

package example;

public class BankSystem {
  public void deposit(javabank.Account account, double amount) {
    account.deposit(amount);
  }
}

Suppose you have created a Bank, Customer with the public access modifier in the javabank package. Any class can reference Bank, Customer, and Account. (+ Stands for public)

public access modifier figure

As shown in the figure, the BankSystem in the example package can refer to all classes in the javabank package. So, you can declare variables type of javabank.Account in the example.BankSystem source code. You can use the import statement to reduce javabank.Account to Account in the class body.

package example;

import javabank.Account;

public class BankSystem {
  public void deposit(Account account, double amount) {
    account.deposit(amount);
  }
}

Suppose you have changed the public to the package-private access modifier in Bank, Customer, and Account class declaration.

package private diagram

In this case, BankSystem cannot refer to Bank, Customer, or Account. So, you will get compile errors if you write the code to BankSystem refer to Bank, Customer, and Account.

Level 2 Access Control is when field and method declarations use access modifiers.

Note: A field is a data structure declared in a class body.
It's easy to understand if you think everything is not a method in a class body.

public

The field or method is accessible from all packages.

protected

The field or method is only accessible from the same package.
In addition, subclasses can access protected fields and methods of the superclass even if the subclass belongs to a different package from the superclass. So, the protected access modifier is more accessible than the package-private access modifier. For the protected access modifier, it's a good idea to review the description below after studying inheritance.
In the figure below, # means protected.

Protected access modifier figure

package-private

The field or method is only accessible from the same package.

private

The field or method is not accessible from the outside.

Encapsulation: Make an object's data accessible only through public methods

Encapsulation allows you to see only the essential parts of the object when viewed from the outside.

When designing a class, We should keep the following as it is the basis of object-oriented programming.

  1. Declare variables as private if they store the object's properties.
  2. Declare public methods for private variables.

Below is encapsulated member class of a website.

User.java
package net.java_school.user;

public class User {
  private String username;
  private String password;
  private String fullName;
  private String email;
	
  public String getUsername() {
    return username;
  }
  public void setUsername(String username) {
    this.username = username;
  }
  public String getPassword() {
    return password;
  }
  public void setPassword(String password) {
    this.password = password;
  }
  public String getFullName() {
    return FullName;
  }
  public void setFullName(String fullName) {
    FullName = fullName;
  }
  public String getEmail() {
    return email;
  }
  public void setEmail(String email) {
    this.email = email;
  }
}

Eclipse

All subsequent chapter examples will use Eclipse.
With Eclipse, you can manage your sources with the directory structure you have practiced before, and you do not have to worry about the classpath when compiling.

http://www.eclipse.org
Download the Eclipse install file and install Eclipse IDE for Java EE Developers.

Run

Eclipse asks you where to specify your workspace.

workspace launcher

Workspaces contain and manage one or more projects.

Specify your workspace.
Click the OK button.
You can see the following welcome message.

welcome

For reference, this article summarizes the welcome page tutorial.

Close the welcome page.
The following workbench appears.

workbench

Eclipse Terminology

Workbench

It refers to the entire window seen in Eclipse.
The window has four areas, which are called views.

Perspective

Including all of the views is called a perspective.
The above is a Java perspective screen.
This perspective consists of the views needed to develop a Java program.
Use the Open Perspective menu bar button in the top right corner to change the perspective.

Package Explorer View

It shows the resources (packages, classes, external libraries) belonging to the Java project.

Hierarchy View

It shows Java's inheritance structure.

Outline View

It shows the structure of the source file in the editor.

Editor View

It has the source code editor.

Problems View

It shows compilation errors or warnings.

Javadoc View

It shows the Java documentation for the selected part in the Package Explorer or Outline View.

Declaration View

It shows briefly how the selected part of the editor is declared.

Practice the Java example using Eclipse

Make sure it is a Java perspective.
In Eclipse, the Java source must belong to the project.
Select File - New - Java Project from the menu bar or click the leftmost button on the toolbar to create a Java project.

toolbar

Name the project HelloWorld.
Other settings do not have to be specified.
Eclipse manages sources in the src directory and bytecodes in the bin directory.
Click Finish, and the HelloWorld project will be created and displayed in the Package Explorer.

project wizard

Click second on the toolbar menu below.

toolbar

Type net.java_school.example in the package name and click Finish.
You will see the package in the Package Explorer view.

package wizard

Select the net.java_school.example package with the mouse and click the last button on the right of the toolbar menu below.

toolbar

Name a class, HelloWorld.
Check the public static void main (String [] args) checkbox.

class wizard

Click on Finish and implement the main method in the editor, as shown below.

HelloWorld.java
package net.java_school.example;

public class HelloWorld {
  public static void main(String[] args) {
    System.out.println("Hello World !");
  }
}

If you have saved the code, you do not have to compile it because Eclipse continues to compile your code in the background. Also, you can see compilation errors right at the Problem View while you write the code.

To run the bytecode, right-click the HelloWorld class in the Package Explorer, open the context menu, and select it as shown below.

run

The Console View prints Hello World!.

console view