Example: We are going to create a student class that holds information about the student and performs actions about the student.
public class Student
{
//Our Fields which are the information/characteristics about our objects
private String name;
private int test1;
private int test2;
private int test3;
//Constructors
public Student() //no-args consructor or default constructor
{
name = "";
test1 = 0;
test2 = 0;
test3 = 0;
}
public Student(String n, int t1, int t2, int t3) //initialize constructor
{
name = n;
test1 = t1;
test2 = t2;
test3 = t3;
}
public Student(Student other)
{
name = other.name;
test1 = other.test1;
test2 = other.test2;
test3 = other.test3;
}
//Accessors
public String getName()
{
return name;
}
public int getTest1()
{
return test1;
}
public int getTest2()
{
return test2;
}
public int getTest3()
{
return test3;
}
//Modifiers
public void setName(String nm)
{
name = nm;
}
public void setTest1(int t1)
{
test1 = t1;
}
public void setTest2(int t2)
{
test2 = t2;
}
public void setTest3(int t3)
{
test3 = t3;
}
//other methods
public int getAverage()
{
return (test1 + test2 + test3)/3;
}
public String toString()
{
return "Name: " + name + "\nTest 1: " + test1 + "\nTest2: " + test2 +
"\nTest3: " + test3;
}
public boolean equals(Object other)
{
Student temp = new Student();
temp = (Student)other;
return (name.equals(temp.name) && test1 ==temp.test1 && test2
==temp.test2 && test3==temp.test3);
}
}
A First Class At the beginning of the course we worked with robot classes in Karel J. Robot. Now it is time to revisit this concept in a more abstract setting. In Object-Oriented Programming design (OOP design), we create and use structures or objects that are capable of storing information and performing actions on that information. We will begin with a class that manages data for a student.
When designing a class, we typically have the following sections that make up that class:
1. Fields
2. Constructors (default, initializing and copy)
3. Methods (accessors, modifiers and output)
Let's look at each section in depth:
Fields (or Instance Variables)
Fields consist of whatever data this class needs to maintain. We declare these variables just like regular variables, with one exception - we put the keyword private in front of them. For example, in the student class, we will maintain a student's name and three test scores, so we declare the following as fields:
private String name;
private int test1, test2, test3;
So what does the keyword private do? By making fields private, we protect their values from outside manipulation. It also means that any attempt to use those variables outside of this file will meet with an undeclared identifier error. In other words, these variables are unknown outside this code (the opposite of private is public, but we will not use that keyword for fields). This is called encapsulation.
Constructors
A constructor is a method whose purpose is to instantiate or construct a new object. It is essentially a means to declare an object in a way similar to the way we declare variables, but involves more detail. Recall that when we declared a new robot object in Karel J. Robot, we had to give the robot a name and some initial information (coordinates, direction and number of beepers). That statement used a Robot constructor. In our example, we will construct a Student. This requires giving the student a name as well as values for the three test scores.
There are three types of constructors:
Default - sets fields to default values
Initializing - sets fields to user-defined values
Copy - sets fields to values copied from another object of the same type
Important: If no constructors are given, Java provides the class with a default constructor which sets all fields to default values.
Default values: 0 for numbers, false for booleans, and null for objects. Remember that if you try to use a method on a null object, you will get a null pointer exception.
Methods
The methods of a class give the programmer functions that can be performed on and by the object. Recall that in Karel J. Robot we created methods to give the robot new skills to perform specific tasks. It is the same here, only more abstract.
As with constructors, there are several types of methods:
Accessors - allow the client code access to the fields
Modifiers - allow the client code to safely make changes to the values of the fields
Other - perform various miscellaneous actions on the object (either public or private) including such tasks as output of the object
Client Code
Now that we have seen the code for the Student class, we need to learn how to use or implement the methods in a client program. A client is a program that makes use of a class. To state it another way, the program is a client of the class.
When writing client code, we must first declare an object of the type defined in the class. That means we will first make use of one of the class's constructors. Since there are two constructors, there are two ways to construct a student object. See the examples below.
Student s1 = new Student();
Student s2 = new Student("Bob", 82, 89, 64);
Using the new keyword automatically calls a constructor (One of the constructors must match exactly those parameters). The first statement above utilizes the default constructor. Since no initial values were given to this object, it received the default values (those specified in the default constructor). For our design, that means the object s1has its name initialized as an empty string and all 3 of its test scores are set to zero.
In the second statement, the object s2 is given initial values for the name and the test scores (the scores are assigned in the order they are given). This is an example of the use of an initializing constructor.
In general, the form of a constructor is
ClassName identifier = new ClassName(list of values - if any);
Accessor Methods
Once an object is instantiated, we can make use of its built-in methods. Some of the methods in our class are accessor methods, which are used to access the private fields. Typically, the names of accessor methods begin with get, since they are used to get data from the object. One such method in our class is getName(). The method getName() returns the name for the given Student object. Its method header is shown below.
public String getName()
What is this method header saying? First it tells us that this method is public, meaning that it can be invoked in any client of the Student class (a private method could only be used within the context of the class). Second, the use of the keyword String means that the method will return a String value (if a method only performs a task and does not have a return value, we make it a void method). Lastly, getName() is the name of the method and must adhere to the same naming rules for all identifiers. Since the parentheses are empty, this method has no parameters or input values. In general, method headers take this form:
public returnType methodName(parameters)
The returned value of a method has to go somewhere. Since this method is returning a String, the value has to go to a String variable or to an output statement. Here are two ways to invoke this method for the Student object s2:
System.out.println(s2.getName());
String studentName = s2.getName());
Modifier Methods
A method that safely changes the value of one of the private fields is called a modifier. The Student class method setName() is an example. The purpose of this method is to allow the user to change the internal name of a Student object. See the header of setName() below:
public void setName(String nm)
This method header tells us that it is public and void (has no return value). It is called setName and has one parameter, a String. This means we must supply the method call with a String that is intended to become the new name of the Student object. Note that the identifier nm is a temporary placeholder for this value and the value in nm gets transferred internally to the field name in the Student class.
Other Methods
In the Student class, there are other methods that are neither accessors or modifiers. These are getAverage(), equals() and toString(). These are examples of methods that perform tasks on the fields. Let's look at each one individually.
While getAverage() appears to be an accessor due to its name, it doesn't actually access data - it simply supplies more information about the data. Specifically, it computes and returns the average of the three test scores as a decimal.
The method toString() gives the class a way to output a visual representation of the object. It does so by returning a String value with all of the data from the object, including the average of the tests (using getAverage()). That String is displayed using a System.out.println() statement. For example, if we have a Student object named s, we can do the following:
System.out.println(s);
When an object is placed in a System.out.println()statement, the toString() method is automatically invoked and the output described in that method is displayed.
Note: The toString() method actually comes from the “Cosmic Superclass” Object. So all of our classes have a toString method that is not very useful, but we change it to make it useful to us.
The equals() method is a common method that we will use to determine if two objects of our class are equal. For two students to be equal, they have to have the same name and the same test scores for test1, test2, and test3.
Note: == works for checking to see if two integers are equal but does check to see if the contents of two objects are equal (i.e. Strings, Students). Instead == checks to see if the two objects have the same address (which is not really helpful).
Example:
String s = “Sapp”;
String t = “Sapp”;
System.out.println(s==t); //will yield false because they are not the same object
Note: The equals method comes from the “Cosmic Superclass” Object – just like the toString() method so we override this method. The equals method originally compares the addresses of two objects to see if they are the same object.
Important: We truly need to override equals(Object other) for equals method to work later on. Otherwise the equals method will be overloaded! This could be a problem later in programs where the original equals method is called.
Example:
public class SAAStudent extends Student
{
private String artsMajor;
public SAAStudent(String n, int t1, int t2, int t3, String a)
{
super(n, t1, t2, t3);
artsMajor = a;
}
public SAAStudent(String a)
{
super();
artsMajor = a;
}
public SAAStudent()
{
this("John Doe", 0,0,0,"None");
}
public String toString()
{
String temp = super.toString() + artsMajor;
return temp;
}
}
Subclass (The “Is A” relationship):
The “extends” keyword signifies that SAAStudent is a subclass of Student. Subclasses maintain the “Is A” relationship. An SAA student “is a” student.
Important: Subclasses inherit fields and methods from their superclass. However, they do not inherit the constructors and they do not have direct access to the fields of the superclass (we use acccessors for this).
Super Keyword for Constructors:
As previously mentioned, subclasses do not inherit constructors, BUT they can invoke a constructor of its superclass. To do this, the word super is used.
In the initialize constructor, a call is made to super(n, t1, t2,t3). For this to work, there must be a constructor in the superclass that takes in a String then three integers in that order.
Note: If you use the super keyword in a constructor it must be the first statement.
Important: One of the superclass’s constructors is always called, but you don’t have to have an explicit super statement. If there is no explicit call to super, then superclass’s no-args constructor is called by default.
If the superclass does not have a no-args constructor you will get an error message(Cannot find symbol: Constructor…).
The “this” keyword in a constructor:
In the SAAStudent’s no-args constructor, a call is made:
this("John Doe", 0,0,0,"None");
This is using one of the other constructors (of the same class) by sending those parameters to the constructor that takes in a String followed by three ints followed by a String in that order.
This does the same thing as:
public SAAStudent()
{
name = “John Doe”;
test1 = 0;
test2 = 0;
test3 = 0;
artsMajor = “none”;
}
Association (The “Has A” relationship):
We already talked about how a tester class is a client class to a class because it uses the class. Another example of a client class is a class that has a field that is an object of another class.
We will look at an example of a Classroom class that has 3 students (one Student and two SAAStudents).
Example:
public class Classroom
{
private Student alice;
private SAAStudent bob;
private SAAStudent cindy;
public Classroom(Student s1, SAAStudent s2, SAAStudent s3)
{
alice = s1;
bob = s2;
cindy = s3;
}
public double getAverage()
{
double average = (alice.getAverage() + bob.getAverage() +
cindy.getAverage())/3.0;
return average;
}
public String toString()
{
return "The names of the student in the class are " + alice.getName() + ", " +
bob.getName() + ", " + cindy.getName();
}
}
A classroom has a field that is a student, so a Classroom has a Student. This client relationship is called a “has-a” relationship.
Scope of Variables (Local Variables vs. Fields)
Scope refers to the parts of code where a variable can be referenced. In the getAverage() method, a local variable called average is created. The variable average can only be referenced inside this method. If you tried System.out.println(average), outside of the getAverage() method, you would get a syntax error.
The scope for a field is the entire class.
Helpful Hint to remember: A variable can only be referenced inside the braces that contain it. For example, the braces that contain the fields are the braces of the class.
Tester Class:
What should the following output be?
public class ClassroomTester
{
public static void main(String[] args)
{
Student first = new Student("John Jacobs", 70, 80, 90);
SAAStudent second = new SAAStudent("Val Kilmer", 50, 50, 50, "Visual");
SAAStudent third = new SAAStudent("Steve Ricciardi", 100, 90, 95, "Dance");
Classroom one = new Classroom(first, second, third);
System.out.println(one.getAverage());
System.out.println(one);
}
}
Answer:
75.0
The names of the student in the class are John Jacobs, Val Kilmer, Steve Ricciardi
Static Variables Example
public class Student
{
// Instance variable: belongs to each individual object
private String name;
// Static variable: shared across all objects
private static int totalStudents = 0;
// Constructor
public Student(String name)
{
this.name = name;
totalStudents++; // Increase static count whenever a new student is created
}
// Instance method
public void printName()
{
System.out.println("Student name: " + name);
}
// Static method
public static void printTotalStudents()
{
System.out.println("Total students: " + totalStudents);
}
}
public class Main
{
public static void main(String[] args)
{
Student s1 = new Student("Alice");
Student s2 = new Student("Bob");
s1.printName(); // prints "Student name: Alice"
s2.printName(); // prints "Student name: Bob"
Student.printTotalStudents(); // prints "Total students: 2"
}
}
Note: We call the printTotalStudents method from the class (Student) not a Student object. We call static methods from the class. (i.e. Math.random()).