Packages are used in Java in order to prevent naming conflicts, to control access, to make searching/locating and usage of classes, interfaces, enumerations and annotations easier, etc. A package can be defined as a grouping of related types (classes, interfaces enumerations etc) providing access protection and name space management.

A package is a collection of related classes and interfaces that provides access protection and namespace management. Java package categorized in two types

  • Java API package
  • User defined packages

Some frequently used Java APIs are:

  • lang : This package contains language support classes
  • awt : This package contains Abstract Toolkit to support GUI
  • io : This package contains classes for handling input and output operations
  • util: This package contains java utility classes
  • net : This package contains classes for networking
  • applet: This package contains classes for creating and implementing applets etc.

 

Uses of Package

A package serves two purposes:

  • It provides a mechanism by which related pieces of a program can be organized as a unit.
  • A package participates in Java’s access control mechanism. Classes defined within a package can be made private and not accessible by outside code.

Defining a Package: To create a package is quite easy: simply include a package command as the first statement in a Java source file. Any classes declared within that file will belong to the specified package. The package statement defines a namespace in which classes are stored. A namespace defines a declarative region.

This is the general form of the package statement:

package pkg;

Here, pkg is the name of the package. For example, the following statement creates a package called MyPackage

package MyPackage.

Java uses file system directories to store package. For example, the .class files for any classes you declare to be part of MyPackage must be stored in a directory called MyPackage. Remember that case is significant, and the directory name must match the package name exactly.

More than one file can include the same package statement. The package statement simply specifies to which package the classes defined in a file belong. It does not exclude other classes in other files from being part of the same package. Most real world packages are spread across many files.

Finding Package and CLASSPATHS

As we know that packages are minored by directories. This raises an important question. How does the Java run time system know where to look for packages that you create? The answer has two parts. First, by default, the Java run time system uses the current working directory as its starting point. Thus, if your package is in the current directory, or a subdirectory of the current directory, it will be found. Second, you can specify a directory path or paths by setting the CLASSPATH environmental variable.

For example, consider the following package specification:

package Mypack;

Inorder for a program to find MyPack, one of two things must be true. Either the program is executed from a directory immediately above MyPack or CLASSPATH must be set to include the path to MyPack. The first alternative is the easiest and does not require a change to CLASSPATH but the second alternative lets your program find MyPack no matter what directory the program is in.

The easiest way is to simply create the package directories below your current development directory, put the .class files into the appropriate directories, and then execute the programs from the development directory.

Creating your own Package

To create a package, you simply put a class or interface in it. To do this, you put a package statement at the top of the source file in which the class or interface is defined

package <package name>

public class<class name>or<interface name>{

               ……..//body of class or interface

}

We can create hierarchy of packages. To do so simply we separate each package name from the one above it by use of a period. The general form of a multilevel packages statement is shown here:

package pk1.pk2.pk3;

i.e package java.awt.image;

Consider the following example to illustrate how to create a package and import it.

// A user defined package, operation for defining some simple arithmetic operations

package operation;

 public class ArithmeticOperation {

     public double add(double x, double y){

         return x+y;

     }

    public double sub(double x, double y){

         return x-y;

     }

    public double mul(double x, double y){

         return x*y;

     }

    public double div(double x, double y){

         return x+y;

     }

    public double sqr(double x){

         return x*x;

     }   

}

 

Using package operation in a program which we define above:

package operation;

public class MathOperation {

    public static void main(String[] args) {   

    ArithmeticOperation a = new ArithmeticOperation ();

        System.out.println("The sum is=  "+a.add(10, 20));

        System.out.println("The difference is = "+a.div(20, 10));

        System.out.println("The product is = "+a.mul(10, 20));

        System.out.println("The division = "+a.div(200, 50));

        System.out.println("Sqaure of a number is = "+a.sqr(4));

    }

}

 

The output of the above program:

The sum is = 30.0

The difference is = 30.0

The product is = 200.0

