CM10228 / Programming Ib:   Lecture 5


Space, Class, Polymorphism & Interfaces


Note: in 2011 Lecture 4 ran long so we did hashes across two weeks.  This should run a little short now as I've taken some stuff out of it.

I. The Big Picture

  1. The main theme of this lecture (as with Lecture 1) is visualizing memory --- understanding where it is.
    1. Everything has to be in memory somewhere --- including the program itself!
    2. Thinking clearly about memory (state) is absolutely critical to thinking clearly about programs, systems & algorithms.
      1. You need to know what you need, and when you need it, and what form it should be in.
  2. Pop quiz:  What is polymorphism?
    1. Here's some good notes about it.
    2. Polymorphism is a simple concept -- just the same method can apply to different objects.  This can be done in different ways:
      1. Overloading means that the things really are fundamentally different, and may even have a different signature.
      2. Overridden means that a subclass has redefined something in a superclass.  This has to have the same signature.
      3. Dynamic Binding means that a single call in code may be talking about different kinds of objects, but dynamically (at run time) it can figure out which method to call based on which object is referenced.
      4. public class AnimalArray
        {
        public static void main(String args[])
        Animal ref[] = new Animal[3]; // assign space for array
        Cow aCow = new Cow("Bossy"); // makes specific objects
        Dog aDog = new Dog("Rover");
        Snake aSnake = new Snake("Earnie");

        // now put them in an array
        ref[0] = aCow; ref[1] = aDog; ref[2] = aSnake;

        // now demo dynamic method binding
        for (int x=0;x<3;++x) { ref[x].speak(); }
        } // this example was from the link above

II. Static Memory and Class Variables

  1. What are class variables & where do they get stored?
    1. Why do you declare them with the word static?
  2. We will start out thinking about languages in general, then look at howearly languages like C have impacted Java.
    1. History affects everything, even programming.
    2. The basic problems don't change, although our approaches to solving them do a bit.
  3. Normally when you make a function or method call, temporary memory is allocated for the variables local to that function.
    1. This is part of why we talk about "entering a function", you are creating a new memory space & then going inside.
    2. local variables there are "added to the stack" (pushed)
    3. "The stack" is the program's memory.
      1. Like a stack of papers, or a list in lisp -- the last thing you put on is the first thing you see if you are searching.
      2. You already leaned about stacks, right?
  4. When you leave the function, the variables aren't needed anymore so they are taken back off the stack (popped).
    1. the program stack is back the way it was before (unless you changed parameters passed by reference)
    2. all the values of function variables are lost.
  5. Once in a while, you don't want this to happen.
    1. Might want to remember a value calculated in a function between calls.
    2. For example, might want to know how often a function addNewUser has been called, so can make a new ID for each user.
  6. To make this happen, you need to ask the compiler to put those variables in permanent memory.
    1. Permanent memory is probably just somewhere very low on the stack.
    2. But anyway, they variable won't get created when you enter the function, or destroyed when you exit.
    3. But they are still private to the function -- no one else can see them.
  7. The way you ask a C compiler to do this is with the keyword static.
    /* returns the current number of users */
    int addNewUser (name)
    char *name;
    {
    static int userID = 0; /*only gets set to 0 the first time the function is called!*/

    addToPasswordFile(name, userID);
    printf ("%s added to password file with userID = %d. There are now %d users.",
    name, userID, ++userID); /*note: this is where userID gets incremented!*/
    return (userID); /* this is now really the number of users */
    } /* addNewUser (name) */
  8. In Java, all memory is kept in an object.
  9. The only memory guaranteed to be around from the beginning to the end of the program is in class objects.
  10. Thus, class variables are sometimes called "static variables."  But this is somewhat naughty...
    1. Class variables are associated with the class & all its instances, not really functions or methods (although of course class's objects' methods can access them).
    2. The fact that they are static is sort of an implementation detail, it's not as salient as the fact they are in the class.
    3. Yet, you have to declare them using the word "static".
      1. No language is perfect!
      2. Java was not designed as a teaching language...
  11. In the old coursework, I used to ask students to put a hash in a class variable.
    1. It would certainly be silly to put a hash in each & every object you are putting in the hash!
    2. Ordinary OOD calls for using two different classes, but we are checking to make sure you have the class variable thing clear.
    3. In fact, the truly ordinary way to do this is to use classes provided in the java library
      1. I suggested doing something similar under "bonus things to do" on Tutorial 2.
      2. Since I don't think anyone got that far in the tutorial, let's have a look at it now (section IV below).
      3. This will also give you important revision on Interfaces, which will be useful when we talk about threading.

