Java I/O – built in I/O classes

Introducing Java I/O

Java I/O stands for Java Input/Output. In the previous chapters, we were actually using Java’s I/O system but without knowing much about it. Java’s I/O system is very elaborate and it is not possible to discuss each and every API Java provides. We will discuss the basic and important APIs here, and it is your responsibility to explore more as a Java developer.

Java I/O system contains many built-in classes. We can classify the Java I/O into two categories as shown below.

  • Text based
  • File based

Java performs I/O operations through streams. An I/O stream is an abstraction that produces or consumes information. A stream is directly linked to a physical device using Java I/O system. All streams behave in the same manner to whatever device it is connected to. The implementation of I/O streams is done in java.io package.

The Byte Stream Classes

Byte streams are defined by two main abstract classes InputStream and OutputStream. InputStream defines common classes that consume byte input from devices whereas OutputStream defines classes to write a byte to devices. There are so many classes derived from these two streams, but they all work in the same manner. If you learn one class then you can easily understand the remaining.

Below is the list of Byte stream classes.

Byte Stream Class Meaning
BufferedInputStream Buffered input stream
BufferedOutputStream Buffered output stream
ByteArrayInputStream Input stream that reads from a byte array
ByteArrayOutputStream Output stream that writes to a byte array
DataInputStream An input stream that contains methods for reading the Java
standard data types
DataOutputStream An output stream that contains methods for writing the Java
standard data types
FileInputStream Input stream that reads from a file
FileOutputStream Output stream that writes to a file
FilterInputStream Implements InputStream
FilterOutputStream Implements OutputStream
InputStream Abstract class that describes stream input
ObjectInputStream Input stream for objects
ObjectOutputStream Output stream for objects
OutputStream Abstract class that describes stream output
PipedInputStream Input pipe
PipedOutputStream Output pipe
PrintStream Output stream that contains print() and println()
PushbackInputStream Input stream that allows bytes to be returned to the stream
SequenceInputStream Input stream that is a combination of two or more input streams that
will be read sequentially, one after the other

The Character Stream

Character streams consume character data. They have two main abstract classes: Reader and Writer. We use Reader for input and Writer for output.

Below are the list of character stream classes.

Character Stream Class Meaning
BufferedReader Buffered input character stream
BufferedWriter Buffered output character stream
CharArrayReader Input stream that reads from a character array
CharArrayWriter Output stream that writes to a character array
FileReader Input stream that reads from a file
FileWriter Output stream that writes to a file
FilterReader Filtered reader
FilterWriter Filtered writer
InputStreamReader Input stream that translates bytes to characters
LineNumberReader Input stream that counts lines
OutputStreamWriter Output stream that translates characters to bytes
PipedReader Input pipe
PipedWriter Output pipe
PrintWriter Output stream that contains print() and println()
PushbackReader Input stream that allows characters to be returned to the input stream
Reader Abstract class that describes character stream input
StringReader Input stream that reads from a string
StringWriter Output stream that writes to a string
Writer Abstract class that describes character stream output

You can learn more information about Java I/O  from Oracle Java help site.

Java throw, finally and throws keywords

throw

Till now we caught exceptions which were generated automatically, but in some cases, we need to raise an exception from our program manually. To raise an exception throw keyword is used. Below is the syntax of throw statement.

throw object;

Here, the object is an object of an exception class. We have to create an object of required exception type and then use that object with throw keyword. In the below sample, we are throwing ArithmeticException manually and when we use throw statement, Java handles it same way as an automatic exception and the corresponding catch block will be called and executed.

/*
This is a simple Java program about Exception Handling.
Call this file KH_throw.java.
*/

class KH_throw {
	public static void main(String args[]) {
		try {
			System.out.println("Before throw.");
			throw new ArithmeticException();
		}
		catch (ArithmeticException exc) {
			System.out.println("Exception caught.");
		}
		System.out.println("After try catch block.");
	}
}

Download the code  Run the code

Output:

Before throw.
Exception caught.
After try catch block.

finally

When we write programs there will many of cases where we need to open a file, open a database connection or open a socket etc. at the beginning of a method. When the method exits, we need to make sure we close all opened connections.

We include all statements such as opening a file inside try block. Now we need to close the file after successful try block execution as well as if any exception is caught. The same code needs to be executed in both cases. To achieve this, we can use finally block. The finally block always gets called at the end of the try block and catch block. Below is syntax to use finally:

try {
    // block of code to monitor for errors
}
catch (ExcepType1 exOb) {
    // handler for ExcepType1
}
catch (ExcepType2 exOb) {
    // handler for ExcepType2
}
//...
finally {
    // finally code
}

