CSIS 3701: Advanced Object-Oriented Programming Static Variables and Methods Static Properties of Sets Up to this point, we have defined "class" and "object" in the following way: A class defines the properties that its objects have. An object actually contains those properties. For example, consider the NameList class. While the class specifies that each NameList contains a names, howMany and max, values for those variables are stored in each individual object: N1 N2 names: [“Bart”, “Homer”] names: [“Fred”] howMany: 2 howMany: 1 max: 5 . max: 3 . That is, N1 and N2 each contain individual state variables -- the NameList class as a whole does not. This may seem like an obvious thing to say -- it is kind of like saying that the int type does not have a value, but individual integer variables do. However, there are some exceptions to this -- it is possible for sets of objects to have properties, just like individual members of that set do. One (rather canonical) example has to do with the number of objects in a set. For example, suppose I create 2 NameLists: NameList N1, N2; The fact that two NameLists exist is a property of the NameList class, rather than the property of any individual NameList. number_of_lists = 2 . names: [“Bart”, “Homer”] names: [“Fred”] howMany: 2 howMany: 1 max: 5 . max: 3 . At this point, you may wonder how useful an ability this really is. The answer: not very. However, Java does use it in some very important ways to get around the restriction that “everything must be an object”, particularly where main is involved. We will discuss how to create such "class properties" in this section, and give some slightly more practical uses of this ability. Static State Variables In Java, "class properties" are defined with the keyword "static". For example, to store the number of total NameLists in a variable called numberOfLists, we would do the following inside the NameList class: public class NameList { private int howMany; private int max; private String[] namess; private static int numberOfLists = 0; ... } Unlike the other state variables, this does not create a numberOfLists state variable in each NameList object. Instead, one numberOfLists variable is created (with an initial value of 0), and stored separately from any NameList object. N1 N2 number: 2 number: 1 ........ ........ NameList class numberOfLists: 2 In order for this to work, we must make sure that this number is incremented whenever a new NameList is constructed: public NameList(int m) { howMany = 0; max = m; names = new String[max]; numberOfLists++; } Static Methods It is also possible to make methods static in Java. This is done by putting the keyword static before the method header. For example, we could use such a method to return the number of total NameLists: public class NameList { ... private static int numberOfLists = 0; ... public static int howManyLists() {return numberOfLists;} ... The unique thing about such methods is how they are invoked -- instead of sending a message to any particular object, we instead send it to the class. For example: int num = NameList.howManyLists(); There are cases where it is much more convenient to send a message to a class than to any individual object (for example, if no databases have yet been created!). This is why it was particularly important to initialize the value of numberOfLists directly in its definition rather than in any method or constructor – there is no guarantee any of these will have been executed before we are asked for the value of numberOfLists. Some encapsulation notes: Like other methods, we must make static methods public in order for users to have access to them. Like any other class method, a static method has access to all private members of any objects in the class. Static Class Constants There are many cases where we would like to make constants a part of a class. A good example is the RosterApp class, which in previous sections we have “hardwired” the size to 10. However, this is not the best approach, as it makes it difficult to modify that limit in the future -- we would have to find and change each relevant "10" in our code every time we needed to change this limit. As you should know by now, a better approach is to use a constant. In C, this would be done with the #define preprocessor command: #define MAX 10 Unfortunately, this would mean that no other class could use the name MAX, since this command changes the value of MAX globally throughout the entire program. Java does not allow the creation of such global constants for that reason. A better approach is to make such constants local to the class they are part of. This is done in Java by making such a constant a final state variable. final means that the value of the variable cannot be changed – it is equivalent to const in C++. For example: public class NameList { . . . private final MAX = 10; . . . However, this is very inefficient, as it means that MAX would be duplicated in every RosterApp ever created! A better way is to make MAX a static member of the class, which means that it will only be stored in a single place: public class RosterApp { . . . private static final int MAX = 10; public RosterApp() { . . . roster = new NameList(MAX); . . . } . . . } Built-in Java Class Constants There are many such class constants built into Java. As an example, we will describe how the alignment of visual objects (such as labels) is specified using class constants. The default alignment of the text in a JLabel is left alignment. However, other alignments (right or center) can be specified either in the constructor or with the setAlignment method. This is done by using public static state variables defined in the class: JLabel.LEFT JLabel.RIGHT JLabel.CENTER For example, to create the following application: We would write the following code: private JLabel larry, curley, moe; public Stooges() { larry = new JLabel("Larry", JLabel.LEFT); curley = new JLabel("Curley", JLabel.CENTER); moe = new JLabel("Moe", JLabel.RIGHT); Static Class Functions As mentioned above, making a method static makes it possible to call it by sending it to the class instead of an object in the class – that is, to invoke a piece of code in a class without creating any objects of that class. This provides a way to get around one of the problems with Java’s requirement that every piece of code must be a method in some class, as there are times when that simply does not make a lot of sense. For example, consider simple mathematical functions, such as square root. In C++, taking the square root can be done by just calling a function: x = sqrt(y); This is illegal in Java, however, as every message must be sent to some object in some class. For example, in Java the sqrt method is in the Math library. Therefore, in order to take the square root of something, we would first have to create a “Math” object, and then send it the sqrt message: Math m = new Math(); x = m.sqrt(y); This is very ugly and unintuitive syntax. Java gets around this problem by making sqrt and other math functions static methods in the Math class. This means that we don’t have to create a “math” object to send the sqrt message to – instead, we just send the message directly to the Math class: x = Math.sqrt(y); Parsing Integers with Static Functions One of the most commonly used functions in Java is the Integer.parseInt method, a static method in the Integer class. The Integer class contains a number of static methods for manipulating integers, as well as static constants related to integers (such as Integer.MAXINT). It can also be used to treat the simple integer type like an object, which we will cover in more detail later. The parseInt method is so important because textfields in Java work with strings instead of numbers. Therefore, if the user types a number into a textfield, I must convert the string in the textfield into a number before I can manipulate it. The following is a simple example of how I can get a number from JTextfield T, add 1 to it, and put the result back into T: String s = T.getText(); // get the number typed into T, // which is in the form of a String int i = Integer.parseInt(s); // parse the string into an // integer, and store in i i++; // increment it T.setText(“” + i); // convert back to a String (by // appending to the empty string) // and display in the textfield For another example, see the MileageApp application in the chapter on ObjectOriented Syntax. The System Class Another useful class with static methods is the System class. This class handles miscellaneous types of communication with the operating system. All of the methods in the class are static, as it is generally not a good idea to create a System object. Some of the more useful methods include: System.exit(0); Exits the currently running program. System.getProperty(String); Returns the system property corresponding to String (such as the name and version of the browser or operating system). It also contains static constants in, out, and err, which are used to access the standard streams. Those streams are also objects, which have their own methods. Probably the most useful is: System.out.println(String); Which prints String to the standard output (that is, the screen). The syntax may look a little strange, but makes sense if you think of it as “get the standard output object of the System class and send it a println message”. A couple of notes about these standard streams: While printing to standard output is simple, reading from standard input is much harder – the input must be translated from 8-bit bytes to 16-bit characters, and your code must also handle potential exceptions related to not being able to read from standard input. The standard streams are not universal to all platforms – for instance, the MacIntosh OS does not have a usable standard output. For those reasons, standard input and output are generally not used to communicate with users in Java. Instead, you should use a visual application of some sort, or the dialog boxes described in the next section. However, as seen in the section on Object-oriented Design and Debugging, the standard output is very useful for debugging. Dialog Boxes for Input/Output Recent versions of Java have introduced pop-up dialogs for simple I/O. These use both static methods in a class called JOptionPane, as well as a list of static constants used as parameters. Simple Output Messages A simple dialog box that displays a message (and an OK button to let the user close the dialog) is called a message dialog. One can be created with the static showMessageDialog method of the JOptionPane class. For example: JOptionPane.showMessageDialog(null, “Hi there!”); displays the following: The first parameter (that is, the null) is a reference to the “parent component” of the dialog (which we just set to null, since it is not really relevant in most situations). The second parameter is the string to display. We can exercise a little more control over the title of the dialog and the icon shown at the left using an overloaded version of the method: JOptionPane.showMessageDialog(null, message, title, messagetype); The message type is one of the static constants in the JOptionPane class: ERROR_MESSAGE INFORMATION_MESSAGE WARNING_MESSAGE QUESTION_MESSAGE PLAIN_MESSAGE no icon For example, the statement: JOptionPane.showMessageDialog(null, “Illegal input!”, “D’oh!”, JOptionPane.ERROR_MESSAGE); would display: Simple String Input Dialog boxes are also the simplest way to get input quickly from the user. The showInputDialog method displays a dialog box that allows the user to enter a single line of text. That text is then returned by the method, in the form of a String object. The method has the same parameters as the message dialog: returnValue = JOptionPane.showInputDialog(null, message, title, messagetype); For example, the following statement: String name = JOptionPane.showMessageDialog(null, “What is your name”, “Hello”, JOptionPane.QUESTION_MESSAGE); would display: The value entered by the user would be returned and stored in the variable name. Note that if the user presses Cancel instead, then null is returned – this is something you must test for! Finally, note that we have only scratched the surface here. You can also create Confirm dialogs (which give the user choices such as yes/no, ok/cancel, etc.) and Option dialogs (which present the user with a list of customized options). These are probably more user friendly that getting a string input. Recent versions of Java contain many options for dialogs, including file dialogs. You can also use inheritance to extend the basic dialog classes, to create custom dialogs. See the textbook for more details. The main Function We conclude by explaining the purpose of the main function used in the applications you have seen so far, and its relationship to static methods. As an example, we will again consider the Hello application in the chapter on Object-Oriented Syntax: public class Hello extends JFrame implements ActionListener, WindowListener { . . . public Hello() { . . . } public static void main(String[] args) { Hello h = new Hello(); // create an object } } Making main static solves a “chicken and the egg” type of problem we have with running programs in Java: The main method is invoked when the java program is run on the compiled .class file. This means that main must initiate the process of creating objects such as the Hello. Like every other piece of code, main must be a member of a class. This means to invoke main, we must first create an object to send that message to. In other words, we must create an object to invoke main on, but it is main which creates the object in the first place! Making main static avoids this problem. When the command java Hello is executed, it essentially runs the method Hello.main(), which starts up everything. Side note: You must include String[] args as the parameter to main. This is a list of command line arguments that can be included in the java command. For example, I could use it in the following very simple program: public class Beavis { public static void main(String[] args) { System.out.println(“HehHeh, you said “ + args[0]); } } If you compiled it, and then run it with the argument “hello”: java Beavis hello HehHeh, you said hello Copyright © 2000 by Dr. John R. Sullins