Classes
Objective #1: Understand how classes are used in Java.
- Decades ago programmers wrote computer programs to solve specific problems. Each program was unique and fine-tuned for the specific problem. It was not easy to reuse portions of one program in another because of the hardware differences between computers and the lack of common operating systems.
- In the 1980's, new object-oriented programming (OOP) languages like C++ allowed programmers to create classes. A class is a set of methods (aka subroutines, procedures, functions, behavior) and variables (aka properties, fields, instance fields, attributes, state) that are saved to a separate file in a way that they can be imported and reused by many programs. You can think of a class as a template or definition for an object. Nowadays, instead of writing programs that solve specific problems, some programmers (aka class developers) create classes (e.g. Google Maps) so that they can be reused by other programmers (aka client programmers) who have specific problems (e.g. find driving directions to a restaurant.) This phenomenom has led to an explosion of computer software. Games, apps, web applications, etc. are produced more easily, inexpensively and quickly because client programmers have access to classes that can be used in unrelated programmers. For example, a spell-checker class that was used by an old version of Microsoft Word could be reused in an app for a Windows smartphone. Or, a collision detection class that was used in a Mario program from the 1990's could be used in Angry Birds for a smartphone.
- Usually, an individual Java project (i.e. program) uses many classes. Each class is stored
and compiled in a separate file. The name of class is usually a noun and it must be the same as the name of its file.
- Java was created and modelled on the language C++ in the early 1990's by the company Sun Microsystems. There are hundreds
or maybe even thousands
of free
Java
classes that are built into Java. The company Oracle now has the rights to the Java language since it bought Sun Microsystems in the 2000's.
Classes that are built into Java
can be found at java.sun.com/j2se/1.4.2/docs/api . There is a link to this Java API on our class home page.
Look along the left column. The classes that you are responsible for knowing
on the AP exam can be found in the AP CS Subset API at www.minich.com/education/wyo/java/apapi/doc which is also a link on our class home page.
- To use some of these classes that are built-in with Java,
you may need to add an import statement at the top of your Java file such as
import java.awt.Rectangle;
which would allow you to use Rectangle objects. The awt refers to the abstract windowing toolkit (awt) package. A
package is a collection of related classes.
- Many classes have also been written by class developers that work at companies like Google, Microsoft, etc. as well as professors, AP exam authors at College Board, and even students. To make use of these external classes, you can sometimes download the source code or compressed jar files. You can use an IDE like Eclipse to connect your Java project to external classes or jar files like we did with the Turtle classes.
Objective #2: Create a new class by adding an instance method to an existing class.
- The easiest way to develop a class is to "extend" an existing class and add methods to it. For example, if you want to draw a square with a Turtle, you could develop a class named SquareTurtle by extending the existing Turtle class and adding an instance method named drawSquare. Your SquareTurtle objects can draw squares but they can also use any methods that Turtle objects already have!
- This is done by typing the first line of the class as
public class SquareTurtle extends Turtle
- In this way all methods of the Turtle class are "inherited" by the SquareTurtle class such as forward, turnRight, etc.
- Since constructors are not inherited, you must type out at least one constructor which we will study later.
- See the SquareTurtleDemo program in our class website for more explanation and to see the difference between the using a static method in a client program to draw a square versus creating a whole new, reusable class that has an instance method. Because a separate SquareTurtle class is reusable in many client programs, it is better to add the drawSquare method there rather than using it as a static method in one specific client program.
Here is the code but you should review the link above to read the more detailed explanation.
public class SquareTurtle extends Turtle
{
// constructor (required, we will study constructors later)
public SquareTurtle(int x, int y, ModelDisplay display)
{
super(x, y, display);
}
// draw a square
public void drawSquare()
{
this.penDown();
this.forward();
this.turnRight();
this.forward();
this.turnRight();
this.forward();
turnRight(); // using the keyword this is optional
forward();
}
}
Objective #3: Develop a whole new class by typing out its instance variables, instance methods, and constructors from scratch.
- The file for a class is called the class definition.
- A class is a list of methods and instance variables (i.e. properties). According to the principles of object-oriented programming, the collection of instance variables is called the state of an object while the set of methods is called the behavior of an object. The set of methods is also sometimes called the class's public interface. Think
of the
API as being a set of class interfaces.
- When someone hires you to develop a class, you must carefully
decide what instance variables and methods (i.e. state and behavior) an object of the class should have.
For example, if
you are creating a class named Student you could have a variable named name and a method named study.
Or you could have two separate instance variables named firstName and lastName rather than one named name.
You may or may not include additional methods like eatLunch and playGames depending on how flexible (or nice) you are as the creator/designer of the Student class.
This process of carefully identifying the essential features
of a class is known as abstraction and the process as a
whole is also called object-oriented design (OOD). It is wise to find a balance of not having too many instance variables and methods while being sure to have just enough that client programmers can make use of objects from the class.
- Implementing
a class means to write out all
of its instance variables and methods. By the way, to implement a method is to write out the code in the body of the method. Note that two programmers might implement the same method differently based on programming style.
- Here is a class with nothing inside of it. In other words, this class has no implementation:
public class Turtle
{
}
- Normally, a class should have the following parts:
public class Turtle
{
default constructor
"other" constructors
accessor methods
modifier methods
"interesting" methods
properties
}
There is no specific order that they should be typed out but I generally type out the constructors first, then the accessors, then the modifiers and the properties in that order.
- After you define and implement a class or even while you
are implementing a class, you should also make a separate test class to test
your newly implemented
class's methods and constructors. A test class is often
named by placing the word Test after the name of the class that you are testing.
For example,
a test class for the Rectangle class might
be named RectangleTest. A test class is
simply a client program that instantiates one or more objects to test the methods in a class.
- What is computer software? Here is an interesting view - http://www.csteachlearn.com/secret_life.html
Objective #4: Add public accessor methods to a class so client programmers can access instance variables of an object.
- Here is an example of a class that only has three instance variable declaration statements that declare three instance variables.
public class Bug
{
private int myAge;
private int myX;
private int myY;
}
Instance variables of a class are also known as properties, attributes, instance
fields or just fields.
Instance variables are sometimes named with the prefix my as in the example above. This is not a requirement though but I encourage it. Some programmers use an underscore as the prefix for instance variables such as _age.
You need to specify a data type (e.g. int, double, or String usually) for each instance variable. In the example above all three instance variables have the data type int.
You should not initialize an instance variable to a given value such
as zero in its declaration statement. That is, you should not use the statement
private int myAge = 0;
- Instance variables should be private rather than public at least according to the College Board AP exam curriculum. Instance variables should
normally be declared as private rather than public.
- The term information hiding is used to describe this tendency for Java programmers to keep the instance variables of a class private and hidden from client programmers.
The term encapsulation is
also used to describe the technique of "encapsulating" and hiding the state of an object in this way. The difference between information hiding and encapsulation is very subtle. For the purposes of this course, the two terms refer to
the same idea.
It's as if the person who designs and implements a class
(i.e. a class developer) does not trust the client programmer who is going to use
objects from that class in a client program.
The client programmer is forced to indirectly access and modify an object's
instance variables through the object's public methods.
Because they are private, you need special methods known as accessor methods so a client programmer can make use of the instance variables. Accessor methods are also known as "gettors".
In the following example, an error occurs because the client programmer cannot legally access the myAge instance variable
// client program
public class BugClient
{
public static void main(String[] args)
{
Bug nemo = new Bug();
System.out.println(nemo.myAge); // error since myAge is private in the regular class
}
}
// regular class
public class Bug
{
private int myAge;
}
- So the following example, fixes that problem since there is a public accessor method that the client programmer can use to access (and display) the Bug's age
// client program
public class BugClient
{
public static void main(String[] args)
{
Bug nemo = new Bug();
System.out.println(nemo.getAge()); // this works!
}
}
// regular class
public class Bug
{
private int myAge;
// accessor method
public int getAge()
{
return myAge;
}
}
The method call nemo.getAge() causes the getAge method to execute and it returns the private myAge to the client. You can access private instance variables within the Bug class itself. You just cannot access private instance variables in another regular class such as Turtle or a client class such as BugClient.
- It is good style to name an access method with the prefix get in front of the name of the instance variable that is being accessed. So here is a more complete version of a Bug class with three instance variables and three accessor methods:
public class Bug
{
private int myAge;
private int myX;
private int myY;
public int getAge()
{
return myAge;
}
public int getX()
{
return myX;
}
public int getY()
{
return myY;
}
}
- Constants are instance variables that cannot be changed when a program executes. They are declared by typing the keyword final in the declaration statement. You must initialize a constant to a value when it is declared as in
public static final double PI = 3.14;
Constants are public instead of private since they are meant to be used by other programmers. Constants should be typed with uppercase letters and underscores separating words.
Normally you need to use the word static in the declaration statement for a constant as well.
Since constants are public, you do not need accessor methods for constants as in
// client program
public class BugClient
{
public static void main(String[] args)
{
Bug nemo = new Bug();
System.out.println(Bug.BUG_LIFE_EXPECTANCY); // because the constant is public this is legal without using an accessor method
// because the constant is static we use Bug instead of nemo in front of the dot operator ( . )
}
}
// regular class
public class Bug
{
private int myAge;
public static final int BUG_LIFE_EXPECTANCY = 9;
public int getAge()
{
return myAge;
}
}
Objective #5: Add modifier methods to a class so client programmers can modify instance variables of an object.
- Accessor methods only give client programmers the ability to access private instance variables. Another type of instance method known as modifier methods should be added to a regular class to make it fully functional. Modifier methods are usually named by adding the prefix set in front of the name of the instance variable. Modifier methods are also known as mutator methods and setters.
- Each object that is instantiated in a client program can store its own unique value in an instance variable. For example, the myAge property
of turtleA could
store a value of 10 while the myAge property
of turtleB may contain a value
of 40.
- Here is a simple Bug class that has one instance variable, one accessor method, and one modifier method
// client program
public class BugClient
{
public static void main(String[] args)
{
Bug nemo = new Bug();
nemo.setAge(5);
System.out.println(nemo.getAge()); // this displays 5
Bug flik = new Bug();
System.out.println(flik.getAge()); // this displays 0 since flik's age wasn't modified
}
}
// regular class
public class Bug
{
private int myAge;
public int getAge()
{
return myAge;
}
public void setAge(int num)
{
myAge = num;
}
}
Notice that void is the return type of a modifier method.
In the example above, the value 5 is passed as an actual parameter and plugs into the formal parameter num. The assignment statement myAge = num; assigns the value 5 to the instance variable myAge which is updated for nemo so that the value displays later in the client program when the acccessor method getAge is called.
Objective #6: Add "interesting" methods to a class.
- You can implement methods in a class that are not accessors and modifiers. I call these "interesting" methods though you will not see them referred in that way on the AP exam.
Here is an example of a Bug class that has an interesting method
// regular class
public class Bug
{
private int myAge;
final public static int BUG_LIFE_EXPECTANCY = 9;
// accessor
public int getAge()
{
return myAge;
}
// modifier
public void setAge(int num)
{
myAge = num;
}
// interesting method
public int computeLife()
{
int num = BUG_LIFE_EXPECTANCY - myAge;
return num;
}
}
It is legal to access myAge from within the Bug class even though it is private.
In a client program this code segment would be used to call the computeLife instance method
Bug nemo = new Bug();
nemo.setAge(5);
System.out.println(nemo.computeLife()); // displays 4 since 9 minus 5 is 4
Note that the computeLife method could be written in this way
public int computeLife()
{
int num = 0; // local variable temporarily used to store the life expectancy
num = BUG_LIFE_EXPECTANCY - this.myAge;
return num;
}
since the keyword this can be used within a regular class to refer to the implicit parameter that is calling the method (i.e. nemo in this case)
The computeLife method could also be written by using the accessor method instead of directly accessing the myAge instance variable but notice that the empty parentheses are requird with getAge() since it is a method:
public int computeLife()
{
int num = 0; // local variable temporarily used to store the life expectancy
num = BUG_LIFE_EXPECTANCY - getAge();
return num;
}
The computeLife method could also be written without the declaration statement of the local variable named num and this can be used with instance methods just as it is used with instance variables:
public int computeLife()
{
return BUG_LIFE_EXPECTANCY - this.getAge();
}