CSCI A201/A597

Lecture Notes 11

Spring 2000


This week we hope to clarify some of the terminology and mechanisms that make Java an object-oriented language. We do this through a few examples, described below.

First we note that there's an exam coming up on Feb 24-25, the first practical exam. You already know what it will be on, you will have two hours to produce a two-dimensional pattern that will be communicated to you at the time of the exam. Patterns will be distributed randomly, in class.

To see how this works we will have this Friday for a practical mock-up in which you will have one hour to produce a simpler pattern that will be distributed in class. Note however that the mock-up practical is not as strict as the real practical about the distribution of patterns.

In addition the mock-up practical will be open-book and your grade on it will be a bonus on the real practical (up to 10%). So if you have a perfect mock-up practical and a perfect practical you'll end up with 110% on the real practical.

Hopefully that much is clear.

A few other considerations:

You will also need to answer a few questions after the mock-up practical, on QuizSite. Among them you will need to identify the section in which you expect to come and take the practical. Failure to answer that question in QuizSite may prevent you from actually taking the practical.

Now let's get to the new stuff.

We've covered primitive types and we're pretty comfortable with them.

We review them here for reference:

  1. whole numbers (we picked int to work with)
  2. numbers with decimals (double)
  3. booleans (a boolean is true or false)
  4. characters (variables of this type are declared with char)
These are interesting and useful data types: In addition to that we have also looked at Strings.

They are not primitive types but we have started working with them already.

A String could store the student's name.

Let's say then that when we think of a Student (for the purpose of this example or this discussion only) we only look at the following pieces of information for any student:

Java allows us to group related pieces of data together in objects whose description is given by the definition of classes.

For example we can group all the definitions mentioned above in a class definition such as this:

public class Student {
  int age;
  char gender; 
  boolean eligible; 
  double gpa; 
  String name; 
}
And we now have a data structure that contains all the elements that we use to model a student in this particular case.

How do we store information about one particular student in this model?

Let's say we want to describe two students, s1 and s2.

The first one

The second one

The test program will be in a class called PlayOne.

You will see that this is very close to setting up the cast (as in the set of actors) and screenplay for a dramatic production. It all happens according to your instructions. You're the director.

The first play simply comes up with the actors, but they don't do anything.

public class PlayOne {
  public static void main(String[] args) {
    Student s1 = new Student(); 
    s1.name = "Mark Anderson"; 
    s1.gpa = 3.75; 
    s1.eligible = false; 
    s1.gender = 'M'; 
    s1.age = 21; 
    Student s2 = new Student(); 
    s2.name = "Sarah Johnson"; 
    s2.gpa = 3.9; 
    s2.eligible = true; 
    s2.gender = 'F'; 
    s2.age = 20; 
  } 
}
We need to explain how this works.

We will draw a diagram in class and trace the program step by step. What we need to realize is this: that every time we need a new Student data structure we can obtain a fresh one that matches the blueprint defined above. Each student data structure, or student record, will have 5 fields, of the types enumerated above, initially empty.

We keep a pointer to the record in a variable of type Student (such as s1 and s2 above). We access the individual fields with the dot notation: name of structure, dot, name of field.

This structure only keeps together data. But it could also keep together procedures, or methods, not just data. Let's look at another example. Let's say that all we care for in a baseball player, for the purpose of our second play, is the name of the player and the team for which he currently plays.

Write a description for a class (data structure) BaseballPlayer. Then set up a play in which there are two baseball players, one named Sammy Sosa that plays for Chicago Cubs, and another one Mark McGwire, playing for the St. Louis Cardinals. The players need not do anything in this play other than show up and be themselves.

Here's the description of the class:

public class BaseballPlayer {
  String name; 
  String team; 
}
And here's the play:
public class PlayTwo {
  public static void main(String[] args) {
    BaseballPlayer b1 = new BaseballPlayer(); 
    BaseballPlayer b2 = new BaseballPlayer(); 
    b1.name = "Sammy Sosa"; 
    b2.name = "Mark McGwire"; 
    b1.team = "Chicago Cubs"; 
    b2.team = "St. Louis Cardinals"; 
  } 
}
That's all there is to it.