The below program demonstrates how finally is used here. As you can see in the output, finally gets executed in both cases.

/*
This is a simple Java program about Exception Handling.
Call this file KH_finally.java.
*/
// Use finally.
class UseFinally {
	public static void genException(int i) {
		int t;
		int nums[] = new int[2];
		System.out.println("Receiving " + i);
		try {
			switch(i) {
				case 0:
					t = 10 / i;
					break;
				case 1:
					nums[4] = 4;
					break;
				case 2:
					return;
			}
		}
		catch (ArithmeticException exc) {
			System.out.println("Can not divide by Zero");
			return;
		}
		catch (ArrayIndexOutOfBoundsException exc) {
			System.out.println("No matching element found.");
		}
		finally {
			System.out.println("Leaving try.");
		}
	}
}

class KH_finally {
	public static void main(String args[]) {
		for(int i=0; i < 3; i++) {
			UseFinally.genException(i);
			System.out.println();
		}
	}
}

Download the code  Run the code

Output:

Receiving 0
Can not divide by Zero
Leaving try.

Receiving 1
No matching element found.
Leaving try.

Receiving 2
Leaving try.

throws

A method which does not handle exceptions within its body, has to specify what type of exceptions it might throw by using throws keyword. Its syntax is:

returntype methodName(parameterlist) throws exceptionlist {
    // body
}

But in our previous cases, we did not use this keyword because all our exceptions are handled and the method is error proof. When a method is defined with throws an exception, Java itself will remember this point.

Below program demonstrates the same, here we are using the prompt method to read input from the user and we have used throws keyword with IOException and inside main we have handled this exception.

/*
This is a simple Java program about Exception Handling.
Call this file KH_throws.java.
*/
class KH_throws {
	
	public static char prompt(String str) throws java.io.IOException {
		System.out.print(str + ": ");
		return (char) System.in.read();
	}

	public static void main(String args[]) {
		char ch;
		try {
			ch = prompt("Enter a letter");
		}
		catch(java.io.IOException exc) {
			System.out.println("I/O exception occurred.");
			ch = 'X';
		}
		System.out.println("You pressed " + ch);
	}
}

Download the code  Run the code

Output:

Enter a letter: a
You pressed a

Methods in Throwable, Java’s Built-in Exceptions, and Custom Exception

Methods in Throwable Class

Till now we are just catching exceptions but not using methods of Throwable class for better handling of an exception. Throwable has a number of methods which can be used to handle or display useful information regarding exception occurred. Below are the list of methods and their description.

Method Description
Throwable fillInStackTrace() This method returns a Throwable object with complete details of the exception.
String getLocalizedMessage( ) Returns localized information of the exception.
String getMessage( ) Returns a information of the exception.
void printStackTrace( ) Displays the stack trace.
void printStackTrace(PrintStream stream) Sends the stack trace to the specified stream.
void printStackTrace(PrintWriter stream) Sends the stack trace to the specified stream.
String toString( ) Returns a String object containing a complete description of the exception. This method is called by println to display information.

Below example demonstrates some of these methods, in general, we use printStackTrace method more to understand where is the problem in a source code.

/*
This is a simple Java program about Exception Handling.
Call this file KH_Throwable.java.
*/

class ExcTest {
	static void genException() {
		int nums[] = new int[4];
		System.out.println("Before exception is generated.");
		nums[7] = 10;
		System.out.println("this won't be displayed");
	}
}
class KH_Throwable {
	
	public static void main(String args[]) {
		try {
			ExcTest.genException();
		}
		catch (ArrayIndexOutOfBoundsException exc) {
			System.out.println("Standard message is: ");
			System.out.println(exc);
			System.out.println("\nStack trace: ");
			exc.printStackTrace();
		}
		System.out.println("After catch statement.");
	}
}

Download the code  Run the code

Output:

Before exception is generated.
Standard message is:
java.lang.ArrayIndexOutOfBoundsException: 7

Stack trace:
java.lang.ArrayIndexOutOfBoundsException: 7
        at ExcTest.genException(KH_Throwable.java:10)
        at KH_Throwable.main(KH_Throwable.java:18)
After catch statement.

Java’s Built-in Exception classes

Under java.lang package Java defines many exception classes to capture exceptions. Below is a list of exception classes available.