The division = 250.0

Square of a number is = 16.0

Access Protection

Packages add another dimension to access control. As we know, Java provides many levels of protection to allow fine grained access control over the visibility of variables and methods within classes, subclasses, and packages.

Classes and packages are both means of encapsulating and containing the name space and scope of the variables and methods. Packages act as a container for classes and other subordinate packages. Classes act as container for data and code. The class is Java’s smallest unit of abstraction. Because of the interplay between classes and packages, Java addresses four categories of visibility for class members:

  • Subclasses in the same package.
  • Non subclasses in the same package
  • Subclasses in different packages
  • Classes that are neither in the same package nor subclasses

The three access specifier, private, public and protected, provides a variety of ways to produce the many levels of access required by these categories.

While Java’s access control mechanism may seem complicated, we can simplify it as follows: Anything declared public can be accessed from anywhere. Anything declared private cannot be seen outside of its class. When a member does not have an explicit access specification, it is visible to subclasses as to other classes in the same package. This is the default access. If you want to allow an element to be seen outside our current package, but only to classes that subclass your directly, then declare that element protected.

A class has only two possible access levels: Default and public: When a class is declared as public, it is accessible by any other code. If a class has default access, then it can only be assessed by other code within its same package.

  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 non subclass No No No Yes

Java’s access control mechanism may seem complicated. We can simplify it as follows. Anything declared public can be accessed from anywhere. Anything declared private cannot be seen outside of its class. When a method does not have an explicit access specification, it is visible to subclasses as well as to other classes in the same package. This is the default access. If we want to allow an element to be seen outside our current package, but only to classes that subclass our class directly, then declare that element protected.

 

An Access Example

The following example shows all combinations of the access control modifiers. This example has two packages and five classes. One point to be noted is that the classes for two different packages need to be stored in directories named after their respective packages – in this case, p1 and p2.

The source for the first package defines three classes: Protection, Derived, and SamplePackage. The first class defines four int variables in each of the legal protection modes. The variable n is declared with the default protection, n_pri is private, n_pro is protected and n_pub is public.

Each subsequent class in this example tries to access the variables in an instance if this class. The line that will not compile due to access restrictions are commented out by use of the single line comment//.

The second class, Derived, is a subclass of Protection in the same package, p1. This grants Derived access to every variable in Protection except for n_pri, the private one. The third class, SampePackage, is not a subclass.

This is file Protection.java

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);

    }

}

This is file Derived.java

package p1;

public class Derived extends Protection {

    Derived (){

        System.out.println ("Derived 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);

    }   

}

 

This is file SamplePackage.java

package p1;

public class SamePackage {

    SamePackage (){

        Protection p = new Protection ();

        System.out.println ("Same package constructor");

        System.out.println ("n = "+p.n);

        //System.out.println ("n_pri = "+p.n_pri);

        System.out.println ("n_pro = "+p.n_pro);

        System.out.println ("n_pub = "+p.n_pub);

    }   

}

 

 Following is the source code for the other package, p2. The two classes defined in p2 cover the other two f conditions which are affected by access control. The first class, Protection2, is a subclass of p1.Protection. This grants access to all of p1.Protection’s variable except for n_pri and n, the variable declared with the default protection. Finally, the class OtherPackage has access to only one variable, n_pub, which was declared public

This is file Protection2.java

package p2;

import p1.Protection;

public class Protection2 extends Protection{

    Protection2(){

        System.out.println("Derived other package constructor");

        //System.out.println("n = "+n);

        //System.out.println("p_pri = "+n_pri);

        System.out.println("n_pro = "+n_pro);

        System.out.println("n_pub = "+n_pub);

    }

}

 

This is file OtherPackage.java

package p2;

import p1.Protection;

class OtherPackage {

OtherPackage(){

Protection p = new Protection();

System.out.println("Other package constructor");

               //System.out.println("n = "+p.n);

        //System.out.println("n_pri = "+p.n_pri);

        //System.out.println("n_pro = "+p.n_pro);

        System.out.println("n_pub = "+p.n_pub);

}

}

 

We can try these two packages; here are two test files we can use. The one for package p1 is shown here:

//Demo package p1

package p1;

public class Demo{

public static void main(String[] args){

               Protection ob1 = new Protection ();

               Derived bo2 = new Derived ();

               SamePackage bo3 = new SamePackage ();

}

}

 

The test file for p2 is show next

//Demo package p2

package p2;

public class Demo {