III. Inheritance vs. Interface

  1. You should have learned about Interfaces last term, but I'm sure some of you are still confused.
  2. Look at your Blue J book, Chapter 10.
  3. Here's a table to help you think more about this:

    Classes
    Interfaces
    State / Memory / Variables
    yes
    no
    Multiple Inheritance
    no
    (not in Java anyway, can in Lisp)
    yes
    (In Java.  Don't exist in Lisp!)
    Methods / Code
    yes
    only specifications



    Bottom Line
    A real thing you can make instances of.
    A contract you can choose to have your objects meet.
  4. Interfaces are cool because you can have multiple different classes that let you do the same thing in different ways.
    1. If you decide to change the back end of how you do something, all you have to change is the class type of the object that you were having do it.
    2. For example, there are multiple classes for doing hashes provided by Java.  
      1. The one that works with threading is slower than any of the others. 
      2. So you probably wouldn't use it.
      3. But if you decide to convert a non-threaded program into a threaded program, then its easy!
      4. The interface all of these hash classes meet is called Map.
  5. What confuses people sometimes is how interfaces differ from abstract classes.  Abstract classes are classes, not interfaces!

    Concrete
    Abstract
    Class
    yes
    yes
    Interface
    no
    no
    Can make instances of
    yes
    no
    Can inherit from
    yes
    yes
    Can call the methods of
    yes
    as long as they aren't abstract!



    Bottom Line
    A real thing you can make instances of.
    An almost real thing that can be the superclass of a real thing.
  6. What's confusing is that Abstract Classes & Interfaces are both sort of specifications, but they are different sorts.
    1. You can think of abstraction as another kind of privacy -- it's so private it can't even call itself!
    2. You can think of interfaces sort of like contracts or roles
      1. People can have multiple jobs or roles, objects can implement multiple interfaces. 
      2. People can only be of one species, an object can only be of one class.
  7. Sometimes abstract classes are provided to help you implement an interface,
    1. e.g. if you subclass from AbstractMap, you'll have most of what you'll need to implement interface Map.
  8. The idea of abstract classes has been around longer than the idea of interfaces.
  9. Some people think that interfaces are more useful than class hierarchy.

IV. Using the Comparable Interface

  1. Comparable is an interface that lives in Collections & allows you to use Collections.sort().
  2. This is a modification of the program I'm going to show you in Lecture 6.
    1. There's a lot of things in it that don't matter to Comparable that I'll explain tomorrow.
    2. Just pay attention to the bits that are in a colour.
    3. These two lectures used to be reversed in order, but I think it makes more sense this way around.
  3. Notice that besides using sort when the user types "sort" (blue), I've also demonstrated the use of class & instance variables (green).
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;

/**
* @author joanna
*
* Demonstrate how to use built-in sorting functions through the
* Comparable interface.
*/
public class SortedBadIndices
implements Comparable {

// class variable holds a list of all instances
private static ArrayList myStuff = new ArrayList();
private int favNumber;

// new constructor to make instances with their favNumber set
// also stores them into myStuff
public SortedBadIndices (int myfav) {
this.favNumber = myfav;
myStuff.add(this);
}

/* (non-Javadoc)
* @see java.lang.Comparable#compareTo(java.lang.Object)
*/
public int compareTo(Object o) {
if (this.favNumber < ((SortedBadIndices) o).favNumber) {
return -1;
} else if (this.favNumber > ((SortedBadIndices) o).favNumber) {
return 1;
} else { // must be equal!
return 0;
}
} // compareTo (Object o)

public static void main(String[] args) {

// this looks pointless, but in fact the constructor is saving the
// instances into myStuff!
new SortedBadIndices(8); // will be the 0th element.
new SortedBadIndices(5);
new SortedBadIndices(13);
new SortedBadIndices(2);

int newIx = -1;
try {
BufferedReader stdin =
new BufferedReader(new InputStreamReader(System.in));
String myNumString;

System.out.print("Welcome to my program. The prompt looks like >>." +
"\n >> ");
while ((myNumString=stdin.readLine()) != null) {
if (myNumString.equals("sort")) {
Collections.sort(myStuff);
}
else try {
newIx = Integer.decode(myNumString).intValue();
} catch (NumberFormatException nfe) {
System.out.println("you nurf herder, put in integers!");
newIx = 0;
} catch (Exception ex) {
System.out.println("Wow, I didn't expect a " + ex);
} finally {
System.out.println("I have " + newIx + " as my index.");
System.out.flush();
}
try {
System.out.println("The fav number at " + newIx + " is " +
((SortedBadIndices) myStuff.get(newIx)).favNumber);
} catch (IndexOutOfBoundsException iobe) {
System.out.println("We're sorry, " +
"there is no such array element.");
}

System.out.print("\n >> ");
} // while reading
} catch (IOException ioe) {
ioe.printStackTrace(); // printStackTrace is always a useful way to see what happened!
System.exit(-3);
}
} // main()

} // class SortedBadIndices

V. The Class Class

  1. For every class that you use in a program, there's an instance of the class Class.
  2. This makes sense, because where else would the class variables go?  Variables live in objects / instances.
  3. You can do cool things with class Class, e.g.
    1. Find out the class of an object you've been passed.
      String s = "Arvice";
      Class myclass = s.getClass();
      System.out.println(myclass.getName()); // prints "java.lang.String"
    2. There's many more things you can do with this, but we'll talk about them after we've talked about errors...

VI. Summary

  1. Variables take space. 
    1. If you think about that space, it makes it more obvious what things are "real", that is, have objects.
  2. Covered classes vs. interfaces, abstract vs. concrete classes, class objects, class variables, and what `static' really means.
  3. Demonstrated using the Comparable interface.
  4. Explained log vs. exp one more time!

page author: Joanna Bryson
22 February 2011