Make your own free website on Tripod.com

Introduction to Java

Java is a modern, platform independent programming language that is object-oriented for reusability of code modules.

Why Use Java

Why should one use Java as an authoring language?

           object oriented programming

           Java applications are platform independent

           Java is security conscious and enforces it through a virtual machine paradigm

           Java is easy to learn as no user programmed memory management or pointers are involved

 

The system environment variables path and classpath will have to be set within AUTOEXEC.BAT to point at the Java binary file installation directories.

MSDOS:

EDIT Autoexec.bat

Windows 9x:

Start -- Run -- Sysedit

Windows XP:

Start - Control Panel - System - Advanced - Environment Variables

Test Examples

To test that the developer's environment has been installed correctly use the following simple HelloWorld application.

Your First Java Application

/*
 * The HelloWorldApp class implements an application that
 * displays "Hello World!" to the standard output device.
 */
public class HelloWorldApp
{
 public static void main(String[] args)
 {
 // Display "Hello World!"
 System.out.println("Hello World!");
 }
}

Save the file as HelloWorldApp.java.

Next compile the source file into bytecode by using the command javac HelloWorldApp.java. If an error message stating Not Found occurs, type the command javac. If there is still an error message it means that the path needs setting. If there is no error at this point then the .java file is missing or there was a typing error. Most typing errors are due to case sensitivity. In Java, UPPER and lower case ARE different.

Finally run the application with the Java interpreter by using the command Java HelloWorldApp.

Books

                     Java 2 - By Example Friesen, QUE

                     Teach Yourself Java Cadenhead & Lemay, Sams

                     Java 2 - Complete Reference Naughton, Osbourne

 

What Are Objects

 

An object is a self-contained entity which has its own private collection of properties (ie. data) and methods (ie. operations) that encapsulate functionality into a reusable and dynamically loaded structure. After a class definition has been created as a prototype, it can be used as a template for creating new classes that add functionality. Objects are programing units of a particular class. Dynamic loading implies that applications can request new objects of a particular class to be supplied on an 'as needed' basis. Objects provide the extremely useful benefit of reusable code that minimizes development time.

 

The Basic Structure of a Java Application

 

A Java application resembles programs in most compiled languages. Code in object format resides on the user's machine and is executed by a run-time interpreter that normally has to be user installed.

/**

* The HelloWorldApp class implements an application

* that displays "Hello World!" to the standard output.

*/

public class HelloWorldApp

{

public static void main(String[] args)

{

// Display Hello World! now

System.out.println("Hello World!");

}

}

The first four lines is a comment on the application's function. Comments are not required but are extremely useful as documentation within the source. Other notes and doc files may get lost but these stay right where they are most useful. A long comment starts with a /* or /** and ends with a */ Short one line comments begin with // and end with the <return>.

The fifth line starts with the reserved word public. This indicates that objects outside the object can invoke (or use) it. The reserved word class indicates that we are building a new object with the name that follows. HelloWorldApp is the object name (your choice) and is case sensitive.

Java 'style' is to capitalize the first letter of each word only. The line concludes with an opening curly bracket that marks the start of the object definition.

static indicates that it calls the class and not an 'instance' of the class. The concept of 'instance' will be discussed later. The method's name is main and the reserved word void indicates that no result is returned back. Main has arguments (aka parameters) in round brackets. String[] indicates the variable type is an array and args is a reserved word indicating that it is the command line values that are being passed over to main. The line finishes with an opening bracket for the main method.

Line eight invokes the println method of the system.out object. What is to be printed is passed in the argument as a string parameter.

Finally closing curly brackets are used for the main and for the object definition.

 

Syntax & Grammar

 

Java like many languages (eg. C, JavaScript, awk, perl) is based on a common syntax and grammar developed by the Bell Labs in the 60's. This makes it easy to cross over from one language to another based on program requirements, resources and politics.

 

Syntax Notation

The specification of a class has the following syntax:

["public"] ["abstract"|"final"]"class" class_name ["extends" object_name]
"{"
// properties declarations
// behavior declarations
"}"

Essentially syntax defines the 'rules' which the compiler will use to check your programs for compilation. Whether they execute correctly is a whole different issue

Lexical Structure

The lexical structure of a programming language is the set of elementary rules that specify how you write a program. It is the lowest level syntax of a language and specifies such things as what identifier names look like. Some of the basic rules for Java are:

           Java is case sensitive.

           Whitespace, tabs, and newline characters are ignored except when part of string constants. They can be added as needed for readability.

           Statements terminate in semicolons! Make sure to always terminate statements with a semicolon.

           Reserved words (or keywords) have special meanings within the language syntax.

           Literals are data constants. They can be either numbers, characters or strings. Examples of numbers are true (boolean), 123 (integer) and 1.2 (floating point). Examples of character literals are 'a' and '\t'. Examples of strings are "hello world" and "hi\n\How are You?".

           Identifiers are names for variables and functions. The first character must be a letter, underscore or dollar sign. Following characters can also include digits. Letters are A to Z, a to z, and Unicode characters above hex 00C0. Java style normally uses an initial capital letter for a class identifier, all uppercase for constants and lowercase for method and variable identifiers. Note: an identifier must not be from the Java reserved word list.

           Single line comments begin with //

           Block comments begin with /* and end with */ [preferred]

           Documentary comments begin with /** and end with **/

 

Literal Constants

Literal constants are values that do not change within a program. Numeric constants default to integer or double unless a suffix is appended. Note that a character can be represented by an ASCII equivalent. Some literal constant types and examples are:

                     Boolean: true, false

                     Integer: 5, 0xFF (hexadecimal)

                     Long Integer: 5l, 0xFFl (hexadecimal)

                     Double Precision: 2.543, 8e12, -4.1E-6

                     Floating Point: 2.543f, 8e12f

                     Char (ie. character): 'c', '\f', 65

                     String: "Fred", "Fred and Ethel"

 

Escape Characters