    public static void main(String[] args) {

        Protection2 ob = new Protection2 ();

               OtherPackage ob2 = new OtherPackage ();

    }

}

 

Importing Packages

Java includes the import statement to bring certain classes or entire packages, into visibility. Once imported, a class can be referred to directly, using only its name. The import statement is a convenience to the programmer and is not technically needed to write a complete Java program.

In a Java source file, import statements occur immediately following the package statement and before any class definitions. This is the general form of the import statement:

import pkg1.pkg2…classname;

Here, pkg1 is the name of a top level package, and pkg2 is the name of a subordinate package inside the outer package separated by a dot. There is no practical limit on the depth of a package hierarchy, except that imposed by the file system.

Finally, we can specify either an explicit classname or a star (*), which indicates that the Java compiler should import the entire package. This code fragment shows both forms in use:

import java.util. Date;

import java.io.*;

Interfaces

In Java, an interface defines a set of methods that will be implemented by a class. Syntactically, interfaces are similar to abstract classes, except that no method can include a body. This means that an interface provides no implementation whatsoever of the methods it defines. Therefore, an interface simply specifies what must be done, but not now.

Once an interface is defined, any number of classes can implement it. A class can implement any number of interfaces.

To implement an interface, a class must provide bodies for the methods described by the interface. Each class is free to determine the details of its implementation.

Defining an interface

 An interface is defined like a class. The general form of an interface is:

access interface interface-name {

return-type method-name1 (parameter list);

return-type method-name2 (parameter list);

…………………………………………………………………..

return-type method-nameN (parameter list);

type final-varname1 = value;

type final-varname2 = value;

…………………………………..

type final-varnameN = value;

}

Here, access is either public or not used. When no access specifier is included, then default access results, and the interface is only available to other members of the package in which it is declared. When it is declared as public, the interface can be used by any other code. name is the name of the interface and can be any valid identifier.

The methods have no bodies and end with semicolon. They are essentially abstract methods.

Variables can be declared inside of interface declarations. They are implicitly final and static. They must be initialized with constant value.

Here is an example of an interface definition. It declares a simple interface which contains one method called callback () that takes a single integer parameter.

Interface Callback {

void callback (int param);

}

Implementing Interface:

Once an interface has been defined, one or more classes can implement that interface. To implement an interface, follow these two steps:

  1. In a class declaration, include an implements clause that specifies the interface being implemented.
  2. Inside the class, implement the methods defined by the interface.

The general form of a class that includes the implements clause looks like this:

access class classname [extends superclass] implements inteface1, interface 2, …………….., interface N {

          Body of class

}

Here, access is either public or not used. The methods that implement an interface must be declared public. Also, the signature of the implementing method must match exactly the type signature specified in the interface definition.

By convention, the implements clause follows extends clause, if there is one.

Let us consider the following example:

package pkginterface;

interface Seriess {

 public int getNext();

    public void reset();

    public void setStart(int x);

}

 class ByTwos implements Seriess{

    int start;

    int val;

    ByTwos(){

        start=0;

        val =0;

    }

    public int getNext(){

        val+=2;

        return val;

    }

    public void reset(){

        val = start;

    }

    public void setStart(int x){

        start = x;

        val = x;

    }

}

public class InterfaceDemo {

