Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Ganesh_JavaSE7_Programming_1z0-804_study_guide.pdf
Скачиваний:
94
Добавлен:
02.02.2015
Размер:
5.88 Mб
Скачать

Chapter 8 Java I/O Fundamentals

the object again. What you can observe from the output is that the value of the field term is not stored by the program. Why? Because you declared term as a transient field. All class members declared as transient are not serialized, so their values are lost after deserialization.

One more thing requires attention here—serialVersionUID. In this example, it’s set it to 1. If you are implementing Serializable and not defining serialVersionUID, you will get a warning message. In fact, if you don’t define it, JVM will define it for you; JVM will compute it based on the class behavior. But why it is required? Well, it is there to prevent mistakenly loading a wrong version of a class while deserializing. Also, defining serialVersionUID enables the serialized program to work across different JVM implementations seamlessly (which might not be a case when you are not defining it explicitly). The bottom line: whenever you make a change in a serialized class, do not forget to change the serialVersionUID also.

Points to Remember

Here are the noteworthy points to help you grasp Java I/O concepts:

When you use buffered streams, you should call flush() once you are done with data transmission. The internal buffer might be holding some data that will be cleared and sent to the destination once you call flush(). However, the method close() on the stream will automatically call flush().

You might have observed that you can combine stream objects. You can create an object of BufferedInputStream that takes a FileInputStream object. In this way, the output of one stream is chained to the filtered stream. This is the important, useful, and beautiful way to customize the stream in a desired way.

The Serializable interface is a marker interface. That means the Serializable interface does not declare any method inside it.

If you want to customize the process of serialization, you can implement readObject() and writeObject(). Note that both of these methods are private methods, which means you are not overriding or overloading these methods. JVM checks the implementation of these methods and calls them instead of the usual methods. It sounds weird but it is the way the customization of serialization process is implemented in the JVM.

As discussed in earlier sections, a serialized object can be communicated over the network and deserialized on another machine. However, the class file of the object must be in the path of the destination machine, otherwise only the state of the object will be restored—not the whole object (i.e., you cannot invoke a method on the restored object).

You can create your own protocol for serialization. For that, you just need to implement the Externalizable interface instead of the Serializable interface.

When you are not specifying serialVersionUID in a serialized class, JVM computes it for you. However, each JVM implementation has different mechanism to compute it; hence, it is not guaranteed that your serialized class will work on two different JVMs when you have not specified the serialVersionUID explicitly. Therefore, it is strongly recommended that you provide serialVersionUID in a class implementing the Serializable interface.

246

Chapter 8 Java I/O Fundamentals

Question Time!

1.Consider the following code snippet:

USPresident usPresident = new USPresident("Barack Obama", "2009 to --", 56); try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("USPresident.data"))){

oos.writeObject(usPresident);

usPresident.setTerm(57);

oos.writeObject(usPresident);

}

If you deserialize the object and print the field term (term is declared as int and is not a transient), what it will print?

A.56

B.57

C.null

D.Compiler error

E.Runtime exception

Answer: A. 56

(Yes, it will print 56 even though you changed the term using its setter to 57 and serialized again. This happens due to serialVersionUID, which is checked by the JVM at the time of serialization. If a class is already serialized and you try to serialize it again, the JVM will not serialize it.)

2.Consider the following code segment:

OutputStream os = new FileOutputStream("log.txt"); System.setErr(new PrintStream(os)); // SET SYSTEM.ERR System.err.println("Error");

Which one of the following statements is true regarding this code segment?

A.The line with comment SET SYSTEM.ERR will not compile and will result in a compiler error.

B.The line with comment SET SYSTEM.ERR will result in throwing a runtime exception since System.err cannot be programmatically redirected.

C.The program will print the text “Error” in console since System.err by default sends the output to console.

D.This code segment redirects the System.err to the log.txt file and will write the text “Error” to that file.

247

Chapter 8 Java I/O Fundamentals

Answer: d. this code segment redirects the System.err to the log.txt file and will write the text “error” to that file.

(note that you can redirect the System.err programmatically using the setErr() method. System.err is of type PrintStream, and the System.setErr() method takes a

PrintStream as an argument. Once the error stream is set, all writes to System.err will be redirected to it. hence, this program will create log.txt with the text “error” in it.)

3.Which one of the following definitions of the AResource class implementation is correct so that it can be used with try-with-resources statement?