Escape (aka backslash) characters are used inside literal strings to allow print formatting as well as preventing certain characters from causing interpretation errors. Each escape character starts with a backslash. The available character sequences are:

Seq

Name

Seq

Name

\b

backspace

\f

formfeed

\t

horizontal tab

\"

double quote

\n

newline

\'

single quote

\r

carriage return

\\

backslash

\###

Latin encoded character

\uHHHH

Unicode encoded character

 

 

Variables

Variables are temporary data holders. Variable names (or identifiers) must begin with a letter, underscore or dollarsign, use ASCII or Unicode characters and underscore only, and are case sensitive. They can not be one of the Java reserved words. Variables are declared with a datatype. Java is a strongly typed language as the variable can only take a value that matches its declared type.

byte x,y,z; /* 08bits long, not assigned, multiple declaration */
short numberOfChildren; /* 16bits long */
int counter; /* 32bits long */
long WorldPopulation; /* 64bits long */
 
float pi; /* 32bit single precision */
double avagadroNumber; /* 64bit double precision */
boolean signal_flag; /* true or false only */
char c; /* 16bit single Unicode character */

Variables can be made constant or read only by prepending the modifier final to the declaration. Java convention uses all uppercase for final variable names.

Arrays

Arrays allow you to store several related values in the same variable (eg. a set of marks).

int i []; /* one dimension array */
char c[][]; /* two dimension array */
float [] f; /* geek speak way */
Bowl shelfA[]; /* array of objects */

Note that the brackets are left blank. Declaration of an array only forms a prototype or specification for the array. Array memory allocation is done explicitly with the new reserved word and will require known static bounds (ie. number of elements).

 

 

Operators, Expressions, Conditions

Operators are actions that manipulate, combine or compare variables. They fall into several categories as follows:

Arithmetic: + - * / % (modulus) ++ (increment) -- (decrement)
Assignment: = += -= \= %=
Array Allocation: new (eg. int a[] = new int[10])
String Concatenation: +
Comparison: == != > >= < <=
Boolean Comparison: ! & | ^ && || (&& are short circuit ops)
Bitwise Comparison: ~ & | ^ (xor) << >> >>>
Bitwise Assignment: &= |= ^= (xor) <<= >>= >>>=
Cast: (var_type)
Conditional: (expr1) ? expr2 : expr3

Statements, Blocks and Scope

Statements are complete program instructions made from constants, variables, expressions and conditions. Statements always end with a semicolon. A program contains one or more statements.

Execution blocks are the sections of code that start and end with curly brackets. Variables maintain their definition (or 'scope') until the end of the execution block that they are defined in. This is the reason why variable declaration and assignment can be a two step process.

 

Assignment Statements

 

Assignment statements use an assignment operator to store a value or the result of an expression in a variable. Memory allocation is done at the time of assignment. Simple examples include first_name = "Fred"; and count +=;

Local variables must be assigned a value prior to use.

Arrays are allocated memory dynamically based on their array size through the use of the new reserved word.

intArray = new int[5]; //previously declared
int markArray = new int[9]; //declaration and allocation at same time
int grades = new int[maxMarks]; //maxMarks must evaluate to positive integer

Conditional Statements

Conditional statements execute a block or set of other statements only if certain conditions are met. The condition is always enclosed in round brackets. The statements to be performed if the condition is true are enclosed in curly brackets. For example:

if (value > 5) { x = 7 };

Occasionally you may want to perform some actions for the false outcome of the condition as well. The else keyword is used to separate branches.

if (name == "Fred")
 {
 x = 4;
 }
 else {
 x = 20;
 };

Loops

For statements allow a set of statements to be repeated or looped through a fixed number of times. The round bracket contains initializer(s) ; conditional test ; incrementer(s). If more than one initializer or incrementer is used they are separated with commas. The test condition is checked prior to executing the block. The incrementing is completed after executing the block. For example to output #1 #2 #3 etc. on separate rows you could write:

int i;
for (i=1; i<=15; i++)
 {
 document.writeln("#"+i);
 };

While statements allow a set of statements to be repeated or looped until a certain condition is met. The test condition is checked prior to executing the block. For example to output #1 #2 #3 etc. on separate rows you could write:

int i = 0;
while (i<=5)
 {
 document.writeln("#"+i);
 i = i + 1;
 };

Do While statements allow a set of statements to be repeated or looped until a certain condition is met. The test condition is checked after executing the block. For example to output #1 #2 #3 etc. on separate rows you could write:

int i = 1;
do {
 document.writeln("#"+i);
 i = i + 1;
 } while (i<=5);

The Switch Statement

Switch (or case) statements are used to select which statements are to be executed depending on a variable's value matching a label. Note that the variable can only be int or char datatype.

char yourchoice;
yourchoice = (char) System.in.read();
switch (yourchoice)
 {
 case '1': System.out.println("You typed a 1"); break;
 case '2': System.out.println("You typed a 2"); break;
 case '3': System.out.println("You typed a 3"); break;
 case '4': System.out.println("You typed a 4"); break;
 default : System.out.println("Oops!, that was an invalid entry.");
 };

Continue, Break and Return

Continue statements are used in looping statements to force another iteration of the loop before reaching the end of the current one. The following is a trivial example. Most often the continue is used as part of a conditional statement that only happens in certain cases.

int x = 0;
while (x < 10)
 {
 x++;
 System.out.println(x);
 continue;
 // you will never get to this point!!
 };

Break statements are used in looping and 'switch' statements to force an abrupt termination or exit from the loop or switch. In the following example the loop is never completed. Once again the normal use of break is as part of a conditional statement.

int x = 0;
while (x < 10)
 {
 x++;
 System.out.println(x);
 break;
 // you will never get to this point!
 };

Return statements are used to force a quick exit from a method. They are also used to pass values back from methods.

Command Line Arguments

Command line arguments are accessible through the args array (assuming that args is the name used in the class header [NOTE: This is a Java coding convention!]). The array does not include the interpreter java command or the class name and the count starts at 0. Each argument is passed as a string but may be converted to other types as in the following:

