1.08k likes | 1.23k Views
Unit 4: Java Classes. Kirk Scott. 4.1 Instance Variables, Constructors, and Methods 4.2 Copying and Using Object References 4.3 Input Using the Scanner Class 4.4 The Null Reference. 4.1 Instance Variables, Constructors, and Methods.
E N D
Unit 4: Java Classes Kirk Scott
4.1 Instance Variables, Constructors, and Methods • 4.2 Copying and Using Object References • 4.3 Input Using the Scanner Class • 4.4 The Null Reference
There are three major components of a class definition. • 1. Instance variables (called fields in the API documentation). • 2. Constructors. • 3. Methods.
The following notes will show how to write code for a user designed class, dealing with each of those three parts in order. • In Unit 1 the idea of a class was introduced by means of a cup containing seeds. • This will be the basis for the following example.
In order to be used by a program, a user written class will be public, like a program class. • The term encapsulation refers to the idea that certain parts of an object should not be directly accessible from the outside. • For example, in general it is desirable that instance variables only be accessible by means of methods.
In order to enforce encapsulation, instance variables are declared private. • Shown below is code for a very simple cup class. • It is syntactically correct, but without methods there is little that could be done with such a class.
public class Cup1 • { • private intseedCount; • }
In order to create instances of the class, constructors are needed. • If the programmer provides no constructors, as in the previous example, the system supplies one by default. • In order to be able to use a constructor or write one of your own it is necessary to understand their characteristics:
1. They are declared public. • 2. They do not have a type. • They always return a reference to an instance of the class. • 3. They have exactly the same name as the class, including capitalization. • 4. They may have 0 or more parameters.
5. There can be more than one constructor. • They all have the same name, but the system can distinguish between them if their parameters lists differ according to data types. • 6. The code inside constructors initializes instance variables.
Here is the second example of the Cup class, this time with constructors included. • It is clear that an instance of the class could be created in a program, but without methods the class is still not very useful.
public class Cup2 • { • private intseedCount; • public Cup2() • { • seedCount = 0; • } • public Cup2(intseedCountIn) • { • seedCount = seedCountIn; • } • }
The code for a constructor is written as a separate block enclosed in braces inside the class definition. • The example shows two possibilities: • A constructor that doesn’t take a parameter, and one that does take a parameter.
In the first, the instance variable is initialized by assigning it a hard-coded value, 0. • In the second, the instance variable is initialized by assigning it the value of the parameter. • In a program using the class, both of the following calls would construct Cup2 objects:
Cup2 myCup = new Cup2(); • Cup2 yourCup = new Cup2(4);
In order to make use of constructed objects, methods are necessary. Methods generally fall into 2 categories: • 1. Accessormethods. These are “get” methods, which return the value of an instance variable without changing it. • 2. Mutatormethods. These are “set” methods, which allow the value of an instance variable to be changed.
Here is the next version of the example class with some methods added to it: • public class Cup3 • { • private intseedCount; • public Cup3() • { • seedCount = 0; • } • public Cup3(intseedCountIn) • { • seedCount = seedCountIn; • } • public intgetSeedCount() • { • return seedCount; • } • public void setSeedCount(intseedCountIn) • { • seedCount = seedCountIn; • } • }
The following observations can be made about methods: • 1. In order to be used by programs outside of the class definition, they are declared public. • 2. After the declaration of public, a type is given. The type may be a simple data type, a reference, or void if the method does not return anything. • 3. Methods may or may not take parameters. • 4. It is customary to use some naming convention that allows you to quickly tell a “get” method from a “set” method.
In particular, the following observations can be made about getSeedCount(): • 1. It is declared public. • 2. It is typed int. • In order to be syntactically and logically correct, the code for such a method has to end with a return statement that returns either a constant or some variable of that type. • 3. It takes no parameters.
The following observations can be made about setSeedCount(): • 1. It is declared public. • 2. It is typed void. • The code for the method does not contain a return statement. • 3. It takes a parameter, and just like in a constructor, the parameter has to be typed. • The method assigns the value of the parameter to the instance variable of the object.
Keep in mind that in a program it isn’t possible to access or change the value of seedCount in an object like myCup except through calls to the methods getSeedCount() and setSeedCount(). • However, in the code contained within the class definition you have direct access to the instance variables of that class.
This line of code in the setSeedCount() method illustrates this fact: • seedCount= seedCountIn;
It is now possible to write a fragment of program code that illustrates the construction and use of an object of this class: • … • Cup3 myCup = new Cup3(); • intmyCount = myCup.getSeedCount(); • System.out.println(myValue); • myCup.setSeedCount(4); • myValue = myCup.getSeedCount(); • System.out.println(myvalue); • …
You would get the following output from this fragment: • 0 • 4
For system supplied classes we have seen that it is possible to make a call to the println() method with an object of such a class as a parameter. • The output of such a call is textual information telling which class the object is an instance of, along with the names and values of instance variables in square brackets.
What happens when you make a call like this using an object from a class you’ve created? • System.out.println(myCup); • You’re hoping for something like this: • Cup3[seedCount=4] • Instead, you get something like this: • Cup3@5d87b2
A class has to have its own implementation of a method called toString() in order for the println() call to give the results hoped for. • Since the Cup3 class doesn’t have this, a system supplied toString() method is called, which gives the results shown.
This version of the method only shows the name of the class, followed by the “@” symbol, followed by what is known as the hash code of the object. • How your class has access to the system supplied version, and how to write your own version of toString() will be covered later.
Now consider a fragment of code where more than one instance is created: • … • Cup3 myCup = new Cup3(); • Cup3 yourCup = new Cup3(); • … • myCup.setSeedCount(4); • yourCup.setSeedCount(5); • …
Method code resides in the class. Each object shares the same copy of code. • Each object has its own instance variables. • However, the names of the instance variables of each object of the class are the same. • The line of code in the setValue() method reads: • seedCount= seedCountIn;
When this line of code is executed, which object’s seedCount is changed? • It is now important to explain more completely the meaning of the model shown here: • object.method(parameters);
For any execution of the method, the object that the method is called on, and only that object, is the one whose instance variable is changed. • Up to this point we’ve referred to the things inside the parentheses simply as parameters. • They are values which are used in the execution of the method.
From now on, when being specific, they will be known as explicit parameters. • This is because the object that a method is called on is also a parameter. • It is something which can also be used inside the method when the method is being executed. • The object that a method is called on is known as the implicit parameter.
It is the implicit parameter which tells the system which object’s instance variable is to be changed by a call to method code in a class definition which is shared by different instances of that class. • There is a keyword that makes it possible to show the use of the implicit parameter. • The keyword is "this".
Here is the line of code from the setSeedCount() method, rewritten with this keyword: • this.seedCount = seedCountIn;
The keyword “this” is the name of the reference to the implicit parameter for any particular execution of the method. • If, for example, this call is made: • myCup.setSeedCount(4); • Then inside setSeedCount() “this” refers to “myCup”.
Methods can be more complicated than the ones shown so far. • A simple example would be a method that allowed you to increase the current seed count by a given amount. • Here is such a method: • public void increaseSeedCount(intaddedNumber) • { • seedCount= seedCount + addedNumber; • }
A class can be written, saved, and compiled separately from any program that might use it. • Just as with program classes, the name of the file a class is saved in has to agree exactly with the name of the class, including capitalization. • A user written class will be available to any program that needs to use it if it is stored in the same project as the program.
The logic of a class can only be tested by a program that uses it. • A complete test program would make use of every constructor and method defined in the class and print output that would allow the user to determine whether those elements were having the desired effect. • Here is a test program for the Cup3 class. • Several remarks follow the program.
/* This program tests all of the constructors and • methods of the Cup3 class. */ • public class TestCup3 • { • public static void main(String[] args) • { • Cup3 myCup; • Cup3 yourCup; • intaValue; • /* Test the constructor that doesn’t take a parameter and the set and get methods. */ • myCup = new Cup3(); • aValue = 5; • myCup.setSeedCount(aValue); • aValue = myCup.getSeedCount(); • System.out.println("myCupseedCount: " + aValue);
/* Test the constructor that does take a parameter. */ • avalue = 7; • yourCup = new Cup3(aValue); • aValue = yourCup.getSeedCount(); • System.out.println("yourCupseedCount: " + aValue); • /* Test the increaseSeedCount() method. */ • avalue = 2; • myCup.increaseSeedCount(aValue); • aValue = myCup.getSeedCount(); • System.out.println("myCupseedCount: " + aValue); • } • }
It should be noted that the variable, aValue, passed from the calling program to the methods, does not have the same name as the parameters, seedCountIn and addedNumber, in the method definitions. • It is not a bad idea to use different names for the same quantities in a program and a class.
It can get confusing when different things have the same names. • The important point is that when a numerical variable like aValue is passed to a method, its value is copied into the explicit parameter of the method.
When starting to write programs it is important to plan the order in which things need to happen in the program. • Beginning programmers often make the following mistake when writing a program that tests a constructor that takes parameters: • They try to construct the object before getting the needed parameter(s) from input.
When simple variable types are declared, a memory location is set aside for them where values of that type can be stored. • Consider the following lines of code: • double var1; • double var2; • var1 = 100.0; • var2 = var1;
At the end of the sequence there are two copies of the value 100.0 stored in two different locations in memory, and each location is referred to by a different name in the program, var1 and var2.
Object references do not work the same way. • Consider the following lines of code: • Cup3 myCup; • Cup3 yourCup; • myCup = new Cup3(4); • yourCup = myCup;
Only one object is created, and so only one object exists. However, there are two valid references and they both refer to that one single object. • The diagram below illustrates this idea. • The boxes on the left represent the named references in the program. • The box on the right represents the actual object as stored in the computer’s memory at run time. • The line segments ending in solid dots graphically represent the relationships between the named references and the object.