Module 11: Classes and Object-Oriented Design


Objectives

 

By the end of this module, you will be able to:

 


Objects and Memory Layout

 

Objects:

Where does this leave classes?

Take the example of the Facebook user class:

public class FBUser {
    private long userId;
    private String firstName, lastName;
    private FBUser[] friends;
    
    public void setId(long id) {
        userId = id;
    }
    public long getId() {
        return userId;
    }
}

The class gives the blueprint for each object:

 

In-Class Exercise 1: Why do we need objects?

What function do objects provide compared to variables, arrays, etc? How do they relate to static variables stored in classes?

 

In-Class Exercise 2: Given the following code that you can add to the FBUser class:

    public static void main(String[] args) {
        long id = FBUser.getId();
        System.out.println(id);
    }

We're trying to invoke the getId method just like we've called static methods in the past. What do you think will happen when you compile your code? When you run it? Try!

 

Multiple objects exist, each with possibly different sets of data. Objects are allocated with new.

    public static void main(String[] args) {
        FBUser user1 = new FBUser();
        FBUser user2 = new FBUser();
        
        user1.setId(5);
        System.out.println(user1.getId() + " " + user2.getId());
    }

 

In-Class Exercise 3: What does the above print out? Why?
 

Methods in a class can operate on an object using the dot notation. If var is a variable referring to an object,

      var.methodName();

invokes the methodName method on var's object.

Read this as "we're invoking the methodName method of the var object"

 

When an object is allocated with new, e.g.:

    A var = new A();

 

A slightly more complicated example:

    FBUser var1 = new FBUser();
    FBUser var2 = var1;
    var2.setId(10);
    System.out.println(var1.getId());

 

In-Class Exercise 4: First, write a new class to use your FBUser class.

Second, fill in the FBUser class with other appropriate methods, and use them from your other class. Create a few users, and populate their friend lists.

public class FBUser {
    private long userId;
    private String firstName, lastName;
    private FBUser[] friends;
    
    public void setId(long id) {
        userId = id;
    }
    public long getId() {
        return userId;
    }
}

 

An even more complicated example:

public class ObjExample {
    private int data;
    public void modify(int v) {
        data = v;
    }
    public int access() {
        return data;
    }
    public void addData(ObjExample o) {
        data += o.access();
    }
    public static void main(String[] args) {
        ObjExample v1 = new ObjExample();
        ObjExample v2 = v1;
        v2.modify(10);
        System.out.println(v1.access());

        ObjExample v3 = new ObjExample();
        v3.modify(3);
        v3.addData(v2);
        System.out.println(v3.access());

        v3.addData(v3);  // what's happening here?
        v1.addData(v2);  // ...and here?
    }
}

 

In-Class Exercise 5: What does the above print out? Why?

What are the last two lines doing? Describe them

 

Object-Oriented Programming (OOP): Goodbye Static!

We can now better understand the static keyword.

 

public class StaticExample {
    private static int staticVar;
    private int objectVar;

    public void objSetVars() {
        objectVar = 10;
        staticSetVars();
    }
    public int[] objGetVars() {
        return new int[]{staticvar, objectVar}; 
    }
    public static void staticSetVars() {
        staticVar = 10;    
        objSetVars();
    }
    public static int[] staticGetVars() {
        return new int[]{staticvar, objectVar}; 
    }
    public static void main(String[] args) {
        staticSetVars();
        objSetVars();

        StaticExample v = new StaticExample();
        v.staticSetVars();
        v.objSetVars();
    }
}

In-Class Exercise 6: Type in this example and compile it. What errors do you get? Fix them where possible.
 


Null Objects

 

null is a valid value for a variable of any non-primitive type. This includes:

  • objects

  • arrays

  • Strings

null is simply a reference to nothing

 

In-Class Exercise 7: Why does null exist?
 

  • null is often used to denote "there is no valid object".

  • It is sometimes returned when an object is expected to denote an error.

  • Example: What if you try and lookup a facebook user that doesn't exist -- FBUser findUser(String first, String last)?

public class NullTest {
    private int n;
    public int getN() {
        return n;
    }
    public static void main(String[] args) {
        NullTest nt = null;
        System.out.println(nt.getN());
    }
}

 

In-Class Exercise 8: Execute this program. What happens when this program is executed? Why?
 

In-Class Exercise 9: What is the default value for variables of a class's type? Write a small program to print out the default value of the variable:

FBUser u;

 


Constructors

 

If a class gives the blueprint to create objects, constructors lay the initial foundation for each object.

Constructors are methods that are invoked when a new object is created that are used to initialize the data of the new object.

FBUser u = new FBUser();

new FBUser(); invokes the constructor on the newly created object.

The constructor can be overloaded just like any other method:

FBUser u = new FBUser("chester", "thecat");

What does a constructor look like? An example:

public class FBUser {
    private long userId;
    private String firstName, lastName;
    private FBUser[] friends;

    public FBUser() {
        // initialize object's data here
    }
    public FBUser(String first, String last) {
        firstName = first;
        lastName = last;
    }
    public void setId(long id) {
        userId = id;
    }
    public long getId() {
        return userId;
    }
}

 

In-Class Exercise 10: Add a print statement to the constructor to see when it is invoked.