int w = Integer.parseInt(args[0]);
// or sometimes you want the argument to be a character type
char s = args[1].charAt(0) // uses first letter of argument only

The number of arguments passed in can be determined by using the args.length property. This is very important if there is a variable number of arguments or when checking for required arguments.

NOTE: All double quote marks are consumed by the Java command line parser and are not passed on to the argument array!

Project: Metric Converter

At this point we need to have a project that allows you to test your knowledge of syntax without getting too involved in a user interface or the complexities of object manipulation. A toy metric converter should be just about right as it allows three basic stages of application development; IPO, branching, and switch selection.

The First Stage [Input - Process - Output]

The goal of the first stage is to input a temperature in degrees Fahrenheit (geezer's unit), calculate the value in Celsius (modern way) and then display the answer. This tests your ability to get some input, do a math process and finally display the output. It also gives some practice working with the development environment and doing compilations.

Our basic input procedure will be to get the Fahrenheit reading from the command line using the method Integer.parseInt(args[0]) which returns an integer from the first argument on the command line.

The math processing part is really easy. This is the basic principle for the formula deg_C=((deg_F-32) * 5)/9. Since division may produce a real number with a decimal value, you should cast the input number into a double and work with double precision floating point numbers.

Once the answer is calculated, it can be output to your display by using the method System.out.println(deg_C)

Second Stage [Branching]

The second stage is to modify the application so that the conversion can be made in either direction. This will require a logical branch based on some additional input. Let's say the input has to look like 40 F or 10 C

 char units = args[1].charAt(0);
 units = Character.toUpperCase(units);
 if (units == 'F')
 {
 //do F --> C conversion
 }
 else
 {
 //do C --> F conversion
 }

Also the command line should be checked to make sure that the number of arguments is correct (which we failed to do in stage one). A simple error message can be printed after checking the count such as:

 if (args.length != 2)
 {
 System.out.println ("Usage: Metric_2 ## F|C");
 return;
 }

Third Stage [Switches]

The third stage is to use the units argument to select the appropriate conversion routine (temperature, mass, distance, etc.) and switch to routines accordingly. For our program just add routines to convert lbs to kilograms and kg to lbs. This stage maxes out the limits of programming in the small. In later tutorials we will use GUI objects to allow for interactive input as well as using custom objects to encapsulate each conversion.

switch (units)
 {
 case 'F': { /* conversion routine */ } ; break;
 case 'C': { /* conversion routine */ } ; break;
 case 'L': { /* conversion routine */ } ; break;
 case 'K': { /* conversion routine */ } ; break;
 default : System.out.println("Oops! I do not understand the units...");
 }

Encapsulation

Encapsulation is the ability of an object to place a boundary around its properties (ie. data) and methods (ie. operations). Programs written in older languages suffered from side effects where variables sometimes had their contents changed or reused in unexpected ways. Some older languages even allowed branching into procedures from external points. This led to 'spaghetti' code that was difficult to unravel, understand and maintain. Encapsulation is one of three basic principles within object oriented programming languages.

Object variables can be hidden completely from external access. These private variables can only be seen or modified by use of object accessor and mutator methods. Access to other object variables can be allowed but with tight control on how it is done. Methods can also be completely hidden from external use. Those that are made visible externally can only be called by using the object's front door (ie. there is no 'goto' branching concept).

Class Specification

A class specifies the properties (data) and methods (actions) that objects can work with. It is a template or prototype for each of many objects made to the class design. The syntax for a class is:

["public"] ["abstract"|"final"]"class" class_name
 ["extends" object_name] ["implements" interface_name]
"{"
// properties declarations
// behavior declarations
"}"

The first optional group indicates the visibility or scope of accessibility from other objects. public means visible everywhere. The default (ie. omitted) is package (aka friendly) or visible within the current package only.

The second optional group indicates the capability of a class to be inherited or extended by other classes. abstract classes must be extended and final classes can never be extended by inheritance. The default (ie. omitted) indicates that the class may or may not be extended at the programmers discretion.

The third option of extends is described in the tutorial on inheritance.

The fourth option of implements is described in the tutorial on interfaces.

Let's use a simple box as an example of a class specification. The box has length, width and height properties as well as a method for displaying the volume. An example of how this might be specified in Java is:

public class Box
{
 // what are the properties or fields
 private int length;
 private int width;
 private int height;
 
 // what are the actions or methods
 public void setLength(int p)
 {length = p;}
 
 public void setWidth(int p)
 {width = p;}
 
 public void setHeight(int p)
 {height = p;}
 
 public int displayVolume()
 {System.out.println(length*width*height);}
}

Note1: There is no main method in a class defining template!
Note2: Class names begin with a capital. Convention uses lowercase for all other names.

Properties (aka Field Variables)

Classes without properties or behaviour are not very useful. Properties in Java are sometimes called field variables. To declare a property use the following syntax:

[ "public" | "private" | "protected" ] [ "final" ]

[ "static" | "transient" | "volatile" ]

data_type var_name [ = var_initializer ] ";"

The items in the first optional group indicate the 'visibility' or accessibility from other objects. public means visible everywhere (global). private indicates accessible only to this class and nested classes. protected means visible to this class or inherited (ie. extended) classes only. The default (keyword omitted) is friendly or visible within the current package (folder) only.

final indicates continuous retention and unchangeable after initial assignment (ie. it is read only or constant).

The third optional group indicates how long a value is retained in the variable. static indicates that the value is shared by all members of the class and exists for all runtime. Static members can be referenced without creating an instance of the class. transient prevents the variable from being transferred during a serial operation such as file i/o. volatile is used in threading to prevent overwrite issues.

The data_type is one of the primitive types and can be optionally initialized.

Types of Methods

Class behaviours are represented in Java by methods. To declare a method use the following syntax:

[ "public" | "private" | "protected" ] [ "final" ]
[ "static" | "abstract" | "native" ]
 return_data_type method_name "(" parameter_list ")"
 "{"
 // some defining actions
 "}"

Accessibility keywords are the same as for properties.

static methods are shared and retained. abstract methods must be redefined on inheritance. native methods are written in C but accessible from Java.

The return_data_type defines the type of value that the calling routine receives from the object (the reply message in object terminology). It can be any of the primitive types or the reserved word void (default value) if no message is to be returned. The statement return variablename; is used to declare the value to be returned to the calling routine.

The parameter_list can contain from zero to many entries of datatype variablename pairs. Entries are separated by commas. Some examples are:

public static void example1() { }
public static int add2(int x) { x+=2; return x; }
public static double example3(int x, double d) { return x*d; }
public static void example4(int x, int y, boolean flagger) { }

Constructor methods allow class objects to be created with fields initialized to values as determined by the methods' parameters. This allows objects to start with values appropriate to use (eg. salary set to a base level or employeeNumber set to an incrementing value to guarantee uniqueness). For our simple box class:

public Box() // default box is point
 {length = 0; width = 0; height = 0;}
public Box(int l,int w,int h) // allows giving initial size
 {length = l; width = w; height = h;}

Note that there is no class keyword or return datatype keyword. Also the method name is the same as the class name. This is what marks the fragment as a constructor method. If no constructor method is defined for a class, a default constructor is automatically used to initialize all fields to 0, false or unicode(0) as appropriate to the datatype. Constructors can be overloaded in the same way that instance methods are.

One clever programming device is to declare the constructor with no parameters as private and use it to initialize all properties. Then other constructors can first call it using this() and then do their own specific property validations/initialization.

Accessor (or observer) methods read property (ie field variable) values and are conventionally named getFoobar() or whatever the property is called.

Mutator (or transformer) methods set property values and are often named setFoobar() etc. Mutators can be used to ensure that the property's value is valid in both range and type.

It is good programming practice to include accessor and mutator methods for each property in the class. They are perfect example of object encapsulization. The exceptions to writing accessor/mutator methods for each property is for those that are used only within the class itself or for properties that are set in more complex ways.

Helper methods are those routines that are useful within the class methods but not outside the class. They can help in code modularization. Normally they are assigned private access to restrict use.

 

Overloading and Recursion

Overloaded methods are methods with the same name signature but either a different number of parameters or different types in the parameter list. For example 'spinning' a number may mean increase it, 'spinning' an image may mean rotate it by 90 degrees. By defining a method for handling each type of parameter you achieve the effect that you want.

Overridden methods are methods that are redefined within an inherited class.

Recursive methods are methods that are defined in terms of themselves. A classic recursion is factorials where n factorial is the product of n and all the products before it down to one. In Java this would be programmed as:

class Factorial
 { int fact(int n)
 { int result;
 if(n==1) return 1;
 result = fact(n-1) * n;
 return result;
 }
 }

Object Creation and Destruction

To create an object of a particular class use the creation method after the particular class has already been specified. For example, now that there is a constructor for the Box class you can make specific instances or discrete copies of a box by using the assignment operator and the new memory allocation operator as in:

Box box_1 = new Box(3,4,5);

Note: Once a class has been created, a datatype exists with the same name.

You do not need to destroy or remove an object when it is no longer needed. Java automatically flags unused objects and applies garbage collection when appropriate. However you may occasionally need to use the finalize method to insure that a non-Java resource such as a file handle or a window font character is released first. The general form is:

void finalize()
{
//cleanup code goes here
}

Inner Classes

Inner classes are classes nested inside another class. They have access to the outer class fields and methods even if marked as private. Inner classes are used primarily for data structures, helper classes, and event handlers. A brief example of how an inner class can be used as a data structure is:

public class Main2
{
 class Person
 {
 // inner class defines the required structure
 String first;
 String last;
 }
 // outer class creates array of person objects with specific properties
 // the objects can be referenced by personArray[1].last for example
 Person personArray[] = {new Person(), new Person(), new Person()};
}

Example 1: The Car Class

Suppose you need to write a traffic simulation program that watches cars going past an intersection. Each car has a speed, a maximum speed, and a license plate that uniquely identifies it. In traditional programming languages you'd have two floating point and one string variable for each car. With a class you combine these into one thing like this.

class Car {
 
 String licensePlate; // e.g. "New York 543 A23"
 double speed; // in kilometers per hour
 double maxSpeed; // in kilometers per hour
 
}

These variables (licensePlate, speed and maxSpeed) are called the member variables, instance variables, or fields of the class.

Fields tell you what a class is and what its properties are.

An object is a specific instance of a class with particular values (possibly mutable) for the fields. While a class is a general blueprint for objects, an instance is a particular object.

Constructing objects with new

class Car {
 
 String licensePlate; // e.g. "New York 543 A23"
 double speed; // in kilometers per hour
 double maxSpeed; // in kilometers per hour
 
}

To instantiate an object in Java, use the keyword new followed by a call to the class's constructor. Here's how you'd create a new Car variable called c:

 Car c;
 c = new Car();

The first word, Car, declares the type of the variable c. Classes are types and variables of a class type need to be declared just like variables that are ints or doubles.

The equals sign is the assignment operator and new is the construction operator.

Finally notice the Car() method. The parentheses tell you this is a method and not a data type like the Car on the left hand side of the assignment. This is a constructor, a method that creates a new instance of a class. You'll learn more about constructors shortly. However if you do nothing, then the compiler inserts a default constructor that takes no arguments.

This is often condensed into one line like this:

 Car c = new Car();

The Member Access Separator .

class Car {
 String licensePlate; // e.g. "New York 543 A23"
 double speed; // in kilometers per hour
 double maxSpeed; // in kilometers per hour
}

Once you've constructed a car, you want to do something with it. To access the fields of the car you use the . separator. The Car class has three fields

Therefore if c is a Car object, c has three fields as well:

You use these just like you'd use any other variables of the same type. For instance:

 Car c = new Car();
 c.licensePlate = "New York A45 636";
 c.speed = 70.0;
 c.maxSpeed = 123.45;
 System.out.println(c.licensePlate + " is moving at " + c.speed + 
"kilometers per hour.");

The . separator selects a specific member of a Car object by name.

Using a Car object in a different class

class Car {
 String licensePlate; // e.g. "New York 543 A23"
 double speed; // in kilometers per hour
 double maxSpeed; // in kilometers per hour
}

The next program creates a new car, sets its fields, and prints the result:

class CarTest {
 public static void main(String args[]) {
 Car c = new Car();
 c.licensePlate = "New York A45 636";
 c.speed = 70.0;
 c.maxSpeed = 123.45;
 System.out.println(c.licensePlate + " is moving at " + c.speed + 
" kilometers per hour."); 
}
}

This program requires not just the CarTest class but also the Car class. To make them work together put the Car class in a file called Car.java. Put the CarTest class in a file called CarTest.java. Put both these files in the same directory. Then compile both files in the usual way. Finally run CarTest. For example,

% javac Car.java
% javac CarTest.java
% java CarTest
New York A45 636 is moving at 70.0 kilometers per hour.

Note that Car does not have a main() method so you cannot run it. It can exist only when called by other programs that do have main() methods.

Initializing Fields

Fields can (and often should) be initialized when they're declared, just like local variables.

class Car {
 String licensePlate = ""; // e.g. "New York 543 A23"
 double speed = 0.0; // in kilometers per hour
 double maxSpeed = 123.45; // in kilometers per hour
}

The next program creates a new car and prints it:

class CarTest2 {
 public static void main(String[] args) {
 Car c = new Car();
 System.out.println(c.licensePlate + " is moving at " + c.speed + 
"kilometers per hour."); 
}
 }

For example,

$ javac Car.java
$ javac CarTest2.java
$ java CarTest
 is moving at 0.0 kilometers per hour.

Methods

Data types aren't much use unless you can do things with them. For this purpose classes have methods. Fields say what a class is. Methods say what a class does. The fields and methods of a class are collectively referred to as the members of the class.

The classes you've encountered up till now have mostly had a single method, main(). However, in general classes can have many different methods that do many different things. For instance the Car class might have a method to make the car go as fast as it can. For example,

class Car {
 String licensePlate = ""; // e.g. "New York 543 A23"
 double speed = 0.0; // in kilometers per hour
 double maxSpeed = 123.45; // in kilometers per hour
 // accelerate to maximum speed
 // put the pedal to the metal
 void floorIt() {
 this.speed = this.maxSpeed; 
}
}

The fields are the same as before, but now there's also a method called floorIt(). It begins with the Java keyword void which is the return type of the method. Every method must have a return type which will either be void or some data type like int, byte, float, or String. The return type says what kind of the value will be sent back to the calling method when all calculations inside the method are finished. If the return type is int, for example, you can use the method anywhere you use an int constant. If the return type is void then no value will be returned.

floorIt is the name of this method. The name is followed by two empty parentheses. Any arguments passed to the method would be passed between the parentheses, but this method has no arguments. Finally an opening brace ( { ) begins the body of the method.

There is one statement inside the method

this.speed = this.maxSpeed;

Notice that within the Car class the field names are prefixed with the keyword this to indicate that I'm referring to fields in the current object.

Finally the floorIt() method is closed with a } and the class is closed with another }.