a.class AResource implements Closeable {

protected void close() /* throws IOException */ { // body of close to release the resource

}

}

B.class AResource implements Closeable {

public void autoClose() /* throws IOException */ { // body of close to release the resource

}

}

C.class AResource implements AutoCloseable {

void close() /* throws IOException */ {

// body of close to release the resource

}

}

d.class AResource implements AutoCloseable {

public void close() throws IOException {

// body of close to release the resource

}

}

Answer:

d.class AResource implements AutoCloseable {

public void close() throws IOException {

// body of close to release the resource

}

}

(AutoCloseable is the base interface of the Closeable interface; AutoCloseable declares close as void close() throws Exception; In Closeable, it is declared as public void close() throws IOException;. For a class to be used with try-with- resources, it should both implement Closeable or AutoCloseable and correctly override the close() method. Option a declares open() protected; since the close() method is declared public in the base interface, you cannot reduce its visibility to protected, so this will result in a compiler error. Option B declares autoClose(); a correct implementation

248

Chapter 8 Java I/O Fundamentals

would define the close() method. Option C declares close() with default access; since the close method is declared public in the base interface, you cannot reduce its visibility to default accesses, so it will result in a compiler error. Option D is a correct implementation of the AResource class that overrides the close() method.)

4.Consider the following code segment:

FileInputStream findings = new FileInputStream("log.txt"); DataInputStream dataStream = new DataInputStream(findings); BufferedReader br = new BufferedReader(new InputStreamReader(dataStream)); String line;

while ((line = br.readLine()) != null) { System.out.println(line);

}

br.close();

Which two options are true regarding this code segment?

A.br.close() statement will close only the BufferedReader object, and findings and dataStream will remain unclosed.

B.The br.close() statement will close the BufferedReader object and the underlying stream objects referred by findings and dataStream.

C.The readLine() method invoked in the statement br.readLine() can throw an IOException; if this exception is thrown, br.close() will not be called, resulting in a resource leak.

D.The readLine() method invoked in the statement br.readLine() can throw an IOException; however, there will not be any resource leaks since Garbage Collector collects all resources.

E.In this code segment, no exceptions can be thrown calling br.close(), so there is no possibility of resource leaks.

Answer: B and C. The br.close() statement will close the BufferedReader object and the underlying stream objects referred to by findings and dataStream. The readLine() method invoked in the statement br.readLine() can throw an IOException;if this exception is thrown, br.close() will not be called, resulting in a resource leak. Note that Garbage Collector will only collect unreferenced memory resources; it is the programmer’s responsibility to ensure that all other resources such as stream objects are released.

Summary

Reading and Writing Data to Console

You can obtain a reference to the console using the System.console() method; if the JVM is not associated with any console, this method will fail and return null.

Many methods are provided in Console-support formatted I/O. You can use the printf() and format() methods available in the Console class to print formatted text; the overloaded readLine() and readPassword() methods take format strings as arguments.

249

Chapter 8 Java I/O Fundamentals

Use the readPassword() method for reading secure strings such as passwords. It is recommended to use Array’s fill() method to “empty” the password read into the character array (to avoid malicious access to the typed passwords).

The methods in the Console class have better support for special characters compared to printing text through PrintStreams.

Read and Write to Files with Streams

The java.io package has classes supporting both character streams and byte streams.

You can use character streams for text-based I/O. Byte streams are used for data-based I/O.

Character streams for reading and writing are called readers and writers respectively (represented by the abstract classes of Reader and Writer).

Byte streams for reading and writing are called input streams and output streams respectively (represented by the abstract classes of InputStream and OutputStream).

You should only use character streams for processing text files (or human-readable files), and byte streams for data files. If you try using one type of stream instead of another, your program won’t work as you would expect; even if it works by chance, you’ll get nasty bugs. So don’t mix up streams, and use the right stream for a given task at hand.

For both byte and character streams, you can use buffering. The buffer classes are provided as wrapper classes for the underlying streams. Using buffering will speed up the I/O when performing bulk I/O operations.

For processing data with primitive data types and strings, you can use data streams.

Serialization: The process of converting the objects in memory into a series of bytes.

Persistence: The mechanism of storing objects in memory into files.

You can use object streams for object persistence (i.e., reading and writing objects in memory to files and vice versa).

250

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]