|
August 11, 1998 This issue presents tips, techniques, and sample code for the following topics:
Filter Streams A filter stream is two or more streams hooked together to provide added functionality. For example, one stream may provide a method to read in a large block of characters efficiently, while another stream built on the first one could offer a mechanism for buffering those characters so they can be read one at a time in an efficient way. Another example of filtering would be support for tracking line numbers. To see how all this works, consider the following program that searches a text file for a pattern, and displays each line containing the pattern along with its line number:
The example uses the LineNumberReader class in preference to the older LineNumberInputStream that has been deprecated. LineNumberReader is a buffered input reader that tracks line numbers as it goes. In other words, successive large chunks of the file are read into a buffer using FileReader. FileReader is a class that sets up a FileInputStream based on an actual file, and then uses the mechanisms of its superclass InputStreamReader to convert a stream of bytes into a sequence of Java language characters. readLine is then called to read each line in turn from the buffer. When a line terminator is detected, an internal line number counter is incremented, and its current value is retrieved using getLineNumber. Note that you can also design your own filter streams. One example is to extend java.io.BufferedReader so that readLine skips blank lines and returns only the lines that contain non-whitespace characters.
Default Constructors
B defines no constructors, but B is extended from A, and A does have a constructor that needs to be invoked for the instance of B. How does this work? What happens is that a default constructor is generated automatically, and the constructor calls the superclass constructor with no arguments. So "new B()" results in the generated default constructor for B being called, and it in turn calls the no-argument constructor for A. The generated constructor is given the access modifier "public" if the class is public, or else the constructor is given the default access implied by no modifier. You can actually observe a default constructor in generated code. For example, for the following source code:
class A {}
the result of "javap -c" (see Tech Tips: Jan 20, 1998), is:
Method A()
0 aload_0
1 invokespecial #3 <Method java.lang.Object()>
4 return
In other words, a constructor for A is generated, and it simply invokes the superclass (in this case java.lang.Object) constructor. Relying on default constructor generation is not necessarily good coding practice. In such a case it might be worth inserting an explanatory comment. Note also that you can control class instantiation by means of protected or private constructors. For example, a class used only as a packaging vehicle for class methods and variables might define a private constructor, making it uninstantiable. | ||||||
|
| ||||||||||||