Invoking Methods

Outside the Car class, you call the floorIt() method just like you reference fields, using the name of the object you want to accelerate to maximum and the . separator as demonstrated below

class CarTest3 {
 public static void main(String args[]) {
 Car c = new Car();
 c.licensePlate = "New York A45 636";
 c.maxSpeed = 123.45;
 System.out.println(c.licensePlate + " is moving at " + c.speed + 
" kilometers per hour.");
 c.floorIt();
 System.out.println(c.licensePlate + " is moving at " + c.speed + 
" kilometers per hour.");
 }
}

The output is:

New York A45 636 is moving at 0.0 kilometers per hour.
New York A45 636 is moving at 123.45 kilometers per hour.

The floorIt() method is completely enclosed within the Car class. Every method in a Java program must belong to a class. Unlike C++ programs, Java programs cannot have a method hanging around in global space that does everything you forgot to do inside your classes.

Implied this

class Car {
 String licensePlate = ""; // e.g. "New York 543 A23"
 double speed = 0.0; // in kilometers per hour
 double maxSpeed = 123.45; // in kilometers per hour
 void floorIt() {
 speed = maxSpeed;
 }
}

Within the Car class, you don't absolutely need to prefix the field names with this. like this.licensePlate or this.speed. Just licensePlate and speed are sufficient. The this. may be implied. That's because the floorIt() method must be called by a specific instance of the Car class, and this instance knows what its data is. Or, another way of looking at it, the every object has its own floorIt() method.

