Classes 2

Methods/Functions

Since everything in Java is defined within a class, all functions are methods. Some are public and thus part of the users interface to the class and others are private and part of the internal structure of the class.

Overloading


Method names can be overloaded. That is, multiple versions of a method can exist with the same name. The most common use of this is in constructors. A class often has several constructors to handle the cases where some or all of the instance variables can be specified by the caller. In Java, a methods true name or signature is determined by a combination of the method name, the number of parameters, their type and the order they appear in the declaration. If any of these are different, the methods are different, even if the names are the same. For example,
	 public void method1();
	 public void method1(int joe);
are different.

Constructors


Called when a variable of that type is declared. Has the same name as the class. Usually several are defined. The simplest takes no args, others take args to help in initialization. The constructor without args is called the default constructor. The default constructor is used when arrays of a class are defined.

Regular Methods

Methods don't have to specify the private members of the class.
 

   public void changeBatteries()
    {
        battery = new Battery[numbatts];
        for(int i=0; i < numbatts; i++)
            battery[i] = new Battery(battype);
    } // changeBatteries
	
	
battery can be treated as a parameter to the function. There is a pointer to the data in the class instance available called this. So the variable above was usable as
 this->battery;

More method stuff

All programming languages have functions. They can be called different things. Subroutine, routines, procedures and functions all describe the same thing. A function is a piece of code that is run by itself. Control is transferred to it from the main program and control returns after the function is completed.

Digression

The control flow of a program is the sequence of instructions that it executes when it runs. The default order in Java is to start at the first statement in the main function and continue from the top to the bottom. We have already seen some control statements that can alter the control flow.

Functions can take arguments and can return results. The general form of a function in Java is

return_type
func_name(type1 arg1, type2 arg2,...)
{
// code for the function
}// func_name

A function can have no arguments. In Java, a function is called by using its name followed by a parenthesized list of arguments.

// Convert Fahrenheit to Celsius

float
ftoc(float ftemp) {
float ctemp;
ctemp = (((ftemp -32 ) *5) / 9.0 );
return ctemp ;
} // ftemp

The return type is float. This means that anywhere a float can be used, a call to this function can be used. Its name is ftoc and it takes one argument, a floating point number. At the end, it returns a float value. In between the braces is the code that implements the function. Variables can be declared inside the function that are local to the function. This means that the variables, like ctemp, are only used inside the function. This variable ctemp would be different from another variable ctemp used somewhere else in the program. A few other comments. If the function doesn't return anything, the return type is void.

Some details about the return statement. If the function doesn't return a value, the return statement is optional as a return occurs when the end of the function is reached. But a return statement can be used if you want to exit the function early. In this case, the form is just return; If there is a value to return,
return expr;
A function can return only one value.

About function calls and how they work.

A typical function call looks like this

new_temp=ftoc(32.0);

When this is executed, the control transfers from where the call to ftoc is in the code to the beginning of the code in the ftoc body. The variables described in the function header are set with the values in the function call. The variables in the function header are called the formal parameters. The values in the call to the function are called the actual parameters. The formal parameters are like local variables in the function code. The code in the function is executed in the usual order. When a return statement is executed, control goes back to the main program just at the point it left. If the function returns a value, then it is as if that value was put in place of the function call. So if the actual call was like this

temp = ftoc(32.0); // note the use of an float constant
Then control starts at the top of the ftoc() function. The formal parameter is a float. All the arguments to the function are evaluated before the code is executed. Then the formal parameter, ftemp is set to the value 32.0. The arithmetic is done using the value in ftemp. The result is stored in the local variable ctemp. In this case, the value is 0.0. The return statement sends the 0.0 back to the calling function. So the program acts as if the line above was changed to temp = 0.0; Then the program goes on from that point as if it had never called the function.

Parameter passing techniques

All parameters in a Java function are pass-by-value. There are two major ways information is passed to a function. One is pass-by-value. This means that the expression that is the parameter is evaluated and the result is stored in a local variable. This value is a copy of the original. In this example from the code,
rtc=ftoc(rtf);
A copy of the value of rtf is stored in the local variable ftemp. If we were to change the ftoc() function to add a line
ftemp=0.0;
this would have no affect on the value of rtf. This is because ftemp is a local variable and is not related to rtf.

The other main method is pass-by-reference. Instead of a copy of the value being passed, a reference to the actual parameter is passed. This means that if the formal parameter is changed, In Java, this happens whenever an object is passed. We don't make a copy of the object, we pass a reference. In this case, if the reference is used to make a change, the actual parameter is accessed directly and thus can be changed. For example, methods on the referred object could be called which would change the state of some instance data. Or maybe the instance data is public. But in any case, if we change the local variable (the formal parameter) to refer to another object, this will not effect the actual parameter.

References can be used outside of function calls. In this case they are a kind of alias of another variable.

There is an example that demonstrates this in Chapter 5 of the book. The code is on the CD but I have linked it in here.

binary operator methods

These are just methods that are called from one object but also reference another object. In another language, these would be a two argument function, looking like this
op(a,b);
But in Java, it is run like this
a.op(b);
Here is a little example involving Strings.

