
In contrast to the immutable string, the java.lang.StringBuilder class is a modifiable and expandable buffer for characters. You can use it to create a big string efficiently. StringBuilder andStringBuffer are twins; they have exactly the same API. StringBuilder was added in Java 5.0 as a drop-in, unsynchronized replacement for StringBuffer. We’ll come back to that in a bit.
First, let’s look at some examples of String construction:
This example creates an unnecessary String object each time we use the concatenation operator (+). Whether this is significant depends on how often this code is run and how big the string actually gets. Here’s a more extreme example:
This example repeatedly produces new String objects. The character array must be copied over and over, which can adversely affect performance. The solution is to use a StringBuilder object and itsappend() method:
Here, the StringBuilder efficiently handles expanding the array as necessary. We can get a String back from the StringBuilder with its toString() method:
You can also retrieve part of a StringBuilder as a String by using one of the substring() methods.
You might be interested to know that when you write a long expression using string concatenation, the compiler generates code that uses a StringBuilder behind the scenes:
It is really equivalent to:
String foo = new StringBuilder().append("To ").append("be ").append("or").toString();In this case, the compiler knows what you are trying to do and takes care of it for you.
The StringBuilder class provides a number of overloaded append() methods for adding any type of data to the buffer. StringBuilder also provides a number of overloaded insert() methods for inserting various types of data at a particular location in the string buffer. Furthermore, you can remove a single character or a range of characters with the deleteCharAt() and delete() methods. Finally, you can replace part of the StringBuilder with the contents of a String using the replace() method. The String and StringBuilder classes cooperate so that, in some cases, no copy of the data has to be made; the string data is shared between the objects.
You should use a StringBuilder instead of a String any time you need to keep adding characters to a string; it’s designed to handle such modifications efficiently. You can convert the StringBuilder to a String when you need it, or simply concatenate or print it anywhere you’d use a String.
As we said earlier, StringBuilder was added in Java 5.0 as a replacement for StringBuffer. The only real difference between the two is that the methods of StringBuffer are synchronized and the methods of StringBuilder are not. This means that if you wish to use StringBuilder from multiple threads concurrently, you must synchronize the access yourself (which is easily accomplished). The reason for the change is that most simple usage does not require any synchronization and shouldn’t have to pay the associated penalty (slight as it is).
Method
Functionality
charAt()
Gets a particular character in the string
compareTo()
Compares the string with another string
concat()
Concatenates the string with another string
contains()
Checks whether the string contains another string
copyValueOf()
Returns a string equivalent to the specified character array
endsWith()
Checks whether the string ends with a specified suffix
equals()
Compares the string with another string
equalsIgnoreCase()
Compares the string with another string, ignoring case
getBytes()
Copies characters from the string into a byte array
getChars()
Copies characters from the string into a character array
hashCode()
Returns a hashcode for the string
indexOf()
Searches for the first occurrence of a character or substring in the string
intern()
Fetches a unique instance of the string from a global shared-string pool
isEmpty()
Returns true if the string is zero length
lastIndexOf()
Searches for the last occurrence of a character or substring in a string
length()
Returns the length of the string
matches()
Determines if the whole string matches a regular expression pattern
regionMatches()
Checks whether a region of the string matches the specified region of another string
replace()
Replaces all occurrences of a character in the string with another character
replaceAll()
Replaces all occurrences of a regular expression pattern with a pattern
replaceFirst()
Replaces the first occurrence of a regular expression pattern with a pattern
split()
Splits the string into an array of strings using a regular expression pattern as a delimiter
startsWith()
Checks whether the string starts with a specified prefix
substring()
Returns a substring from the string
toCharArray()
Returns the array of characters from the string
toLowerCase()
Converts the string to lowercase
toString()
Returns the string value of an object
toUpperCase()
Converts the string to uppercase
trim()
Removes leading and trailing whitespace from the string
valueOf()
Returns a string representation of a value
Swing is Java’s graphical user interface toolkit. The javax.swing package (and its numerous subpackages) contain classes representing interface items such as windows, buttons, combo boxes, trees, tables, and menus—everything you need to build a modern, rich client-side application.
Swing is part of a larger collection of software called the Java Foundation Classes (JFC), which includes the following APIs:
The Abstract Window Toolkit (AWT), the original user interface toolkit and base graphics classes
Swing, the pure Java user interface toolkit
Accessibility, which provides tools for integrating nonstandard input and output devices into your user interfaces
The 2D API, a comprehensive set of classes for high-quality drawing
Drag and Drop, an API that supports the drag-and-drop metaphor
JFC is one of the largest and most complex parts of the standard Java platform, so it shouldn’t be any surprise that we’ll take several chapters to discuss it. In fact, we won’t even get to talk about all of it, just the most important parts—Swing and the 2D API.
Let’s take a look at producing some image data. A picture is worth a thousand words, and, fortunately, we can generate a pretty picture in significantly fewer than a thousand words of Java. If we just want to render image frames byte by byte, you can put together a BufferedImage pretty easily.
The following application, ColorPan, creates an image from an array of integers holding RGB pixel values:
BufferedImage can also be used to update an image dynamically. Because the image’s data arrays are directly accessible, you can simply change the data and redraw the picture whenever you want. This is probably the easiest way to build your own low-level animation software. The following example simulates the static on an old black-and-white television screen. It generates successive frames of random black and white pixels and displays each frame when it is complete. Figure 21-5 shows one frame of random static.
An image filter is an object that performs transformations on image data. The Java 2D API supports image filtering through the BufferedImageOp interface. An image filter takes a BufferedImage as input (the source image) and performs some processing on the image data, producing another BufferedImage (the destination image).
An affine transformation is a kind of 2D transformation that preserves parallel lines; this includes operations like scaling, rotating, and shearing. The java.awt.image.AffineTransformOp image operator geometrically transforms a source image to produce the destination image. To create an AffineTransformOp, specify the transformation you want in the form of an java.awt.geom.AffineTransform. TheImageProcessor application includes two examples of this operator, one for rotation and one for scaling. As before, the AffineTransformOp constructor accepts a set of hints; we’ll just pass null to keep things simple:
In both cases, we obtain an AffineTransform by calling one of its static methods. In the first case, we get a rotational transformation by supplying an angle. This transformation is wrapped in anAffineTransformOp. This operator has the effect of rotating the source image around its origin to create the destination image. In the second case, a scaling transformation is wrapped in anAffineTransformOp. The two scaling values, .5 and .5, specify that the image should be reduced to half its original size in both the x and y axes.
When using an AffineTransformOp to scale images, it’s important to note two things. Scaling an image up will always result in poor quality. When scaling an image down, and more generally with any affine transform, you can choose between speed and quality. Using AffineTransformOp.TYPE_NEAREST_NEIGHBOR as the second argument in your AffineTransformOp constructor will give you speed. For the best quality use AffineTransformOp.TYPE_BICUBIC. AffineTransformOp.TYPE_BILINEAR balances speed and quality.
One interesting aspect of AffineTransformOp is that you may “lose” part of your image when it’s transformed. For example, when using the rotate image operator in the ImageProcessor application, the destination image will have clipped some of the original image out. Both the source and destination images have the same origin, so if any part of the image gets transformed into negative x or y space, it is lost. To work around this problem, you can structure your transformations such that the entire destination image is in positive coordinate space.
We’ve spent a lot of time talking about loading images from files and generating and transforming image data, but nothing about saving it. First, let’s remember that saving an image to a file such as a JPG or GIF really implies doing two things: encoding it (highly compressing the data in a way optimized for the type of image) and then writing it to a file, possibly with various metadata. As we mentioned earlier, the core AWT does not provide tools for encoding image data, only decoding it. By contrast, the ImageIO framework has the capability of writing images in any format that it can read.
Writing a BufferedImage is simply a matter of calling the static ImageIO write() method:
The second argument is a string identifier that names the image type. You can get the list of supported formats by calling ImageIO.getWriterFormatNames(). We should note that the actual type of the image argument is something called RenderedImage, but BufferedImage implements that interface.
You can get more control over the encoding (for example, JPG quality settings) by getting an ImageWriter for the output format and using ImageWriteParams. The process is similar to that in the reader progress listener snippet from the section ImageIO.
A constructor can refer to another constructor in the same class or the immediate superclass using special forms of the this and super references. We’ll discuss the first case here and return to that of the superclass constructor after we have talked more about subclassing and inheritance. A constructor can invoke another overloaded constructor in its class using the self-referential method call this()with appropriate arguments to select the desired constructor. If a constructor calls another constructor, it must do so as its first statement:
In this example, the class Car has two constructors. The first, more explicit, one accepts arguments specifying the car’s model and its number of doors. The second constructor takes just the model as an argument and, in turn, calls the first constructor with a default value of four doors. The advantage of this approach is that you can have a single constructor do all the complicated setup work; other auxiliary constructors simply feed the appropriate arguments to that constructor.
The special call to this() must appear as the first statement in our delegating constructor. The syntax is restricted in this way because there’s a need to identify a clear chain of command in the calling of constructors. At the end of the chain, Java invokes the constructor of the superclass (if we don’t do it explicitly) to ensure that inherited members are initialized properly before we proceed.
There’s also a point in the chain, just after invoking the constructor of the superclass, where the initializers of the current class’s instance variables are evaluated. Before that point, we can’t even reference the instance variables of our class. We’ll explain this situation again in complete detail after we have talked about inheritance.
For now, all you need to know is that you can invoke a second constructor (delegate to it) only as the first statement of your constructor. For example, the following code is illegal and causes a compile-time error:
The simple model name constructor can’t do any additional setup before calling the more explicit constructor. It can’t even refer to an instance member for a constant value:
The instance variable defaultDoors is not initialized until a later point in the chain of constructor calls setting up the object, so the compiler doesn’t let us access it yet. Fortunately, we can solve this particular problem by using a static variable instead of an instance variable:
The static members of a class are initialized when the class is first loaded into the virtual machine, so it’s safe to access them in a constructor.
扫码加好友,拉您进群



收藏
