Wednesday 2 March 2016

Our Color Methods

Now we have an array of Color objects and a variable with which to index the array. Two private methods do the actual work for us. The private modifier on these methods specifies that they can be called only by other methods in the same instance of the class. They cannot be accessed outside the object that contains them. We declare members to be private to hide the detailed inner workings of a class from the outside world. This is called encapsulation and is another tenet of object-oriented design as well as good programming practice. Private methods are created as helper functions for use solely in the class implementation. The first method, currentColor(), is simply a convenience routine that returns the Color object representing the current text color. It returns the Color object in the someColors array at the index specified by our colorIndex variable:

 synchronized private Color currentColor() {  
 return someColors[colorIndex];  
 }  
We could just as readily have used the expression someColors[colorIndex] everywhere we use currentColor(); however, creating methods to wrap common tasks is another way of shielding ourselves from the details of our class. In an alternative implementation, we might have shuffled off details of all color-related code into a separate class. We could have created a class that takes an array of colors in its constructor and then provides two methods: one to ask for the current color and one to cycle to the next color (just some food for thought). The second method, changeColor(), is responsible for incrementing the colorIndex variable to point to the next Color in the array. changeColor() is called from our actionPerformed() method whenever the button is pressed:
 synchronized private void changeColor() {  
 // Change the index to the next color, awkwardly.  
 if ( ++colorIndex == someColors.length )  
 colorIndex = 0;  
 setForeground( currentColor() ); // Use the new color.  
 repaint();  
 }  
Here we increment colorIndex and compare it to the length of the someColors array. All array objects have a variable called length that specifies the number of elements in the array. If we have reached the end of the array, we wrap around to the beginning by resetting the index to 0. We’ve flagged this with a comment to indicate that we’re doing something fishy here. But we’ll come back to that in a moment. After changing the currently selected color, we do two things. First, we call the component’s setFore ground() method, which changes the color used to draw text in our component. Then we call repaint() to cause the component to be redrawn with the new color for the draggable message. What is the synchronized keyword that appears in front of our currentColor() and changeColor() methods? Synchronization has to do with threads, which we’ll examine in the next section. For now, all you need to know is that the synchronized keyword indicates that these two methods can never be running at the same time. They must always run in a mutually exclusive way. The reason for this is related to the fishy way we increment our index. Notice that in changeColor(), we increment colorIndex before testing its value. Strictly speaking, this means that for some brief period of time while Java is running through our code, colorIndex can have a value that is past the end of our array. If our currentColor() method happened to run at that same moment, we would see a runtime “array out of bounds” error. Now, it would be easy for us to fix the problem in this case with some simple arithmetic before changing the value, but this simple example is representative of more general synchronization issues that we need to address. We’ll use it to illustrate the use of the synchronized keyword. In the next section, you’ll see that Java makes dealing with these problems relatively easy through language-level synchronization support.

0 comments:

Post a Comment