//********************************************************************
//  BinaryOp.java       Author: Kent Archie
//
//  Demonstrates the use of binary methods and command line args
//********************************************************************

class BinaryOp
{
   public static void main (String[] args)
   {
   		  String one = "hello " , two = "there."; 
		  System.out.println(one.concat(two));
		  /* now concat the args on the command line.
		  	 Each element in the args array is a String object.
		  	 Note that the phrase args[0].concat(" ") is
		  	 a string object so has methods we can call
		  */
		  System.out.println(args[0].concat(" ").concat(args[1]));
   } // main
} // BinaryOp

If we run this, we get
C:\depaul\cs212\web\examples>javac BinaryOp.java
C:\depaul\cs212\web\examples>java BinaryOp
hello there.
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException
        at BinaryOp.main(BinaryOp.java:14)

C:\depaul\cs212\web\examples>java BinaryOp kent archie
hello there.
kent archie

A bit more about references and garbage collection

Objects in Java are rarely seen directly. Variables that hold objects actually hold references. A reference is not the thing itself, but tells us where the thing is. This is like addresses in envelopes. The address is not the house, but it tells us where it is. Java references are like pointers in C++, but not quite as powerful. But they are also not nearly as dangerous.

When defined, a reference has no particular value. This means it doesn't point to a particular object. Java supports a special constant called null to help with this.

	 String str;
This create a variable that can hold a reference to a String object. But it neither holds one now nor is a String object created. To indicate that this variable is unused at the moment, we can set it to null.
str = null;
References are not initialized in Java. This is why you usually see them associated with a new statement. Some more examples.

picture of null references
Now. let's make a String object and look again.
Same picture after one='hello'
If we assign one reference variable to another, this happens.
Same picture after two=one
If we were to execute the following if statement
     if(one == two)
        System.out.println("they are equal");
     else
        System.out.println("they are different");
It would print they are equal. This is because the two references are referring to the same object. In this next example, we create two string objects that are different but contain the same string.
two strings,same value
If we executed that same if statement now, it would print they are different. This is because the references are referring to different objects, even if the values are the same. To compare the character strings contained in two objects, you have to use the equals() method.

Now let's get rid of one of them by assigning one to the other.

after two=one
Now the object that was pointed to be the two variable, is not pointed to by any variable. In many other programming languages, this would be a memory leak and over time, could cause the system to fail. Java doesn't require the programmer to handle this. Periodically, a separate program called the garbage collector is run to look for unused objects like this and reclaim the space. The plus is that you don't have to worry about this common problem. The minus is that your program stops running when the GC runs and it's hard to tell when this will happen. Sometimes there is some action, like closing files, disconnection from networks, that needs to happen when an object is destroyed. This is controlled by adding a finalize() method to the class. This is not often needed.

Interfaces

An interface is a special kind of class in Java. An interface consists of constants and abstract methods. Abstract methods are just the header part of a method. They specify the return type, name and arguments of the method but there is no code to implement the method. A class may implement several interfaces. If it does, it promises to implement all the methods listed in the interface declaration.

One of the purposes of interfaces is to provide a common set of methods for a set of classes. An example might be that there are many ways to represent the idea of a book. There are traditional paper based books, there are several kinds of e-books and there are web books. These would all be represented by different classes. But in order to call itself a book, it must provide methods to go to a specific page, save the readers place and other things. Building an interface to specify these methods would ensure that anything calling itself a book would have at least these methods. A class that implements an interface can have other methods that are not specified in the interface. In this case, the interface would look something like

public interface book
{
   public int howManyPages();
   public void goToPage(int pg);
   public void savePlace();
}

Interfaces also help support polymorphism. We can create variables of the interface type. These variables can contain any object of a class that implements the interface. So if we had

public class ebook implements book
{
 	   public in howManyPages()
	   {
	   		  // code to get the number of pages
	   } // howManyPages
	   // other interface methods
	   public void search(String str)
	   {
	      // code to search for a string
	   } // search
} // ebook

public class wbook implements book
{
 	   public in howManyPages()
	   {
	   		  // code to get the number of pages from a web book
	   } // howManyPages
	   // other interface methods
	   public void search(String str)
	   {
	      // code to search for a string in a web book
	   } // search
	   public String getURL()
	   {
	      // code to fetch this pages URL
	   } // getURL
} // wbook
If we have a variable of type book like book tome;, we can set it to point to objects of type ebook like this tome = new ebook();. If we invoke the pages method like this int p = tome.howManyPages it would call the version in the ebook class. The type of the object determines what is done, not the type of the reference. If we later set the variable to tome = new wbook();, and then as for the pages, we execute the version of the method defined in the wbook class.

However, if we tried to invoke the non-interface method search(), like this: tome.search(); it would fail. The interface variable can only access methods specified in the interface. To do this, we have to cast the reference to the right class like this (ebook)tome.search();. We can also make the parameters to method use the interface type. This would allow the method to accept any object that implements the interface. The formal parameter would act just like the interface variable declared above.