Exception Meaning
ArithmeticException Arithmetic error, such as integer divide-by-zero.
ArrayIndexOutOfBoundsException Array index is out-of-bounds.
ArrayStoreException Assignment to an array element of an incompatible type.
ClassCastException Invalid cast.
EnumConstantNotPresentException An attempt is made to use an undefined enumeration value.
IllegalArgumentException Illegal argument used to invoke a method.
IllegalMonitorStateException Illegal monitor operation, such as waiting on an unlocked thread.
IllegalStateException Environment or application is in an incorrect state.
IllegalThreadStateException Requested operation not compatible with current thread state.
IndexOutOfBoundsException Some type of index is out-of-bounds.
NegativeArraySizeException The array created with a negative size.
NullPointerException Invalid use of a null reference.
NumberFormatException Invalid conversion of a string to a numeric format.
SecurityException Attempt to violate security.
StringIndexOutOfBoundsException Attempt to index outside the bounds of a string.
TypeNotPresentException Type not found.
UnsupportedOperationException An unsupported operation was encountered.
ClassNotFoundException Class not found.
CloneNotSupportedException Attempt to clone an object that does not implement the Cloneable interface.
IllegalAccessException Access to a class is denied.
InstantiationException Attempt to create an object of an abstract class or interface.
InterruptedException One thread has been interrupted by another thread.
NoSuchFieldException A requested field does not exist.
NoSuchMethodException A requested method does not exist.
ReflectiveOperationException Superclass of reflection-related exceptions.

Creating Custom Exception Class

Java provides a rich set of exception classes to use, but Java’s ability to handling exceptions is not limited to these built-in classes. Java allows us to write our own exception classes and use them as built-in classes. To create an exception class, it should be a subclass of Exception class. Of course, we can create a subclass of Throwable but in practice, we use Exception class as the superclass for our custom class. Exception class is also derived from Throwable and it does not do anything. Once we derived our class from Exception class, we can override any method which is present in Throwable class and create custom output.

In the below example, we have created a custom exception class NotEvenException and it is derived from Exception class. In this custom class, we override the toString method to display our custom string as output. In the main method, we have used catch blocks to catch our custom exception along with built-in exception classes. When given integer is not an even number then the main method throws our custom exception.

/*
This is a simple Java program about Exception Handling.
Call this file KH_CustomException.java.
*/

class NotEvenException extends Exception {
	int n;
	NotEvenException(int i) {
		n = i;
	}	
	public String toString() {
		return "The number " + n + " is not even number.";
	}
}
class KH_CustomException {
	
	public static void main(String args[]) {
		int number[] = { 4, 8, 15, 32, 64, 127, 256, 512 };
		for(int i=0; i<number.length; i++) {
			try {
				if((number[i]%2) != 0)
					throw new NotEvenException(number[i]);
				else
					System.out.println("The number " + number[i] + " is even number.");					
			}
			catch (ArithmeticException exc) {
				System.out.println("Can't divide by Zero!");
			}
			catch (ArrayIndexOutOfBoundsException exc) {
				System.out.println("No matching element found.");
			}
			catch (NotEvenException exc) {
				System.out.println(exc);
			}
		}
	}
}

Download the code  Run the code

Output:

The number 4 is even number.
The number 8 is even number.
The number 15 is not even number.
The number 32 is even number.
The number 64 is even number.
The number 127 is not even number.
The number 256 is even number.
The number 512 is even number.

Multiple catch blocks and nested try blocks

Multiple catch blocks with single try block

Sometimes a set of statements combined can result in different types of exceptions. For example, when processing two arrays and performing division operation on each of the elements of an array, there is a possibility to get ArrayIndexOutOfBoundsException or ArithmeticException. In such cases how to handle them? This can be achieved by multiple catch blocks to a single try block. Below program explains the same functionality of Java. Here, denom array is having zeros and we are performing a division operation. Hence, I wrote two catch blocks which handle different types of exceptions.

/*
This is a simple Java program about Exception Handling.
Call this file KH_MaultipleCatch1.java.
*/

class KH_MaultipleCatch1 {
	public static void main(String args[]) {
		int number[] = { 4, 8, 16, 32, 64, 128, 256, 512 };
		int denom[]  = { 2, 0, 4, 4, 0, 8 };
		for (int i=0; i<number.length; i++) {
			try {
				System.out.println(number[i] + " / " +
				denom[i] + " is " + number[i]/denom[i]);
			}
			catch (ArithmeticException exc) {
				System.out.println("Can't divide by Zero!");
			}
			catch (ArrayIndexOutOfBoundsException exc) {
				System.out.println("No matching element found.");
			}
		}
	}
}

Download the code  Run the code

Output:

4 / 2 is 2
Can't divide by Zero!
16 / 4 is 4
32 / 4 is 8
Can't divide by Zero!
128 / 8 is 16
No matching element found.
No matching element found.