    public static void main(String[] args) {

        ByTwos ob = new ByTwos();

        System.out.println("At the beginning ");

        for(int i=0;i<10;i++)

        System.out.print(ob.getNext()+" ");

        ob.reset();

        System.out.println("\nAfter reset ");

        for(int i=0;i<10;i++)

        System.out.print(ob.getNext()+" ");

        System.out.println("\nAfter seting new value");

        ob.setStart(100);       

        for(int i=0;i<10;i++)

        System.out.print(ob.getNext()+" ");

}   

}

 

The output of the above program is:

At the beginning

2 4 6 8 10 12 14 16 18 20

After reset

2 4 6 8 10 12 14 16 18 20

After setting new value

102 104 106 108 110 112 114 116 118 120

 

Nested Interface

An interface can be declared as a member of a class or another interface. Such an interface is called a member interface or a nested interface. A nested interface can be declared as public, private or protected. This differs from top level interface, which must be declared as public or use the default access level. When a nested interface is used outside of its enclosing scope, it must be qualified by the name of the class or interface of which it is a member. Thus, outside of the class or interface in which a nested interface is declared, its name must be fully qualified.

Here is an example that demonstrates a nested interface:

package pkginterface;

class First{

    public interface NestedIF{

    boolean isNotNegative(int x);

}

}

    class Second implements First.NestedIF {

    public boolean isNotNegative(int x){

    return x<0?false:true;

    }

}

public class NestedInterfaceDemo {

    public static void main(String[] args) {

    Second nif = new Second();

    if(nif.isNotNegative(10))

    System.out.println("10 is not negative");

    if(nif.isNotNegative(-12))

    System.out.println("This won't be displayed");

    }   

}

 

 

Applying Interfaces

To understand the power of interface, we look at more practical example. Let us consider the example of class Stack that implements a simple fixed sized stack. However there are many ways to implement a stack. For example, the stack may be of fixed sized or growable. The stack can also be held in an array, a linked list, or binary tree etc. No matter how the stack is implemented, the interface to the stack remains the same. That is, the methods push() and pop() define the interface to the stack independently of the details of the implementation. Because the interface to a stack is separate from its implementation, it is easy to define a stack interface, leaving it to each implementation to define the specifics.

The following program creates an interface called IntStack and this interface is implemented by class Stack that creates a stack of fixed size.

Static Stack

i

nterface IntStack {

    void push(int item);

    int pop();

}

class Stack implements IntStack{

    private int stck[];

    private int tos;

    Stack(int size){

        stck = new int[size];

        tos =-1;

    }

    public void push(int item){

        if(tos==stck.length-1)

            System.out.println("Stack Full");

        else

            stck[++tos] = item;

    }

    public int pop(){

        if(tos<0){

            System.out.println("Stack underflow");

            return 0;

        }

        else

            return stck[tos--];

    }

}

public class StackDemo {

    public static void main(String[] args) {

        Stack s = new Stack(5);

        for(int i=0;i<6;i++)

        s.push(10*i);

        System.out.println("The stack contains");

        for(int i=0;i<6;i++)

        System.out.print(s.pop()+" ");

    }   

}

 

The output of above program is:

Stack Full

The stack contains

40 30 20 10 0 Stack underflow

0

 

Dynamic Stack

Following is another implementation of IntStack that creates a dynamic stack by use of the same interface definition. In this implementation, each stack is constructed with an initial length. If this initial length is exceeded, then the stack is increased in size. Each time more room is needed, the size of the stack is doubled.

interface IntStack{

    void push(int item);

    int pop();

}

class DynStack implements IntStack{

    private int stck[];

    private int tos;

    DynStack(int size){

        stck = new int[size];

        tos =-1;

    }

    public void push(int item){

        if(tos==stck.length-1){

            int temp[] = new int[stck.length*2];

            for(int i=0;i<stck.length;i++)

            temp[i]=stck[i];

            stck = temp;

            stck[++tos] = item;

        }

        else

            stck[++tos] = item;

    }

    public int pop(){

        if(tos<0){

            System.out.println("Stack underflow");

            return 0;

        }

        else

            return stck[tos--];

    }

}

public class DynamicStackDemo {

