Ch. 7 | Object-Oriented Programming, Part 2: User-Defined Classes
Writing Constructors
- a constructor is a special method that is called when an object is instantiated using the new keyword - a class can have several constructors; the job of the class constructors is to initialize the fields of the new object - the constructor can either assign default values to the instance variables or the constructor can accept initial values from the client through parameters The syntax for a constructor follows: accessModifier ClassName( parameter list ) { // constructor body } Notice that a constructor has the same name as the class and has no return type—not even void; its important to use the public access modifier for the constructors so that applications can instantiate objects of the class
Public Accessor Method
- because clients cannot directly access private instance variables of a class, classes usually provide public accessor methods for the instance variables. - the getter (get) method takes no arguments and simply returns the current value of the instance variable; thus, the return type is the same data type as the instance variable These methods have a simple, almost trivial, standard form: public returnType getInstanceVariable( ) { return instanceVariable; }
Static Class Variables
- classes can define class variables, which are created only once, when the JVM initializes the class - class variables exist before any objects are instantiated, and each class has only one copy of its class variables - static variables that are constants are usually declared to be public because they typically are provided to make it easier to use the class - if, however, you define a static variable for your class that is not a constant, it is best to define it as private and provide accessor and mutator methods, as appropriate, for client access to the static variable - when you define a static variable for your class, its accessor and mutator methods must be defined as static methods, also called class methods Methods that are defined to be static are subject to the following important restrictions: static methods can reference only static variables. static methods can call only static methods. static methods cannot use the object reference this.
User Defined Class
- classes that encapsulate data and methods for use by applications or service classes are called user-defined classes because the user, rather than java, creates them - classes encapsulate the data and functionality for a person, place, or thing, or more generally, an object - use a noun for the class name, and start the class name with a capital letter - inside the curly braces we define the data of the class, called its fields, and the methods; the fields and methods of a class are called the members of the class - an important function performed by the class methods is maintaining the values of the class data for the client programs, which are the users of the class, in that the clients create objects and call the methods of the class For example, a class might be defined to represent a student, a college, or a course. To define a class, we use the following syntax: accessModifier class ClassName { // class definition goes here }
identifierList
- consists of one or more names for instance variables of the same data type and can optionally assign initial values to the instance variables - if more than one instance variable name is given, a comma is used as a separator and, by convention, identifier names for instance variables are nouns and begin with a lowercase letter; internal words begin with a capital letter - each instance variable and class variable must be given a name that is unique to the class
Access Modifiers
- the accessModifier for a class will be public, and we know that a public class must be stored in a file named ClassName.java where ClassName is the name of the class Access Modifier | Class or Member can Be Referenced by ... public | methods of the same class, as well as methods of other classes private | methods of the same class only protected | methods in the same class, as well as methods of subclasses and methods in classes in the same package no modifier (package access) | methods in the same package or same folder only Example: Let's start to define a class that represents an automobile, which we can use to calculate miles per gallon. We'll name the class Auto, and we'll use the public access modifier so that any application can use this class. The class header will look like the following: public class Auto { } Define instance variables to hold the model of the automobile, the number of miles the auto has been driven, and the gallons of gas used. As a result, our Auto class definition now becomes the following: public class Auto { private String model; private int milesDriven; private double gallonsOfGas; }
Writing Class Methods
- the method caller sends arguments, or actual parameters, to the method; the method refers to these arguments as its formal parameters - like instance variables, the method name should begin with a lowercase letter, with internal words beginning with a capital letter; typically method names are verbs - the access modifier for methods that provide services to the client will be public; methods that provide services only to other methods of the class are typically declared to be private - the return type of a method is the data type of the value that the method returns to the caller, the return type can be any of Java's primitive data types, any class type, or void; methods with a return type of void do not return a value to the caller - forgetting to enclose the body of a method in curly braces generates one or more compiler errors Methods have this syntax: accessModifier returnType methodName( parameter list ) // method header { // method body } where parameter list is a comma-separated list of data types and variable names.
Class Scope
- the same name cannot be used for more than one instance variable or class variable
Default Initial Values of Instance Variables
Data Type | Initial Value byte | 0 short | 0 int | 0 long | 0 float | 0.0 double | 0.0 char | null character ('\u0000') boolean | false object reference | null if we do provide a constructor, any instance variables our constructor does not initialize will still be given the predefined default value. Also, if we do provide a constructor, the compiler no longer generates a default constructor for us
Useful Methods for enum Objects
Return Type | Method Name + Argument List int | compareTo( Enum eObj ) - compares two enum objects and returns a negative number if this object is less than the argument, a positive number if this object is greater than the argument, and 0 if the two objects are the same boolean | equals( Object eObj ) - returns true if this object is equal to the argument eObj; returns false otherwise int | ordinal( ) - returns the numeric value of the enum object; by default, the value of the first object in the list is 0, the value of the second object is 1, and so on String | toString( ) - returns the name of the enum constant enum | valueOf( String enumName ) - static method that returns the enum object whose name is the same as the String argument enumName Enum Method Example: public class EnumDemo { public enum Days { Sun, Mon, Tue, Wed, Thur, Fri, Sat }; public static void main( String [ ] args ) { Days d1, d2; // declare two Days object references d1 = Days.Wed; d2 = Days.Fri; System.out.println( "Comparing objects using equals" ); if ( d1.equals( d2 ) )System.out.println( d1 + " equals " + d2 ); else System.out.println( d1 + " does not equal " + d2 ); System.out.println( "\nComparing objects using compareTo" ); if ( d1.compareTo( d2 ) > 0 ) System.out.println( d1 + " is greater than " + d2 ); else if ( d1.compareTo( d2 ) < 0 ) System.out.println( d1 + " is less than " + d2 ); else System.out.println( d1 + " is equal to " + d2 ); System.out.println( "\nGetting the ordinal value" ); System.out.println( "The value of " + d1 + " is " + d1.ordinal( ) ); System.out.println( "\nConverting a String to an object" ); Days day = Days.valueOf( "Mon" ); System.out.println( "The value of day is " + day ); } } Output: Comparing objects using equals Wed does not equal Fri Comparing objects using compareTo Wed is less than Fri Getting the ordinal value The value of Wed is 3 Converting a String to an object The value of day is Mon
Graphical Objects
The Sprite Class Example: import javafx.scene.canvas.*; import javafx.scene.paint.*; public class Sprite { private int sX; private int sY; private double scale; /** default constructor * sX = sY = 0; scale is set to 1 */ public Sprite( ) { scale = 1; } /* overloaded constructor accepts values for starting x and y coordinates and scale*/ public Sprite( int sX, int sY, double scale ) { setCoordinates( sX, sY ); setScale( scale ); } /* setCoordinates * accepts new values for starting x and y; * returns a reference to this object */ public Sprite setCoordinates( int sX, int sY ) { this.sX = sX; this.sY = sY; return this; } /* mutator for scale * returns a reference to this object */ public Sprite setScale( double scale ) { this.scale = ( scale > 0 ? scale : this.scale ); return this; } /* draw method * draws Sprite at current sX and sY * multiplying lengths by scale * accepts GraphicsContext for canvas */ public void draw( GraphicsContext gc ) { gc.setFill( Color.CORAL ); // body gc.fillOval( sX, sY + 15 * scale, 90 * scale, 120 * scale ); gc.setFill( Color.DARKGOLDENROD ); // hat gc.fillRect( sX + 23 * scale, sY, 45 * scale, 22 * scale ); gc.setStroke( Color.DARKGOLDENROD ); // hat brim gc.setLineWidth( 3 ); gc.strokeLine( sX, sY + 23 * scale, sX + 90 * scale, sY + 23 * scale ); gc.setFill( Color.CHOCOLATE ); // eye 67 gc.fillOval( sX + 60 * scale, sY + 45 * scale, 18 * scale, 12 * scale ); gc.setFill( Color.DARKSALMON ); // feet gc.setLineWidth( 1 ); gc.fillOval( sX + 45 * scale, sY + 125 * scale, 45 * scale, 12 * scale ); gc.strokeOval( sX + 45 * scale, sY + 125 * scale, 45 * scale, 12 * scale ); gc.fillOval( sX + 27 * scale, sY + 127 * scale, 45 * scale, 12 * scale ); gc.strokeOval( sX + 27 * scale, sY + 127 * scale, 45 * scale, 12 * scale ); } } The Sprite Client Class: import javafx.application.Application; import javafx.scene.canvas.GraphicsContext; import javafx.stage.Stage; public class SpriteClient extends Application { private Sprite s1, s2, s3; @Override public void start( Stage stage ) { GraphicsContext gc = JIGraphicsUtility.setUpGraphics( stage, "Sprites", 700, 400 ); s1 = new Sprite( 100, 50, .5 ); s2 = new Sprite( 225, 100, 1 ); s3 = new Sprite( ).setCoordinates( 400, 150 ).setScale( 1.5 ); s1.draw( gc ); s2.draw( gc ); s3.draw( gc ); } public static void main( String [ ] args ) { launch( args ); } }
Access Restrictions for static and Non-static Methods
| Static method | Non-Static method Access instance variables? | no | yes Access static class variables? | yes | yes Call static class methods? | yes | yes Call non-static instance methods? | no | yes Use the reference this? | no | yes
Rules of Scope:
A method in a class can access: the instance variables of its class any parameters sent to the method any variable the method declares within its body from the point of declaration until the end of the method or until the end of the block in which the variable was declared, whichever comes first any methods in the class
Enumeration Types
- enumeration types are designed to increase the readability of programs - the enumeration type enum is a special kind of class declaration; it allows us to define a set of named constant objects that can be used instead of numbers in a program - enum types are useful for managing ordered sets where each member of the set has a name; examples are the days of the week, months of the year, and playing cards. To represent these sets in a program, we often use numbers, such as 1 through 7 for days of the week or 1 through 12 for months of the year - the enum functionality is built into java.lang, so we can define enum types without using an import statement The syntax for creating a set of enum objects is: enum EnumName { obj1, obj2, . . . }; where obj1, obj2, etc. are names for the constant objects. For example, the following statement defines an enum type to represent the days of the week: enum Days { Sun, Mon, Tue, Wed, Thur, Fri, Sat }; When that statement is executed, an object is instantiated for each name in the list. Each name in the list, therefore, is a reference to an object of the enum type Days.
Instance Variable
- holds the data for each object of that class; the instance variables represent the properties of the object - define instance variables of a class as private so that only methods of the class will be able to set or change their values; private modifier is typically used for the nonconstant instance variables of the class which permits only methods of the same class to set or change the values of the instance variables Instance variables are defined using the following syntax: accessModifier dataType identifierList; The following statements are examples of instance variable definitions: private String name = ""; // an empty String private final int PERFECT_SCORE = 100, PASSING_SCORE = 60; private int startX, startY, width, height;
Package
- is a collection of related classes that can be imported into programs - an individual can also create their own packages, which allows us to reuse a class without needing to physically store that class in the same folder as our other source files; we create the package and import the class from that package into our source file
Mutator Method
- it is customary to provide a public mutator method for any instance variable that the client will be able to change - because the method names usually start with "set," mutator methods are often called setters. - declare mutator methods as public so that client programs can use the methods to change the values of the instance variables - it doesn't return a value, so declare the return type as void The general form of a mutator method is the following: public void setInstanceVariable( dataType newValue ) { // validate newValue, then assign to the instance variable }
Encapsulation
- keeping details (like data and procedures) together in one part of a program so that programmers working on other parts of the program don't need to know about them - the class provides a protective shell around the data
Data Hiding
- maintains activities at different security levels to separate these levels from each other - the programmer will not publish the implementation (or code) of the class, however; in other words, the programmer will publish the APIs of the methods, but not the method bodies - a client program can use the class without knowing how the class is implemented, and we, as class authors, can change the implementation of the methods as long as we don't change the interface, or APIs
toString and equals Method
- the toString method is called automatically when an object reference is used as a String; the function of the toString method is to return a printable representation of the object data - the equals method is designed to compare two objects for equality; that is, it typically returns true if the corresponding instance variables in both objects are equal in value; the equals method takes an Object reference parameter that is expected to be an Auto reference and returns true if the values of its fields are equal to the values of the fields of this Auto object, false otherwise Use the same header as the methods in the Object class but provide a new method body. This is called overriding a method. The APIs of the toString and equals methods are the following: public String toString( ) public boolean equals( Object o ) The instanceof Operator - syntax: objectReference instanceof ClassName, Operation: evaluates to true if objectReference is of ClassName type; false otherwise **the class methods should communicate directly with the client, and the client should handle the communications with the user**
Implicit Parameter
- when a method begins executing, the JVM sets the object reference, this, to refer to the object for which the method has been called - when a method references an instance variable, it will access the instance variable that belongs to the object that the implicit parameter references; by default, any instance variable referred to by a method is considered to be this.instanceVariable Some programmers would code the setModel mutator as follows: public void setModel( String model ) { this.model = model; } Some programmers, particularly in the Android community, would code the setModel mutator so that it returns a reference to this Auto, as follows: public Auto setModel( String model ) { this.model = model; return this; }
Communication Flow among the User, Client and Class
1) class methods should communicate only with the client 2) the client, in turn, communicates with the user 3) the class methods should not output anything; the decision on what to output should be left to the client of the class 4) the client accepts requests from the user, calls the class methods and receives the returned values from the class, and then communicates those results to the user
HTML Files Generated by Javadoc
File Name | Short Description Auto.html | Auto class documentation (without frames) allclasses-frame.html | List of the classes with links (with frames) allclasses-noframe.html | List of the classes with links (without frames) constant-values.html | Constants of the class with links index.html | Auto class documentation (with frames) package-frame.html | Frame for this package package-list | List of packages package-summary.html | Class hierarchy script | Javascript file stylesheet.css | Style sheet To write comments that will be included in the Javadoc documentation, we use a special form of block comment ahead of any class, field, constructor, or method. The syntax for including Javadoc comments follows: /** Javadoc comment here */ As we already know, the syntax for a Java block comment is: /* Java block comment here */ We recommend the following syntax: /** * A Javadoc comment here * A second Javadoc comment here * . . . . */ Class documentation comprises two parts: A description section A tag section Javadoc recognizes two types of tags: block tags and inline tags Selected Javadoc Tags: Tag | Common Syntax | Explanation @param | @param variableName description | Adds a parameter to the parameter section @return | @return text | Adds a description for the return type
The Auto Client Example: Version 3
public class Auto { // instance variables private String model; // model of auto private int milesDriven; // number of miles driven private double gallonsOfGas; // number of gallons of gas // Default constructor: // initializes model to "unknown"; // milesDriven is autoinitialized to 0 and gallonsOfGas to 0.0 public Auto( ) { model = "unknown"; } // Overloaded constructor: // allows client to set beginning values for model, milesDriven, and gallonsOfGas public Auto( String startModel, int startMilesDriven, double startGallonsOfGas ) { model = startModel; setMilesDriven( startMilesDriven ); setGallonsOfGas( startGallonsOfGas ); } // Accessor method: // returns current value of model public String getModel( ) { return model; } // Accessor method: // returns current value of milesDriven public int getMilesDriven( ) { return milesDriven; } // Accessor method: // returns current value of gallonsOfGas public double getGallonsOfGas( ) { return gallonsOfGas; } // Mutator method: // allows client to set model public void setModel( String newModel ) { model = newModel; } // Mutator method: // allows client to set value of milesDriven; // if new value is not less than 0 public void setMilesDriven( int newMilesDriven ) { if ( newMilesDriven >= 0 ) milesDriven = newMilesDriven; } // Mutator method: // allows client to set value of gallonsOfGas; // if new value is not less than 0.0 public void setGallonsOfGas( double newGallonsOfGas ) { if ( newGallonsOfGas >= 0.0 ) gallonsOfGas = newGallonsOfGas; } }
The Auto Class Example, Version 1:
public class Auto { // instance variables private String model; // model of auto private int milesDriven; // number of miles driven private double gallonsOfGas; // number of gallons of gas // Default constructor: // initializes model to "unknown"; // milesDriven is autoinitialized to 0 // and gallonsOfGas to 0.0 public Auto( ) { model = "unknown"; } // Overloaded constructor: // allows client to set beginning values for model, milesDriven, and gallonsOfGas. public Auto( String startModel, int startMilesDriven, double startGallonsOfGas ) { model = startModel; // validate startMilesDriven parameter if ( startMilesDriven >= 0 ) milesDriven = startMilesDriven; // validate startGallonsOfGas parameter if ( startGallonsOfGas >= 0.0 ) gallonsOfGas = startGallonsOfGas; } }
The Auto Class Example: Version 2
public class Auto { // instance variables private String model; // model of auto private int milesDriven; // number of miles driven private double gallonsOfGas; // number of gallons of gas // Default constructor: // initializes model to "unknown"; // milesDriven is autoinitialized to 0 and gallonsOfGas to 0.0 public Auto( ) { model = "unknown"; } // Overloaded constructor: // allows client to set beginning values for model, milesDriven, and gallonsOfGas. public Auto( String startModel, int startMilesDriven, double startGallonsOfGas ) { model = startModel; // validate startMilesDriven parameter if ( startMilesDriven >= 0 ) milesDriven = startMilesDriven; 33 // validate startGallonsOfGas parameter if ( startGallonsOfGas >= 0.0 ) gallonsOfGas = startGallonsOfGas; } // Accessor method: // returns current value of model public String getModel( ) { return model; } // Accessor method: // returns current value of milesDriven public int getMilesDriven( ) { return milesDriven; } // Accessor method: // returns current value of gallonsOfGas public double getGallonsOfGas( ) { return gallonsOfGas; } }
The Auto Client Example, Version 2:
public class AutoClient { public static void main( String [ ] args ) { Auto sedan = new Auto( ); String sedanModel = sedan.getModel( ); int sedanMiles = sedan.getMilesDriven( ); double sedanGallons = sedan.getGallonsOfGas( ); System.out.println( "sedan: model is " + sedanModel + "\n miles driven is " + sedanMiles + "\n gallons of gas is " + sedanGallons ); Auto suv = new Auto( "Trailblazer", 7000, 437.5 ); String suvModel = suv.getModel( ); int suvMiles = suv.getMilesDriven( ); double suvGallons = suv.getGallonsOfGas( ); System.out.println( "suv: model is " + suvModel + "\n miles driven is " + suvMiles + "\n gallons of gas is " + suvGallons ); } } Ouput: sedan: model is unknown miles driven is 0 gallons of gas is 0.0 suv: model is Trailblazer miles driven is 7000 gallons of gas is 437.5
The Auto Client Example, Version 3:
public class AutoClient { public static void main( String [ ] args ) { Auto suv = new Auto( "Trailblazer", 7000, 437.5 ); // print initial values of instance variables System.out.println( "suv: model is " + suv.getModel( ) + "\n miles driven is " + suv.getMilesDriven( ) + "\n gallons of gas is " + suv.getGallonsOfGas( ) ); // call mutator method for each instance variable suv.setModel( "Sportage" ); suv.setMilesDriven( 200 ); suv.setGallonsOfGas( 10.5 ); // print new values of instance variables System.out.println( "\nsuv: model is " + suv.getModel( ) + "\n miles driven is " + suv.getMilesDriven( ) + "\n gallons of gas is " + suv.getGallonsOfGas( ) ); // attempt to set invalid value for milesDriven suv.setMilesDriven( -1 ); // print current values of instance variables System.out.println( "\nsuv: model is " + suv.getModel( ) + "\n miles driven is " + suv.getMilesDriven( ) + "\n gallons of gas is " + suv.getGallonsOfGas( ) ); } } Output: suv: model is Trailblazer miles driven is 7000 gallons of gas is 437.5 suv: model is Sportage miles driven is 200 gallons of gas is 10.5 suv: model is Sportage miles driven is 200 gallons of gas is 10.5
The Auto Client Example, Version 1:
public class AutoClient { public static void main( String [ ] args ) { System.out.println( "Instantiate sedan" ); Auto sedan = new Auto( ); System.out.println( "\nInstantiate suv" ); Auto suv = new Auto( "Trailblazer", 7000, 437.5 ); System.out.println( "\nInstantiate mini" ); // attempt to set invalid value for gallons of gas Auto mini = new Auto( "Mini Cooper", 200, -1.0 ); } }