We need to consider one important point when writing multiple catch blocks to a single try block,  which type is the subclass of which type. For example, we know that all exceptions are a subclass of Throwable type. then when we write two catch block with ArrayIndexOutOfBoundsException and Throwable, the order of catch blocks is very important. When an exception occurs Java check for catch block for the same type from top to bottom. If it matches then executes that catch block. In above case, if we write Throwable as first catch block and ArrayIndexOutOfBoundsException later, then our second block never executes because Throwable is a superclass of ArrayIndexOutOfBoundsException. Hence ArrayIndexOutOfBoundsException matches with first catch block and always the first block executes. This lead to unreachable code in our program and unreachable code in Java is an error.

/*
This is a simple Java program about Exception Handling.
Call this file KH_MaultipleCatch2.java.
*/

class KH_MaultipleCatch2 {
	public static void main(String args[]) {
		int number[] = { 4, 8, 16, 32, 64, 128, 256, 512 };
		int denom[] = { 2, 0, 4, 4, 0, 8 };
		for(int i=0; i<number.length; i++) {
			try {
				System.out.println(number[i] + " / " +
				denom[i] + " is " +
				number[i]/denom[i]);
			}
			catch (ArrayIndexOutOfBoundsException exc) {
				// catch the exception
				System.out.println("No matching element found.");
			}
			catch (Throwable exc) {
				System.out.println("Can't divide by Zero!");
			}
			
		}
	}
}

Download the code  Run the code

Output:

4 / 2 is 2
Can't divide by Zero!
16 / 4 is 4
32 / 4 is 8
Can't divide by Zero!
128 / 8 is 16
No matching element found.
No matching element found.

Below is output if I swap two catch blocks.

