cs176:501b:introduction_to_classes_and_oop
Table of Contents
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.
- Classes model problems. One advantage of encapsulating data and methods in a class is to make programming objects that reflect “objects” in the problem domain. If your problem deals with orders and products, then you'll very likely have classes called Order and Product.
- Classes reduce complexity. Another advantage of classes is reducing complexity. Complexity limits the size and reliability of programs. Complexity is reduced by increasing cohesion (putting things together that belong together) and reducing coupling (interconnections). The proper use of classes can make large improvements in both of these.
- 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”.
- Examples showing classes as groups of attriutes:
- Instead of working with simple temperature numbers, you might have TemperatureMeasurement objects, which have several attributes: the temperature, the time, method of temperature detection, and the location.
- A Student class would represent information about a student: name, id, address, … Each object of this class would have a data about a specific student.
- A Classroom class would have information about a classroom's building, room number, capacity, whether it has a projector, etc.
- 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
- Typically there is one class definition per file, so this would be stored in Student.java .
// 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
- A class is a template that defines what attributes an object can have. You make one class definition, then create objects of that class using the “new” keyword.
- 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
- Unlike local variables in a method, fields do have default values (like the default values in arrays).
- Object references are null, numbers are zero, and booleans are 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
- A class defines which fields an object has in it. You need to use “new” to create a new object from the class by allocating memory and assigning a default value to each field. A little later you will learn how to write a “constructor” to control the initialization.
- The following example creates a couple of objects of a class:
// 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
- The “private” keyword.
- Methods defined without the “static” keyword are instance methods.
- Constructor syntax - like a method but with class name and implicit type/value.
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
- To make more reliable software, it's essential to protect the data in an object - insure that it is initialized, and prevent illegal or inconsistent values.
- The key to this is to declare the variables private.
- Private data also reduces potential complexity in programs.
- Risk: Public variables put the integrity of objects at risk.
- Example: Nothing prevents the following bad statements from being executed if the variables are public:
TimeOfDay3 thatTime = new TimeOfDay3(); thatTime.minute = 99; // AVOIDS ANY VALIDITY CHECK
- A couple more examples:
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
- Private data. The key to making classes safer and easier to change is to declare variables private.
- Methods in the same class can use the private variables, but no one outside the class can see them.
- However, if they're private, something must be done to allow getting and setting the values.
- This is done with so called getter and setter methods.
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.
- The Java convention is to begin such method name with “get” or “set” followed by the attribute that should be obtained or set.
- Warning. Getters and setters can be evil.
- Don't simply write getter and setter methods for every private instance variable.
- They can make your code inflexibly dependent on a particular implementation.
- There is often no need for others to know about every private variable.
- Don't write both a getter and setter if both are not appropriate.
- Getter and setter methods do not even need to correspond to specific variables – they provide a user interface to your class, but internally you are free to make changes.
- Example: TimeOfDay3 and DemoTimeOfDay3
// 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
- Avoid bad object initializations.
- Can check for and fix invalid variable values when creating objects.
- Convenience:
- Defining a constructor makes creation of an object easier to write.
Constructor Syntax
- Similar to a method.
- A constructor is similar to a method – it's called like a method, has parameters like a method, and it returns.
- But it must have the same name as the class for which it is a constructor.
- Also, the type and return value are implicit.
- Example: TimeOfDay4 and DemoTimeOfDay4
// 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
- Class variables (instance variables) are always initialized when an object of the class is constructed.
- If no value is assigned to a variable in a constructor, some default value is assigned.
- For int, float or double instance variables, 0 is the default value that is assigned.
- For boolean instance variables, false is the default value that is assigned.
- For object-type instance variables, such as Strings, null is the default that is assigned.
- There is no default value, however, for instance variables that are final; these should be initialized manually in a constructor.
- Example:
// 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
- Since constructors are specialized methods, they can also be overloaded.
- A class can have multiple constructors, and of course, they must all have the same name as the class itself.
- Both the methods and constructor of a class can be overloaded, but it's most common to overload constructors.
- Example: TimeOfDay4 constructor:
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);
- We can add a second TimeOfDay4 constructor that only takes one input parameter (int h) to the TimeOfDay4 class:
//================================================ constructor #2 public TimeOfDay4( int h ) { setHour( h ); }
- To use the new constructor in DemoTimeOfDay4.java, we can do the following:
// Use 1-parameter overloaded TimeOfDay4 constructor: TimeOfDay4 later = new TimeOfDay4( 9 );
- We can also add a TimeOfDay4 constructor that takes no input parameters: the “default” or “no-arg” constructor
//================================================ constructor #3 public TimeOfDay4() { // An empty constructor body is legal. }
- To use this default constructor in DemoTimeOfDay4.java, do this:
// Use default constructor: TimeOfDay4 later = new TimeOfDay4();
- As we expand the TimeOfDay4 class, we may want to add even more constructors:
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
- The default (no-arg) constructor is sufficient to create class objects if you have appropriate setter methods defined.
- Example: To create a TimeOfDay class object with _hour=8 and _minute=35, we could just use the default constructor and the two setter methods:
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.
- In these situations, if you need the default constructor, you have to define it yourself.
cs176/501b/introduction_to_classes_and_oop.txt · Last modified: 2015/01/23 14:49 by jchung