Exercise 8.1: Go to the Java API documentation and see if you can find classes related to files.
package org.marvel.avengers; public class TopSecretMission { // etc ... }
Java has organized its vast library into packages:
// File: Blah.java // // Author: ... // Import all classes in a package: import java.io.*; // Alternatively: import only a specific class: import java.util.StringTokenizer;
We will list a few important ones below, as a quick "tour" of the "core" packages:
Other packages will undoubtedly be added to the library of future versions.
Java has evolved over the years. It is sometimes useful to understand the distinction between different versions:
Consider the class
java.lang.Math:public final class Math { // Two constants: public static final double E; public static final double PI; // Some class methods: public static int abs (int i); public static double abs (double x); // long and float versions // also available public static native double sin (double x); public static native double cost (double x); public static native double log (double x); public static native double exp (double x); public static native double sqrt (double x); public static native double pow (double x, double y); public static native long round (double); }
The String class in java.lang implements some class methods and many instance methods:
public final class String implements Serializable { // ... }
Note: the Serializable
interface indicates that String
instances can be written to files using serialization
public String (byte[] b); // Ascii representation.
public static String valueOf (double d);
This converts a double into a String.
// Get the character at i-th position. public char charAt (int i); // Compare strings: return -1 (less), 0 (equals) or 1. public int compareTo (String s); // Does it end with suffix s? public boolean endsWith (String s); // Does the instance equal string s? public boolean equals (String s); // Ignore case in testing equality. public boolean equalsIgnoreCase (String s); // Number of characters. public int length(); // Replace all occurences of a character. public String replace (char old, char new); // Does it start with prefix s? public boolean startsWith (String s); // Convert to lowercase. public String toLowerCase (); // Convert to uppercase. public String toUpperCase (); // Remove blanks on either side, but // not in the middle. public String trim ();
Next, consider the class Object:
public class Object { // Constructor. public Object (); // Test equality: really intended for // overriding. public boolean equals (Object obj); // Get class information dynamically. // Cannot be overridden. public final native Class getClass(); // Compute a hashcode. public native int hashCode(); // Convert to String. Intended to // be overridden. public String toString (); // Bitwise copy if Cloneable interface // is declared as implemented. protected native Object clone () throws CloneNotSupportedException. // For cleaning up. Meant to be // overridden. protected void finalize () throws Throwable; // These are all for Thread synchronization: public final native void notify (); public final native void notifyAll (); public final native void wait (long millis) throws InterruptedException; public final native void wait (long millis, long nanos) throws InterruptedException; public final native void wait () throws InterruptedException; }
Note:
Consider next the class java.lang.Integer:
public final class Integer extends Number { // Constructors. // Constants. // Class methods. // Instance methods. }
// Takes in the integer value. public Integer (int i); // Takes in a String and parses it. public Integer (String s) throws NumberFormat
// Largest possible integer. public static final int MAX_VALUE; // Smallest (most negative) integer. public static final int MIN_VALUE;
// Parses a String into an int. public static int parseInt (String s) throws NumberFormatException; // A base or radix can be specified. public static int parseInt (String s, int radix) throws NumberFormatException; // Convert int value to binary (String). public static String toBinaryString (int i); // Convert to hex. public static String toHexString (int i); // These are different from the standard toString(). public static String toString (int i); public static String toString (int i, int radix);
// Return the int as a double. public double doubleValue (); // equals() and toString() have // been overridden. public boolean equals (Object obj); public String toString ();
The class java.math.BigInteger can be used for arbitrary precision arithmetic.
Consider computing the powers of 2 using int's:
Here is how BigInteger can be used: (source file)
import java.math.*; public class TestBig { public static void main (String[] argv) { // Initialize. int i = 1; BigInteger I = new BigInteger ("1"); // We will need this constant. BigInteger Two = new BigInteger ("2"); // Compute successive powers of 2. for (int j=1; j<=64; j++) { i = i * 2; I = I.multiply (Two); System.out.println ("2 to the power " + j); System.out.println ("i = " + i); System.out.println ("I = " + I); System.out.print ("\n"); } } }
Note:
In-class Exercise 8.1: Write a program to print out numbers in the Fibonacci sequence. Print out the first 200 numbers in the sequence.
Micro-tutorial on Fibonacci numbers:
Unlike C/C++, Java's standard output streams do not provide convenient formatting mechanisms.
Without formatting explicitly, output can appear jagged, for example: (source file)
for (int i=0; i<=1000; i+=200) { int sqr = i * i; double root = Math.sqrt (i); System.out.println ("The square of " + i + " is " + sqr + " and the square root is " + root);
The output is:
The square of 0 is 0 and the square root is 0.0 The square of 200 is 40000 and the square root is 14.142135623730951 The square of 400 is 160000 and the square root is 20.0 The square of 600 is 360000 and the square root is 24.49489742783178 The square of 800 is 640000 and the square root is 28.284271247461902 The square of 1000 is 1000000 and the square root is 31.622776601683793
To format numbers, use DecimalFormat or NumberFormat instances:
First, consider formatting integers:
for (int i=0; i<=1000; i+=200) { int sqr = i * i; // Create a DecimalFormat instance, specifying // width in the constructor. DecimalFormat df = new DecimalFormat ("00000000"); // Extract a string by passing an int. String s = df.format (sqr); // Print the string. System.out.println (s + " is the square of " + i); }
The output is:
00000000 is the square of 0 00040000 is the square of 200 00160000 is the square of 400 00360000 is the square of 600 00640000 is the square of 800 01000000 is the square of 1000
Thus, each integer occupies 8 characters, with
leading zeroes filled in.
for (int i=0; i<=1000; i+=200) { int sqr = i * i; // Create a DecimalFormat instance, specifying // width in the constructor. DecimalFormat df = new DecimalFormat ("########"); // Extract a string by passing an int. String s = df.format (sqr); // Print the string. System.out.println (s + " is the square of " + i);
The output is:
0 is the square of 0 40000 is the square of 200 160000 is the square of 400 360000 is the square of 600 640000 is the square of 800 1000000 is the square of 1000
Note: using the #-symbol
does not achieve fixed-width formatting.
0 is the square of 0 40000 is the square of 200 160000 is the square of 400 360000 is the square of 600 640000 is the square of 800 1000000 is the square of 1000
we need to pad blanks.
DecimalFormat df = new DecimalFormat ("#");
is equivalent to:
DecimalFormat df = new DecimalFormat ("########");
Next, consider formatting double's:
double d1 = 9876.543; double d2 = 9876.0; double d3 = 0.543; DecimalFormat df = new DecimalFormat ("#.#"); String s1 = df.format (d1); String s2 = df.format (d2); String s3 = df.format (d3); System.out.println ("d1=" + s1 + " d2=" + s2 + " d3=" + s3); // Prints "d1=9876.5 d2=9876 d3=.5" df = new DecimalFormat ("####.####"); s1 = df.format (d1); s2 = df.format (d2); s3 = df.format (d3); System.out.println ("d1=" + s1 + " d2=" + s2 + " d3=" + s3); // Prints "d1=9876.543 d2=9876 d3=.543" df = new DecimalFormat ("0.0"); s1 = df.format (d1); s2 = df.format (d2); s3 = df.format (d3); System.out.println ("d1=" + s1 + " d2=" + s2 + " d3=" + s3); // Prints "d1=9876.5 d2=9876.0 d3=0.5" df = new DecimalFormat ("0000.0000"); s1 = df.format (d1); s2 = df.format (d2); s3 = df.format (d3); System.out.println ("d1=" + s1 + " d2=" + s2 + " d3=" + s3); // Prints "d1=9876.5430 d2=9876.0000 d3=0000.5430"
Finally, noting how complicated it is to use DecimalFormat, we provide some simple methods to specify precision: (source file)
class EasyFormat { // Pad blanks as required (for both int's and double's). static String pad_blanks (String s, int target_len, boolean is_int) { int slen = s.length(); // No decimal point to worry about with int's. if (is_int) { if (slen >= target_len) return s; // Otherwise we pad from front for (int i=1; i <= target_len-slen; i++) s = ' ' + s; return s; } // Otherwise check up to decimal point int i = s.indexOf ('.'); if ((i < 0) || (i >= slen)) { System.out.println ("ERR: pad_blanks: no decimal point"); System.exit(1); } if (i+1 >= target_len) return s; // Otherwise, pad with blanks for (int j=1; j < =target_len-(i+1); j++) s = ' ' + s; return s; } // Format integers. public static String format (long i, int width) { DecimalFormat df_i = new DecimalFormat ("#"); String s_i = df_i.format (i); s_i = pad_blanks (s_i, width, true); return s_i; } // Format double's. public static String format (double d, int before_dec_pt, int after_dec_pt) { // Use '#' symbols before decimal point. String s = ""; for (int i=1; i < before_dec_pt; i++) s = s + '#'; // Force a zero for numbers less than 1.0 s = s + "0."; // Include zeroes as specified by width. for (int i=1; i < =after_dec_pt; i++) s = s + '0'; DecimalFormat df_d = new DecimalFormat (s); String s_d = df_d.format (d); // Pad blanks. s_d = pad_blanks (s_d, before_dec_pt, false); return s_d; } } public class TestNumber4 { public static void main (String[] argv) { for (int i=0; i<=1000; i+=200) { String s = EasyFormat.format (i, 4); int sqr = i * i; String sqr_string = EasyFormat.format (sqr, 8); double root = Math.sqrt (i); String root_string = EasyFormat.format (root, 5, 3); System.out.println ("The square of " + s + " is " + sqr_string + " and the square root is " + root_string); } } }
The output is:
The square of 0 is 0 and the square root is 0.000 The square of 200 is 40000 and the square root is 14.142 The square of 400 is 160000 and the square root is 20.000 The square of 600 is 360000 and the square root is 24.494 The square of 800 is 640000 and the square root is 28.284 The square of 1000 is 1000000 and the square root is 31.622
public class TestNumber5 { public static void main (String[] argv) { for (int i=0; i<=1000; i+=200) { int sqr = i * i; double root = Math.sqrt (i); System.out.printf ("The square of %5d is %10d and the square root is %6.3f\n", i, sqr, root); } } }
The square of 0 is 0 and the square root is 0.000 The square of 200 is 40000 and the square root is 14.142 The square of 400 is 160000 and the square root is 20.000 The square of 600 is 360000 and the square root is 24.495 The square of 800 is 640000 and the square root is 28.284 The square of 1000 is 1000000 and the square root is 31.623
One of the methods in class java.lang.Object is the following:
public class Object { // ... public final native Class getClass(); // ... }
Notice that the return value is something called Class (capital C).
What is this thing called Class?
public final class Class implements Serializable { // Class methods: public static native Class forName (String name) throws ClassNotFoundException; // Some instance methods: public native String getName (); public Constructor[] getConstructors () throws SecurityException; public Field[] getFields () throws SecurityException; public Method[] getMethods () throws SecurityException; }
What it it used for?
Obj_A a = new Obj_A (); Class c = a.getClass (); // getClass() is inherited from Object.
A simple example:
String s = "hello"; // A String is a class. Class c = s.getClass (); // Get info about String's. System.out.println (c); // Print.
This is the output:
class java.lang.String
In this case, the name of the class (java.lang.String) is printed out.
Now suppose we define Obj_A as:
class Obj_A { // Data. int n; double x; // Constructors. public Obj_A (int n, double x) { this.n = n; this.x = x; } public Obj_A () { this (0, 0); } // Methods. public static void print () { System.out.println ("Obj_A"); } public String toString () { return "Obj_A: n=" + n + ", x=" + x; } }
Suppose now we want to extract information about the definition of Obj_A given an instance. Here's how:
Obj_A a = new Obj_A (); c = a.getClass (); System.out.println (c);
Instead of only getting the name, we can actually find out everything about Obj_A.
For example, we can count the constructors of Obj_A:
// Get constructors of Obj_A. Constructor[] ctor = c.getConstructors (); System.out.println ("Obj_A has " + ctor.length + " constructors");
or print a list of its methods:
// Get methods of Obj_A. Method[] method = c.getMethods(); System.out.println ("Obj_A has " + method.length + " methods: "); for (int i=0; i < method.length; i++) { String name = method[i].getName(); System.out.println (" " + name); }
Note:
public final class Method implements Member { // Member is an interface in java.lang.reflect. // Some instance methods: public Class getDeclaringClass(); // Get name of class. public String getName(); // Get method name. public Class[] getParameterTypes(); // Get list of parameter types. public Class getReturnType(); // Get return value type. // A very useful method - for dynamic invocation. public native Object invoke (Object obj, Object[] params) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException; }
You can go a step further: given just the name of a class, you can create an instance and use it: (source file
import java.lang.reflect.*; class Obj_A { // Data. int n; double x; // Constructors. public Obj_A (int n, double x) { this.n = n; this.x = x; } public Obj_A () { this (0, 0); } // Methods. public static void print () { System.out.println ("Obj_A"); } public String toString () { return "Obj_A: n=" + n + ", x=" + x; } } public class TestClass { public static void call_toString (String obj_name) { try { // Get the Class instance first. Class c = Class.forName (obj_name); // Get a list of methods. Method[] method = c.getMethods(); // Go through and look for toString() for (int i=0; i < method.length; i++) { // Get name of i-th method. String name = method[i].getName(); // If it is toString ... if (name.equals ("toString")) { System.out.println (obj_name + " has a toString() method"); try { // Create an instance of the object on the fly. Object instance = c.newInstance (); // No parameters, so a size=0 array is passed. Object[] obj_array = new Object[0]; // Call the powerful invoke() method. // Note: toString returns a string. String output = (String) method[i].invoke (instance, obj_array); // Print out the string returned from toString() System.out.println ("String returned: " + output); } // Catch a whole bunch of exceptions. catch (InstantiationException e) { System.out.println (e); } catch (IllegalAccessException e) { System.out.println (e); } catch (InvocationTargetException e) { System.out.println (e); } } } } catch (ClassNotFoundException e) { System.out.println (e); } } public static void main (String[] argv) { call_toString ("Obj_A"); } }
Since Obj_A has a toString(), it gets called and here's what is printed out:
Obj_A has a toString() method String returned: Obj_A: n=0, x=0.0
Thus, the class Class and the classes in java.lang.reflect can be used to dynamically create instances of any class.