CSIS 3701: Advanced Object-Oriented Programming

Object-Oriented Syntax in Java

In this section, we introduce the basic syntax of creating and using classes in Java. Further sections will expand upon this, giving more advanced syntax and more details on the concepts behind them.

An Example Sum Class

For this section, we will create a very simple class called Sum that represents the concept of a “running total”. More specifically:  Objects in this class will keep a running total of the integers that are passed to them as a state variable.  When an object in this class is constructed its running total will initially be 0.  Users may use methods to add new integers to the total (using a method called add) and find the current running total (using a method called getSum).

This could be implemented with the flowing class, which would be stored in a file called Sum.java.

// Sum is a class representing a running integer total. // Users can add to the total, and find the total. public class Sum {

private int total; // Internal state variable

// The constructor sets the internal running total to 0.

public Sum() { total = 0; }

// The add method increments the running total, modifying // the state of the object.

public void add(int x) { total = total + x; }

// The getSum method returns the current value of the // running total. It does not modify the state.

public int getSum() { return total; }

}

Some syntax nodes about the above example:

Basic class structure:  The keyword class is used to indicate that Sum is a new class with the constructor and methods defined inside the { }. Unlike C++, you cannot define the methods separately from the class.  Defining the variable int total inside the class makes it a state variable of the class. Every Sum object will have its own individual total.  Using the word public before the class, constructor, and methods make them available to the user. Using the word private before the state variable hides it from the user. This is related to a topic called encapsulation, which we will talk about in more detail later.  The class must be stored in a .java file with the same name as the class – in this case, Sum.java. This will make things like separate compilation much easier, as the compiler will not need a makefile to figure out what files to look in.

Constructor:  The constructor for the class has the same name as the class. This is true for most object-oriented programming languages.  The constructor does not return anything (not even void). Forgetting this can lead to some strange compiler errors.  Other than the above two qualifications, there are no restrictions on what a constructor can do. They can take parameters (we will see examples of this later), read from files, allocating memory, etc. – in other words, do whatever is necessary to set up the initial state of the object.

Methods:  The syntax for a method is very similar to that of a function in C – you must define parameters and return type, as well as the code that is executed when the method is invoked.  Note that the variable total is used in the methods (and the constructor as well), but is not declared as a local variable of any of these. In this case, total refers to the state variable of the object – invoking any of the methods modifies or accesses the current value of that state variable.

This means that if we were to call the add method of some Sum called S, the call would end up changing S's total state variable. In a sense, this means that these methods act as an interface to the state variables of each Sum. That is, the user will not directly manipulate the state variables, but will instead manipulate them through these methods:

add USER -----> ---> total getSum

This allows users to treat our Sum objects as abstractions. They only need to know what interface methods affect the Sum, but not how the Sum is represented.

Finally, one very important thing to be aware of is that everything in Java must be a member of a class. This accounts for some of the more unusual looking syntax in Java, such as the main function being inside of a class. There are ways around this using the static keyword that we will see later.

Constructing Objects

As mentioned previously, objects (whether they be part of a Java library like Button or programmer-defined like Sum) must be created using the new command. This does the following things: 1. Allocates space in memory for the object. 2. Invokes the constructor for the object. 3. Returns a reference to the object. For example, to create a new Sum object called odometer we would do the following:

Sum odometer = new Sum();

Note that (unlike C++) you must use the parentheses ( ) to invoke the constructor even if there are no parameters. At this point, we can think of odometer as looking something like this: void add(int) total: 0 int getSum()

Executing object methods The syntax to invoke the methods of an object is:

objectname.methodname(parameters);

For example, to add 37 to our Sum odometer, we would do the following: odometer.add(37); As described above, this would call the add method for odometer. This would have the effect of changing the total state variable of odometer. In effect, it would be identical to: odometer.total = odometer.total + 37; At this point, we can think of odometer as looking something like this: void add(int) total: 37 int getSum()

And after another add: odometer.add(62); void add(int) total: 99 int getSum()

