New concepts in Java

super and this predefined variables

In Java we do not have the scope resolution operator :: that we had in C++. We have the super and this predefined variables instead:

  • super - allows us to refer to states and methods of the parent class directly. So, super.display() would call the display() method, written or inherited by the parent class. If the parent class of the parent class with a display() method also had a display() method, we do not have access to that method. This super predefined variable can also be used in an unusual way to call the parent constructor from within the child constructor, provided it is used as the first line of the child constructor (just like member initialisation lists in Java).

  • this - allows us to refer to "this object", i.e. to access states or methods for the class that the code is currently within. It allows us to pass a reference to the current object and it also allows us to access the states of the class that are currently out of scope.

So, an example of super and this would be:

	
  public class TestParent
  {
    protected int y=2; // example parent state
    
    public TestParent(int a) // example parent constructor
    {
      y=a;
    }
  }	
	
  public class Test extends TestParent // inheritance
  {
    private int x;

    public Test(int a)
    {
       super(a); // calls the parent constructor
       x = 5;
    }
			
    public void someMethod(int x)
    {
       this.x = x;   // this.x refers to the state of the class
       super.y = 5;	 // sets the y state of the parent class to a value of 5.
				
       someOtherMethod(this); // passes the current object to the 
                              // someOtherMethod() method
    }
  }
  

Abstract Classes in Java

While abstract classes are not much different to abstract classes in C++, there are some points to note.

Once again, abstract methods are a place-holder that define a set of operations within the class that have not yet been implemented. In Java you can actually set a class to be abstract, even if it has no abstract methods. This would prevent this class from being instantiated. However, if one or more methods in a class are abstract then the class must be defined as abstract. For example:


  public abstract class Car
  {
    public abstract void display();
  } 
  

  public class SportsCar extends Car
  {
	public abstract void display()
	{
		System.out.println(" Sports car - etc.");
	}
  }

Some points to note:

  • Not all methods in an abstract class need to be abstract.

  • Abstract classes cannot have private abstract methods.

  • Abstract classes cannot have static abstract methods.

Interfaces

A Java Interface is a way of grouping methods that describe a particular behaviour. They allow developers to reuse design and they capture similarity, independent of the class hierarchy. We can share both methods and constants using Interfaces, but there can be no states in an interface. Methods in an interface are implicitly public and abstract. Constant states in an interface are implicitly public, static and final.

Interfaces differ from abstract classes in that an interface cannot have an implementation for any method, i.e. all methods are abstract. Classes can implement many interfaces, all unconstrained by a class inheritance structure.


  interface Demo
  {
    public static final String demoConst = "hello";  
    			// public static final can be omitted
    			// as is implicit
    
    void go();   	// these methods are public and abstract 
    void stop();    // even if public abstract is omitted
  }

  class SomeClass extends Object implements Demo
  {
	public void go()
	{
		// write implementation here
	}

	public void stop()
	{
		// write implementation here
	}
  }
  
  public class TestApp
  {

	public static void main(String args[])
	{
		SomeClass c = new SomeClass();
		System.out.println(SomeClass.demoConst); // will print out "hello"
	}

  }

Consider the mouse. We may write many applications that use the mouse, and within these applications, the mouse may be used in many different ways. We can define a common interface for the mouse that each one of these applications must implement. These applications then share a common defined interface, without having to create an IS-A/IS-A-PART-OF relationship.

Interfaces are Java's replacement for multiple inheritance in C++. Since methods and constants are shared through interfaces, and not states, we do not have the difficulties experienced with multiple inheritance when implementing multiple interfaces:

  • A class can implement as many interfaces as desired. They are listed one after the other and comma separated.

  • An interface should always begin with a capital letter, e.g. MouseListener.

  • You can define your own interfaces, in the same way that you can define your own classes.

Strings in Java

Strings in Java are very similar to the strings we discussed in C++, through the use of the #include<string.h>.

The String class provides a convenient mechanism for working with strings in Java. String objects in Java are immutable - once assigned a value, it cannot be changed. The compiler converts string constants to String objects directly.

Some notes on strings:

  • String object comparisons are achieved using the compareTo() and equals() methods.

  • The String class in Java is the only class in Java with overloaded operators of "+" and "=". You should not use "==". So, the "+" operator allows two strings to be concatenated to form a new String object.

  • Java strings are not null terminated, like C++ strings.

