Java in a Nutshell: A Desktop Quick Reference

Java in a Nutshell: A Desktop Quick Reference

by David Flanagan
     
 

View All Available Formats & Editions

The third edition of this bestselling book covers Java 2. It contains an advanced introduction to Java and its key APIs and provides its classic quick-reference material on all the classes and interfaces in the following APIs: java.lang, java.io, java.math, java.net, nava.text, java.util, and java.security.See more details below

Overview

The third edition of this bestselling book covers Java 2. It contains an advanced introduction to Java and its key APIs and provides its classic quick-reference material on all the classes and interfaces in the following APIs: java.lang, java.io, java.math, java.net, nava.text, java.util, and java.security.

Product Details

ISBN-13:
9781565924871
Publisher:
O'Reilly Media, Incorporated
Publication date:
11/30/1999
Series:
In a Nutshell (O'Reilly) Series
Edition description:
Third Edition
Pages:
666
Product dimensions:
6.04(w) x 9.00(h) x 1.21(d)

Read an Excerpt

Chapter 4: The Java Platform

4.7 Types, Reflection, and Dynamic Loading

The java.lang.Class class represents data types in Java and, along with the classes in the java.lang.reflect package, gives Java programs the capability of introspection (or self-reflection); a Java class can look at itself, or any other class, and determine its superclass, what methods it defines, and so on. There are several ways you can obtain a Class object in Java:

// Obtain the Class of an arbitrary object o Class c = o.getClass(); 
// Obtain a Class object for primitive types with various predefined 
constants c = Void.TYPE;          
// The special "no-return-value" type c = Byte.TYPE;          
// Class object that represents a byte c = Integer.TYPE;      
 // Class object that represents an int c = Double.TYPE;      
   // etc.  See also Short, Character, Long, Float. 
   // Express a class literal as a type name followed by ".class" c = int.class;          
// Same as Integer.TYPE c = String.class;      
 // Same as "dummystring".getClass() c = byte[].class;     
   // Type of byte arrays c = Class[][].class;   
    // Type of array of arrays of Class objects

Once you have a Class object, you can perform some interesting reflective operations with it:

import java.lang.reflect.*; Object o;                  
 // Some unknown object to investigate Class c = o.getClass();    
  // Get its type 
  // If it is an array, figure out its base type while (c.isArray()) c =
   c.getComponentType(); 
// If c is not a primitive type, print its class hierarchy if (!c.isPrimitive())
 {  for(Class s = c; s != null; s = s.getSuperclass()) 
// Try to create a new instance of c; 
this requires a no-arg constructor Object newobj = null;try { newobj =
 c.newInstance(); }catch (Exception e) { 
   // Handle InstantiationException, IllegalAccessException}
    // See if the class has a method named setText that takes a single String 
	// If so, call it with a string argumenttry {   Method m =
	 c.getMethod("setText", new Class[] { String.class });  
	  m.invoke(newobj, new Object[] { "My Label" }); } catch(Exception
	   e) { /* Handle exceptions here */ }

Class also provides a simple mechanism for dynamic class loading in Java. For more complete control over dynamic class loading, however, you should use a java.lang.ClassLoader object, typically a java.net.URLClassLoader. This technique is useful, for example, when you want to load a class that is named in a configuration file, instead of being hardcoded into your program:

// Dynamically load a class specified by name in a config file String classname = 
                    // Look up the name of the class   config.getProperties("filterclass",  
// The property name try {  Class c = Class.forName(classname); 
 // Dynamically load the class   Object o = c.newInstance();       
    // Dynamically instantiate it } catch (Exception e) { /* Handle exceptions */	 } 
// If the class to be loaded is not in the classpath, create a custom 
	 // class loader to load it.
	  // Use the config file again to specify the custom path import java.net.URLClassLoader; 
String classdir = config.getProperties("classpath");
try {   ClassLoader loader = new URLClassLoader(new URL[] { new URL(classdir) });
   Class c = loader.loadClass(classname);} catch (Exception e) { /* Handle exceptions */ }

4.8 Threads

java makes it easy to define and work with multiple threads of execution within a program. java.lang.Thread is the fundamental thread class in the Java API. There are two ways to define a thread. One is to subclass Thread, override the run() method, and then instantiate your Thread subclass. The other is to define a class that implements the Runnable method (i.e., define a run() method) and then pass an instance of this Runnable object to the Thread() constructor. In either case, the result is a Thread object, where the run() method is the body of the thread. When you call the start() method of the Thread object, the interpreter creates a new thread to execute the run() method. This new thread continues to run until the run() method exits, at which point it ceases to exist. Meanwhile, the original thread continues running itself, starting with the statement following the start() method. The following code demonstrates:

final List list;  
// Some long unsorted list of objects; initialized elsewhere
 /** A Thread class for sorting a List in the background 
 */ class BackgroundSorter extends Thread {  List l;   public
  BackgroundSorter(List l) { this.l = l; }    
  // Constructor   public void run() { Collections.sort(l); }         
  // Thread body} 
  // Create a BackgroundSorter thread Thread sorter = new
   BackgroundSorter(list); 
   // Start it running; the new thread runs the run() method above, while
    // the original thread continues with whatever statement comes next.
	 sorter.start();  
	 // Here's another way to define a similar thread Thread t = new Thread(new Runnable() {         
 // Create a new thread   public void run() { Collections.sort(list); }
  // to sort the list of objects. });t.start();  
                                      // Start it running

Threads can run at different priority levels. A thread at a given priority level does not run unless there are no higher-priority threads waiting to run. Here is some code you can use when working with thread priorities:

// Set a thread t to lower-than-normal priority
 t.setPriority(Thread.NORM_PRIORITY-1); 
// Set a thread to lower priority than the current thread
 t.setPriority(Thread.currentThread().getPriority() - 1);
  // Threads that don't pause for I/O should explicitly yield the CPU 
  // to give other threads with the same priority a chance to run. 
  Thread t = new Thread(new Runnable() {  public void run() {

Often, threads are used to perform some kind of repetitive task at a fixed interval. This is particularly true when doing graphical programming that involves animation or similar effects:

public class Clock extends Thread {   java.text.DateFormat f =      
// How to format the time for this locale   boolean keepRunning = true; 
 public Clock() {        
  // The constructor   public void run() {      
  // The body of the thread  
   public void pleaseStop() { keepRunning = false; }}

Notice the pleaseStop() method in the previous example. You can forcefully terminate a thread by calling its stop() method, but this method has been deprecated because a thread that is forcefully stopped can leave objects it is manipulating in an inconsistent state. If you need a thread that can be stopped, you should define a method such as pleaseStop() that stops the thread in a controlled way.

In Java 1.3, the java.util.Timer and java.util.TimerTask classes make it even easier to run repetitive tasks. Here is some code that behaves much like the previous Clock class:

import java.util.*; 
// How to format the time for this locale final java.text.DateFormat timeFmt = 
  java.text.DateFormat.getTimeInstance(java.text.DateFormat.MEDIUM); 
  // Define the time display taskTimerTask displayTime = new TimerTask() {  
   public void run() { System.out.println(timeFmt.format(new Date())); }};
    // Create a timer object to run the task (and possibly others) Timer timer =
	 new Timer(); 
	 // Now schedule that task to be run every 1000 milliseconds, starting now
	  Timer.schedule(displayTime, 0, 1000);
	  // To stop the time display task displayTime.cancel();

Sometimes one thread needs to stop and wait for another thread to complete. You can accomplish this with the join() method:

List list; 
 // A long list of objects to be sorted; initialized elsewhere 
 // Define a thread to sort the list: lower its priority, so it only runs 
 // when the current thread is waiting for I/O and then start it running. 
 Thread sorter = new BackgroundSorter(list);               
 // Defined earlier sorter.setPriority(Thread.currentThread.getPriority()-1); 
 // Lower priority sorter.start();                                         
   // Start sorting 
   // Meanwhile, in this original thread, read data from a file byte[] data =
    readData();  
// Method defined elsewhere
 // Before we can proceed, we need the list to be fully sorted, so 
 // we've got to wait for the sorter thread to exit, if it hasn't
  already. sorter.join();

When using multiple threads, you must be very careful if you allow more than one thread to access the same data structure. Consider what would happen if one thread was trying to loop through the elements of a List while another thread was sorting those elements. Preventing this problem is called thread synchronization and is one of the central problems of multithreaded computing. The basic technique for preventing two threads from accessing the same object at the same time is to require a thread to obtain a lock on the object before the thread can modify it. While any one thread holds the lock, another thread that requests the lock has to wait until the first thread is done and releases the lock. Every Java object has the fundamental ability to provide such a locking capability.

The easiest way to keep objects thread-safe is to declare any sensitive methods synchronized. A thread must obtain a lock on an object before it can execute any of its synchronized methods, which means that no other thread can execute any other synchronized method at the same time. (If a static method is declared synchronized, the thread must obtain a lock on the class, and this works in the same manner.) To do finer-grained locking, you can specify synchronized blocks of code that hold a lock on a specified object for a short time.....

Read More

Customer Reviews

Average Review:

Write a Review

and post it to your social network

     

Most Helpful Customer Reviews

See all customer reviews >