Member Variables vs. Local Variables

class Car {
 String licensePlate = ""; // member variable
 double speed; = 0.0; // member variable
 double maxSpeed; = 123.45; // member variable
 boolean isSpeeding() {
 double excess; // local variable 
excess = this.maxSpeed - this.speed; 
if (excess < 0) return true;
 else return false;
 }
}

The licensePlate, speed and maxSpeed variables of the Car class, belong to a Car object, not to any individual method. They are defined outside of any methods but inside the class and are used in different methods. They are called member variables or fields.

Member variable, instance variable, and field are different words that mean the same thing. Field is the preferred term in Java. Member variable is the preferred term in C++.

A member is not the same as a member variable or field. Members include both fields and methods.

Passing Arguments to Methods

class Car {

String licensePlate = ""; // e.g. "New York 543 A23"

double speed = 0.0; // in kilometers per hour

double maxSpeed = 123.45; // in kilometers per hour

// accelerate to maximum speed

// put the pedal to the metal

void floorIt() {

this.speed = this.maxSpeed;

}

void accelerate(double deltaV) {

this.speed = this.speed + deltaV;

if (this.speed > this.maxSpeed) {

this.speed = this.maxSpeed;

}

if (this.speed < 0.0) {

this.speed = 0.0;

}

}

}

