Java | |
GOT JAVA? | |
UNDERSTANDING WHILE LOOPS
AN ALTERNATE WAY TO DECLARE ARRAY VARIABLES Here is the standard way to declare a variable that will hold an array of char values:
That's usually how you'll see the job done. However, you might prefer the syntax
which has precisely the same effect. This approach more closely associates the array brackets with the variable name (in this case, varname). Either syntax is legal, and you can even mix them in the same program. Doing so isn't a great idea, though--pick whichever you like and stick with it, so your code will have a consistent look and be easier to trace.
CREATING AN ARRAY Once you've created an array variable, you'll want to create an array for it to contain. An array is an example of what's called an object. An object is an instance of a particular kind of thing. (For those of you keeping track, a kind of thing--as opposed to an instance of that thing--is called a class.) Objects are, however, different from instances of basic data type, such as float and int values.
DEFAULT VALUES IN AN ARRAY
the array isn't empty. Believe it or not, it actually contains default values. The default values depend on the kind of data the array has been declared to hold. In the example above, the varname array holds five instances of '\u0000', which is the Unicode character specification for a null character.
INTRODUCING ARRAYS
POPULATING AN ARRAY
ASSIGNING A SERIES OF VALUES TO AN ARRAY VARIABLE
we can do the following:
GETTING THE LENGTH OF AN ARRAY
where length is the number of elements in the array. As it happens, there's an easy way to get the number of elements in any given array. It's easy because arrays are objects. Objects can have (among other things) properties that describe them. An array object has a property called length, which is an integer that represents the number of elements in the array. You refer to the length property like this:
INTRODUCING TWO-DIMENSIONAL ARRAYS While it's possible to impose external rules upon a one-dimensional array (for example, remembering that the odd-numbered elements contain one kind of data and the even-numbered elements contain something else), this approach is needlessly complex and invites error. Since there is no inherent structure to the data, you have to remember the artificial (even/odd) rules, and errors will result if you don't. Happily, Java provides a better method of handling multidimensional arrays. These "arrays of arrays" are exactly what the name implies--arrays in which each element is another array. To declare a variable to hold such an array, use this syntax: int datesAndTimes[][]; Then, to put a two-dimensional array in that variable, use something like this: datesAndTimes = new int[3][2]; This creates an array of three elements, each of which contains another array of two elements. MULTIPLE DATA TYPES? NO... In thinking about multidimensional arrays (which is to say, two-dimensional arrays for the moment), it's tempting to ask if there's a way to get them to hold data of multiple types. The answer, as far as the basic data types are concerned, is no. You see, when you make the declaration int datesAndTimes[][] = new int[3][2]; you get an array of three elements, each of which contains another array object of two elements. The elements of the three-element array are occupied by the references to the subsidiary two-element arrays. There's no room for anything else there. REFERRING TO THE CONTENTS OF A TWO-DIMENSIONAL ARRAY Okay, so you've created a two-dimensional array with a statement like this: int datesAndTimes[][] = new int[3][2]; Now, you want to populate that array with integers representing dates and times. Element 0 in each subsidiary (two-element) array will be the date of a Monday in December, while element 1 in those arrays will be an hour. Here's how to do the assignments: datesAndTimes[0][0] = 6; datesAndTimes[0][1] = 13; datesAndTimes[1][0] = 13; datesAndTimes[1][1] = 9; datesAndTimes[2][0] = 20; datesAndTimes[2][1] = 22; This data structure refers to 1300 on December 6; 0900 on December 13; and 2200 on December 20. Note that we're still imposing artificial rules on the arrays. We still must remember that every 0th element in every subsidiary array is a date, while every 1st element is a time. Still, there's now some inherent structure to the data. USING EXTERNAL RULES TO DEFINE DATA STRUCTURES By now, declaring an array should be no problem for you. The fastest way to do it is with a statement similar to this one: int[] mondays = {6, 13, 20, 27}; This statement yields a single variable that contains an ordered list of the dates in December 1999 that fall on a Monday. Accordingly, you can refer to the second Monday's date as mondays[1]. But what if you want to use the same variable to refer to specific times on those Mondays? You could do something awkward, like remember that the first element in the array and every third element thereafter was a date, while intermediate elements held times, like this: int[] datesAndTimes = {6, 9, 15, 13, 13, 21}; Under this awkward system, the array would represent the times 0900 and 1500 on December 6 and the times 1300 and 2100 on December 13. This would work, but the possibility for error is large. As it happens, Java provides a handy way to structure this kind of data--which we call two-dimensional arrays. Now that you know the hard way to do it, you'll have to tune in tomorrow to learn the easy way. HOW TO THINK OF TWO-DIMENSIONAL ARRAYS Consider this two-dimensional array we've been working with for the past few days: int datesAndTimes[][] = new int[3][2]; You can think of a two-dimensional array as a table or grid. In the example above, the imaginary grid would be three spaces across by two spaces down. You can refer to any element in the table by its "across" coordinate (remembering to start counting at 0) followed by its "down" coordinate. The element in the lower-right corner of the table could be referred to as datesAndTimes[2][1]. ARRAYS OF MORE THAN TWO DIMENSIONS If you really want to, you can declare multidimensional arrays of more than two dimensions--arrays of arrays of arrays (in the case of a three-dimensional array), if you like. The syntax is familiar--just more of the same, really. For example, you might start by declaring the array like this: int dataCube[][][] = new int[3][3][3]; Then, to reference an element, use something like this: int dataCube[0][0][3] = 56; There's no rule that says a multidimensional array must be cubic. You can just as well do this: int dataCube[][][] = new int[5][4][4]; which results in the creation of an array of five two-dimensional arrays, each four-by-four elements. ASSIGNING A VALUE TO A STRING VARIABLE Once you've declared a variable and noted that it will contain a String object, as in String quote = new String; you're free to define that String object more specifically. A String object incorporates a sequence of characters. When you define a String object by explicitly stating the sequence of characters--by using a "string literal," to put it another way--you enclose the sequence in quotation marks (""). Here's how it looks: quote = "We have nothing to fear but fear itself."; To accomplish the same effect with a single line of code, we could have used this statement: String quote = "We have nothing to fear but fear itself."; Next time, we'll start to examine some of the ways a String object behaves like an Array objects containing data of type char. CONVERTING THE CASE OF A STRING'S CHARACTERS Say you've declared a String object with this declaration: String quote = "We have nothing to fear but fear itself."; Later in your program, you decide that you want President Roosevelt's statement to carry more emphasis. You can use the String object's toUpperCase() method to convert each character in the string to its capital equivalent (the method has no effect on uppercase letters, spaces, and punctuation marks). So, if you did this: String strongQuote = quote.toUpperCase(); you'd have a second String object, contained in the variable strongQuote, that held "WE HAVE NOTHING TO FEAR BUT FEAR ITSELF." There's a similar method, toLowerCase(), that converts a string to a sequence of lowercase characters. GETTING THE LENGTH OF A STRING Recall that if you declare an Array object like this: char[] letters = {'a', 'b', 'c'}; you can find the number of elements in the array by using the length property that all arrays have. In other words, this: letters.length is equal to the value 3. Strings, being similar to arrays of characters, also have length properties. If you use the declaration String quote = "We have nothing to fear but fear itself."; and then make reference to quote.length, you'll find that quote.length has the numerical value 40. There are 40 characters in the string referred to by the variable called quote. Note that the quotation marks are not part of the string; they're just delimiters. REFERRING TO CHARACTERS IN A STRING You know that you can declare a string like this: String quote = "We have nothing to fear but fear itself."; and that you can get the number of characters in the string by referring to its length property. That sounds like an Array object, eh? Well, then, it stands to reason that you can refer to characters in the string just as you would refer to elements in an array. But you can't, not exactly. Although the characters in a string have index values and the first character in a string has index 0 (not 1), you can't use the square-bracket syntax to access characters in a string. Instead, you must use a method of the String object called charAt(). The best way to illustrate the behavior of charAt() is to give some examples. Working with the string contained by variable quote, as defined above, these statements are true: char character; character = quote.charAt(0); // Variable character holds 'W'. character = quote.charAt(5); // Variable character holds 'v'. character = quote.charAt(39); // Variable character holds '.'. THINKING OF STRINGS AS ARRAYS An array is a collection of data, organized into an ordered series of elements and referred to by a common name. You could, for example, declare an array of elements of type char. If you think about it, a string--a sequence of characters that means something, either in a human language or to a machine--is really an array of characters. Java acknowledges this fact and allows you to work with strings as arrays of characters. A string stored in a variable is a special data type--a kind of object called a String object. The String object behaves much like an Array object. You declare a variable for holding a String much like you'd declare a variable for holding an Array. The syntax looks like this: String quote = new String; As you can see, the keyword new comes into play here, just as it does when you declare an Array object. BOOLEAN COMPARISONS OF STRINGS Here's a neat piece of truth. You might expect that if you made the two declarations String aString = "ABCDE"; String bString = "ABCDE"; and then did a boolean comparison of the two string variables, like this: aString == bString) that the comparison would yield the boolean value true. Not so. Even though the strings are the same, character for character, the variables refer to different String objects and so are different. The comparison yields false. On the other hand, if you did this: String aString = "ABCDE"; String bString = aString; and then compared the two variables, the comparison would yield true. USING ESCAPED CHARACTERS IN STRINGS Last time, we played with string concatenation by using this code: String quote = "We have nothing to fear but fear itself" + ", said President Roosevelt."; That yields "We have nothing to fear but fear itself, said President Roosevelt." We need a way to distinguish the actual quote from the attribution. We should do this with quotation marks, but if we just stuck quotation marks into the strings, the Java compiler would interpret them as delimiting the strings. If we use the escape sequence for quotation marks, though, we can avoid this problem. Here's how it works: String quote = "\"We have nothing to fear but fear itself" + ",\" said President Roosevelt."; The sequence \" denotes a quotation mark that's part of the string, not part of its definition. The code above yields what we want when it is printed: "We have nothing to fear but fear itself," said President Roosevelt. Note that each \" sequence counts as a single character for indexing and character-counting purposes. AN INTRODUCTION TO OBJECTS An object is a thing--something you can think about as a unit. You can think of an object as anything you can name with a noun. For example, let's say we want to talk about a particular bicycle--the bicycle Miguel Indurain was riding when he finished the 1996 Tour de France. This is one bike, a particular bicycle distinct from all others. The bike is a definable object. We can think of it in terms of a hierarchy of objects. 1) Definable things. 2) Vehicles. 3) Wheeled vehicles. 4) Bicycles. 5) Racing bicycles. 6) The particular racing bicycle Miguel Indurain was riding when he finished the 1996 Tour de France. We could design the hierarchy differently, but this is one way to do it. The important thing to understand is that Java organizes its objects in hierarchies such as this one. GETTING RID OF EXTRA SPACES If you've ever done any work that involves taking input from a user by way of a command-line interface or a text field in a form or Web page, you know that users can put all kinds of extra characters in their input. Extra spaces (leading and trailing) are among users' favorites. Say, for example, you expected a variable to contain a name, but in fact it contained the string " Kate " That could really mess up your formatting. The String object makes it easy to get rid of leading spaces, trailing spaces, or both. Here's how you'd do it: String name = " Kate "; name = name.lTrim(); This results in name holding "Kate ". The lTrim() method strips spaces from the left side of the string. The rTrim() method does the same on the right side of the string. To do both sides at once, use the trim() method: String name = " Kate "; name = name.trim(); This results in name holding "Kate", which is what you want. AN INTRODUCTION TO METHODS We've seen that objects have describable, inspectable characteristics called properties. Objects also can do things. Every kind of object can do a particular set of things that may or may not be unique to that object. Let's imagine, for example, that we have the bicycle Miguel Indurain was riding when he finished the 1996 Tour de France. I will instruct you to make that bike do things. Ready? - Apply the bike's rear brake. Okay, you say. - Release the bike's rear brake. Okay. - Pedal the bike forward 20 yards. Okay. - Put the bike in its lowest gear. Okay. - Turn the bike's handlebars 15 degrees to the right. Okay. - Sell the bicycle for a sum not less than $5,000. All those are things you can do with the object we defined. Most of the actions I asked you to perform are generic to multi-speed bicycles, but the last item asks you to do something with Indurain's bike that you probably couldn't do with that old Schwinn you keep out in the shed. Likewise, if I had asked you to start the bike's motor, you would have protested, since that's not something you can do with a bicycle. Java objects have methods that work much the same way. Each object has a set of methods you can invoke individually to cause certain things to happen. You've used methods to a limited degree already, in converting the case of characters in strings and stripping extra spaces from them. GETTING FAMILIAR WITH FIELDS An object is a readily identifiable thing. Identifiable things have characteristics that we can describe. In the language of object orientation, such characteristics are called fields (sometimes they're called properties, too). For example, we might discern the following fields about a particular object (in this case, Miguel Indurain's bicycle). - What is the color of the bicycle Miguel Indurain was riding when he finished the 1996 Tour de France? That bicycle is red. - What is the weight of that bicycle? That bicycle weighs 12 pounds. - Is that bicycle for sale? No, it is not. (By the way, these replies are all guesses, for you nitpicking cyclists out there.) The point of this is that objects have characteristics we can inspect, just as Java objects have fields. You've already seen a couple of them, in the form of the length properties of the Array and String objects. ADDING A METHOD TO A CLASS--PART 1 OF 2 Most objects will have methods in addition to their fields. To define a method in a class, you just add a special block of code inside the curly brackets that surround the class's code. The generic syntax for a method declaration is this: returnDataType methodName(arguments) { // Method code. } In this example, returnDataType is a data type--either one of the basic data types (int, long, char, and so on) or a class (String, JDialog, whatever). It represents the kind of data that the method returns, or sends back to the point from which it was called. Some methods don't return any value--in which case they should have the keyword void in place of returnDataType. Continuing, methodName is a unique name by which to identify the method. Strictly speaking, it need not be absolutely unique among the methods in its class, but there are special conditions for duplicating method names. The parentheses, in turn, contain arguments, which represent values that must be sent to the method for processing. (More on those arguments another day.) ADDING A METHOD TO A CLASS--PART 2 OF 2 Again using the example of our Java checking account, let's say you want to add a method to the Check class that returns the number of the bank account to which the Check applies. You could define the method like this: class Check { // Instance variables follow: double amount = 0.0; String payee = ""; String memo = ""; // Class variables follow: final static int accountNumber = 234234; // Methods follow: int getAccountNumber() { return accountNumber; } // Further defining code goes here. } In this case, the method getAccountNumber() is declared in order to return a value of type int and to take no arguments. The only line of code in the class is the keyword return and the name of the variable accountNumber, which means that accountNumber's value is to be returned to wherever this method is called. ADDING CLASS VARIABLES TO A CLASS Recently, we've been discussing objects and variables using the example of a checking account. Checks drawn on a given account have several things in common, one of which is the bank account number of the payor (the person writing the check and giving it to a payee). It stands to reason that in a class whose objects represent individual checks, the field containing the payor's account number would be a class variable--that is, it would be the same across all instances of the class and accessible even if no instances of the class existed at a given moment. Here, then, is how we'd modify our class declaration to bring about this effect: class Check { // Instance variables follow: double amount = 0.0; String payee = ""; String memo = ""; // Class variables follow: static int accountNumber = 234234; // Further defining code goes here. } As you can see, all that is required to make a field a class variable is to precede its declaration with the word static. This makes the variable (and its value) the same across all instances of the class Check. Don't forget, though, that changing the variable in one instance of the class causes the same change to show up in all other instances. However, as you'll see next time, there is a way to make the value unchangeable. ADDING INSTANCE VARIABLES TO A CLASS Recently, we defined classes and objects using the example of a checking account. Now, let's take a look at the syntax that would implement our Check class, which will be used to create objects representing checks drawn on a bank account. These objects will need some instance variables, unique to each instance of the class, representing the payee, the amount, and a memo field (we'll ignore dates for now). Here's how we'd declare those fields: class Check { double amount = 0.0; String payee = ""; String memo = ""; // Further defining code goes here. } No big deal, really. You just declare those variables and their data types in the normal way. No further adornment is needed. Every instance of the Check class (that is, every Check object) will have fields called amount (initially 0.0), payee (initially an empty string), and memo (also initially an empty string). Each field may be manipulated independently of the fields in other instances of the Check object. DEALING WITH MULTIPLE ARGUMENTS You've already seen that you can send values to a method for processing by putting them in the parentheses following the method's name. Sometimes (well, quite often, actually), methods require multiple arguments. In those situations, you just separate the arguments with commas. The Math object, for example, has a method called min() that returns the smaller of the two specified integers. Accordingly, the code int smaller = Math.min(15,14); results in the variable smaller holding 14. Interestingly, the Math object has four min() methods. In addition to the one that evaluates values of type int, there are others for values of types double, float, and long. Thankfully, the Java Virtual Machine (JVM) evaluates what kind of values are being sent to min() and automatically invokes the proper method in response. FIELD TYPE 1: INSTANCE VARIABLES Objects may have fields, which are inspectable values (or references to values). When you define a field in a class (a class being the template from which instances of that class--objects--are created), you may want to allow each instance to have unique values for its fields. For example, if you were creating a class that was to be used to create objects that represented checks drawn against your checking account, you'd want each check (each instance of the class) to have its own value for the amount paid. Similarly, each check would have its own values for date and payee, even though those values would occasionally be the same on different checks. Fields that are unique to individual objects are called instance variables. When you create an object from a class, instance variables can have initial values, but those values can be changed without affecting identically named fields in other instances of the same class. Using the checking example again, you might create two check objects (or two instances of the check class). Both might have initial "amount paid" values (contained, say, in a field called amountPaid) of 0. Shortly, though, one instance of the class might have its amountPaid field changed to 100.00, while the other could be changed, independently, to 19.95. HOW JAVA REPRESENTS THE OBJECT HIERARCHY Java has a much more limited knowledge of the world than you and I. It wouldn't know a Zip drive from a tube of hair oil. The objects it knows are all figments of computer memory, but those figments are what concerns you when you're trying to build programs. The way you think of different kinds of bicycles, for example, Java thinks of strings. Likewise, the way you conceive of toasters, Java understands windows in a graphical user interface (GUI). Java identifies its objects the same way you do: via a hierarchy of progressively more specific objects. Java knows that a window, for example, has certain characteristics, such as its size and whether it is capable of being resized. The language knows how to make browser windows do certain things, such as open or close. Java knows the characteristics (which it calls properties) and capabilities (which it calls methods) of a whole bunch of objects that have to do with the various kinds of data you can manipulate with a Java program. The syntax may look a little bit unusual at first. Java identifies objects by a series of special words separated by periods. Here's an example: java.lang.Math Now don't panic. That hierarchy simply refers to the Math object, which is a part of the java.lang set of objects (a set of objects is called a package in this case). See? Not too hard at all. OBJECTS VERSUS CLASSES As we've recently discussed, an object is a particular thing (my bicycle, as distinct from your bicycle and all other bicycles, for example). In terms of programming, an object is a particular instance of a kind of logical structure. In fact, you can declare a String object that contains one sentence, and another String object that contains a line from a poem, and you have two distinct String objects floating around (you'd still have two objects if they both contained the same thing, by the way). But obviously, the two String objects have something in common. Indeed--they both come from the same class. You can think of a class as a cookie-cutter. Once you've created a class, you can use it to create numerous instances of its particular kind of object. The class contains the names and definitions of all methods that objects of that class will implement, as well as the names and associated values of the fields. There are, however, two kinds of fields and two kinds of methods that classes can include. (More on that next time.) REFERRING TO FIELDS IN JAVA Once you've used the correct Java syntax to identify the object you want to work with, you can go on to specify the field you want to inspect or the method you want to employ. You do that by tacking another period on the end of your object reference, then specifying the name of the field or method to which you want to refer. For example, whenever the Java Virtual Machine (JVM) is active, an object called Math exists and is available for reference. The Math object has a field called PI, which is equal to the number 3.141592553589793. Math is an object, PI is one of its fields, and the value of PI is always 3.141592553589793. Whenever you need to use the constant pi in your calculations, you can refer to Math.PI and save yourself the trouble of entering the whole value in your code. That's the syntax for referring to a field: the name of the object, followed by a period and the name of the property. Accordingly, these two calculation are the same: double area = Math.PI * radius * radius; double area = 3.141592553589793 * radius * radius; REFERRING TO METHODS IN JAVA To refer to a method of a Java object, you use much the same syntax you use to refer to a property. In fact, the only syntactic difference is that methods always have parentheses after them (the parentheses sometimes contain extra stuff, but not always). For example, it so happens that the Math object has a number of methods--one of which is called random(). The random() method generates a number (at random, for all intents and purposes) that is greater than or equal to 0.0 and less than 1.0. The generated number is of type double. Accordingly, to invoke that method, we'd use this syntax: Math.random() The following is a valid bit of code involving this method: double oneToTen = 10 * Math.random(); This code generates a double value between 0.0 and 9.999999999999999. SENDING ARGUMENTS TO METHODS As we've discussed recently, all references to an object's methods are followed by parentheses, as in double randomValue = Math.random(); Some methods, however, require raw material to process. These pieces of raw material are called arguments. For example, there's a method of the Math object, sin(), which returns (in double form) the sine of a number you specify in the parentheses. Accordingly, the code double sine = Math.sin(90); results in the variable sine holding the value 1.0. ADDING A CONSTRUCTOR THAT DUPLICATES AN EXISTING OBJECT At some point in the execution of your checkbook-management program, you might want to duplicate an existing instance of the Check object. One of the ways to do this is with a special constructor that takes a Check object as an argument. You can make the constructor copy the instance variables out of the argument object and assign them to the new object's instance variables. Such a constructor for the Check object might look like this (ignoring the rest of the class): Check(Check checkToCopy) { this(); amount = checkToCopy.amount; payee = checkToCopy.payee; memo = checkToCopy.memo; } You've seen the use of the dots before--they separate an object's name from the names of the variables and (in cases other than this one) methods it contains. CALLING ONE CONSTRUCTOR FROM ANOTHER While it's possible to write multiple constructors for the same class, you'll frequently find that the settings you make with each of a class's several constructors are similar. In our check example, the payor and the checking account number will pretty much always be the same. Let's modify our check class so it has several constructors: - A "blank check" constructor that specifies only payor and account number - A "standard" constructor that specifies the above data, plus the payee and an amount - A "standard plus memo" constructor that includes the above, plus a memorandum string Let's start with the blank check constructor. We'll eliminate a lot of the variables and methods we put in earlier--they'd just get in the way now. class Check { String payor = "Ruth Ann Krinklemeyer"; String accountNumber = "123-123X"; double amount = 0.0; String payee = ""; String memo = ""; // Further defining code goes here. } That's the default constructor--the one that's called when someone instantiates the class without any arguments. Next time, we'll move on and refer to that default constructor from another constructor that does take arguments. CALLING SEVERAL CONSTRUCTORS IN A CHAIN We want to modify our Check class so that you can declare an instance of the class with three arguments: a payee, an amount, and a memo field. If we design a constructor that can take and assign the memo field, we can leave the rest of the work up to other constructors, thanks to a special use of the this() call. Here's how: class Check { String payor = "Ruth Ann Krinklemeyer"; String accountNumber = "123-123X"; double amount = 0.0; String payee = ""; String memo = ""; // Further defining code goes here. } Now, let's modify that class so it includes a constructor that creates a check with the regular information, plus a payee and an amount. Here's how that would look: class Check { String payor = "Ruth Ann Krinklemeyer"; String accountNumber = "123-123X"; double amount = 0.0; String payee = ""; String memo = ""; Check(String namedPayee, double namedAmount) { this(); payee = namedPayee; amount = namedAmount; } Check(String namedPayee, double namedAmount, String namedMemo) { this(namedPayee, namedAmount); memo = namedMemo; } // Further defining code goes here. } The newly added constructor makes reference to this() in this way: this(namedPayee, namedAmount); It tells the Java interpreter to instantiate the current class (Check) with its two-argument constructor. Two of the three arguments that came to the three-argument constructor are sent to the other constructor, and the assignment of the third is handled locally. Note that the two-argument constructor uses this() as well. It's a chain of references. DECLARING A CLASS METHOD WITH STATIC You may have noticed that in the latest version of the Check class (discussed in the previous tip), the getAccountNumber() method referred only to the accountNumber class variable (which in turn is declared with static). Because of the static status, it makes sense to declare the getAccountNumber() method to be a class method, accessible even when no objects of class Check have been instantiated. To do this, we use basically the same syntax we use to make a field a class variable, preceding the method declaration with the keyword static. (Note that class methods can only refer only to class variables and constants. If you try to refer to instance variables, you'll run into trouble when someone attempts to run the class method when no instances of the class exist.) Here, then, is the (slightly) modified class: class Check { // Instance variables follow: double amount = 0.0; String payee = ""; String memo = ""; // Class variables follow: final static int accountNumber = 234234; // Methods follow: static int getAccountNumber() { return accountNumber; } // Further defining code goes here. } ENDOWING A CLASS WITH A CONSTRUCTOR A constructor is a special kind of method that serves to create an instance (an object) of the class in which the constructor appears. A constructor always has the same name as the class it instantiates, and a constructor never has a return data type (nor is it declared to be void). Usually, constructors serve only to set instance variables to values specified as arguments in the call to the constructor. Accordingly, here's our Check class (from the Java checking account example we've been using recently), with a new constructor: class Check { // Instance variables follow: double amount = 0.0; String payee = ""; String memo = ""; // Class variables follow: final static int accountNumber = 234234; // Methods follow: static int getAccountNumber() { return accountNumber; } void setAmount(double newAmount) { amount = newAmount; return; } //Constructor follows: Check (double initialAmount, String initialPayee, String initialMemo) { amount = initialAmount; payee = initialPayee; memo = initialMemo; } // Further defining code goes here. } Now, with this constructor in place, we can create a new object of class Check by using a call such as this: Check check834 = new Check(100.00, "Ruth Anne Krinklemeyer", "Song and dance"); This statement creates a new Check object (attached to the variable check834) with three initial values that represent the amount, payee, and memo. INCLUDING MULTIPLE CONSTRUCTORS You can have multiple constructors in a given class, which in turn allows objects of the class to be created with different sets of information. In the case of our Java checking account, for example, it would be reasonable to allow the creation of new Check objects without specifying any contents for the new object's memo field. To allow that to happen, we must create a second constructor that doesn't expect a memo argument. Here's how it looks: class Check { // Instance variables follow: double amount = 0.0; String payee = ""; String memo = ""; // Class variables follow: final static int accountNumber = 234234; // Methods follow: static int getAccountNumber() { return accountNumber; } void setAmount(double newAmount) { amount = newAmount; return; } //Constructors follow: Check (double initialAmount, String initialPayee, String initialMemo) { amount = initialAmount; payee = initialPayee; memo = initialMemo; } Check (double initialAmount, String initialPayee) { amount = initialAmount; payee = initialPayee; } // Further defining code goes here. } In this case, the second Check constructor doesn't expect a memo value, as does the first constructor. Accordingly, you could call the two constructors (one with memo, and one sans) with this code: Check check834 = new Check(100.00, "Ruth Anne Krinklemeyer", "Song and dance"); Check check835 = new Check(19.95, "Late-Night TV Marketing Company"); The Java Virtual Machine (JVM) can route the instantiation call to the proper constructor, based on the number and type of arguments included in the call. SETTING UP A METHOD THAT TAKES ARGUMENTS A lot of times, you'll want to send values to a method so that the method can use them in performing its work. These values are called arguments. To declare a method as one that takes an argument, use this syntax: returnDataType methodName(argumentType argumentName) You've seen the stuff at the beginning of this line, but the material in the parentheses may be new. In this case, argumentType represents the data type of the argument, while argumentName represents the name by which the argument will be known inside the method. If you want to accept more than one argument, separate the type/name pairs with commas. Accordingly, here's our Check class (from the example we've been using the last week or so), modified with a setAmount() method that takes an argument. class Check { // Instance variables follow: double amount = 0.0; String payee = ""; String memo = ""; // Class variables follow: final static int accountNumber = 234234; // Methods follow: static int getAccountNumber() { return accountNumber; } void setAmount(double newAmount) { amount = newAmount; return; } // Further defining code goes here. } One more thing to note: In setAmount(), that final return on a line by itself is optional. It signifies that the method (which is declared as void and therefore returns no value) is finished executing, and execution should return to the point at which this method was called. However, encountering a method's closing curly bracket has the same meaning, so the return in non-branching void methods is there only to help clarify the source code. THIS() REFERENCES THE DEFAULT CONSTRUCTOR Last time, we created a class--having only a default constructor that creates a "blank check"--that looks like this: class Check { String payor = "Ruth Ann Krinklemeyer"; String accountNumber = "123-123X"; double amount = 0.0; String payee = ""; String memo = ""; // Further defining code goes here. } Now, let's modify that class so it includes a constructor that creates a check with the regular information, plus a payee and an amount. Here's how that would look: class Check { String payor = "Ruth Ann Krinklemeyer"; String accountNumber = "123-123X"; double amount = 0.0; String payee = ""; String memo = ""; Check(String namedPayee, double namedAmount) { this(); payee = namedPayee; amount = namedAmount; } // Further defining code goes here. } The key here is this(). The this() call refers to the current object--in this case, Check. When we call this() in the two-argument constructor, it calls the default constructor (the one that takes no arguments and sets the payor and accountNumber variables). The two-argument constructor then fills in the other two variables' values. Assigning Subclasses to Superclass Variables by David Wall and Venkat Subbarao Say you have a class called Vehicle, which has a subclass called Motorcycle. You can make variables of type Vehicle hold objects of type Motorcycle, but you can't make Motorcycle variables hold Vehicle objects (not without jumping through hoops, anyway). This code is valid, assuming the Vehicle and Motorcycle classes exist: Vehicle vehicleHolder; Motorcycle harley = new Motorcycle(); vehicleHolder = harley;No problem. Even though vehicleHolder is technically a Vehicle object, it can hold instances of any of its subclasses. All Motorcycle objects are also Vehicle objects. - Using Explicit Casting - So, now we know the above is valid JavaScript. This is because all Motorcycle objects are also Vehicle objects, but not all Vehicle objects are Motorcycle objects. You can account for this with what's called explicit casting, in which you acknowledge that you're creating an instance in which a superclass fits into a subclass. This code is valid: Motorcycle harley; Vehicle conveyance = new Vehicle(); harley = (Vehicle) conveyance;The Class name in parenthesis is called an explicit cast. ***** Invoking a Servlet Bean is Similar to Invoking Servlets by Venkat Subbarao To invoke a Servlet Bean from the browser, simply type (into the location text box) the URL for the Bean. To call a Servlet Bean from an applet, create a URL specifying the Bean address and then call the ShowDocument() method using this URL. The source code for this looks like: String urlstring = "http://machineaddress/servlet/myBean"; URL Location = new URL(urlstring); getAppletContext.showDocument(Location,"_blank"); What’s Up With Get and Set? by David Wall You may have noticed that recent examples have included "get" and "set" functions. You may wonder why you would have a getWhatever() method that returns the value of variable whatever and a setWhatever() method that alters its value. Why wouldn't it be easier to just alter the fields directly, by referring to the name of whatever instance you were concerned with, and the name of the variable? In other words, how is... Check.setValue(45); ..different from Check.value = 45; Well, in simple cases, get and set methods are inefficient. Their advantage becomes more apparent in larger programs that might require modification. You might have a class that has getMass() and setMass() methods, and programs that referred to those methods that send and expect values in kilograms. If, for some reason, you had to change the internal workings of your program to use English units (the English unit of mass is the slug, interestingly), you could keep the external callers happy with relative ease by doing the conversion in the get and set methods. It's a maintenance thing. | |
Using toString() by David Wall Methods | |
Error Handling with VetoChangeException of JavaBeans by Venkat Subbarao | |
Defining Abastract Methods by David Wall | |
Getting Started With EJB by Venkat Subbarao | |
Using Access Attributes To Restrict Importability by David Wall | |
How to Display Pop-up Windows from Applets by Venkat Subbarao | |
Bust Out | |
E-mail Validation | |
Status Bar Scroll | |
Spawning a Window | |
Implementing Different Types of Entity Beans | |
More About Interfaces | |
Implementing Different Types of Session Beans By Venkat Subbarao | |
Using Interfaces by David Wall | |
Roles in EJB Architecture: By Venkat Subbarao | |
Getting A Handle on Exceptions By David Wall | |
Buttons to Close a Window | |