    public static void main(String[] args) {

        DynStack s = new DynStack(5);

        for(int i=0;i<15;i++)

        s.push(10*i);

        System.out.println("The stack contains");

        for(int i=0;i<17;i++)

        System.out.print(s.pop()+" ");

    }   

}

 

The output of the above program is:

The stack contains

140 130 120 110 100 90 80 70 60 50 40 30 20 10 0 Stack underflow

0 Stack underflow

0

Variables in Interfaces

We can use interfaces to import shared constants into multiple classes by simply declaring an interface that contains variables which are initialized to the desired values. When we include that interface in a class, all of those variable names will be in scope as constants. It is as if that class were importing the constant variables into the class name space as final variables. Let us consider the following example:

interface ConstantInterface {

    int MIN = 0;

    int MAX = 10;

    String ERRORMSG = "Boundary Error";

}

public class InterfaceConstantDemp implements ConstantInterface {

   public static void main(String[] args) {

        int nums[] = new int[MAX];

        for(int i = MIN;i<=MAX;i++){

            if(i>=MAX)

                System.out.println (ERRORMSG);

            else{

                nums[i] = i;

                System.out.print(nums[i]+ " ");

            }               

        }

    }   

}

 

The output of the above program is:

0 1 2 3 4 5 6 7 8 9 Boundary Error

The following is one more example:

import java.util.Random;

import static pkginterface.Constant.NO;

interface Constant{

    int NO = 0;

    int YES = 1;

    int MAYBE = 2;

    int LATER = 3;

    int SOON = 4;

    int NEVER = 5;   

}

class Question implements Constant{

 Random r = new Random();

 int ask(){

     int p = r.nextInt()%100;

     if(p<30)

     return NO;

     else if(p<60)

         return YES;

     else if(p<75)

         return NEVER;

     else if(p<85)

         return LATER;

     else if(p<98)

         return SOON;

     else

         return NEVER;

 }

}

public class SharedConstants implements Constant{

    static void answer(int result){

        switch(result){

            case NO:

                System.out.println("No");

                break;

            case YES:

                System.out.println("YES");

                break;

            case MAYBE:

                System.out.println("MAYBE");

                break;

             case LATER:

                System.out.println("LATER");

                break;

             case SOON:

                System.out.println("SOON");

                break;

             case NEVER:

             System.out.println("No");

                break;

        }

    }

    public static void main(String[] args) {

       Question q = new Question();

       for(int i=0;i<10;i++)

       answer(q.ask());

    }

}

 

The output of the above program is:

No

SOON

No

SOON

No

No

LATER

No

No

No

Interfaces can be Extended

One interface can inherit another by use of the keyword extends. The syntax is the same as for inheriting classes. When a class implements an interface that inherits another interface, it must provide implementations for the methods within the interface inheritance chain. Following is an example.

i

nterface A{

    void meth1();

    void meth2();

}

interface B extends A{

    void meth3();

}

class MyClass implements B{

    public void meth1(){

        System.out.println("Implements meth1().");

    }

    public void meth2(){

        System.out.println("Implements meth2().");

    }

    public void meth3(){

        System.out.println("Implements meth3().");

    }

}

public class ExtendedInterfaceDemo {

    public static void main(String[] args) {

        MyClass ob = new MyClass();

        ob.meth1();

        ob.meth2();

        ob.meth3();

    }

}

 

The output of the above program is:

Implements meth1().

Implements meth2().

Implements meth3().

 

Interface versus Abstract Class

  • An abstract class can contain non static and non-final fields where as an interface has static final fields by default.
  • An abstract class should contain at least one abstract method whereas an interface has all the methods abstract by default. That is, an abstract class can have some implemented methods but an interface does not.
  • A class can extend at most one abstract class where as it can implement any number of interfaces.

Leave a Reply

Your email address will not be published. Required fields are marked *