Object-Oriented Programming 95-712

Download Report

Transcript Object-Oriented Programming 95-712

Object-Oriented Programming
95-712
MISM/MSIT
Carnegie Mellon University
Lecture 10: I/O, RTTI
Today’s Topics
The File class
 Using command line arguments
 More on the Java I/O classes
 The SimpleInput class, in detail
 Java’s compression classes (briefly)
 Run-time type identification (RTTI)
 A little on javadoc

The File Class
Think of this as holding a file name, or a list
of file names (as in a directory).
 You create one by giving the constructor a
pathname, as in

File f = new
File(D:\Together5.02\myprojects\JavaCourse\Week9\DirList\.);
This is a directory, so now the File f holds a
list of (the names of) files in the directory.
 It’s straightforward to print them out.

Listing Files
import java.io.*;
import java.util.*;
public class DirList {
public static void main(String[] args) {
File path = new File(".");
String[] list;
System.out.println(path.getAbsolutePath());
if(args.length == 0)
list = path.list();
else
list = path.list(new DirFilter(args[0]));
for (int i = 0; i < list.length; i++)
System.out.println(list[i]);
}
}
With No Command Line Args…
D:\Together5.02\myprojects\JavaCourse\Week9\DirList\.
default.dfPackage
default.dfPackage.wmf
DirFilter.java
DirList.java
DirList.tpr
DirList.tws
With “.java” on the Command Line
D:\Together5.02\myprojects\JavaCourse\Week9\DirList\.
DirFilter.java
DirList.java
DirFilter is a FilenameFilter

Its only method is accept():
import java.io.*;
import java.util.*;
public class DirFilter implements FilenameFilter {
String afn;
DirFilter(String afn) { this.afn = afn; }
public boolean accept(File dir, String name) {
String f = new File(name).getName();
return f.indexOf(afn) != -1;
}
}
Using the “args” in main()

