Classes and Object Oriented Programming (OOP)
Introduction to Classes and OOP
Overview
Classes combine data and methods.
A class defines a data type.
Classes correspond to concepts in the problem domain.
Classes reduce complexity by increasing coherence and reducing coupling.
Introduce classes to store data in “value objects.”
Classes versus objects.
How to create objects and assign values to the instance variables (fields).
Good practice: One class per file is the standard.
Terminology
Instance variable = Variable declared in class outside a method. Typically private.
Field = Synonym for instance variable, attribute. Common informal term.
Attribute = Synonym for instance variable, field. Often used in the design phase.
Property = Synonym for instance variable, field. Common term if field is known publicly.
New Java language features
Declaring fields (instance variables).
Using “new” to create an object.
Referencing fields using dot (“.”) notation.
Object-Oriented Programming (OOP) concepts
Class = data + methods. Everything (data and methods) in Java is contained in classes. So far you've been using classes to hold methods (main and perhaps a few other static methods). These methods use local variables, which are completely private to the method, and which disappear when the method returns.
Historical development. Classes can also be used to store data. Historically, programming languages had something similar to classes for grouping data, usually called structs or records. These were used for storing only data, not methods. Eventually, advantages of combining both data and the methods to work on that data were recognized.
Class, object, OOP. The name “class” was almost universally adopted for programming language structure which combines data and methods, object is used for each instance of a class that is created, and the practices that developed around these ideas is called Object-Oriented Programming (OOP).
Value objects - Data-first approach. We'll start with classes that represent data, and then add constructors and methods. Ultimately you will be more concerned with methods than data, and you'll see how (and why) methods are used to completely hide the data implementation.
A class stores the attributes (data) of something
Group values. Classes are used to group a number of related, named, data values associated with an entity. By entity we mean something that is typically a noun when you are talking about a problem you are solving. For example, in a university computing system, you might have a class to represent a student, an instructor, a classroom, a department, a course, a section of a course, ….
Student example. The information you would store about students, would be their name, id, etc. We'll keep this example simple and just save name and id information.
Declare each field. A class contains declarations of the fields (instance variables, attributes) that hold the data associated with a student. These declarations are like declaring a local variable in a method, except that you will also specify the visibility. We'll start by using the visibility modifier public, which lets anyone see them. For example, the following Student class can be used to represent a student. As you go through these notes, we'll make improvements to this class.
public class Student {
public String firstName;
public String lastName;
public int id;
}
A class is a type
Noun. Classes are usually given the name of a noun, and the fields (variables) in it are attributes associated with that noun. Predefined Java classes that you have already used are “String”, which contains the characters in the string and the length, “Array”, which contains the contents of the array and its length(s), etc. These predefined Java classes are used for the programming infrastructure that you need. Many common infrastructure classes are available in the 3000+ predefined Java library classes. But, of course, these don't address your problems.
Objects. Most classes you define will concern your problem domain, where they represent objects (Student, TimeOfDay, Order, …).
Declaring object variables is like declaring any other variable. Use the class name as a type, just as you've used String, int, etc. For example, the following declares two Student variables.
Student bestInClass; // This variable references a Student object.
Student t; // And here is another
These don't have values yet, but we'll do that in the next section.
Does your problem require classes or simple variables?
If the data you are working with, for example a temperature, can be expressed as a simple value and the operations on it are all defined by operators, then just use a simple variable for it (int, double, String, …). Often the data associated with an entity in your problem is not a simple value, but has multiple attributes, like “Student”.
Object-Oriented Design involves deciding which classes you need to represent the things (entities) in your problem. For simple programs, you often use only simple variables, but as programs get larger, you will define more and classes to represent the things you are working with.
Standard practice: One class per file
// File : Student.java
// Purpose: Information about a student
public class Student {
public String firstName; // First name
public String lastName; // Last name
public int id; // Student id
}
Class versus object
Analogy: Cookie cutter and cookies. A cookie cutter is like a class definition. It isn't a cookie, but can be used to create a cookie. Each cookie will have the same attributes (shape), but each cookie can have different values for the attributes (type of dough, thickness, …).
Analogy: Dog and Fido. The concept of Dog is like a class, but there are many possible instances of this class, eg, my dog Fido, or your dog Rover.
Use "new" to create a new object
A class defines what fields (data) an object will have when it's created. When a new “Student” object is created, a block of memory is allocated, which is big enough to hold its three fields – as well as some extra overhead that all objects have.
Student fred;
fred = new Student(); // Create Student object with new.
"new" and parentheses
To create a new object, write “new” followed by the name of the class (eg, Student), followed by parentheses. Later we'll see that we can specify arguments in the parentheses when creating a new objects.
Default field values - null, zero, false
Access public fields with dot notation
The fields (firstName, lastName, id) are data which are stored in each object. Another term for field is instance variable. All public fields can be referenced using dot notation (later we'll see better ways to access and set fields). To reference a field, write the object name, then a dot, then the field name.
Student fred; // Declare a variable to hold a Student object.
//... Create a new Student object for Fred.
fred = new Student(); // Create a new Student object with default values.
fred.firstName = "Fred"; // Set values of the fields.
fred.lastName = "Schwartz";
fred.id = 9950842;
JOptionPane.showMessageDialog(null, "One student is named: "
+ fred.lastName + ", " + fred.firstName);
A class definition is a template for creating objects
// File : TestStudent.java
import javax.swing.*;
public class TestStudent {
public static void main(String[] args) {
Student fred;
Student pupil;
//... Create new Student object with new.
fred = new Student();
fred.firstName = "Fred";
fred.lastName = "Schwartz";
fred.id = 9950842;
//... Create another Student object.
pupil = new Student();
pupil.firstName = JOptionPane.showInputDialog(null, "First name");
pupil.lastName = JOptionPane.showInputDialog(null, "Last name");
pupil.id = Integer.parseInt(JOptionPane.showInputDialog(null, "ID"));
JOptionPane.showMessageDialog(null, "One student is named: "
+ fred.lastName + ", " + fred.firstName
+ "\n and another is named: "
+ pupil.lastName + ", " + pupil.firstName);
}
}
Data Hiding & Constructors
Purpose of this lesson
Make class data private for reliability.
Write getters and setters (“get” and “set” methods) to work with private data.
Instance methods can use instance variables.
To introduce the concept of constructors.
New Java language features
Good Practices
Only define getters (“get” methods) for data that people need to know about.
Create setters (“set” methods) only for data that needs to be changed.
Be consistent with class variable names and the methods used to access them.
More reliable programs using private, getters, and setters
TimeOfDay3 thatTime = new TimeOfDay3();
thatTime.minute = 99; // AVOIDS ANY VALIDITY CHECK
thatTime.minute = userValue; // AVOIDS ANY VALIDITY CHECK
thatTime.minute++; // WHAT HAPPENS AFTER 59?
Solution - private variables + public methods to get or set the private variables
Getters and Setters
The interface to private object attributes.
Naming. If it's appropriate for the user of a class to get or set variable values, the convention is to write public getting and setting methods.
// File : TimeOfDay3.java
// Purpose: A 24 hour time-of-day class to demo intro OOP concepts.
// Issues : Makes variables private, adds getters and setters.
//
public class TimeOfDay3 {
//========================================= instance variables
private int _hour;
private int _minute;
//================================================== getHour
public int getHour() {
return _hour;
}
//================================================== setHour
public void setHour(int h) {
if (h < 0 || h > 23) {
throw new IllegalArgumentException(
"TimeOfDay setHour: Bad hour value: " + h);
}
_hour = h;
}
//================================================ getMinute
public int getMinute() {
return _minute;
}
//================================================ setMinute
public void setMinute(int m) {
if (m < 0 || m > 59) {
throw new IllegalArgumentException(
"TimeOfDay setMinute: Bad minute value: " + m);
}
_minute = m;
}
}
// File : DemoTimeOfDay3.java
// Purpose: Test the TimeOfDay3 class..
//
import javax.swing.*;
public class DemoTimeOfDay3 {
public static void main(String[] args) {
TimeOfDay3 then = new TimeOfDay3();
TimeOfDay3 now = new TimeOfDay3();
// Code goes here to set then to 8:35 :
// Code goes here to set now to 14:05 :
//... Print the hours and minutes of the times.
JOptionPane.showMessageDialog(null,
"From " + then.getHour() + ":" + then.getMinute()
+ " to " + now.getHour() + ":" + now.getMinute());
// THE FOLLOWING WOULD BE ILLEGAL
// now._hour = 99; // Can't reference private variable.
}
}
Constructors
Add a constructor for better object initialization
Constructor Syntax
// File : TimeOfDay4.java
// Purpose: A 24 hour time-of-day class to demo intro OOP concepts.
// Issues : Makes variables private, adds getters and setters.
//
public class TimeOfDay4 {
//========================================= instance variables
private int _hour;
private int _minute;
//================================================ constructor
public TimeOfDay4(int h, int m) {
//... Check values for validity.
if (h < 0 || h > 23 || m < 0 || m > 59) {
throw new IllegalArgumentException(
"TimeOfDay: Bad constructor value: " + h + ":" + m);
}
_hour = h;
_minute = m;
}
//================================================== getHour
public int getHour() {
return _hour;
}
//================================================== setHour
public void setHour(int h) {
if (h < 0 || h > 23) {
throw new IllegalArgumentException(
"TimeOfDay setHour: Bad hour value: " + h);
}
_hour = h;
}
//================================================ getMinute
public int getMinute() {
return _minute;
}
//================================================ setMinute
public void setMinute(int m) {
if (m < 0 || m > 59) {
throw new IllegalArgumentException(
"TimeOfDay setMinute: Bad minute value: " + m);
}
_minute = m;
}
}
// File : DemoTimeOfDay4.java
// Purpose: Test the TimeOfDay4 class.
//
import javax.swing.*;
public class DemoTimeOfDay4 {
public static void main(String[] args) {
// Use constructor:
TimeOfDay4 then = new TimeOfDay4(8, 35);
TimeOfDay4 now = new TimeOfDay4(14, 5);
//... Print the hours and minutes of the times.
JOptionPane.showMessageDialog(null,
"From " + then.getHour() + ":" + then.getMinute()
+ " to " + now.getHour() + ":" + now.getMinute());
// THE FOLLOWING WOULD BE ILLEGAL
// now._hour = 99; // Can't reference private variable
}
}
Constructors & Default Instance Variable Values
// DefVals.java:
// Check default values that are assigned to class instance
// variables.
//
class DefVals {
private int anint;
private int anotherint;
private final int ANINTFINAL;
private double adouble;
private boolean aboolean;
private String astring;
// Default constructor will initialize ANINTFINAL and anint only:
public DefVals() {
ANINTFINAL = -255;
anint = 255;
}
// Use toString() method to show value of all variables:
public String toString() {
String allvalues = "anint: " + anint + "\n" +
"anotherint: " + anotherint + "\n" +
"ANINTFINAL: " + ANINTFINAL + "\n" +
"adouble: " + adouble + "\n" +
"aboolean: " + aboolean+ "\n" +
"astring: " + astring + "\n";
return allvalues;
}
}
// TestDefVals.java:
// Test the DefVals class.
//
public class TestDefVals {
public static void main( String [] args ) {
// Construct DefVals object using default constructor:
DefVals dvobj = new DefVals();
// Use dvobj's toString() method:
System.out.println( dvobj );
// also valid // System.out.println( dvobj.toString() );
}
}
Overloading Methods and Constructors
Overloading Methods
“Overloading”: One or more methods have the same name but have different numbers and/or types of parameters and possibly a different return value.
The method name and parameter list form the method “signature,” so that the program knows which method of an overloaded set of methods you are actually calling.
Overloading Constructors
TimeOfDay4.java contains:
//================================================ constructor #1
public TimeOfDay4(int h, int m) {
// Can use set methods to set _hour and _minute:
setHour( h );
setMinute( m );
}
DemoTimeOfDay4.java contains:
// Use constructor:
TimeOfDay4 then = new TimeOfDay4(8, 35);
TimeOfDay4 now = new TimeOfDay4(14, 5);
//================================================ constructor #2
public TimeOfDay4( int h ) {
setHour( h );
}
// Use 1-parameter overloaded TimeOfDay4 constructor:
TimeOfDay4 later = new TimeOfDay4( 9 );
//================================================ constructor #3
public TimeOfDay4() {
// An empty constructor body is legal.
}
// Use default constructor:
TimeOfDay4 later = new TimeOfDay4();
public class TimeOfDay4 {
//========================================= instance variables
private int _hour;
private int _minute;
// more variables added:
private int _seconds;
private bool twelveHour; // 12-hour clock or 24-hour (military) clock
private String ampm; // either "AM" or "PM"
// More constructors might be added, in addition to more get/set methods:
//
//================================================ constructor #4
public TimeOfDay4( int h, int m, int s ) {
setHour( h );
setMinute( m );
setSecond( s );
}
//================================================ constructor #5
public TimeOfDay4( int h, int m, String ap ) {
setHour( h );
setMinute( m );
setTwelveHour( true );
setAmpm( ap );
//
// Additional get/set methods to be added after this
//
}
More on default constructors
TimeOfDay now = new TimeOfDay();
now.setHour( 8 );
now.setMinute( 35 );
Additional constructors that take input parameters such as TimeOfDay( int h, int m ) make creating objects more convenient, since creating the object and setting object variables can be done in just one line of code.
// This also makes the code easier to understand.
TimeOfDay now = new TimeOfDay( 8, 35 );
If a class has no constructors defined, the Java compiler provides a default constructor at compile time.
If you define your own constructor(s), and none of them is a default (no-arg) constructor, then the compiler does not provide a default constructor.