Given this current state of odometer, the message: int distanceSoFar = odometer.getSum(); would return 99. Terminology note: We often use the term message instead of "call" to describe the process of invoking a method. This better expresses the idea that we are sending that call to a particular object. For example, we could say that odometer.add(37) is "sending a message to the odometer object to add the parameter 37". Syntax Notes:

 Note that these calls are sent to odometer, and no other object (which is another reason that this is referred to as a "message"). For example, if we had constructed another Sum called somethingElse: Sum odometer(), somethingElse(); then a call of the form: somethingElse.add(86); would only affect the total variable of somethingElse. It would have no affect on odometer.

 If a state variable (such as total) is redeclared in a method, then references to that variable will affect the local variable only (sort of like what happens if you redeclare a global variable locally in C). For example: public void doNothing() { int total; // total is redeclared locally total = 0; // this only changes the local total } Overloaded Methods and Constructors One potential problem with the convention that the name of the constructor must be the same as the name of the class is that it might only allow us one way to initialize objects in the class – that is, while we may have many different methods in a class (such as add and getSum), we can only have one constructor (Sum), since it must have the same name as the class. Suppose I wanted to give the user two different options for creating Sum objects. Specifically:

 A default constructor, which allows the user to create a Sum with an initial total of 0 (like the one given above).

 An additional constructor, which allowed the user to specify the initial total to something other than 0. That is, I would like to modify the above class as follows:

// Sum is a class representing a running integer total. // Users can add to the total, and find the total. public class Sum {

private int total; // Internal state variable

// The default constructor sets the internal running total to 0.

public Sum() { total = 0; }

// The additional constructor sets the running total to the given // parameter.

public Sum(int t) { total = t; }

// The add method increments the running total.

public void add(int x) { total = total + x; }

// The getSum method returns the current value of the // running total.

public int getSum() { return total; } } In the above example, I have overloaded the Sum constructor. Overloading a method or constructor refers to reusing the same name with more than one definition. In C, this would give us a compiler error, as you cannot redefine a function any more than you can redefine a variable. In Java, however, we can give the same constructor or method more than one definition, as long as it is possible to disambiguate between them based on either:

 The number of parameters

 The type of parameters For example, consider the following lines of code:

Sum s1 = new Sum(); Sum s2 = new Sum(42); Java will choose the definition of Sum that matches the type and number of parameters. s1 would be created using the first constructor, and s2 would be created using the second constructor.

An Example Application

To better illustrate how objects can be use, we give a sample Java application that creates a Sum object and uses it to compute trip mileage. You won’t understand everything this application does at this point; however, you should be able to understand all of the lines in bold, which are related to the Sum. import javax.swing.*; import java.awt.event.*; public class MileageApp extends JFrame implements ActionListener, WindowListener { JButton moreMileage; JTextField getMileage, showMileage;

Sum odometer; // a reference to a Sum object

public MileageApp() {

// Create visual objects moreMileage = new JButton(“add distance to next city”); getMileage = new JTextField(5); showMileage = new JTextField(5); showMileage.setEditable(false); JLabel showLabel = new JLabel(“Total distance: “);

// Create a panel to display the objects, and add them // to the panel. JPanel P = new JPanel(); getContentPane().add(P); P.add(moreMileage); P.add(getMileage); P.add(showLabel); P.add(showMileage);

// Listen for events on the button, and for the closing // of the window. moreMileage.addActionListener(this); addWindowListener(this);

// create the Sum object odometer = new Sum();

}

// This event handler is invoked when the button is // pressed. It gets the number in the getMileage field // and sends it to the odometer. It then gets the total // mileage from the odometer and displays it in the // showMileage field.

public void actionPerformed(ActionEvent e) {

// read the number of miles from the textfield and // convert it to an integer int miles = Integer.parseInt(getMileage.getText());

// Invoke the add method to add that many miles to the // odometer. odometer.add(miles);

// Use the getSum method to get the total number of // miles. int totalMiles = odometer.getSum();

// Display it in the other textfield showMileage.setText(“” + totalMiles);

}

// Called by java, use to create and display a MileageApp object public static void main(String[] args) { MileageApp m = new MileageApp(); // create an object m.setSize(280, 120); // set its size m.show(); // display it }

}

When run, the applet will look something like this:

Another important thing to note about this example is the way the developer of the Sum class and the author of this application are able to know as little as possible about each other. Specifically:  The author of the application of the Sum class is able to use it without understanding how it works – to them, it is just something to keep track of mileage traveled so far.  The author of the Sum class does not have to know how the class will be used – that is, they don’t have to be aware in any way that it is being used to keep track of mileage traveled.

Arrays and Strings Revisited

Now that we have introduced basic OOP syntax and concepts in Java, we can talk a bit more about arrays and Strings in Java.

While arrays are not completely treated like objects (there are no methods or constructors), they behave like objects in certain ways. Like other objects, arrays must be allocated with the new command. They also have properties that can be accessed (sort of like state variables in a class).

The most useful property to be able to find out is the length of an array. This can be accessed using the form: arrayname.length

For example, we can easily iterate through an entire array using a for loop by accessing its length property. For example: for (int i = 0; i < A.length; i++) { … }

Strings are full-fledged classes in Java, with many methods for accessing individual characters, finding the length, searching, etc. Probably the most useful method, however, is the equals method, which allows you to compare two strings to determine whether they contain the same sequence of characters (recall that this cannot be done with the == operator, as it just checks whether two things refer to the same object). For example:

String name = T.getText(); // read in a name from // textfield T if (name.equals(“Fred”)) { // not name == “Fred”!!! T.setText(“hello Fred!”); }

Copyright © 2000 by Dr. John R. Sullins