Setter Methods

Setter methods, also known as mutator methods, merely set the value of a field to a value specified by the argument to the method. These methods almost always return void.

One common idiom in setter methods is to use this.name to refer to the field and give the argument the same name as the field. For example,

class Car {

String licensePlate; // e.g. "New York A456 324"

double speed; // kilometers per hour

double maxSpeed; // kilometers per hour

// setter method for the license plate property

void setLicensePlate(String licensePlate) {

this.licensePlate = licensePlate;

}

// setter method for the maxSpeed property

void setMaximumSpeed(double maxSpeed) {

if (maxSpeed > 0) this.maxSpeed = maxSpeed;

else this.maxSpeed = 0.0;

}

// accelerate to maximum speed

// put the pedal to the metal

void floorIt() {

this.speed = this.maxSpeed;

}

void accelerate(double deltaV) {

 

this.speed = this.speed + deltaV;

if (this.speed > this.maxSpeed) {

this.speed = this.maxSpeed;

}

if (this.speed < 0.0) {

this.speed = 0.0;

}

}

}

class CarTest5 {

public static void main(String args[]) {

Car c = new Car();

c.setLicensePlate("New York A45 636");

c.setMaximumSpeed(123.45);

System.out.println(c.licensePlate + " is moving at " + c.speed +

" kilometers per hour.");

for (int i = 0; i < 15; i++) {

c.accelerate(10.0);

System.out.println(c.licensePlate + " is moving at " + c.speed +

" kilometers per hour.");

}

}

}

Here's the output:

$ java CarTest5

New York A45 636 is moving at 0.0 kilometers per hour.

New York A45 636 is moving at 10.0 kilometers per hour.

New York A45 636 is moving at 20.0 kilometers per hour.

New York A45 636 is moving at 30.0 kilometers per hour.

New York A45 636 is moving at 40.0 kilometers per hour.

 
 

New York A45 636 is moving at 123.45 kilometers per hour.

 

Returning Values From Methods

For example, the following getLicensePlate() method returns the current value of the licensePlate field in the Car class.

String getLicensePlate() {

return this.licensePlate;

}

A method like this that merely returns the value of an object's field or property is called a getter or accessor method.

Returning Multiple Values From Methods

It is not possible to return more than one value from a method. You cannot, for example, return the licensePlate, speed and maxSpeed fields from a single method. You could combine them into an object of some kind and return the object. However this would be poor object oriented design.

The right way to solve this problem is to define three separate methods, getSpeed(), getMaxSpeed(), and getLicensePlate(), each of which returns its respective value. For example,

class Car {

String licensePlate = ""; // e.g. "New York 543 A23"

double speed = 0.0; // in kilometers per hour

double maxSpeed = 123.45; // in kilometers per hour

// getter (accessor) methods

String getLicensePlate() {

return this.licensePlate;

}

double getMaxSpeed() {

return this.maxSpeed;

}

double getSpeed() {

return this.speed;

}

// setter method for the license plate property

void setLicensePlate(String licensePlate) {

this.licensePlate = licensePlate;

}

// setter method for the maxSpeed property

void setMaximumSpeed(double maxSpeed) {

if (maxSpeed > 0) this.maxSpeed = maxSpeed;

else this.maxSpeed = 0.0;

}

// accelerate to maximum speed

// put the pedal to the metal

void floorIt() {

this.speed = this.maxSpeed;

}

 

void accelerate(double deltaV) {

this.speed = this.speed + deltaV;

if (this.speed > this.maxSpeed) {

this.speed = this.maxSpeed;

}

if (this.speed < 0.0) {

this.speed = 0.0;

}

}

}

Constructors

A constructor creates a new instance of the class. It initializes all the variables and does any work necessary to prepare the class to be used. In the line

Car c = new Car();

Car() is the constructor. A constructor has the same name as the class.

If no constructor exists Java provides a generic one that takes no arguments (a noargs constructor), but it's better to write your own. You make a constructor by writing a method that has the same name as the class. Thus the Car constructor is called Car().

Constructors do not have return types. They do return an instance of their own class, but this is implicit, not explicit.

The following method is a constructor that initializes license plate to an empty string, speed to zero, and maximum speed to 120.0.

Car() {

this.licensePlate = "";

this.speed = 0.0;

this.maxSpeed = 120.0;

}

Better yet, you can create a constructor that accepts three arguments and use those to initialize the fields as below.

Car(String licensePlate, double speed, double maxSpeed) {

this.licensePlate = licensePlate;

this.speed = speed;

if (maxSpeed > 0) this.maxSpeed = maxSpeed;

else this.maxSpeed = 0.0;

if (speed > this.maxSpeed) this.speed = this.maxSpeed;

if (speed < 0) this.speed = 0.0;

else this.speed = speed;

}

Or perhaps you always want the initial speed to be zero, but require the maximum speed and license plate to be specified:

Car(String licensePlate, double maxSpeed) {

this.licensePlate = licensePlate;

this.speed = 0.0;

if (maxSpeed > 0) this.maxSpeed = maxSpeed;

else this.maxSpeed = 0.0;

}

Using Constructors

The next program uses the constructor to initialize a car rather than setting the fields directly.

class CarTest7 {

public static void main(String args[]) {

Car c = new Car("New York A45 636", 123.45);

System.out.println(c.getLicensePlate() + " is moving at " + c.getSpeed() +

" kilometers per hour.");

for (int i = 0; i < 15; i++) {

c.accelerate(10.0);

System.out.println(c.getLicensePlate() + " is moving at " + c.getSpeed()

+ " kilometers per hour.");

}

}

}

You no longer need to know about the fields licensePlate, speed and maxSpeed. All you need to know is how to construct a new car and how to print it.

