Packages and Interfaces

Packages

Packages are directory structures used to organize classes and interfaces, Packages provide a mechanism for software reuse, they also provide a convention for unique class names. When coding for a large project, sometimes classes can be called the same name, especially if third party developers are involved by using packages you can distinguish between class names. Normally you supply your domain name as a package location.

Java uses the current path, the -classpath option (java, javac, etc) or CLASSPATH environment variable to find packages.

Java uses two ways to protect classes, access control and modules (which i will discuss in another section), I have already discuss variable and method modifiers so you have some idea on how package modifiers will work as they are similar. Because of the interplay between classes and packages, Java has four categories of visibility for class members.

The three access modifiers are private, public and protected which provide many ways to protect the categories above. This can be summarized in the table below

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

To create a package you use the keyword package as in the below example

Package Example
package uk.co.datadisk;			// the directory structure uk/co/datadisk will contain your classes. 

The import directive tells the compiler where to look for the class definitions when it comes upon a class that it cannot find in the default java.lang package.

Import examples
import java.util.*;  			// using a * is known as import-on-demand
 
import uk.co.datadisk.buildings.*  	// the classes can be found in uk/co/datadisk/buildings
import uk.co.datadisk.*  		// the classes can be found in uk/co/datadisk, be careful this wont see the builings folder classes, 
					// only the folder level you specified, there is no drilling down the directories using a wildcard
					
import uk.co.datadisk.StockQuote 	// specifying a particlar class is known as single-type-import 

Note: single-type-import takes precedence of the import-on-demand declaration import.java.Util.* (lower precedence)
Static Import examples
import static java.lang.Math.PI 	// single-type-import
import static java.lang.Math.sqrt 	// single-type-import
import static java.lang.Math.* 		// import-on-demand

Interface Implementation

When you create a interface you are defining a contract for what a class can do, without saying anything about how the class will do it. A interface is a contract. Interfaces can be implemented by any class from any inheritance tree, this lets you take radically different classes and give them a common characterstic. By defining a interface within the class you agree to provide the code for any of the interfaces methods, an interface generally has abstract methods (a abstract class can contain both abstract and non-abstract methods). There are many interfaces supplied by Java for example java.lang.Comparable, java.io.Serializable and java.util.List.

The rules of an interface are

Interface declaration
public abstract interface Rollable { ... }       # should use the below declaration as the keyword abstract is
                                                 # redundant, but this is acceptable
interface Rollable { ... }                       # there is no need to specify the abstract or public keywords
Method declaration

public interface Bounceable {
   public abstract void bounce();
   void setBounceFactor();
}

Note: you do not need to specify the public abstract modifiers (now redundant), so both above methods are acceptable, all methods are public and abstract no matter what you see.

Default method
interface Bounceable {
    default void defaultMethod() {
        System.out.println("This is an interface default method");    
    }
}

Note: default methods must be implemented and are not abstract but can be overriden, also becareful of implementing multiple default methods (with the same signature) from multiple interfaces, you will get a compiler error
Interface Constants

public interface Bounceable {
   public static final int LOW_BOUNCE = 1;
   int HIGH_BOUNCE = 10;                      # HIGH_BOUNCE will be implicity be defined as public final static
}

Note: by putting constants in an interface you are guaranteeing that any class implementing the interface will have access to the same constant. They are also used to associate values with easy names to remember. as with the same with methods you do not need to specify the public final static modifiers (now redundant), so both above declarations are acceptable, all constants are public final static no matter what you see.

Implementing a interface

public class rubberBall implements Bounceable {
   public void bounce() { ... }               # must supply the code for the implemented interfaces method
}

Note: you are binded by a contract to supply the code for any of the interfaces methods, otherwise the compiler will complain. The signature of the method must be same as in the interface.

Also a abstract class can implement a interface but at somepoint the interface methods code must be implemented to honour the binding contract.

Using a static method in a interface
interface Bounceable {
    static String publicStaticMethod() {
        return "Interfaces public static method";
    }
}

Note: you can use the public static method by calling Bounceable.publicStaticMethod();
Implementing multiple interfaces

public class rubberBall implements Bounceable, Serializable, Runnable { ... }

Extending an interface public interface Bounceable extends Moveable { ... }

Note: an interface can itself extend another interface but never implement anything
Using interface references
interface TestInterface3 {
    int i = 5;
}

class Client implements TestInterface3 {
    public String method1() {
        return "Client class method1";
    }
}

public class TestInterface2 {

    public static void main(String[] args) {
        TestInterface3 int3 = new Client();                                         # int3 is a interface reference to a Client object
        Client cl1 = new Client();

        System.out.println("Variable i from interface: " + int3.i);                 # accessing the interface by reference
        // System.out.println("Calling class method1: " + int3.method1());          # you cannot access the objects in the Client class
        System.out.println("Calling class method1: " + cl1.method1());
    }
}

Note: when you interfaces as references note that you will only have access whats specified in the interface only, you wont have access to whats in the class, this process is similar
      to using the superclass reference to access a subclass.
Nested Interface
class TestClass4 {
    
    public interface NestedInterface {          // nested interface
        boolean isNotNegative(int x);
    }
    
}

class TestClass5 implements TestClass4.NestedInterface {

    @Override
    public boolean isNotNegative(int x) {
        return x < 0 ? false: true;
    }
}

A complete example explaining implementing an interface

Implementing an interface class arrayTest {
   public static void main(String[] args) {

      test t1 = new test();
      t1.methodA();
   }
}

class test implements inter1 {                        // enter into the interfaces contract, abstraction rules now apply

   public void methodA() {                            // method body for abstract methodA
      System.out.println("interface inter1 - methodA");
      count = 50;                                     // illegal - count has been marked public, static and final by the interface
      System.out.println("count" + count);
   }
}

interface inter1 {                                    // 100% abstract class - all methods are abstract
   int count = 20;                                    // implicity marked public, static and final - even if not stated

   public void methodA();                             // implicity marked public and abstract - even if not stated

   public void methodB() {                            // illegal - must be abstract method - no curly braces
      System.out.println("class test - methodB");
   }
}

Note: this program will not compile as there are a number of errors.

I have already covered abstract classes, I have a table in the abstract classes section of the differences between abstract classes and interfaces