So for example:

 1 
 2 
 3   import java.lang.*;
 4 
 5   public class StringTest
 6   {
 7     public static void main(String args[])
 8     {
 9       String x = "Hello ";
10       String y = new String("World!");
11       
12       String z = new String(x + y);
13       System.out.println(z);
14       System.out.println("The length of this string is " 
15          + z.length() + " characters.");
16       
17       String c = "Cat";
18       String d = "Dog";
19       if (c.compareTo(d)<=0)
20       {
21         System.out.println( c + " is less than " + d);
22       }
23       
24       if (c.equals("Cat"))
25       {
26         System.out.println("The c object is equal to Cat");
27       }
28       
29       String shout = "HELLO!";
30       System.out.println("A bit quieter - " + shout.toLowerCase());
31     }
32   }
33 
34 

The full source code for this example is in StringTest.java.

The output of this example is:


 C:\Temp>javac StringTest.java

 C:\Temp>java StringTest
 Hello World!
 The length of this string is 12 characters.
 Cat is less than Dog
 The c object is equal to Cat
 A bit quieter - hello!
 

As of J2SE 1.5 an alternative format is available as demonstrated in StringTest2.java which demonstrates an alternative form (C Style) outputting, where we can have slightly more control over our output. For example,

  ...
  System.out.printf("The length of this string is %d characters.\n", z.length());
  ...
  System.out.printf( "%s is less than %s \n", c, d);
  ...

This is the new PrintStream printf method. This method allows us to use format specifiers as placeholders for different types, e.g. %d for an integer variable and %s for a string. Note that in this example printf is used instead of println for this task. The % in the format string denotes the start of a format specifier. The %s and %d in this example indicates the insertion of a String and <typename>int</typename> value. The use of a %s on an object will trigger the call to toString().

A full list of the methods available in the String can be found in the Java API documentation under the java.lang.String class description. Note that the String class is hyperlinked in the notes HTML documentation. Were possible I have hyperlinked standard classes to provide direct access to the API documentation.

The StringBuffer object can be used instead of a String object when more flexibilty is required in the object. The StringBuffer class is mutable and so can grow in size as the application runs.

We can convert directly between a String object and a StringBuffer object when required. Some of the functionality available in the StringBuffer includes:

     Constructors:
     
     StringBuffer()
     StringBuffer(String s)
     
     Methods:
     
     int length()
     char charAt(int index)
     String toString()
     StringBuffer append(String s)
     StringBuffer insert(int offset, String s)
    

So, for example:

 1 
 2 
 3  import java.lang.*;
 4 
 5  public class StringBufferTest
 6  {
 7    public static void main(String args[])
 8    {
 9 	String s = new String("Hello World!");
10 	StringBuffer buffer = new StringBuffer(s);
11 
12 	buffer.insert(5, " to the");
13 
14 	String t = buffer.toString();
15 	System.out.println(t);
16    }
17  }
18     
19 

The full source code for this example is in StringBufferTest.java

Java Arrays

Java Arrays are quite like those of C++. There is a special length state that returns the size of the array. With arrays in Java, the Virtual machine constantly checks to see if the index goes out of bounds, and throws an exception if it does (we will talk about exceptions later!).


 char s[];          // a variable s to be an array of char
 int[] anArray;  	// a variable anArray to be an array of type int
 int[][] a2DArray;  // a 2-D array of type int
 int initArray[][] = { {1,2,3}, {4,5,6}, {7,8,9} };
	// Creates an initialised 3x3 array of type int.

 //You cannot write int A[5]; as in C++

 int myArray[];         // just 4 bytes of memory
 myArray = new int[10];	// allocate the room for 10 ints.

The rules are similar to C++ when dealing with arrays of objects.


  Object objArray[];
  objArray = new Object[5];

  // we have allocated room for 5 objects, but we have
  // not created 5 objects.

  for (int i=0; i<objArray.length; i++)
  {
	objArray[i] = new Object(); // create the object using the constructor
  }
  

The Object class

This may be a little confusing, but Java has an Object class. By default, every class extends the Object class, even if you don't extend any class. The Object class provides methods that are inherited by all Java classes, such as equals() , getClass(), toString() and more.

Consider the advantages in a common behaviour of every class:

  • Since Object is the parent of all classes, then every class must have a toString() method. So when we write System.out.println("Value =" + someObject); It can immediately be converted to System.out.println("Value =" + someObject.toString()); by the compiler, as each object must have this method.

  • Consider passing data across a network. We could write methods to send Object objects (no typo!) across the network. Since every class extends the Object class, we can convert any class to an object of the Object class, transmit it, and then extract it again on the receiving end. This will prove very useful.

The Class class

Objects of this class, the Class class (called class descriptors) are automatically created and associated with the objects to which they refer. For example, the getName() and toString() methods return the String containing the name of the class or interface. We could use this to compare the classes of objects.