It's like a play, but underneath two records (or data structures) get initialized. The initialization procedure can be specified as part of the class definition in the form of a constructor.

First we need to mention that before we assign any values the them, the fields in the defintion of the data structure get initialized to default values as follows:

Let's define a new data structure, called Slugger, that will contain: The Slugger data structure will be very similar with the BaseballPlayer of a few lines above, except it will define one more variable, call it homeRuns.

public class Slugger {
  String name; 
  String name; 
  int homeRuns; 
}
Let's say the play (PlayThree) now involves two Sluggers by the names of Sammy Sosa (Chicago Cubs) and Mark McGwire (Cardinals) that keep hitting home run after home run. Our story starts with McGwire at 59, and Sosa at 61. McGwire hits three more home runs, and then the unexplainable happens: he moves to the Atlanta Braves.

Let's write this short play:

public class PlayThree {
  public static void main(String[] args) {
    System.out.println("You are watching PlayThree with Mark McGwire "); 
    Slugger s1 = new Slugger(); 
    s1.name = "Mark McGwire"; 
    s1.team = "St. Louis Cardinals"; 
    s1.homeRuns = 59; 
    System.out.println("... and Sammy Sosa."); 
    Slugger s2 = new Slugger(); 
    s2.name = "Sammy Sosa"; 
    s2.team = "Chicago Cubs"; 
    s2.homeRuns = 61; 
    System.out.println("Mark hits 3 more to reach 62"); 
    s1.homeRuns = s1.homeRuns + 3; 
    System.out.println("... and then he moves to Atlanta."); 
    s1.team = "Atlanta Braves"; 
  } 
}
Run this play, experience it, strive to understand it.

Now let's come back with a question: what are constructors?

They are parameterized initialization procedures.

Data can be specified at the time of creation, such as in the following rewriting of PlayThree:

public class PlayThree {
  public static void main(String[] args) {
    System.out.println("You are watching PlayThree with Mark McGwire "); 
    Slugger s1 = new Slugger("Mark McGwire", "St. Louis Cardinals", 59); 

    System.out.println("... and Sammy Sosa."); 
    Slugger s2 = new Slugger("Sammy Sosa", "Chicago Cubs", 61);  

    System.out.println("Mark hits 3 more to reach 62"); 
    s1.homeRuns = s1.homeRuns + 3; 

    System.out.println("... and then he moves to Atlanta."); 
    s1.team = "Atlanta Braves"; 
  } 
}
For this to be a valid play we need to define the initialization procedure in the description of class Slugger. Keep the following in mind: the order in which we pass data to the the initialization procedure is very important. For example in the code above we pass
  1. the name
  2. the team's name and
  3. the initial number of home runs
in that order to the initialization procedure.

In class Slugger we add the initialization procedure (in blue):

public class Slugger {
  String name; 
  String name; 
  int homeRuns; 
  Slugger(String n, String t, int h) {
    name = n; 
    team = t; 
    homeRuns = h; 
  } 
}
So now class Slugger is complete and ready for PlayThree. (I hope that you enter these programs in your computers, compile and run them).

How does the constructor work?

Essentially when it's called the actual parameters ("Sammy Sosa", "Chicago Cubs", 61) match the types (String, String, int) and the order of the formal arguments (in the abstract definition of the initialization procedure) and for the duration of the initialization procedure will be known under the formal parameters' names (n, t and h).

The fields defined by the Slugger data structure definition are called: instance variables and are going to be available directly (that is, by their names) to the initialization procedure as long as care is taken to ensure that none of the parameters in the definition has the same name as one of the fields of the class. That's why we named the parameters n, t and h respectively.

We need to do one more thing and then we will be prepared for the rest of chapter 2 and all of chapter 8, as well as chapter 4: let's teach the Sluggers to introduce themselves, by reporting to us (upon our request) their names, teams for which they play, and number of home runs hit that season.

There are many ways of doing this, but one results in the following modification to the Slugger class:

public class Slugger {
  String name; 
  String team; 
  int homeRuns; 
  Slugger(String n, String t, int h) {
    name = n; 
    team = t; 
    homeRuns = h; 
  }
  void talk() {
    System.out.println("Hello, my name is " + name + 
      " and I play for " + team + ".\nI have hit " + 
      homeRuns + " home runs " + "so far.\n"); 
  }   
}
So talk() is a procedure that describes what should happen when a Slugger is required to talk(). Notice that parentheses don't contain any formal arguments declarations, so there will be no actual parameters passed to it when invoked.

The definition of talk() indicates that the function is not returning anything as a result of being invoked. That's the meaning of the void with which its definition starts.

Here's PlayFour:

public class PlayFour {
  public static void main(String[] args) {
    Slugger s1, s2; 
    s1 = new Slugger("Mark McGwire", "St. Louis Cardinals", 59); 
    s2 = new Slugger("Sammy Sosa", "Chicago Cubs", 61);  

    s1.talk(); 
    s2.talk(); 

    s1.homeRuns = s1.homeRuns + 3; 

    s1.talk(); 
   
    s1.team = "Atlanta Braves"; 

    s1.talk(); 
    s2.talk(); 

  } 
}
Here's the output of this play if we compile and run it:
frilled.cs.indiana.edu%javac PlayFour.java
frilled.cs.indiana.edu%java PlayFour
Hello, my name is Mark McGwire and I play for St. Louis Cardinals.
I have hit 59 home runs so far.

Hello, my name is Sammy Sosa and I play for Chicago Cubs.
I have hit 61 home runs so far.

Hello, my name is Mark McGwire and I play for St. Louis Cardinals.
I have hit 62 home runs so far.

Hello, my name is Mark McGwire and I play for Atlanta Braves.
I have hit 62 home runs so far.

Hello, my name is Sammy Sosa and I play for Chicago Cubs.
I have hit 61 home runs so far.

frilled.cs.indiana.edu%
Before we move on to finish the overview of the element package we need to make sure you have been exposed to one more concept, without which some notation will seem mysterious, probably.

Let's say we write a short play with the three Stooges.

Each Stooge has a name, and can talk().

Beeing stooges they each have a supervisor, another Stooge.

When they talk() they say their name and their supervisor's name.

Here's the Stooge class.

public class Stooge {
  String name;
  Stooge supervisor;   
  Stooge(String n) {
    name = n; 
  } 
  void talk() {
    System.out.println("I'm " + name + " Stooge " +
      "playing subordinate to " + supervisor.name); 
  }  
}
The initialization procedure only needs to know the name of the Stooge that is being created since the supervisor fields can be initialized only after all the Stooges are available. So we do that from the main play called StoogesPlay.

Here's the StoogesPlay:

public class StoogesPlay {
  public static void main(String[] args) {
    Stooge l = new Stooge("Larry"), 
           c = new Stooge("Curly"), 
           m = new Stooge("Moe"); 
    l.supervisor = m; 
    m.supervisor = c; 
    c.supervisor = l; 
    l.talk();
    m.talk(); 
    m.supervisor.talk(); 
  } 
}
The last line looks very much like
c.out.println();
where c is a reference to a
ConsoleWindow
type of object.

Here's the output of StoogesPlay:

frilled.cs.indiana.edu%ls -ld Stooge*
-rw-------   1 dgerman       310 Feb 15 02:42 Stooge.java
-rw-------   1 dgerman       406 Feb 15 02:47 StoogesPlay.java
frilled.cs.indiana.edu%javac StoogesPlay.java
frilled.cs.indiana.edu%java StoogesPlay
I'm Larry Stooge playing subordinate to Moe
I'm Moe Stooge playing subordinate to Curly
I'm Curly Stooge playing subordinate to Larry
frilled.cs.indiana.edu%
If this last example is a bit tricky (it should not be) work a simpler one, in which any Stooge will have a preferred Slugger and create the sluggers first then pass them to the initialization procedure of the Stooge class.

But this example should be clear enough as it is.

We will next move to describe

of the element package completely.

The vast majority of the examples will be from Chapter 2, which you are encouraged to devour (as in to read up greedily or ravenously) while thinking of this set of lecture notes that you are reading now. All the examples in Chapter 2 will be presented and described by analogy with what has been presented here.

And we are now ready for chapter 4, 5 and 8, in that order.


Last updated February 15, 2000 by Adrian German