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 |
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 { 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 { 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 { 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 interface inter1 { // 100% abstract class - all methods are abstract 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