Unit 4: Java Classes

Preview:

DESCRIPTION

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. - PowerPoint PPT Presentation

Citation preview

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

• 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 int seedCount;• }

• 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 int seedCount;•  • public Cup2()• {• seedCount = 0;• }•  • public Cup2(int seedCountIn)• {• 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. Accessor methods. These are “get” methods, which return the value of an instance variable without changing it.

• 2. Mutator methods. 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 int seedCount;•  • public Cup3()• {• seedCount = 0;• }•  • public Cup3(int seedCountIn)• {• seedCount = seedCountIn;• }•  • public int getSeedCount()• {• return seedCount;• }•  • public void setSeedCount(int seedCountIn)• {• 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();• int myCount = 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(int addedNumber)

• {• 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;•  • int aValue;•• /* 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("myCup seedCount: " + aValue);•  

• /* Test the constructor that does take a parameter. */•  • avalue = 7;•  • yourCup = new Cup3(aValue);• aValue = yourCup.getSeedCount();• System.out.println("yourCup seedCount: " + aValue);•  • /* Test the increaseSeedCount() method. */•  • avalue = 2;•  • myCup.increaseSeedCount(aValue);• aValue = myCup.getSeedCount();• System.out.println("myCup seedCount: " + 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.

4.2 Copying and Using Object References

• 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.

Cup3 objectseedCount = 4(Unless assigned to a reference, the object itself does not have a name. Internally it is uniquely identified by a hash code.)

myCup

yourCup

• In the following examples assume that the declarations have been made.

• Now consider these lines of code:• • myCup = new Cup3(4);• myCup = new Cup3(5);

• This time two objects are created, but there is only one reference.

• A reference can only refer to one object at a time.

• As a result, when the second object is created and its reference is assigned to myCup, the first object no longer has a reference to it.

• Here is a diagram illustrating this situation.

Cup3 objectseedCount = 4

myCupCup3 object

seedCount = 5

This reference no longer exists.

• When this happens, the object without a reference still exists in the system, but it can no longer be used in the program because the program has lost its handle on it.

• It is possible to do this accidentally, but in generally it’s perfectly all right to do this intentionally.

• In Java, the system searches for objects that are no longer accessible and disposes of them.

• This is referred to as “garbage collection”, and you as a programmer don’t have to worry about it.

• Now consider the following lines of code:• • myCup = new Cup3(4);• yourCup = new Cup3(5);• yourCup = myCup;

• In this case there are two objects and two references, but when the assignment, or copying of myCup to yourCup takes place, the reference to the object that yourCup originally referred to is lost.

• Both yourCup and myCup now refer to the same object.

• Here is a diagram illustrating this situation:

Cup3 objectseedCount = 4

yourCup

Cup3 objectseedCount = 5

myCup

• Unlike the assignment of variable values, the copying of object references does not result in a new copy of the object.

• It simply results in multiple references to the same object.

• If a new copy of an object is desired, it is possible to write a method that will return a reference to a copy.

• This is referred to as cloning and will be taken up later.

• In the meantime, it is already possible to make copies of simple objects using the constructors and methods we have.

• Consider the following lines of code:

• myCup = new Cup3(4);• yourCup = new Cup3(5);• int someValue = myCup.getSeedCount();• yourCup.setSeedCount(someValue);

• At the end of the sequence, the instance variables of myCup and yourCup have the same values, but myCup and yourCup are two separate objects.

• The two objects are faithful copies of each other. • However, there is no link between them, and

further actions could cause their contents to differ again.

• Here is a diagram illustrating this situation:

Cup3 objectseedCount = 4

yourCup

Cup3 objectseedCount = 4

myCup

4.3 Input Using the Scanner Class

• Just as it's possible to print output by making a call to System.out.println(), it is also possible to obtain input from a user into a running programming.

• Input and output are frequently done in pairs, where a message is printed by a program telling the user what kind of value is expected, followed by a line of code in the program which will receive input entered by the user.

• Input is based on a system supplied class named Scanner.

• First of all, using the Scanner requires importing the class at the beginning of a program.

• The follow line of code illustrates this:

• import java.util.Scanner;

• In the body of a program, using the Scanner requires constructing an object and passing it a parameter.

• The parameter that will be passed is a system defined constant which we will simply accept for the time being.

• The following line of code shows how to construct an instance of the Scanner class which will be named "in":

• • Scanner in = new Scanner(System.in);

• The Scanner class has several methods. • For our purposes these three are of

importance:• • int nextInt()• double nextDouble()• String nextLine()

• These methods take in an int, a double, and a String, respectively.

• They will be illustrated shortly. • There is one more thing to know about using the Scanner. • In order to prevent a compiler warning, your program should

end with a line of code like this:• • in.close();

• The reality is that the examples in these notes typically will not include this.

• The use of the Scanner will be illustrated with one example that expects an int.

• Its use is analogous with doubles and Strings. • The example is introduced by means of the

screenshot below:

• The screenshot illustrates all of the points raised above.

• It also shows that the prompt asking the user for input appears in the Console.

• In order to respond to the program it's necessary to click the mouse after the prompt.

• If you do not do that, anything you type will go into the program editor.

• As shown here, the user clicked the mouse on the line in the Console following the prompt and hit the enter key.

• At that point, the program took the input in, and the println() statement in the program printed it out again in the Console.

• This process of taking in input and printing it out again in order to test a program is known as echoing.

4.4 The Null Reference

• It is possible to declare names for object references and not assign object references to them.

• Such names literally refer to nothing at all. • It is also possible for a reference to be

assigned the special value “null”. • Although no object exists, this is not the same

as referring to nothing at all.

• A programmer can make such an assignment and in certain situations the system will make such an assignment by default.

• Even if you choose not to use null in your code, you need to know about it since the system may make use of it.

• Various errors can arise from improper use of null references, and it is important to be able deal with these errors, and distinguish them from errors arising from references to nothing at all.

• Here is a null reference assignment:

• Cup3 myCup;• myCup = null;

• This could be used, for example to dispose of a previously constructed object without creating a new one:

• • Cup3 myCup;• myCup = new Cup3(4);• …• myCup = null;

• What follows is a class definition and a set of examples showing various different things that can happen within programs that use the class.

• These things are either the result of an object name referring to nothing at all, or a null reference.

• Here is the class:

• public class Shampoo• {• private String kind;• private int rating;•  • public Shampoo(String kindIn)• {• kind = kindIn;• }•  • public Shampoo(int ratingIn)• {• rating = ratingIn;• }•

• public void setKind(String kindIn)• {• kind = kindIn;• }•  • public String getKind()• {• return kind;• }•  • public void setRating(int ratingIn)• {• rating = ratingIn;• }•  • public int getRating()• {• return rating;• }• }

• Here is the first example. • It illustrates that using an object name as a parameter in a method call does

not work if the object does not exist. • The compiler can detect a problem like this.• • public class Test1• {• public static void main(String[] args)• {• Shampoo myShampoo;• System.out.println(myShampoo);• }• }

• In the Eclipse development environment the line of code with the error will be marked with a red X box at the left, and there will also be an error message in the Problems tab at the bottom.

• If you move the mouse over the red X box by the line of code, the box shown below with the explanatory messages will appear:

• Error messages are occasionally worded in an unhelpful way, or sometimes the compiler can't determine absolutely what might be wrong.

• This error message is worded helpfully, but it says "may" just because something else might be wrong.

• But in this case, the fact that myShampoo does not refer to an actual object is the problem, and that is indicated by the error message.

• If the compiler ends with such an error, no program is created and it is impossible to run the code.

• If you try to run the code anyway, this is what you'll see:

• If you press the proceed button, the system will repeat the compiler error message.

• Here is the second example, which illustrates a similar situation. • An object name is declared, but no object exists, and a method is called on

that name.• • public class Test2• {• public static void main(String[] args)• {• Shampoo myShampoo;• int someRating = myShampoo.getRating();• System.out.println(someRating);• }• }

• The second example generates exactly the same kind of compiler error as the first example, and no program results.

• Now consider the third example. • It is similar to the first example, in that it considers the case where an object

reference is to be passed as a parameter. • No object exists but in this case the reference has been given the value null.• • public class Test3• {• public static void main(String[] args)• {• Shampoo myShampoo = null;• System.out.println(myShampoo);• }• }

• The program compiles and runs successfully. • It prints out the value of the reference

myshampoo with no problem. • Here is the output:• • null

• Now consider the fourth example. • It is similar to the second example, in that it considers the case where a method is

to be called on an object reference. • No object exists but in this case the reference has been given the value null.• • public class Test4• {• public static void main(String[] args)• {• Shampoo myShampoo = null;• int someRating = myShampoo.getRating();• System.out.println(someRating);• }• }

• This program compiles without a red X box, but the compiler does mark the middle line of code with this warning message:

• The system will still let you run the program even though it is not possible to successfully make a method call on a null reference.

• If you run the code, this message will appear in the Console tab at the bottom of the environment.

• Notice that this is a runtime error, not a compiler error. • That's why it appears in the Console, where output normally

appears, not in the Problems tab. • • Exception in thread "main" java.lang.NullPointerException

• at TestShampoo.main(TestShampoo.java:5)

• Even though you hope to catch all of your problems up front through compiler warnings, and so on, it is worthwhile to be aware of the NullPointerException message and know that it signifies, in simple terms, that in your code you tried to call a method on an object reference that contained the null value.

• As the next example will show, this kind of problem can crop up.

• The first four examples were relatively straightforward.

• They illustrate problems that a beginning programmer should be able to manage.

• However, there is a more subtle source of null references in programs.

• The Shampoo class has an instance variable that is a string.

• Since String is a class, this instance variable is an object reference.

• The Shampoo class has a constructor that takes a single int as a parameter.

• In the code for that constructor, nothing is done to explicitly initialize the String instance variable.

• If any initialization does occur, it is by default. • The key point is that the system will initialize the

String instance variable by default, to the value null.

• Now consider the fifth example, which makes use of this constructor.

• public class Test5• {• public static void main(String[] args)• {• Shampoo myShampoo;•  • String someKind;• int someRating = 5;•  • myShampoo = new Shampoo(someRating);•  • someKind = myShampoo.getKind();•  • System.out.println(someKind);• }• }

• This is the output from the fifth example:• • null

• This program runs successfully because it is possible to have a null reference as an explicit parameter.

• However, it illustrates that null references can arise in programs from unexpected sources.

• The sixth example illustrates how a program may fail due to a null reference that was obtained from elsewhere.

• public class Test6• {• public static void main(String[] args)• {• Shampoo myShampoo;•  • String someKind;• int someRating = 5;•  • myShampoo = new Shampoo(someRating);•  • someKind = myShampoo.getKind();•  • System.out.println(someKind);•  • int length = someKind.length();•  • System.out.println(length);• }• }

• The program runs correctly through this line of code:

• • System.out.println(someKind);

• It causes this output in the Console tab at the bottom, with "null" being the result of this last successfully executed line of code:

• • null• Exception in thread "main" java.lang.NullPointerException

• at TestShampoo.main(TestShampoo.java:15)

• The program then encounters a problem in this line of code:• • int length = someKind.length();• • This is what causes this runtime error message:• • Exception in thread "main" java.lang.NullPointerException

• at TestShampoo.main(TestShampoo.java:15)

• The error is the same as the one noted before. • It is not possible to call a method on a null

reference. • The compiler is not all-knowing. • It can only see one level deep—it can't see what a

reference may contain at run time. • Only the programmer can foresee and avoid

problems like this, or correct them after they have been discovered.

• References that refer to nothing and null references are possible in Java.

• The default initialization of instance variables in objects can cause null references in programs.

• This is a subtle source of problems that the programmer needs to be aware of.

• The examples above are not exhaustive, but they show some representative cases and the results that they lead to.

• If you encounter an error message similar to one of those shown above, you may be able to figure out what your problem is by looking at the examples again.

The End

Recommended