Java Packages and Member Access


In the previous tutorial, you have learned about the Java access control system and various aspects of its access modifiers. You already know that private members of a class can only be used by other members of that class. Packages add another dimension to access control. As you can see, Java provides many layers of protection to allow fine-grained control over the visibility of variables and methods between classes, subclasses, and packages.


Member Access

Classes and packages are both means of encapsulation and containing the namespace and scope of variables and methods. Packages act as containers for classes and different subordinate packages. The class is the smallest unit of Java abstraction. As it relates to the interplay between classes and packages, Java addresses four categories of visibility for class members:

The three access modifiers provide a variety of ways to create the multi-level access required for these categories, private, public, and protected.

Private No Modifier Protected Public
Same class Yes Yes Yes Yes
Same package subclass No Yes Yes Yes
Same package non-subclass No Yes Yes Yes
Different package subclass No No Yes Yes
Different package subclass No No No Yes

While the Java access control system may seem complicated, we can simplify it as follows. Anything declared public can be accessed from different classes and different packages. Anything declared private will not be seen outside of its class when a member has no explicit access specification is called default access. If you want to allow viewing of an element outside of your current package, only in classes that directly subclass your class, then declare that element protected.

Non-nested classes have only two possible access levels: default and public. When a class is declared public, it is accessible outside of its package. If a class has default access, it can only access other codes within its same package. When a class is public, it must be the only public class declared in the file, and the file must have the same name as the class.


Same package example

Program
package p1;

public class Protection {
 int n=1;
 private int n_pri=2;
 protected int n_pro=3;
 public int n_pub=4;
 public Protection() {
  System.out.println("base constructor");
  System.out.println("n = "+n);
  System.out.println("n_pri = "+n_pri);
  System.out.println("n_pro = "+n_pro);
  System.out.println("n_pub = "+n_pub);
 }
}

Program
package p1;

public class Derived extends Protection {
 Derived(){
  System.out.println("derived constructor");
  System.out.println("n = "+n);
  //class only
  //System.out.println("n_pri = "+n_pri);
  System.out.println("n_pro = "+n_pro);
  System.out.println("n_pub = "+n_pub);
 }
}

Program
package p1;

public class SamePackage {
 SamePackage()
 {
  Protection p1=new Protection();
  System.out.println("same package constructor");
  System.out.println("n = "+p1.n);
  //class only
  //System.out.println("n_pri = "+p1.n_pri);
  System.out.println("n_pro = "+p1.n_pro);
  System.out.println("n_pub = "+p1.n_pub);
 }
}


Different package example

Program
package p2;

public class Protection2 extends p1.Protection {
 Protection2()
 {
  System.out.println("derived other package constructor");
  
  //same class or package only
  //System.out.println("n = "+n);
  
  //class only
  //System.out.println("n_pri = "+n_pri);
  
  System.out.println("n_pro = "+n_pro);
  System.out.println("n_pub = "+n_pub);
 }
}

Program
package p2;

public class OtherPackage {
 OtherPackage(){
  p1.Protection p=new p1.Protection();
  System.out.println("other package constructor");
  //same class or package only
  //System.out.println("n = "+p.n);
  
  //class only
  //System.out.println("n_pri = "+p.n_pri);
  
  //class, subclass or package only
  //System.out.println("n_pro = "+p.n_pro);
  
  System.out.println("n_pub = "+p.n_pub);
 }
}


Importing Packages

In a Java source file, import statements follow the package statement and precede any class definition. This is the general form of the import statement:


import p1[.p2].(classname|*);

Here p1 is the name of a top-level package, and p2 is the name of a subordinate package inside the outer package separated by a dot(.). There is no practical limit o the depth of a package hierarchy, except that imposed by the file system. Finally, you specify either an explicit class name or a star(*), which indicates that the Java compiler should import the entire package.


import java.util.Date;
import java.io.*;

Primary language functions are stored in a package called java.lang. Normally, you have to import the package or class you want to use, but Java is useless without increasing the functionality of Java.


import java.lang.*;

The compiler will be silent if you try to use one of the classes if two different packages that you import using the star form contain the same class of the same name. In that case you will get a compilation-time error and you have to specify the package and write the name of the class clearly.

It must be emphasized that the import statement is optional. You can use a fully qualified name anywhere you use a class name, including its full package classification.


import java.util.*;
class MyDate extends Date{
}

The same example without the import statement looks like this:


class MyDate extends java.util.Date{
}