Client/Server Tic-Tac-Toe Using a Multithreaded Server

Client Server Tic Tac Toe Using a Multithreaded Server

In this section, we present the popular game Tic-Tac-Toe implemented by using client/server techniques with stream sockets. The program consists of a TicTacToeServer application (Fig. 24.13Fig. 24.14) that allows two TicTacToeClient applications (Fig. 24.15Fig. 24.16) to connect to the server and play Tic-Tac-Toe. Sample outputs are shown in Fig. 24.17.

Figure 24.13. Server side of client/server Tic-Tac-Toe program.

(This item is displayed on pages 1140 - 1145 in the print version)

 1 // Fig. 24.13: TicTacToeServer.java
 2 // This class maintains a game of Tic-Tac-Toe for two clients.
 3 import java.awt.BorderLayout;
 4 import java.net.ServerSocket;
 5 import java.net.Socket;
 6 import java.io.IOException;
 7 import java.util.Formatter;
 8 import java.util.Scanner;
 9 import java.util.concurrent.ExecutorService;
10 import java.util.concurrent.Executors;
11 import java.util.concurrent.locks.Lock;
12 import java.util.concurrent.locks.ReentrantLock;
13 import java.util.concurrent.locks.Condition;
14 import javax.swing.JFrame;
15 import javax.swing.JTextArea;
16 import javax.swing.SwingUtilities;
17 
18 public class TicTacToeServer extends JFrame
19 {
20 private String[] board = new String[ 9 ]; // tic-tac-toe board
21 private JTextArea outputArea; // for outputting moves
22 private Player[] players; // array of Players
23 private ServerSocket server; // server socket to connect with clients
24 private int currentPlayer; // keeps track of player with current move
25 private final static int PLAYER_X = 0; // constant for first player
26 private final static int PLAYER_O = 1; // constant for second player
27 private final static String[] MARKS = { "X", "O" }; // array of marks
28 private ExecutorService runGame; // will run players
29 private Lock gameLock; // to lock game for synchronization
30 private Condition otherPlayerConnected; // to wait for other player
31 private Condition otherPlayerTurn; // to wait for other player's turn
32 
33 // set up tic-tac-toe server and GUI that displays messages
34 public TicTacToeServer()
35 {
36 super( "Tic-Tac-Toe Server" ); // set title of window
37 
38 // create ExecutorService with a thread for each player
39 runGame = Executors.newFixedThreadPool( 2 );
40 gameLock = new ReentrantLock(); // create lock for game
41 
42 // condition variable for both players being connected
43 otherPlayerConnected = gameLock.newCondition();
44 
45 // condition variable for the other player's turn
46 otherPlayerTurn = gameLock.newCondition();
47 
48 for ( int i = 0; i < 9; i++ )
49 board[ i ] = new String( "" ); // create tic-tac-toe board
50 players = new Player[ 2 ]; // create array of players
51 currentPlayer = PLAYER_X; // set current player to first player
52 
53 try
54 {
55 server = new Server-Socket( 12345, 2 ); // set up ServerSocket
56 } // end try
57 catch ( IOException ioException )
58 {
59 ioException.printStackTrace();
60 System.exit( 1 );
61 } // end catch
62 
63 outputArea = new JTextArea(); // create JTextArea for output
64 add( outputArea, BorderLayout.CENTER );
65 outputArea.setText( "Server awaiting connections
" );
66 
67 setSize( 300, 300 ); // set size of window
68 setVisible( true ); // show window
69 } // end TicTacToeServer constructor
70 
71 // wait for two connections so game can be played
72 public void execute()
73 {
74 // wait for each client to connect
75 for ( int i = 0; i < players.length; i++ )
76 {
77 try // wait for connection, create Player, start runnable
78 {
79 players[ i ] = new Player( server.accept(), i ); 
80 runGame.execute( players[ i ] ); // execute player runnable
81 } // end try
82 catch ( IOException ioException )
83 {
84 ioException.printStackTrace();
85 System.exit( 1 );
86 } // end catch
87 } // end for
88 
89 gameLock.lock(); // lock game to signal player X's thread
90 
91 try
92 {
93 players[ PLAYER_X ].setSuspended( false ); // resume player X
94 otherPlayerConnected.signal(); // wake up player X's thread
95 } // end try
96 finally
97 {
98 gameLock.unlock(); // unlock game after signalling player X
99 } // end finally
100 } // end method execute
101 
102 // display message in outputArea
103 private void displayMessage( final String messageToDisplay )
104 {
105 // display message from event-dispatch thread of execution
106 SwingUtilities.invokeLater(
107 new Runnable()
108 {
109 public void run() // updates outputArea
110 {
111 outputArea.append( messageToDisplay ); // add message
112 } // end method run
113 } // end inner class
114 ); // end call to SwingUtilities.invokeLater
115 } // end method displayMessage
116 
117 // determine if move is valid
118 public boolean validateAndMove( int location, int player )
119 {
120 // while not current player, must wait for turn
121 while ( player != currentPlayer )
122 {
123 gameLock.lock(); // lock game to wait for other player to go
124 
125 try
126 {
127 otherPlayerTurn.await(); // wait for player's turn
128 } // end try
129 catch ( InterruptedException exception )
130 {
131 exception.printStackTrace();
132 } // end catch
133 finally
134 {
135 gameLock.unlock(); // unlock game after waiting
136 } // end finally
137 } // end while
138 
139 // if location not occupied, make move
140 if ( !isOccupied( location ) )
141 {
142 board[ location ] = MARKS[ currentPlayer ]; // set move on board
143 currentPlayer = ( currentPlayer + 1 ) % 2; // change player
144 
145 // let new current player know that move occurred
146 players[ currentPlayer ].otherPlayerMoved( location );
147 
148 gameLock.lock(); // lock game to signal other player to go
149 
150 try
151 {
152 otherPlayerTurn.signal(); // signal other player to continue
153 } // end try
154 finally
155 {
156 gameLock.unlock(); // unlock game after signaling
157 } // end finally
158 
159 return true; // notify player that move was valid
160 } // end if
161 else // move was not valid
162 return false; // notify player that move was invalid
163 } // end method validateAndMove
164 
165 // determine whether location is occupied
166 public boolean isOccupied( int location )
167 {
168 if ( board[ location ].equals( MARKS[ PLAYER_X ] ) ||
169 board [ location ].equals( MARKS[ PLAYER_O ] ) )
170 return true; // location is occupied
171 else
172 return false; // location is not occupied
173 } // end method isOccupied
174 
175 // place code in this method to determine whether game over
176 public boolean isGameOver()
177 {
178 return false; // this is left as an exercise
179 } // end method isGameOver
180 
181 // private inner class Player manages each Player as a runnable
182 private class Player implements Runnable
183 {
184 private Socket connection; // connection to client
185 private Scanner input; // input from client
186 private Formatter output; // output to client
187 private int playerNumber; // tracks which player this is
188 private String mark; // mark for this player
189 private boolean suspended = true; // whether thread is suspended
190 
191 // set up Player thread
192 public Player( Socket socket, int number )
193 {
194 playerNumber = number; // store this player's number
195 mark = MARKS[ playerNumber ]; // specify player's mark
196 connection = socket; // store socket for client
197 
198 try // obtain streams from Socket
199 {
200 input = new Scanner( connection.getInputStream() ); 
201 output = new Formatter( connection.getOutputStream() );
202 } // end try
203 catch ( IOException ioException )
204 {
205 ioException.printStackTrace();
206 System.exit( 1 );
207 } // end catch
208 } // end Player constructor
209 
210 // send message that other player moved
211 public void otherPlayerMoved( int location )
212 {
213 output.format( "Opponent moved
" ); 
214 output.format( "%d
", location ); // send location of move
215 output.flush(); // flush output 
216 } // end method otherPlayerMoved
217 
218 // control thread's execution
219 public void run()
220 {
221 // send client its mark (X or O), process messages from client
222 try
223 {
224 displayMessage( "Player " + mark + " connected
" );
225 output.format( "%s
", mark ); // send player's mark
226 output.flush(); // flush output 
227 
228 // if player X, wait for another player to arrive
229 if ( playerNumber == PLAYER_X )
230 {
231 output.format( "%s
%s", "Player X connected",
232  "Waiting for another player
" ); 
233 output.flush(); // flush output 
234 
235 gameLock.lock(); // lock game to wait for second player
236 
237 try
238 {
239 while( suspended )
240 {
241 otherPlayerConnected.await(); // wait for player O
242 } // end while
243 } // end try
244 catch ( InterruptedException exception )
245 {
246 exception.printStackTrace();
247 } // end catch
248 finally
249 {
250 gameLock.unlock(); // unlock game after second player
251 } // end finally
252 
253 // send message that other player connected
254 output.format( "Other player connected. Your move.
" );
255 output.flush(); // flush output 
256 } // end if
257 else
258 {
259 output.format( "Player O connected, please wait
" );
260 output.flush(); // flush output 
261 } // end else
262 
263 // while game not over
264 while ( !isGameOver() )
265 {
266 int location = 0; // initialize move location
267 
268 if ( input.hasNext() )
269 location = input.nextInt(); // get move location
270 
271 // check for valid move
272 if ( validateAndMove( location, playerNumber ) )
273 {
274 displayMessage( "
location: " + location );
275 output.format( "Valid move.
" ); // notify client
276 output.flush(); // flush output 
277 } // end if
278 else // move was invalid
279 {
280 output.format( "Invalid move, try again
" );
281 output.flush(); // flush output 
282 } // end else
283 } // end while
284 } // end try
285 finally
286 {
287 try
288 {
289 connection.close(); // close connection to client
290 } // end try
291 catch ( IOException ioException )
292 {
293 ioException.printStackTrace();
294 System.exit( 1 );
295 } // end catch
296 } // end finally
297 } // end method run
298 
299 // set whether or not thread is suspended
300 public void setSuspended( boolean status )
301 {
302 suspended = status; // set value of suspended
303 } // end method setSuspended
304 } // end class Player
305 } // end class TicTacToeServer

Figure 24.14. Class that tests Tic-Tac-Toe server.

(This item is displayed on page 1146 in the print version)

 1 // Fig. 24.14: TicTacToeServerTest.java
 2 // Tests the TicTacToeServer.
 3 import javax.swing.JFrame;
 4
 5 public class TicTacToeServerTest
 6 {
 7 public static void main( String args[] )
 8 {
 9 TicTacToeServer application = new TicTacToeServer();
10 application.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
11 application.execute();
12 } // end main
13 } // end class TicTacToeServerTest
 

Figure 24.15. Client side of client/server Tic-Tac-Toe program.

(This item is displayed on pages 1147 - 1152 in the print version)

 1 // Fig. 24.15: TicTacToeClient.java
 2 // Client that let a user play Tic-Tac-Toe with another across a network.
 3 import java.awt.BorderLayout;
 4 import java.awt.Dimension;
 5 import java.awt.Graphics;
 6 import java.awt.GridLayout;
 7 import java.awt.event.MouseAdapter;
 8 import java.awt.event.MouseEvent;
 9 import java.net.Socket;
10 import java.net.InetAddress;
11 import java.io.IOException;
12 import javax.swing.JFrame;
13 import javax.swing.JPanel;
14 import javax.swing.JScrollPane;
15 import javax.swing.JTextArea;
16 import javax.swing.JTextField;
17 import javax.swing.SwingUtilities;
18 import java.util.Formatter;
19 import java.util.Scanner;
20 import java.util.concurrent.Executors;
21 import java.util.concurrent.ExecutorService;
22 
23 public class TicTacToeClient extends JFrame implements Runnable
24 {
25 private JTextField idField; // textfield to display player's mark
26 private JTextArea displayArea; // JTextArea to display output
27 private JPanel boardPanel; // panel for tic-tac-toe board
28 private JPanel panel2; // panel to hold board
29 private Square board[][]; // tic-tac-toe board
30 private Square currentSquare; // current square
31 private Socket connection; // connection to server
32 private Scanner input; // input from server
33 private Formatter output; // output to server
34 private String ticTacToeHost; // host name for server
35 private String myMark; // this client's mark
36 private boolean myTurn; // determines which client's turn it is
37 private final String X_MARK = "X"; // mark for first client
38 private final String O_MARK = "O"; // mark for second client
39 
40 // set up user-interface and board
41 public TicTacToeClient( String host )
42 {
43 ticTacToeHost = host; // set name of server
44 displayArea = new JTextArea( 4, 30 ); // set up JTextArea
45 displayArea.setEditable( false );
46 add( new JScrollPane( displayArea ), BorderLayout.SOUTH );
47 
48 boardPanel = new JPanel(); // set up panel for squares in board
49 boardPanel.setLayout( new GridLayout( 3, 3, 0, 0 ) );
50 
51 board = new Square[ 3 ][ 3 ]; // create board
52 
53 // loop over the rows in the board
54 for ( int row = 0; row < board.length; row++ )
55 {
56 // loop over the columns in the board
57 for ( int column = 0; column < board[ row ].length; column++ )
58 {
59 // create square
60 board[ row ][ column ] = new Square( ' ', row * 3 + column );
61 boardPanel.add( board[ row ][ column ] ); // add square
62 } // end inner for
63 } // end outer for
64 
65 idField = new JTextField(); // set up textfield
66 idField.setEditable( false );
67 add( idField, BorderLayout.NORTH );
68 
69 panel2 = new JPanel(); // set up panel to contain boardPanel
70 panel2.add( boardPanel, BorderLayout.CENTER ); // add board panel
71 add( panel2, BorderLayout.CENTER ); // add container panel
72 
73 setSize( 300, 225 ); // set size of window
74 setVisible( true ); // show window
75 
76 startClient();
77 } // end TicTacToeClient constructor
78 
79 // start the client thread
80 public void startClient()
81 {
82 try // connect to server, get streams and start outputThread
83 {
84 // make connection to server
85 connection = new Socket( 
86  InetAddress.getByName( ticTacToeHost ), 12345 );
87 
88 // get streams for input and output
89 input = new Scanner( connection.getInputStream() ); 
90 output = new Formatter( connection.getOutputStream() );
91 } // end try
92 catch ( IOException ioException )
93 {
94 ioException.printStackTrace();
95 } // end catch
96 
97 // create and start worker thread for this client
98 ExecutorService worker = Executors.newFixedThreadPool( 1 );
99 worker.execute( this ); // execute client
100 } // end method startClient
101 
102 // control thread that allows continuous update of displayArea
103 public void run()
104 {
105 myMark = input.nextLine(); // get player's mark (X or O)
106 
107 SwingUtilities.invokeLater(
108 new Runnable()
109 {
110 public void run()
111 {
112 // display player's mark
113 idField.setText( "You are player "" + myMark + """ );
114 } // end method run
115 } // end anonymous inner class
116 ); // end call to SwingUtilities.invokeLater
117 
118 myTurn = ( myMark.equals( X_MARK ) ); // determine if client's turn
119 
120 // receive messages sent to client and output them
121 while ( true )
122 {
123 if ( input.hasNextLine() )
124 processMessage( input.nextLine() );
125 } // end while
126 } // end method run
127 
128 // process messages received by client
129 private void processMessage( String message )
130 {
131 // valid move occurred
132 if ( message.equals( "Valid move." ) )
133 {
134 displayMessage( "Valid move, please wait.
" );
135 setMark( currentSquare, myMark ); // set mark in square
136 } // end if
137 else if ( message.equals( "Invalid move, try again" ) )
138 {
139 displayMessage( message + "
" ); // display invalid move
140 myTurn = true; // still this client's turn
141 } // end else if
142 else if ( message.equals( "Opponent moved" ) )
143 {
144 int location = input.nextInt(); // get move location
145 input.nextLine(); // skip newline after int location
146 int row = location / 3; // calculate row
147 int column = location % 3; // calculate column
148 
149 setMark( board[ row ][ column ],
150 ( myMark.equals( X_MARK ) ? O_MARK : X_MARK ) ); // mark move
151 displayMessage( "Opponent moved. Your turn.
" );
152 myTurn = true; // now this client's turn
153 } // end else if
154 else
155 displayMessage( message + "
" ); // display the message
156 } // end method processMessage
157 
158 // manipulate outputArea in event-dispatch thread
159 private void displayMessage( final String messageToDisplay )
160 {
161 SwingUtilities.invokeLater(
162 new Runnable()
163 {
164 public void run()
165 {
166 displayArea.append( messageToDisplay ); // updates output
167 } // end method run
168 } // end inner class
169 ); // end call to SwingUtilities.invokeLater
170 } // end method displayMessage
171 
172 // utility method to set mark on board in event-dispatch thread
173 private void setMark( final Square squareToMark, final String mark )
174 {
175 SwingUtilities.invokeLater(
176 new Runnable()
177 {
178 public void run()
179 {
180 squareToMark.setMark( mark ); // set mark in square
181 } // end method run
182 } // end anonymous inner class
183 ); // end call to SwingUtilities.invokeLater
184 } // end method setMark
185 
186 // send message to server indicating clicked square
187 public void sendClickedSquare( int location )
188 {
189 // if it is my turn
190 if ( myTurn )
191 {
192 output.format( "%d
", location ); // send location to server
193 output.flush(); 
194 myTurn = false; // not my turn anymore
195 } // end if
196 } // end method sendClickedSquare
197 
198 // set current Square
199 public void setCurrentSquare( Square square )
200 {
201 currentSquare = square; // set current square to argument
202 } // end method setCurrentSquare
203 
204 // private inner class for the squares on the board
205 private class Square extends JPanel
206 {
207 private String mark; // mark to be drawn in this square
208 private int location; // location of square
209 
210 public Square( String squareMark, int squareLocation )
211 {
212 mark = squareMark; // set mark for this square
213 location = squareLocation; // set location of this square
214 
215 addMouseListener(
216 new MouseAdapter()
217 {
218 public void mouseReleased( MouseEvent e )
219 {
220 setCurrentSquare( Square.this ); // set current square
221 
222 // send location of this square
223 sendClickedSquare( getSquareLocation() );
224 } // end method mouseReleased
225 } // end anonymous inner class
226 ); // end call to addMouseListener
227 } // end Square constructor
228 
229 // return preferred size of Square
230 public Dimension getPreferredSize()
231 {
232 return new Dimension( 30, 30 ); // return preferred size
233 } // end method getPreferredSize
234 
235 // return minimum size of Square
236 public Dimension getMinimumSize()
237 {
238 return getPreferredSize(); // return preferred size
239 } // end method getMinimumSize
240 
241 // set mark for Square
242 public void setMark( String newMark )
243 {
244 mark = newMark; // set mark of square
245 repaint(); // repaint square
246 } // end method setMark
247 
248 // return Square location
249 public int getSquareLocation()
250 {
251 return location; // return location of square
252 } // end method getSquareLocation
253 
254 // draw Square
255 public void paintComponent( Graphics g )
256 {
257 super .paintComponent( g );
258 
259 g.drawRect( 0, 0, 29, 29 ); // draw square
260 g.drawString( mark, 11, 20 ); // draw mark
261 } // end method paintComponent
262 } // end inner-class Square
263 } // end class TicTacToeClient

Figure 24.16. Test class for Tic-Tac-Toe client.

(This item is displayed on page 1153 in the print version)

 1 // Fig. 24.16: TicTacToeClientTest.java
 2 // Tests the TicTacToeClient class.
 3 import javax.swing.JFrame;
 4
 5 public class TicTacToeClientTest
 6 {
 7 public static void main( String args[] )
 8 {
 9 TicTacToeClient application; // declare client application
10
11 // if no command line args
12 if ( args.length == 0 )
13 application = new TicTacToeClient( "127.0.0.1" ); // localhost
14 else
15 application = new TicTacToeClient( args[ 0 ] ); // use args
16
17 application.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
18 } // end main
19 } // end class TicTacToeClientTest

Figure 24.17. Sample outputs from the client/server Tic-Tac-Toe program.

(This item is displayed on pages 1153 - 1154 in the print version)

 

TicTacToeServer Class

As the TicTacToeServer receives each client connection, it creates an instance of inner-class Player (lines 182301 of Fig. 24.13) to process the client in a separate thread. These threads enable the clients to play the game independently. The first client to connect to the server is player X and the second is player O. Player X makes the first move. The server maintains the information about the board so it can determine whether a player's move is valid or invalid.

We begin with a discussion of the server side of the Tic-Tac-Toe game. When the TicTacToeServer application executes, the main method (lines 712 of Fig. 24.14) creates a TicTacToeServer object called application. The constructor (lines 3469 of Fig. 24.13) attempts to set up a ServerSocket. If successful, the program displays the server window, then main invokes the TicTacToeServer method execute (lines 72100). Method execute loops twice, blocking at line 79 each time while waiting for a client connection. When a client connects, line 79 creates a new Player object to manage the connection as a separate thread, and line 80 executes the Player in the runGame thread pool.

When the TicTacToeServer creates a Player, the Player constructor (lines 192208) receives the Socket object representing the connection to the client and gets the associated input and output streams. Line 201 creates a Formatter (see Chapter 28) by wrapping it around the output stream of the socket. The Player's run method (lines 219297) controls the information that is sent to and received from the client. First, it passes to the client the character that the client will place on the board when a move is made (line 225). Line 226 calls Formatter method flush to force this output to the client. Line 241 suspends player X's thread as it starts executing, because player X can move only after player O connects.

After player O connects, the game can be played, and the run method begins executing its while statement (lines 264283). Each iteration of this loop reads an integer (line 269) representing the location where the client wants to place a mark, and line 272 invokes the TicTacToeServer method validateAndMove (declared at lines 118163) to check the move. If the move is valid, line 275 sends a message to the client to this effect. If not, line 280 sends a message indicating that the move was invalid. The program maintains board locations as numbers from 0 to 8 (0 through 2 for the first row, 3 through 5 for the second row and 6 through 8 for the third row).

Method validateAndMove (lines 118163 in class TicTacToeServer) allows only one player at a time to move, thereby preventing them from modifying the state information of the game simultaneously. If the Player attempting to validate a move is not the current player (i.e., the one allowed to make a move), it is placed in a wait state until its turn to move. If the position for the move being validated is already occupied on the board, validMove returns false. Otherwise, the server places a mark for the player in its local representation of the board (line 142), notifies the other Player object (line 146) that a move has been made (so that the client can be sent a message), invokes method signal (line 152) so that the waiting Player (if there is one) can validate a move and returns true (line 159) to indicate that the move is valid.

TicTacToeClient Class

Each TicTacToeClient application (Fig. 24.15) maintains its own GUI version of the Tic-Tac-Toe board on which it displays the state of the game. The clients can place a mark only in an empty square on the board. Inner class Square (lines 205262 of Fig. 24.15) implements each of the nine squares on the board. When a TicTacToeClient begins execution, it creates a JTextArea in which messages from the server and a representation of the board using nine Square objects are displayed. The startClient method (lines 80100) opens a connection to the server and gets the associated input and output streams from the Socket object. Lines 8586 make a connection to the server. Class TicTacToeClient implements interface Runnable so that a separate thread can read messages from the server. This approach enables the user to interact with the board (in the event-dispatch thread) while waiting for messages from the server. After establishing the connection to the server, line 99 executes the client with the worker ExecutorService. The run method (lines 103124) controls the separate thread of execution. The method first reads the mark character (X or O) from the server (line 105), then loops continuously (lines 121125) and reads messages from the server (line 124). Each message is passed to the processMessage method (lines 129156) for processing.

If the message received is "Valid move.", lines 134135 display the message "Valid move, please wait." and call method setMark (lines 173184) to set the client's mark in the current square (the one in which the user clicked) using SwingUtilities method invokeLater to ensure that the GUI updates occur in the event-dispatch thread. If the message received is "Invalid move, try again.", line 139 displays the message so that the user can click a different square. If the message received is "Opponent moved.", line 145 reads an integer from the server indicating where the opponent moved, and lines 149150 place a mark in that square of the board (again using SwingUtilities method invokeLater to ensure that the GUI updates occur in the event-dispatch thread). If any other message is received, line 155 simply displays the message. Figure 24.17 shows sample screen captures of two applications interacting via the TicTacToeServer.

Introduction to Computers, the Internet and the World Wide Web

Introduction to Java Applications

Introduction to Classes and Objects

Control Statements: Part I

Control Statements: Part 2

Methods: A Deeper Look

Arrays

Classes and Objects: A Deeper Look

Object-Oriented Programming: Inheritance

Object-Oriented Programming: Polymorphism

GUI Components: Part 1

Graphics and Java 2D™

Exception Handling

Files and Streams

Recursion

Searching and Sorting

Data Structures

Generics

Collections

Introduction to Java Applets

Multimedia: Applets and Applications

GUI Components: Part 2

Multithreading

Networking

Accessing Databases with JDBC

Servlets

JavaServer Pages (JSP)

Formatted Output

Strings, Characters and Regular Expressions

Appendix A. Operator Precedence Chart

Appendix B. ASCII Character Set

Appendix C. Keywords and Reserved Words

Appendix D. Primitive Types

Appendix E. (On CD) Number Systems

Appendix F. (On CD) Unicode®

Appendix G. Using the Java API Documentation

Appendix H. (On CD) Creating Documentation with javadoc

Appendix I. (On CD) Bit Manipulation

Appendix J. (On CD) ATM Case Study Code

Appendix K. (On CD) Labeled break and continue Statements

Appendix L. (On CD) UML 2: Additional Diagram Types

Appendix M. (On CD) Design Patterns

Appendix N. Using the Debugger

Inside Back Cover





Java(c) How to Program
Java How to Program (6th Edition) (How to Program (Deitel))
ISBN: 0131483986
EAN: 2147483647
Year: 2003
Pages: 615
Similar book on Amazon

Flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net