Initialize the data in the constructor, and then use a method to access the data, and verify it was initialized correctly.

 


Classy Scope

 

Where is the problem in the following code?

public class FBUser {
    private long userId;
    private String firstName, lastName;
    private FBUser[] friends;

    public FBUser(String firstName, String lastName) {
        // uh oh...
    }
    public void setId(long id) {
        userId = id;
    }
    public long getId() {
        return userId;
    }
}

Scope works the same with an object's variable as it did for global variables:
  • A local variable shadows an object's global variable.
  • You can avoid these conflicts by choosing your variable names to be different from global variables.
  • But what if you want to use the same name?
 

public class FBUser {
    private long userId;
    private String firstName, lastName;
    private FBUser[] friends;

    public FBUser(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
    public void setId(long id) {
        userId = id;
    }
    public long getId() {
        return userId;
    }
}

  • this is a new keyword that denotes "the current object".
  • Thus, this.firstName references the object's firstName variable, not the method argument, or a local variable.
  • The type of this is the type of the object: FBUser, in this case.

 

this is, generically, a variable that references the "current" object.

If a method takes a FBUser argument, or a variable holds a FBUser, this can be used.

public class FBUser {
    private long userId;
    private String firstName, lastName;
    private FBUser[] friends;

    public FBUser() {
        friends    = new FBUser[10];
        friends[0] = this;
    }
}

 

In-Class Exercise 11: Add a method to your FBUser class:

void addFriend(FBUser friend)

However, add a check that will prevent a FBUser from adding itself to its own friend list. In the main, this undesirable action might be done with:

	FBUser user = new FBUser();
	user.addFriend(user);

 

In-Class Exercise 12: Add a method to your FBUser class:

void addAsFriend(FBUser otherUser)

This method adds the current FBUser as a friend in the otherUser.

 


Zombies. Objectified Zombies. Yeeeees.

 

Zombies...

  • Eat brains of humans.

  • Turn bit humans into zombies.

  • Can be killed by humans.

Humans...

  • Shoot zombies in the brain (so much with the brains!).

  • Fight other humans, and might kill them. (Why so mean?)

  • Are turned into zombies when bit.

  • Have names.

 

In-Class Exercise 13:

  1. Make a Person class, and a ZombiesMain class. The latter has the main that will use the Person class.
  2. Each Person object is either a human or a zombie.
  3. If a Person object is a human, it has a name.
  4. Humans can shoot Person objects.
  5. Zombies can bite humans, which turns them into a zombie.
  6. Person objects created with constructors with no arguments are zombies.
Your job is to define a set of methods and data for the Person class that will tell a story when each of the humans and zombies take actions. All of your data in the Person class must be private. Be creative!!! A possible story line follows:

Person joe  = new Person("Joe");
Person bob  = new Person("Bob");
Person jane = new Person("Jane");
Person z    = new Person();

System.out.println(Person.numHumans() + " humans vs. " + Person.numZombies() + " zombies.");
z.bite(bob); // poor bob
bob.bite(z); // confused zombie
Person derpbie = bob;
derpbie.bite(derpbie); // this is getting ridiculous
System.out.println(Person.numHumans() + " humans vs. " + Person.numZombies() + " zombies.");

jane.shoot(z);    // humans FTW!
jane.shoot(joe);  // wait...what?
jane.shoot(jane); // oh...oh no.
System.out.println(Person.numHumans() + " humans vs. " + Person.numZombies() + " zombies.");

while (true) {
    derpbie.bite(derpbie); // bored zombie is bored
}

An example execution of this program would be:
Joe, ready for action!
Bob, ready for action!
Jane, ready for action!
...mmmm, brains.  Oh noes, a zombie!
3 humans vs. 1 zombies.
Bob is gnawed on by a zombie.
The zombie formerly known as Bob bites a zombie, like an idiot.
The zombie formerly known as Bob is hungry...and remembers he has an arm.  Nomnomnomnom.
...etc...
 


OO Design

 

Why does Object-Oriented Programming (OOP) exist?

  • Why is it useful? Why use OOP instead of making all code and data static?

  • Come up with two examples where it has utility.

 

In-Class Exercise 14: Imagine you wanted to write a card game platform to support playing many different card games.

Design a set of classes and objects to describe cards for the card game "War". Write "prototype" classes that include the classes, data in the classes, and methods, but do not provide an implementation of the methods.

  • What methods would you use?
  • What data would each object contain?
  • How would the objects be related? Which objects contain which other objects?
  • How are objects initialized, and related to other objects?

 

A fundamental goal of object oriented design is reuse.

  • Code written for one situation should be, within reason, reusable in other situations

  • Writing fairly generic classes enables this.

  • It is important to design your classes before writing your code. I've been doing this for you in homeworks.

 

In-Class Exercise 15:

Take your design from the previous Exercise.

  • How easy is it to modify it to implement the five-card-stud variant of poker?
  • How about blackjack?

Redesign your objects so that many of them can be reused between games

Other factors to consider:

  • We want to implement an online card game site where many people can be playing games at the same time. Do we need to more classes and relationships between objects to support multiple concurrent games?
  • Take care in designing how cards move from various locations (deck, board, hand).
  • Also take care in designing how decisions on who wins in the various games are made.