You may ask whether the setLicensePlate() method is still needed since it's now set in a constructor. The general answer to this question depends on the use to which the Car class is to be put. The specific question is whether a car's license plate may need to be changed after the Car object is created.

Overloading

Overloading is when the same method or operator can be used on many different types of data. For instance the + sign is used to add ints as well as concatenate strings. The plus sign behaves differently depending on the type of its arguments. Therefore the plus sign is inherently overloaded.

Methods can be overloaded as well. System.out.println() can print a double, a float, an int, a long, or a String. You don't do anything different depending on the type of number you want the value of. Overloading takes care of it.

Programmer-defined classes can overload methods as well. To do this simply write two methods with the same name but different argument lists.

public class Car {

private String licensePlate; // e.g. "New York A456 324"

private double speed; // kilometers per hour

private double maxSpeed; // kilometers per hour

// constructors

public Car(String licensePlate, double maxSpeed) {

this.licensePlate = licensePlate;

this.speed = 0.0;

if (maxSpeed >= 0.0) {

this.maxSpeed = maxSpeed;

}

else {

maxSpeed = 0.0;

}

}

 

public Car(String licensePlate, double speed, double maxSpeed) {

this.licensePlate = licensePlate;

if (maxSpeed >= 0.0) {

this.maxSpeed = maxSpeed;

}

else {

maxSpeed = 0.0;

}

if (speed < 0.0) {

speed = 0.0;

}

if (speed <= maxSpeed) {

this.speed = speed;

}

else {

this.speed = maxSpeed;

}

}

 

// other methods...

}

Normally a single identifier refers to exactly one method or constructor. When as above, one identifier refers to more than one method or constructor, the method is said to be overloaded.

If there are no arguments to the constructor, or two or three arguments that aren't the right type in the right order, then the compiler generates an error because it doesn't have a method whose signature matches the requested method call. For example

Error: Method Car(double) not found in class Car.

Car.java line 17

Inheritance

Code reusability is claimed to be a key advantage of object-oriented languages over non-object-oriented languages. Inheritance is the mechanism by which this is achieved. An object can inherit the variables and methods of another object. It can keep those it wants, and replace those it doesn't want.

In this example you begin by defining a more general MotorVehicle class.

public class MotorVehicle {

 

private String licensePlate; // e.g. "New York A456 324"

private double speed; // kilometers per hour

private double maxSpeed; // kilometers per hour

private String make; // e.g. "Harley-Davidson", "Ford"

private String model; // e.g. "Fatboy", "Taurus"

private int year; // e.g. 1998, 1999, 2000, 2001, etc.

private int numberPassengers; // e.g. 4

// constructors

public MotorVehicle(String licensePlate, double maxSpeed,

String make, String model, int year, int numberOfPassengers) {

this(licensePlate, 0.0, maxSpeed, make, model, year, numberOfPassengers);

}

 

public MotorVehicle(String licensePlate, double speed, double maxSpeed,

String make, String model, int year, int numberOfPassengers) {

 

this.licensePlate = licensePlate;

this.make = make;

this.model = model;

this.year = year;

this.numberPassengers = numberOfPassengers;

 

if (maxSpeed >= 0.0) {

this.maxSpeed = maxSpeed;

}

else {

maxSpeed = 0.0;

}

if (speed < 0.0) {

speed = 0.0;

}

if (speed <= maxSpeed) {

this.speed = speed;

}

else {

this.speed = maxSpeed;

}

}

// getter (accessor) methods

public String getLicensePlate() {

return this.licensePlate;

}

 

public String getMake() {

return this.make;

}

 

public String getModel() {

return this.model;

}

 

public int getYear() {

return this.year;

}

public int getNumberOfPassengers() {

return this.numberPassengers;

}

public int getNumberOfPassengers() {

return this.numberWheels;

}

public double getMaxSpeed() {

return this.maxSpeed;

}

 

public double getSpeed() {

return this.speed;

}

 

// setter method for the license plate property

protected void setLicensePlate(String licensePlate) {

this.licensePlate = licensePlate;

}

 

// accelerate to maximum speed

// put the pedal to the metal

public void floorIt() {

this.speed = this.maxSpeed;

}

public void accelerate(double deltaV) {

 

this.speed = this.speed + deltaV;

if (this.speed > this.maxSpeed) {

this.speed = this.maxSpeed;

}

if (this.speed < 0.0) {

this.speed = 0.0;

}

}

}

Inheritance: the Motorcycle subclass

The MotorVehicle class has all the characteristics shared by motorcycles and cars, but it leaves the number of wheels unspecified, and it doesn't have a numberDoors field since not all motor vehicles have doors.

Next you define two subclasses of MotorVehicle, one for cars and one for motorcycles. To do this you use the keyword extends.

public class Motorcycle extends MotorVehicle {

private int numberWheels = 2;

// constructors

public Motorcycle(String licensePlate, double maxSpeed,

String make, String model, int year, int numberOfPassengers) {

this(licensePlate, 0.0, maxSpeed, make, model, year, numberOfPassengers);

}

 

public Motorcycle(String licensePlate, double speed, double maxSpeed,

String make, String model, int year, int numberOfPassengers) {

// invoke superclass constructor

super(licensePlate, speed, maxSpeed, make, model, year,

numberOfPassengers);

}

public int getNumberOfWheels() {

return this.numberWheels;

}

}

Inheritance: The Car subclass

public class Car extends MotorVehicle {

private int numberWheels = 4;

private int numberDoors;

// constructors

public Car(String licensePlate, double maxSpeed,

String make, String model, int year, int numberOfPassengers,

int numberOfDoors) {

this(licensePlate, 0.0, maxSpeed, make, model, year, numberOfPassengers,

numberOfDoors);

}

 

public Car(String licensePlate, double speed, double maxSpeed,

String make, String model, int year, int numberOfPassengers) {

this(licensePlate, speed, maxSpeed, make, model, year,

numberOfPassengers, 4);

}

 

public Car(String licensePlate, double speed, double maxSpeed,

String make, String model, int year, int numberOfPassengers,

int numberOfDoors) {

super(licensePlate, speed, maxSpeed, make, model,

year, numberOfPassengers);

this.numberDoors = numberOfDoors;

}

public int getNumberOfWheels() {

return this.numberWheels;

}

public int getNumberOfDoors() {

return this.numberDoors;

}

}

