Classes and Objects




Each pattern describes a problem which occurs over and over again in our environment, and then describes the core of the solution to that problem, in such a way that you can use this solution a million times over, without ever doing it in the same way twice.
            - C. Alexander



Read about inheritance in the online Java Tutorial.



Recall: Instance variables vs. local variables






Homework: before our next class, review:
the static methods Integer.parseInt() and Double.parseDouble()



An Introduction to Inheritance



Consider a program that involves different types of animals: you write the classes Dog, Cat, and Bird.

As you write these classes, you will notice that they contain some common instance variables:
And some common methods:

Since some of the data and functionality for these classes overlap, we may put common code in a parent class or superclass.



For our program, we may want a parent class called Animal that contains the common instance variables and methods we described above.


Dog, Cat and Bird will be subclasses of the Animal Class, and they will inherit the instance variables and methods in Animal.

The advantage of having the superclass, Animal,  is that we save ourselves the hassle of rewriting code over and over in the subclasses.



Code Re-use and Inheritance



In the real world, we categorize objects - starting with a general category and then becoming more specific.

Example:
Think about people - a general category. Suppose we want a Java class that represents any person. What attributes does every person have? What actions does every human being know how to do?

Person
name
age
SSN

talk
play
eat


In diagrams like this one, the class name goes in the first box, data for the class appears in the second box, and behaviors go in the third box.

Now consider a subcategory of Person - UTStudent. If we also want a Java class that is a blueprint for every UT student, some of the data and behavior for any UTStudent is already represented in the Person class.  We don't want to reinvent the work we did for the Person class - so when we write the UTStudent class, we will only think about data and behavior that only applies to UT students, not all people.

We will re-use the data and behavior in the Person class by having our UTStudent class inherit from Person.


UTStudent ("a kind of" Person):
attributes that did not appear in Person class? UTEID, class schedule, feesOwed
behavior that did not appear in Person class? payFees, study, talk about UT



Person
name
age
SSN

talk
play



UTStudent
UTEID
classSchedule
fees

study
talk (about UT)



Note:

How does inheritance look in Java?

public class Person {
    private String name;
    private int age;
    private String SSN;

    public void play() {
       System.out.println("Out having fun...");
    }

    public void talk() {
       System.out.println("Hi!");
    }
}

UTStudent is a subclass of Person - it automatically has all the data fields and methods from Person class. We say that Person is the superclass, or parent class, of UTStudent.

public class UTStudent extends Person {
    // don't repeat inherited data here - UTStudent objects have name,
    // age, SSN fields

    private String UTEID;
    private String[] classSchedule;
    private double fees;

    public void study() {
       System.out.println("I'm in the lab writing Java code...");
    }

    public void talk() {
       System.out.println("Hi, Java spoken here...");
    }
}

Now: Each UTStudent object automatically...



   

Inheritance



Syntax for a sub-class:
public class <childName> extends <parentName> {
    // Data fields and methods not inherited from parent  go here
    // Methods that we are overriding from the parent class go here
}

Example:
public class Lion extends Animal {
...
}




An Inheritance Example: Rectangle and Square



Squares are a subcategory of Rectangles. A square is a rectangle with equal height and width.

Since a Square "is a kind of" Rectangle, Square can inherit from Rectangle.


If we wrote the Square class from scratch, much of the code would duplicate code from our Rectangle class. Instead, we will eliminate that redundancy by having Square inherit that code from Rectangle.


public class Rectangle {
    private double length;
    private double width;

    public Rectangle(double len, double wth) {
       length = len;
       width = wth;
    }

    public double getWidth() {
       return width;
    }

    public double getLength() {
       return length;
    }

    public double area() {
       return length*width;
    }

    public void setLength(double length) {
       if(length >= 0) this.length = length;
    }

    public void setWidth(double width) {
       if(width >= 0) this.width = width;
    }

    public String toString() {
       // return String representation of rectangle
       String repr = "Rectangle[width = " + width + ", length = " + length + "]";
       return repr;
    }
}




How are Square and Rectangle different?



Square only needs one size parameter in its constructor:
    Square sq = new Square(2);
  Rectangle rect = new Rectangle(4, 5);


Squares should print their string representation differently with toString():
    "Square[side = 2]"
  "Rectangle[length = 4, width = 5]"





Inheritance and the Square Class



A Square is just a special Rectangle, and a square automatically inherits:

Note that in the child class, the superclass constructor can be invoked using the keyword super.


public class Square extends Rectangle {

    // initialize this Square's length, width to the constructor's argument

    public Square(double size) {
       super(size, size); // invoke superclass constructor
    }

    // over-ride toString() method inherited from Rectangle
    // When toString() called on a Square object, this version executed
    public String toString() {
       return "Square[side = " + this.getLength() + "]";
    }
}



Note: To access the length of the Square, we must use this.getLength(), not this.length, since length is a private field in the Rectangle class.








Object: The Superclass of Every Java Class



Every class automatically inherits from class Object - this means that every class extends Object and can use the methods in class Object.

The Object class contains methods that you want every object to have. We've used one of them briefly before.


Object's methods are very general: here are the most useful ones.


Since these methods are so general, it is a good idea to override them in your own classes. Recall that we override a method by providing our own implementation of it.





Writing the equals() method: Testing the Class Type of an Object






The instanceof Operator

Syntax: <object> instanceof <ClassName>
This operator returns true if the object is an instance of ClassName and false otherwise.



Example:
if (x instanceof Square)
{
   Square xSqr = (Square) x;
...
}


Overriding Object's Methods: An Example




Write a Square class which overrides the toString(), equals(), and clone() methods inherited from the Object class. Then write a SquareTest class that tests the Square class.