All this time we’ve been dumbly typing
public static void main(String[] args) {…
args is an array of Strings, but for us it’s
usually been empty.
 It contains any command line parameters
we choose to include.
 If we’re at a DOS or Unix command line,
we might type >java DirList .java
 In Together, we set the Run Configuration

Setting the Run Configuration
Other File Methods
canRead()
 canWrite()
 exists()
 getParent()
 isDirectory()
 isFile()
 lastModified()
 length()

File Methods for Modifying
createNewFile()
 delete()
 makeDir()
 makeDirs()
 renameTo()
 setLastModified()
 setReadOnly()

More on Input
I nputStream
read():int
read():byte[]
All of these
return bytes!
Fi lterI nputStream Fi leInpu tStream
ObjectIn putStream
read():int
readObject():Object
read():int
B ufferedI nputStream D ataI nputStream
I nfl atorIn putStream
read():int
read():int
readByte():byte
readChar():char
readDouble():double
readInt():int
FilterInputStream JavaDoc



A FilterInputStream contains some other input
stream, which it uses as its basic source of data,
possibly transforming the data along the way or
providing additional functionality.
The class FilterInputStream itself simply overrides
all methods of InputStream with versions that pass
all requests to the contained input stream.
Subclasses of FilterInputStream may further
override some of these methods and may also
provide additional methods and fields.
Readers
R eader
read():int
These return
chars!
B ufferedR eader I nputStreamR eaderStringR eader
Fi leReader
We Saw These Last Time
BufferedReader br =
new BufferedReader(new
InputStreamReader(System.in));
InputStreamReader isr = new
InputStreamReader(new
FileInputStream("FileInput.java")); //slow: unbuffered
This is easier (if we’re happy with the default
character encoding and buffer size:
InputStreamReader isr = new
FileReader(" FileInput.java");
OutputStreams and Writers
Basically, a “mirror image” of
InputStreams and Readers.
 Wrapping is the same, e.g.,

BufferedWriter bw =
new BufferedWriter(new OutputStreamWriter(System.out));
String s;
try {
while ((s = br.readLine()).length() != 0) {
bw.write(s, 0, s.length());
bw.newLine();
bw.flush();
}
}
FileWriter

Again, basically the same. The constructors are
–
–
–
–



FileWriter(File file)
FileWriter(FileDescriptor fd)
FileWriter(String s)
FileWriter(String s, boolean append)
The last one allows appending, rather than writing
to the beginning (and erasing an existing file!).
These will create files!
There is also PrintWriter
PrintWriter
PrintWriter out =
new PrintWriter(new BufferedWriter(new FileWriter("Test.txt")));
String s;
try {
while ((s = br.readLine()).length() != 0) {
bw.write(s, 0, s.length());
bw.newLine();
bw.flush();
out.println(s);
//out.flush();
}
}
catch(IOException e) {
}
out.close();
// also flushes
The SimpleInput Class


You’ve used this class (by David Barnes) a
number of times, now let’s examine it.
The idea is to make it easy to open a file, and
provide methods like
–
–
–
–
–
–
–

short nextShort()
double nextDouble()
…all the other primitive types
String nextWord()
String nextLine()
String getDelimiters()
void setDelimiters(String)
The “file” could be System.in.
SimpleInput (cont.)
This functionality is provided in C++ by the
standard iostream library. Why something
similar isn’t “stock” in Java mystifies me…
 SimpleInput uses the StringTokenizer
class
 The StreamTokenizer class is similar, but
with more features (and some drawbacks).
 What’s a “token”? Any sequence of nondelimiter characters.

StringTokenizer Example
StringTokenizer st = new StringTokenizer("this is a test");
while (st.hasMoreTokens()) {
println(st.nextToken());
}
This prints:
this
is
a
test
The default delimiter string is " \t\n\r\f"
How Does It Work?
Tokenizer initialized with a String:
t h i s
i s
a
t e s t
delimiters { \t\n\r\f}
Call nextToken(); search forward for next non-delimiter,
and remember its position
t h i s
i s
a
t e s t
(A very short search this time!)
delimiters { \t\n\r\f}
How Does It Work (cont.)
Search forward for next delimiter,
and remember its position
t h i s
i s
a
t e s t
delimiters { \t\n\r\f}
Create and return the substring between these two positions.
t h i s
i s
a
t e s t
t h i s
delimiters { \t\n\r\f}
The Basic Plan


A StringTokenizer holds the current line.
Upon a request for a token:
– if there are tokens remaining in the current line, try to
convert the next token to the desired type, and return it
– otherwise, skip and try to convert the next token
– otherwise, read a new line, and try again

Upon a request for the next line:
– discard the “left-over” line
– read a new line and return it
Private Variables
import java.io.*;
import java.util.StringTokenizer;
public class SimpleInput {
private static final BufferedReader stdinReader =
new BufferedReader(new InputStreamReader(System.in));
private BufferedReader reader = stdinReader;
private String delimiters = " ";
private StringTokenizer tokenizer = new StringTokenizer("");
}
Private Variables
This illustrates the way that Java
implements “default values”.
 A class simply initializes member variables
to default values in its class declaration, and
leaves it to a constructor to change the
defaults as required.
 This is equivalent to the C++ technique of
default constructor arguments.
 There are “set `n get” methods for these:

Private vs. Public Set `n Gets
private BufferedReader getReader() { return reader; }
private void setReader(BufferedReader r) { reader = r; }
private StringTokenizer getTokenizer() { return tokenizer; }
private void setTokenizer(StringTokenizer t) { tokenizer = t; }
public String getDelimiters() { return delimiters; }
public void setDelimiters(String d) {
if ((d != null) && (d.length() > 0))
delimiters = d;
}
SimpleInput Constructors
public SimpleInput() { // uses standard input }
public SimpleInput(String file) throws RuntimeException {
File details = new File(file);
if (!details.exists())
throw new RuntimeException(file + " does not exist.");
else if (!details.canRead())
throw new RuntimeException(file + " exists but is unreadable.");
else if (!details.isFile())
throw new RuntimeException(file + " is not a regular file.");
else {
try {
setReader(new BufferedReader(new FileReader(details)));
}
catch (FileNotFoundException e) {
throw new RuntimeException("Failed to open " + file + " for unknown reason.");
}
}
}
getLine() (Note It’s public)
public String nextLine() throws RuntimeException {
try {
discardLine();
BufferedReader reader = getReader();
String line = reader.readLine();
//if (line == null)
// throw new RuntimeException("End of input.");
return line;
}
catch (IOException e) {
// pass it on as an unchecked exception
throw new RuntimeException(e.getMessage());
}
}
Is EOF An Exception?
Exceptions are things we don’t expect will
ever happen.
 But EOF happens for every file!
 Is null an OK thing to return from
getLine()?
 Isn’t null just what a Reader returns?
 Will this cause problems elsewhere?

Now nextToken()
private String nextToken() throws RuntimeException {
StringTokenizer t = getTokenizer();
final String delimiters = getDelimiters();
if (!t.hasMoreTokens()) {
do {
String line = nextLine(); //could throw exception
t = new StringTokenizer(line, delimiters);
setTokenizer(t);
} while (!t.hasMoreTokens());
}
return t.nextToken(delimiters); // could throw exception
}
nextWord(), nextBoolean()
public String nextWord() throws RuntimeException {
return nextToken();
}
public boolean nextBoolean() throws RuntimeException {
for ( ; ; ) {
String s = nextWord();
if (s.equalsIgnoreCase("t") || s.equalsIgnoreCase("true"))
return true;
else if (s.equalsIgnoreCase("f") || s.equalsIgnoreCase("false"))
return false;
}
}
Where Are We?



So far, everything is in place to read lines and
extract tokens.
An Exception structure is in place to report EOF.
The public methods so far are
– nextLine()
– nextWord()
– nextBoolean()


Now some methods for numbers.
The plan: so long as we can find something
recognizable as a double, cast it to the required
type.
private double nextNumber() throws RuntimeException {
Double number = null; // note this is Double, not double!
do {
String numString = null;
try {
numString = nextToken();
number = new Double(numString);
}
catch (NumberFormatException e) {
numString = numString.toLowerCase();
numString = numString.replace('d', 'e');
try {
number = new Double(numString);
}
catch (NumberFormatException ex) {
// failed again
}
}
} while (number == null);
return number.doubleValue();
}
A Little About Double




The constructor used is Double(String s)
“Constructs a newly allocated Double object that
represents the floating- point value of type double
represented by the string. The string is converted
to a double value as if by the valueOf method.”
See the description of valueOf() (it’s a bit
complicated, but rest assured it tries hard!)
Acceptable Strings include 12, -1.34, -1.0e-10,
etc.
These Two Are Natural
public float nextFloat() throws RuntimeException {
return (float)nextNumber();
}
public double nextDouble() throws RuntimeException {
return (double)nextNumber();
}
These Are Less Natural
public short nextShort() throws RuntimeException {
return (short)nextNumber();
}
public int nextInt() throws RuntimeException {
return (int)nextNumber();
}
public long nextLong() throws RuntimeException {
return (long)nextNumber();
}
SimpleInput: Summary

Some hard design decisions
– Do everything possible to return the type asked
for.
– Use exceptions freely to make problems visible.

Are other choices possible? As always, yes!
– Throwing exceptions from nextInt(), etc. seem
reasonable, but EOF is a common occurrence.
– Why not a hierarchy of specialized exceptions
to make clearer just what has gone wrong?
Java’s Compression Classes
These are used to write and read streams in
Zip and GZIP formats.
 As always, these classes are wrappers
around existing I/O classes, for
“transparent” use.
 These classes are astonishingly easy to use!
 C++ should have this…
 Here is a picture of the input classes (the
output classes are similar):

The Compression Input Classes
Fi lterI nputStream
read():int
B ufferedI nputStream D ataI nputStream
I nfl atorIn putStream C heckedI nputStream
read():int
read():int
readByte():byte
readChar():char
readDouble():double
readInt():int
GZIPI nputStream
Zi pInputStream
Eckel’s GZIP Example (1st part)
import java.io.*;
import java.util.zip.*;
public class GZIPCompress {
public static void main(String[] args) throws IOException {
BufferedReader in = new BufferedReader(
new FileReader(args[0]));
BufferedOutputStream out = new BufferedOutputStream(
new GZIPOutputStream(new FileOutputStream("test.gz")));
System.out.println("Writing file");
int c;
while((c = in.read()) != -1)
out.write(c);
in.close();
out.close();
GZIP Example (2nd part)
System.out.println("Reading file");
BufferedReader in2 =
new BufferedReader(
new InputStreamReader(
new GZIPInputStream(
new FileInputStream("test.gz")))); // whew!
String s;
while((s = in2.readLine()) != null)
System.out.println(s);
}
}
Comments
GZIP and Zip are specific algorithms for
compressing and uncompressing. You’ll
have to wait for details until Prof.
McCarthy’s course.
 This program works pretty well:

– DancingMen.txt is 51KB
– test.gz is 21KB
RTTI
We know this is possible, first, because of
the Cats`n`Dogs example.
 An ArrayList of Cats, with a Dog somehow
placed in it.
 Calling purr() for the Cats works, but not
for the Dog: ClassCastException.
 Second, we’ve seen this example:

Finding a Battery
boolean takeAnAABattery() {
Iterator i = contents.iterator();
Object aa = null;
// initialize, or compiler complains
while(i.hasNext()) {
if ( (aa = i.next()) instanceof AABattery ) {
contents.remove(aa);
return true;
}
}
return false;
}
RTTI and Polymorphism
class Shape {}
class Circle extends Shape {public void draw(){}}
class Square extends Shape {public void draw(){}}
public class Shapes {
public static void main(String[] args) {
ArrayList s = new ArrayList();
s.add(new Circle());
s.add(new Square());
Iterator e = s.iterator();
while(e.hasNext())
((Shape)e.next()).draw();
}
}
Class Objects




Contain information about each of the classes in
our program.
When we write and compile a class, say MyClass,
the Class object for MyClass is generated.
When we use MyClass at runtime (by creating an
object or calling a static method), the Class object
is loaded, and it creates the new MyClass object.
The same Class object is used to make any other
MyClass objects we require.
Using Class Objects

We can get a reference to a Class object:
MyClass.class;

The Class class (whew!) has a number of useful
methods:
–
–
–
–
–
–
Method[] getMethods()
Field[] getFields()
String getName()
boolean isArray()
boolean isInstance(Object)
Object newInstance()
newInstance()
ArrayList s = new ArrayList();
Class[] shapes = {Circle.class, Square.class};
try {
for (int i = 0; i < 10; i++) {
int r = Random.nextInt(2);
s.add(shapes[r].newInstance());
}
}
catch(InstantiationException e) {throw e;}
catch(IllegalAccessException e) {throw e;}

An alternative to the clone method we used in
genetic programming.
Run-Time Class Information
RTTI can give you the precise type of an
object at run-time, but the existence of the
type must be known at compile-time.
 What if we get a bunch of bytes (over the
Web, maybe) at runtime, and we’re told
they represent a class. Can we use it?
 Think of an application builder tool.
 Think of business rules in middleware on a
distant machine.

Run-Time Class Information
The Class class supports “reflection”, which
is a way to get information about a class
unknown at compile-time.
 The classes Field, Method and Constructor
can be used to find this information.
 These form the basis for RMI, serialization,
JavaBeans, and javadoc.
 Too advanced for me…