It may look like these classes aren't as complete as the earlier ones, but that's incorrect. Car and Motorcycle each inherit the members of their superclass, MotorVehicle. Since a MotorVehicle has a make, a model, a year, a speed, a maximum speed, a number of passengers, cars and motorcycles also have makes, models, years, speeds, maximum speeds, and numbers of passengers. They also have all the public methods the superclass has. They do not have the same constructors, though they can invoke the superclass constructor through the super keyword, much as a constructor in the same class can be invoked with the this keyword.

 

The Java Class Library

Java contains an extensive library of pre-written classes you can use in your programs. These classes are divided into groups called packages.

The Java 1.1 packages

Each package defines a number of classes, interfaces, exceptions, and errors.

Packages can be split into sub-packages. for example, the java.lang package has a sub-package called java.lang.reflect. These are really completely different packages. A class in a sub-package has no more access to a class in the parent package (or vice versa) than it would to a class in a completely different package.

Importing Classes

Fully qualified names like java.net.URL are not the most convenient thing to have to type. You can use the shorter class names like URL without the java.net part if you first import the class by adding an import statement at the top of the file. For example,

import java.net.URL;

import java.net.MalformedURLException;

 

 

public class URLSplitter {

public static void main(String[] args) {

for (int i = 0; i < args.length; i++) {

try {

URL u = new URL(args[i]);

System.out.println("Protocol: " + u.getProtocol());

System.out.println("Host: " + u.getHost());

System.out.println("Port: " + u.getPort());

System.out.println("File: " + u.getFile());

System.out.println("Ref: " + u.getRef());

}

catch (MalformedURLException e) {

System.err.println(args[i] + " is not a valid URL");

}

}

}

Interfaces

Interfaces are the next level of abstraction. An interface is like a class with nothing but abstract methods and final, static fields. All methods and fields of an interface must be public.

However, unlike a class, an interface can be added to a class that is already a subclass of another class. Furthermore an interface can apply to members of many different classes. For instance you can define an Import interface with the single method calculateTariff().

public interface Import {

 

public double calculateTariff();

 

}

You might want to use this interface on many different classes, cars among them but also for clothes, food, electronics and moore. It would be inconvenient to make all these objects derive from a single class. Furthermore, each different type of item is likely to have a different means of calculating the tariff. Therefore you define an Import interface and declare that each class implements Import.

The syntax is simple. Import is declared public so that it can be accessed from any class. It is also possible to declare that an interface is protected so that it can only be implemented by classes in a particular package. However this is very unusual. Almost all interfaces will be public. No interface may be private because the whole purpose of an Interface is to be inherited by other classes.

The interface keyword takes the place of the class keyword. Line 3 looks like a classic method definition. It's public (as it must be). It's abstract, also as it must be. And it returns a double. The method's name is calculateTariff() and it takes no arguments. The difference between this method and a method in a class is that there is no method body. That remains to be created in each class that implements the interface.

You can declare many different methods in an interface. These methods may be overloaded. An interface can also have fields, but if so they must be final and static (in other words constants).

Implementing Interfaces

To actually use this interface you create a class that includes a public double calculateTariff() method and declare that the class implements Import. For instance here's one such class:

public class Car extends MotorVehicle implements Import {

 

int numWheels = 4;

 

public double calculateTariff() {

return this.price * 0.1;

}

 

}

One of the advantages of interfaces over classes is that a single class may implement more than one interface. For example, this Car class implements three interfaces: Import, Serializable, and Cloneable

import java.io.*;

 

public class Car extends MotorVehicle

implements Import, Serializable, Cloneable {

 

int numWheels = 4;

 

public double calculateTariff() {

return this.price * 0.1;

}

 

}

Serializable and Cloneable are marker interfaces from the class library that only add a type to a class, but do not declare any additional methods.

What is an Exception?

Consider this program:

public class HelloThere {

 

public static void main(String[] args) {

System.out.println("Hello " + args[0]);

}

}

Suppose it's run like this:

$ java HelloThere

Notice that's there's no args[0]. Here's what you get:

$ java HelloThere

java.lang.ArrayIndexOutOfBoundsException: 0

at HelloThere.main(HelloThere.java:5)

This is not a crash. The virtual machine exits normally. All memory is cleaned up. All resources are released.

What is an Exception?

Why use exceptions instead of return values?

  1. Forces error checking
  2. Cleans up your code by separating the normal case from the exceptional case. (The code isn't littered with a lot of if-else blocks checking return values.)
  3. Low overhead for non-exceptional case

Traditional programming languages set flags or return bad values like -1 to indicate problems. Programmers often don't check these values.

Java throws Exception objects to indicate a problem. These cannot be ignored.

try-catch

public class HelloThere {

 

public static void main(String[] args) {

try {

System.out.println("Hello " + args[0]);

}

catch (ArrayIndexOutOfBoundsException e) {

System.out.println("Hello Whoever you are.");

}

}

}

Catching multiple exceptions

public class HelloThere {

public static void main(String[] args) {

int repeat;

try {

repeat = Integer.parseInt(args[0]);

}

catch (ArrayIndexOutOfBoundsException e) {

// pick a default value

repeat = 1;

}

catch (NumberFormatException e) {

// print an error message

System.err.println("Usage: java HelloThere repeat_count" );

System.err.println(

"where repeat_count is the number of times to say Hello" );

System.err.println("and given as an integer like 1 or 7" );

return;

}

for (int i = 0; i < repeat; i++) {

System.out.println("Hello");

}

}

}