KH_MaultipleCatch2.java:19: error: exception ArrayIndexOutOfBoundsException has
already been caught
                        catch (ArrayIndexOutOfBoundsException exc) {
                        ^
1 error

Nesting try blocks

It is possible to nest one try block into another try block. When an exception occurred in inner try block first its corresponding catch blocks will get executed. If this exception is not handled by inner try catch then it transfers to outer try catch blocks. In the below example, inner try catch blocks handle ArithmeticException and outer try catch block handles ArrayIndexOutOfBoundsException. The output of this program explains everything.

/*
This is a simple Java program about Exception Handling.
Call this file KH_Nestingtry.java.
*/

class KH_Nestingtry {
	public static void main(String args[]) {
		int number[] = { 4, 8, 16, 32, 64, 128, 256, 512 };
		int denom[]  = { 2, 0, 4, 4, 0, 8 };
		try {
			for(int i=0; i<number.length; i++) {
				try {
					System.out.println(number[i] + " / " +
					denom[i] + " is " +
					number[i]/denom[i]);
				}
				catch (ArithmeticException exc) {
					System.out.println("Can't divide by Zero!");
				}
			}
		}
		catch (ArrayIndexOutOfBoundsException exc) {
			System.out.println("No matching element found.");
		}
			
	}
}

Download the code  Run the code

Output:

4 / 2 is 2
Can't divide by Zero!
16 / 4 is 4
32 / 4 is 8
Can't divide by Zero!
128 / 8 is 16
No matching element found.

In general practice, we use inner blocks to handle less complicated exceptions and the outer block is used to handle more severe and more complicated exceptions.

Java Exception Handling

Run time errors are those that happen while the program is executing. The reason might be you are dividing by zero or opening a file which is not present in system or some other unforeseen scenario. These type of errors occur at run-time, hence, it not possible to check for every condition to error safely. Even though we write code to safeguard all conditions, it may still lead to other unforeseen errors. To avoid these problems Java provides an efficient way of handling these errors, called Exception Handling.

Java defines different classes for the different types of exceptions. All these classes are derived from the base class Throwable. When an exception occurs in a program, Java creates an object of type Throwable and sends it to our program. By studying this object we can perform safety operations.

There are two direct subclasses of Throwable: Exception and Error.

In general exceptions of type Error are related to JVM, so we do not handle these exceptions. But the exceptions that are of type Exception class are related to our own program operations such as divide-by-zero or file not found etc. We need to handle these exceptions. The important subclass of Exception is RuntimeException, which is used to handle common issues that occur at run-time.

By using five keywords we can handle all exceptions in Java, they are: try, catch, throw, throws and finally. These are all interrelated and have their own purpose in handling exceptions. We will look at these keywords one by one.

try and catch

The try and catch keywords form the basis of complete exception handling in Java. The set of statements or code you want to monitor should be present in the try block, which should be followed by catch block with a specific exception type. Below is the simple syntax of try catch blocks.

try {
    // code to monitor for errors
}
catch (ExceptionType exOb) {
    // handle ExceptionType here
}

In the above syntax, ExceptionType is the class of the object we are expecting the statements present in the try block to throw. When the program is executing statements under the try block, it checks for any run-time errors. If any error occurred in try block then Java creates an object of that type and passes control to catch block by skipping any statements below the problematic statement. If no error occurs then it completely skips catch block.

In this below program, we have created an integer array of size 6 and we are initializing this array using for loop. We know that if we pass index value which is greater than or equal to the size of the array, the program crashes as we are accessing a memory location which does not exist. We place this assignment inside  a try block. As array index is the problem here, we wrote catch block with the exception of type ArrayIndexOutOfBoundsException. Here intentionally we iterated the for loop to go beyond the size of the array. When i becomes equal to the size of the array, program control jumps to catch block and skips println statement. The catch block will be executed.

/*
This is a simple Java program about Exception Handling.
Call this file KH_trycatchSample.java.
*/

class KH_trycatchSample {
	public static void main(String args[]) {
		int numbers[] = new int[6];				
		try {
			for (int i = 0; i <= 6; i++){ // equal is the cause of error
				numbers[i] = i+1;
				System.out.println("Value at index " + i + " is " + numbers[i]);
			}
		}
		catch(ArrayIndexOutOfBoundsException ex){
			System.out.println("Caught Index out of bounds exception");
		}
		System.out.println("End of try catch block");
	}
}

Download the code  Run the code

Output

Value at index 0 is 1
Value at index 1 is 2
Value at index 2 is 3
Value at index 3 is 4
Value at index 4 is 5
Value at index 5 is 6
Caught Index out of bounds exception
End of try catch block

Java Interface References and Extending Interfaces

Interface References

As you know we can not create objects of an abstract class, but we can create objects of an interface. And we can refer this object to any object of a class which implements its interface. When you call a method of the interface by using interface reference object, the method defined in the class which implements this interface gets executed. We update our SequenceDemo program so that it explains this concept.

In the below program, we have created a reference to interface Sequence and assigned to an object of Twos class. When we call getNextNumber method it executes getNextNumber defined in Twos class. As a practice for you try to create Threes class which implements Sequence interface and use our interface reference object to call methods of Twos and Threes alternatively.

/*
This is a simple Java program about Interface.
Call this file KH_InterfaceReference.java.
*/
interface Sequence {
	
	int getNextNumber();
	int setInitialValue(int x);
	void restart();
}

class Twos implements Sequence {
	int start;
	int val;
	Twos() {
		start = 0;
		val = 0;
	}
	public int getNextNumber() {
		val += 2;
		return val;
	}
	public void restart() {
		val = start;
	}
	public int setInitialValue(int x) {
		start = x;
		val = x;
		return start;
	}
}

class KH_InterfaceReference {
	public static void main(String args[]) {
		Sequence ref;
		Twos ob = new Twos();
		
		ref = ob;
		
		for(int i=0; i < 5; i++)
			System.out.println("Next value is " + ref.getNextNumber());
		
		System.out.println("\nResetting");
		ref.restart();
		
		for(int i=0; i < 5; i++)
			System.out.println("Next value is " + ref.getNextNumber());
		
		System.out.println("\nStarting at 100");
		ref.setInitialValue(100);
		for(int i=0; i < 5; i++)
			System.out.println("Next value is " + ref.getNextNumber());
	}
}

Download the code  Run the code

Output:

Next value is 2
Next value is 4
Next value is 6
Next value is 8
Next value is 10

Resetting
Next value is 2
Next value is 4
Next value is 6
Next value is 8
Next value is 10

Starting at 100
Next value is 102
Next value is 104
Next value is 106
Next value is 108
Next value is 110

Extending Interfaces

We can also derive one interface from another interface using extends keyword. And the class which implements derived interface must implement all methods of all interfaces. In the below example interface X defines two methods func1 and func2. The next interface Y which extends from interface X defines one method func3.

Now if a class Example implements interface Y. As Y extends from X, class Example has to implement all three functions func1, func2, and func3. Just to confirm our discussion, remove func1 method from class Example and try to execute and it will spit compile errors..

/*
This is a simple Java program about Interface.
Call this file KH_InterfaceExtends.java.
*/
interface X {
	
	void func1();
	void func2();	
}

interface Y extends X{
	
	void func3();
}

class Example implements Y {
	public void func1(){
		System.out.println("Function 1");
	}
	public void func2(){
		System.out.println("Function 2");
	}
	public void func3(){
		System.out.println("Function 3");
	}
}

class KH_InterfaceExtends {
	public static void main(String args[]) {
		Example ob = new Example();
		
		ob.func1();
		ob.func2();
		ob.func3();
	}
}

Download the code  Run the code

Output:

Function 1
Function 2
Function 3

Java Interface Variables and Default Methods

Java interface aariables

We can declare variables in Java interfaces. By default, these are public, final and static. That is they are available at all places of the program, we can not change these values and lastly only one instance of these variables is created, it means all classes which implement this interface have only one copy of these variables in the memory. The below example demonstrates:

/*
This is a simple Java program about Interface.
Call this file KH_InterfaceVariables.java.
*/
interface X {
	int max = 10;
}

class Example implements X {
	public void getMax(){
		System.out.println(max);
	}
}

class KH_InterfaceVariables {
	public static void main(String args[]) {
		Example ob = new Example();		
		ob.getMax();		
		//ob.max = 20; //uncommenting this will generate compile error
	}
}

Download the code Run the code

Output:

10

Even though we can create variables in interfaces, but in general we rarely use this.

Default Methods

With respect to interfaces we have one major rule: A class must implement all methods which are declared in the interface. But after some years of usage we got a big issue. Consider we have created an interface and it became very famous and so many people have used this for their own implementation. But you have to change this interface to add a new method after some years. Then all people who have used our interface has to change their source to match with our interface. This is practically very difficult because all previous implementations were done some years back. So they might not have source code with them, then they can not use your latest interface.

To avoid this problem Java has introduced default method to an interface in JDK 8. This means that we can write our own default implementation to our interface methods. Now any class which is implementing this interface need to implement default method. If default method is not implemented in class then default implementation in the interface is executed. If any class implements default method then this implementation hides interface default implementation. To make a method and implementation as default then we need to use default keyword.

For example, we change setInitialValue() method of Sequence interface. We make it default method by adding default keyword and write body to it so that it returns 1 as default. Now we do not implement this method in Twos class. For more understanding try to add setInitialValue method in a class and see how it works. One point to remember is, to use this feature you should be working with JDK 8 and above.

/*
This is a simple Java program about Interface.
Call this file KH_InterfaceDefault.java.
*/
interface Sequence {
	
	int getNextNumber();
	default int setInitialValue(int x) {
		return 1;
	}
	void restart();
}

class Twos implements Sequence {
	int start;
	int val;
	Twos() {
		start = 0;
		val = 0;
	}
	public int getNextNumber() {
		val += 2;
		return val;
	}
	public void restart() {
		val = start;
	}
	
}

class KH_InterfaceDefault {
	public static void main(String args[]) {
		Twos ob = new Twos();
		
		ob.start = ob.val = ob.setInitialValue(0);
		
		for(int i=0; i < 5; i++)
			System.out.println("Next value is " + ob.getNextNumber());
	}
}

Download the code Run the code

Output:

Next value is 3
Next value is 5
Next value is 7
Next value is 9
Next value is 11

Java interfaces

Sometimes it will be helpful to define a class which contains rules on what must be done by the class but not how to do it. Yes, we have learned this in an abstract method. An abstract method defines the signature of a method but does not contain any information about how to do it. A subclass has to implement this method as per its requirement. To enhance the power of abstract classes Java provides interfaces.

An interface is almost similar to the abstract class, where we can define methods with no body. These methods must be implemented in the class which implements this interface.

  • Like abstract classes, any number of classes can implement an interface.
  • Unlike abstract classes, a single class can implement any number of interfaces.
  • An abstract class can have both abstract and non abstract methods. Where as an interface only contains all abstract methods but they don’t use abstract keyword.

To create an interface we need to use interface keyword in place of class and define its methods signatures. Below is simple syntax of it:

access-modifier interface interface-name {
    returntype methodname1(paramlist);
    returntype methodname2(paramlist);
    ....
    returntype methodnameN(paramlist);
    
    
    type var1 = value;
    type var2 = value;
    ....
    type varN = value;
}

In the syntax access modifier can be either public or empty. If no modifier is used then this interface is available within that package. We will learn about packages in later sections. If you specify public access modifier then you must have a separate file with the same name as the interface name. Below is sample interface called Sequence which contains three methods such as getNextNumber, setInitialValue, and restart but it does not contain any information about how to do it.

interface Sequence {
	
	void getNextNumber();
	int  setInitialValue(int x);
	void restart();
}

Implementing an Interface

After an interface is defined, we need to create classes which implement our interface. To implement an interface we need to use implements keyword in class definition, the simple syntax is shown below,

class class_name extends super_class implements interface_name {
    // class-body
}

To implement more than one interface then each interface is separate by a comma. And more importantly, the methods we are implementing in the class must be public and should match the same signature as that of an interface. Now let us create a class Twos which implements our Sequence interface. It adds functionality to getNextNumber(), setInitialValue () and restart() methods. You can see that it uses the same signature as that of Sequence interface and all these methods are public. In addition to the methods from the interface, the class can have its own methods and data members too.

/*
This is a simple Java program about Interface.
Call this file KH_Interface.java.
*/
interface Sequence {
	
	int getNextNumber();
	int setInitialValue(int x);
	void restart();
}

class Twos implements Sequence {
	int start;
	int val;
	Twos() {
		start = 0;
		val = 0;
	}
	public int getNextNumber() {
		val += 2;
		return val;
	}
	public void restart() {
		val = start;
	}
	public int setInitialValue(int x) {
		start = x;
		val = x;
		return start;
	}
}

class KH_Interface {
	public static void main(String args[]) {
		Twos ob = new Twos();
		
		for(int i=0; i < 5; i++)
			System.out.println("Next value is " + ob.getNextNumber());
		
		System.out.println("\nResetting");
		ob.restart();
		
		for(int i=0; i < 5; i++)
			System.out.println("Next value is " + ob.getNextNumber());
		
		System.out.println("\nStarting at 100");
		ob.setInitialValue(100);
		for(int i=0; i < 5; i++)
			System.out.println("Next value is " + ob.getNextNumber());
	}
}

Download the code  Run the code

Output:

Next value is 2
Next value is 4
Next value is 6
Next value is 8
Next value is 10

Resetting
Next value is 2
Next value is 4
Next value is 6
Next value is 8
Next value is 10

Starting at 100
Next value is 102
Next value is 104
Next value is 106
Next value is 108
Next value is 110

Multilevel Inheritance and Referencing

Multilevel Inheritance

Till now we have seen creating a subclass from a superclass. Java also supports creating a new subclass from another subclass. This new class inherits properties of the immediate superclass and its grand superclass. For example, let’s derive a new colorReactangle class from Rectangle class. This new class holds properties of Rectangle class style and Shape class width and height. Also, this can have its own properties such as color.

Below program demonstrates this.

/*
This is a simple Java program about Inheritance.
Call this file KH_MultilevelInheritance.java.
*/
class Shape {
	
	private double width;
	private double height;
	
	public Shape(double width, double height){
		this.width = width;
		this.height = height;
	}
	double getWidth(){
		return width;
	}
	void setWidth(double w){
		width = w;
	}
	double getHeight(){
		return height;
	}
	void setHeight(double h){
		height = h;
	}
	void showDimensions(){
		System.out.println("Width: " + width + ", Height: " + height);
	}
}

class Rectangle extends Shape {
	String style;
	public Rectangle(String style, double width, double height){
		super(width, height);
		this.style = style;
	}
	public void showStyle() {
		System.out.println("Style: " + style);
	}
}

class ColorRectangle extends Rectangle {
	String color;
	public ColorRectangle(String color, String style, 
               double width, double height) {
		super(style, width, height);
		this.color = color;
	}
	public void showColor() {
		System.out.println("Color: " + color);
	}
}

class KH_MultilevelInheritance {
	public static void main(String args[]) {
		ColorRectangle ob = new ColorRectangle("Red", "outlined", 10, 5);
		ob.showDimensions();
		ob.showStyle();
		ob.showColor();
	}
}

Download the code  Run the code

Output:

Width: 10.0, Height: 5.0
Style: outlined
Color: Red

Referencing

As we already know Java is strongly typed language. This means that one type of object can not refer to another type. For example, create two classes X and Y. In the main method create new objects x and y for each X and Y class. And create a new object x2. Now try to refer x2 to x and x2 to y. The first case x2 to x is valid because these two are of the same type. But second case x2 to y is not valid because they both are of different types.

/*
This is a simple Java program about Inheritance.
Call this file KH_ReferencingInheritance.java.
*/
class X {
	void showX(){
		System.out.println("Class X");
	}	
}

class Y {
	void showY(){
		System.out.println("Class Y");
	}	
}

class KH_ReferencingInheritance {
	public static void main(String args[]) {
		X x = new X();
		Y y = new Y();
		
		X x2;
		
		x2 = x;
		x2.showX();
		
		x2 = y;
		//x2.showY();//Error as x2 is not of type class Y
	}
}

Download the code  Run the code

Output:

KH_ReferencingInheritance.java:31: error: incompatible types: Y cannot be conver
ted to X
                x2 = y;
                     ^
1 error

However, this is slightly exempted in case of inheritance. Where an object of type superclass reference can be assigned to a subclass object. In above program lets derive class Y from class X. Now x2 to Y is valid because x2 is of type superclass and y is of type subclass.

But there is one important point to note is that this reference is not full type reference, in this case, it is limited to what members can be accessed. This x2 can only access the members of y which are inherited from superclass X. That is x2 can not access members of subclass Y. Why is this behavior? Because superclass reference x2 does not know anything about the subclass. x2 only knows that the referred object has its own type and it maps to those own types and does not map to subclass members. For example below the program which illustrates this, try to uncomment the line where x2 accesses the member of class Y and see how our program behaves.

/*
This is a simple Java program about Inheritance.
Call this file KH_ReferencingInheritance1.java.
*/
class X {
	void showX(){
		System.out.println("Class X");
	}	
}

class Y extends X{
	void showY(){
		System.out.println("Class Y");
	}	
}

class KH_ReferencingInheritance1 {
	public static void main(String args[]) {
		X x = new X();
		Y y = new Y();
		
		X x2;
		
		x2 = x;
		x2.showX();
		
		x2 = y;
		x2.showX();
		//x2.showY();
           //Error as x2 is of type class X, so it can only 
           // access members of class X	
	}
}

Download the code  Run the code

Output:

Class X
Class X

Output when you uncomment line: x2.showY()

KH_ReferencingInheritance1.java:32: error: cannot find symbol
                x2.showY();//Error as x2 is not of type class Y
                  ^
  symbol:   method showY()
  location: variable x2 of type X
1 error

Method Overriding and Run Time Polymorphism

Method Overriding

When you create a method in a subclass with the same signature (name, return type, parameters, types) as that of superclass then the subclass has overridden a method in the superclass. This overridden subclass method hides the corresponding method in the superclass. Whenever you call this method from subclass object, an overridden method in subclass gets called.

For example, consider following the program, where we have created a superclass X and it is having a show() method which prints its data members a and b. A subclass Y derived from superclass X and it overrides show function of superclass X. When we create a new object to class Y and call method show(), what happens? show method defined in subclass gets called. This way we can perform method overriding.

And to call superclass’s show method then we have to use super keyword as shown below.

/*
This is a simple Java program about Inheritance.
Call this file KH_MethodOverriding.java.
*/
class X {
	void show(){
		System.out.println("Simple show in class X");
	}	
	void display(){
		System.out.println("Simple display in class X");
	}
}

class Y extends X {
	void show(){
		System.out.println("Simple Show in class Y");
	}
	void display(){
		System.out.println("Simple Display in class Y");
		super.display();
	}	
}

class KH_MethodOverriding {
	public static void main(String args[]) {
		Y y = new Y();
		y.show(); //only executes class of Y
		y.display();//It executes method in both x and y
	}
}

Download the code  Run the code

Output:

Simple Show in class Y
Simple Display in class Y
Simple display in class X

Run Time Polymorphism

Method overriding is one of the most powerful concepts of Java which provides dynamic method dispatch. Dynamic method dispatch is how an overridden method call is resolved at run-time rather than compile time. This is Java’s run-time polymorphism.

Generally, any call to a method is resolved at compile time, that is which method to call and who owns that method etc are decided at compile time only. But in the case of method overriding, this will be decided when the program is executing. Prior to execution, we do not know which method gets called.

We know that a superclass reference can refer to a subclass object. Java uses this feature to call overridden methods at execution time. When calling overridden methods Java first checks the reference by which this method is getting called at run-time. Based on this reference it decides whether to call superclass method or subclass method.

To understand more, let us look into below program which is an extension of above program, where we have to create two object y1 and y2 for subclass Y and an object x to superclass X. And also defined a reference object ref of type superclass X. Now we will assign ref with object x and call show method. In the same way, we will do for remaining 2 objects y1 and y2. From the output it is clear that when the ref is referencing x of type superclass X, it calls show method of superclass X. And in other cases, it calls to show a method of subclass Y. This is how run-time polymorphism achieved in Java.

/*
This is a simple Java program about Inheritance.
Call this file KH_RuntimePolymorphism.java.
*/
class X {
	void show(){
		System.out.println("Simple show in class X");
	}	
	void display(){
		System.out.println("Simple display in class X");
	}
}

class Y extends X {
	void show(){
		System.out.println("Simple Show in class Y");
	}
	void display(){
		System.out.println("Simple Display in class Y");
		super.display();
	}	
}

class KH_RuntimePolymorphism {
	public static void main(String args[]) {
		Y y1 = new Y();
		Y y2 = new Y();		
		X x1 = new X();
		X x;
		
		x = y1;
		x.show();
		
		x = x1;
		x.show();
		
		x = y2;
		x.show();
	}
}

Download the code  Run the code

Output:

Simple Show in class Y
Simple show in class X
Simple Show in class Y
Copyright 2005-2016 KnowledgeHills. Privacy Policy. Contact .