Thinking in Java
Thinking in Java
Bruce Eckel
Israel
)ne o" the absolutely best %rogra##ing tutorials I ve seen "or any language. Joakim Ziegler, FIX sysop Thank you "or your wonder"ul, wonder"ul book on Java. r! "avin #illay, $egistrar, %ing &'(ar' VIII Hospital, )o*th Africa Thank you again "or your aweso#e book. I was really "loundering *being a non'+ %rogra##er,, but your book has brought #e u% to s%eed as "ast as I could read it. It s really cool to be able to understand the underlying %rinci%les and conce%ts "ro# the start, rather than having to try to build that conce%tual #odel through trial and error. (o%e"ully I will be able to attend your se#inar in the not'too'distant "uture. $an'all $! Ha(ley,
Telecomm*nications
8reat book. Best book on Java I have seen so "ar. Jeff )inclair,
allas
)ther books cover the :(6T o" Java *describing the synta& and the libraries, or the (): o" Java *%ractical %rogra##ing e&a#%les,. Thinking in Java is the only book I know that e&%lains the :(/ o" Java; why it was designed the way it was, why it works the way it does, why it so#eti#es doesn t work, why it s better than +<<, why it s not. 6lthough it also does a good 0ob o" teaching the what and how o" the language, Thinking in Java is de"initely the thinking %erson s choice in a Java book.
$obert )! )tephenson
Thanks "or writing a great book. The #ore I read it the better I like it. My students like it, too. -h*ck Iverson I 0ust want to co##end you "or your work on Thinking in Java. It is %eo%le like you that digni"y the "uture o" the Internet and I 0ust want to thank you "or your e""ort. It is very #uch a%%reciated. #atrick 2arrell,
like a dry te&tbook. /ou cover the #ost i#%ortant yet the least covered conce%ts o" Java develo%#ent= the whys. )ean 2ra'y /our e&a#%les are clear and easy to understand. /ou took care o" #any i#%ortant details o" Java that can t be "ound easily in the weak Java docu#entation. 6nd you don t waste the reader s ti#e with the basic "acts a %rogra##er already knows. %ai &ngert, Innovative )oft(are,
"ermany
I # a great "an o" your Thinking in C++ and have reco##ended it to associates. 6s I go through the electronic version o" your Java book, I # "inding that you ve retained the sa#e high level o" writing. Thank you.
#eter $! /e*(al'
VE5/ well'written Java book...I think you ve done a 85E6T 0ob on it. 6s the leader o" a +hicago'area Java s%ecial interest grou%, I ve "avorably #entioned your book and :eb site several ti#es at our recent #eetings. I would like to use Thinking in Java as the basis "or a %art o" each #onthly SI8 #eeting, in which we review and discuss each cha%ter in succession.
1ark &rtes
I really a%%reciate your work and your book is good. I reco##end it here to our users and Ph.7. students. H*g*es +eroy 55 Irisa6Inria $ennes
Thinking in Java based on #y e&%erience with Thinking in C++, and I was not disa%%ointed. Jaco van 'er 1er(e, )oft(are )pecialist, ataF*sion )ystems +t', )tellenbosch, )o*th Africa
This has to be one o" the best Java books I ve seen. &!F! #ritchar', )enior )oft(are &ngineer, -ambri'ge Animation )ystems +t'!, Unite' %ing'om /our book #akes all the other Java books I ve read or "li%%ed through see# doubly useless and insulting. 2rett g #orter, )enior
that your book isn t a co##ercial brochure "or Java. It also shows the bad sides o" Java. /)4 have done a great 0ob here. Fre'erik Fi4, 2elgi*m I have been hooked to your books all the ti#e. 6 cou%le o" years ago, when I wanted to start with +<<, it was C++ Inside & Out which took #e around the "ascinating world o" +<<. It hel%ed #e in getting better o%%ortunities in li"e. Cow, in %ursuit o" #ore knowledge and when I wanted to learn Java, I bu#%ed into Thinking in Java9no doubts in #y #ind as to whether I need so#e other book. Just "antastic. It is #ore like rediscovering #ysel" as I get along with the book. It is 0ust a #onth since I started with Java, and heart"elt thanks to you, I a# understanding it better now. Anan' %*mar )!, )oft(are &ngineer,
-omp*tervision, In'ia
/our book stands out as an e&cellent general introduction. #eter $obinson, University of -ambri'ge -omp*ter +aboratory It s by "ar the best #aterial I have co#e across to hel% #e learn Java and I 0ust want you to know how lucky I "eel to have "ound it. T(6C>S. -h*ck
University, Jakarta
The #ere "act that you have #ade this work "ree over the Cet %uts #e into shock. I thought I d let you know how #uch I a%%reciate and res%ect what you re doing. )hane +e2o*thillier, -omp*ter &ngineering
It s the best Java book I have ever read9and I read so#e. Jean6:ves 1&/"A/T, -hief )oft(are Architect /AT6):)T&1, #aris, France
Thinking in Java gives the best coverage and e&%lanation. Very easy to read, and I #ean the code "rag#ents as well. $on -han, #h! !, &4pert -hoice, Inc!, #ittsb*rgh #A
/our book is great. I have read lots o" %rogra##ing books and your book still adds insights to %rogra##ing in #y #ind. /ing8ian 0ang,
Information )ystem &ngineer, The Vang*ar' "ro*p Thinking in Java is an e&cellent and readable book. I reco##end it to all #y students. r! #a*l "orman, epartment of -omp*ter )cience, University of .tago, *ne'in, /e( Zealan'
/ou #ake it %ossible "or the %roverbial "ree lunch to e&ist, not 0ust a sou% kitchen ty%e o" lunch but a gour#et delight "or those who a%%reciate good so"tware and books about it. Jose )*riol, )cyla4 -orporation Thanks "or the o%%ortunity o" watching this book grow into a #aster%iece. IT IS T(E BEST book on the sub0ect that I ve read or browsed. Jeff +apchinsky, #rogrammer, /et $es*lts
Technologies
/our book is concise, accessible and a 0oy to read. %eith $itchie, Java
$esearch ,
The best book I have seen on Java. $ich Hoffarth, )enior Architect,
0est "ro*p
Thank you "or a wonder"ul book. I # having a lot o" "un going through the cha%ters. Fre' Trimble, Acti*m -orporation /ou have #astered the art o" slowly and success"ully #aking us gras% the details. /ou #ake learning VE5/ easy and satis"ying. Thank you "or a truly wonder"ul tutorial. $a8esh $a*, )oft(are -ons*ltant
Thinking in Java rocks the "ree world. 1iko .;)*llivan, #resi'ent, I'ocs Inc!
!This book is a tre#endous achieve#ent. /ou owe it to yoursel" to have a co%y on your shel". The cha%ter on iostrea#s is the #ost co#%rehensive and understandable treat#ent o" that sub0ect I ve seen to date.$
!Eckel s book is the only one to so clearly e&%lain how to rethink %rogra# construction "or ob0ect orientation. That the book is also an e&cellent tutorial on the ins and outs o" +<< is an added bonus.$
Thinking in Java
Second Edition
Bruce Eckel
President, MindView, Inc.
Library of Congress Cataloging-in-Publication Data Eckel, Bruce. Thinking in Java / Bruce Eckel.-- n! e!. ". c#. $%B& '-()-' *)+)-, (. Java -Co#"uter "rogra# language. $. Title. /0*+.*).J)1E , ''' '',.()2)--!c ( ''-')*, C$P
Editorial/Production Su ervision! Cicholas 5adhuber "c#uisitions Editor! Paul Petralia Manu$acturing Manager! Maura 8oldstaub Marketing Manager! Bryan 8a#brel Cover %esign! 7aniel :ill'(arris Interior %esign! 7aniel :ill'(arris, www.will'harris.co#
J K@@@ by Bruce Eckel, President, MindView, Inc. Published by Prentice (all PT5 Prentice'(all, Inc. 4%%er Saddle 5iver, CJ @G?HI
The in"or#ation in this book is distributed on an !as is$ basis, without warranty. :hile every %recaution has been taken in the %re%aration o" this book, neither the author nor the %ublisher shall have any liability to any %erson or entitle with res%ect to any liability, loss or da#age caused or alleged to be caused directly or indirectly by instructions contained in this book or by the co#%uter so"tware or hardware %roducts described herein. 6ll rights reserved. Co %art o" this book #ay be re%roduced, in any "or# or by any #eans, without %er#ission in writing "ro# the %ublisher. Prentice'(all books are widely used by cor%orations and govern#ent agencies "or training, #arketing, and resale. The %ublisher o""ers discounts on this book when ordered in bulk Auantities. Eor #ore in"or#ation, contact the +or%orate Sales 7e%art#ent at I@@'LIK'L?M2, "a&= K@M'KL3'GM?M, e#ail=cor sales& renhall' com or write= +or%orate Sales 7e%art#ent, Prentice (all PT5, )ne Dake Street, 4%%er Saddle 5iver, Cew Jersey @G?HI. Java is a registered trade#ark o" Sun Microsyste#s, Inc. :indows 2H and :indows CT are trade#arks o" Microso"t +or%oration. 6ll other %roduct na#es and co#%any na#es #entioned herein are the %ro%erty o" their res%ective owners.
Bruce Eckels Hands-On Java Seminar Multimedia CD Its like coming to the seminar! Available at www.BruceEckel.com
)verhead slides and synchroni1ed audio voice narration "or all the lectures. Just %lay it to see and hear the lectures. +reated and narrated by Bruce Eckel. Based on the #aterial in this book.
7edication
To the %erson who, even now, is creating the ne&t great co#%uter language
Pre"ace.................................................................................... M Introduction........................................................................... 2 M= Introduction to )b0ects............................................................................. L@ K= Everything is an )b0ect......................................................................... M@3 L= +ontrolling Progra# Elow.............................................. ML2 ?= Initiali1ation N +leanu%........................................................................... M2I H= (iding the I#%le#entation........................................... KHK 3= 5eusing +lasses.............................................................. KIM G= Poly#or%his#................................................................ LKK I= Inter"aces N Inner +lasses............................................. L3K 2= (olding /our )b0ects....................................................................... ?KK M@= Error (andling with E&ce%tions................................................................... HHM MM= The Java IF) Syste#......................................................................... H2? MK= 5un'ti#e Ty%e Identi"ication....................................... 3IH ML= +reating :indows N 6%%lets............................................................................. GM3 M?= Multi%le Threads.......................................................... IH3 MH= 7istributed +o#%uting................................................. 2LG 6= Passing N 5eturning )b0ects....................................... M@HL B= The Java Cative Inter"ace *JCI,................................... MM@3
Pre"ace.................................................................................... M
Pre"ace to the Knd edition............................................................................ ?
Java K........................................................................................................................................... 3
The +7 5)M.................................................................................................. G
Introduction........................................................................... 2
PrereAuisites.................................................................................................. 2 Dearning Java............................................................................................... M@ 8oals.............................................................................................................. MM )nline docu#entation................................................................................ MK +ha%ters........................................................................................................ ML E&ercises....................................................................................................... M2 Multi#edia +7 5)M..................................................................................K@ Source code.................................................................................................. K@
+oding standards....................................................................................................................... KK
Java versions................................................................................................KL Se#inars and #entoring............................................................................K? Errors............................................................................................................ K? Cote on the cover design............................................................................ KH 6cknowledge#ents..................................................................................... K3
Internet contributors................................................................................................................. K2
M= Introduction to )b0ects............................................................................. L@
The %rogress o" abstraction....................................................................... LM 6n ob0ect has an inter"ace..........................................................................L? 6n ob0ect %rovides services........................................................................LG The hidden i#%le#entation...................................................................... LG 5eusing the i#%le#entation..................................................................... L2
E&ce%tion handling= dealing with errors..................................................3M Multithreading............................................................................................ 3K Persistence................................................................................................... 3? Java and the Internet................................................................................. 3?
:hat is the :ebO....................................................................................................................... 3H +lient'side %rogra##ing..........................................................................................................3G Server'side %rogra##ing.......................................................................................................... GH 6 se%arate arena= a%%lications..................................................................................................GH
E&tre#e %rogra##ing............................................................................... 2L
:rite tests "irst.......................................................................................................................... 2L Pair %rogra##ing.....................................................................................................................2H
)verloading with %ri#itives...................................................................................................K@? )verloading on return values.................................................................................................K@2 7e"ault constructors................................................................................................................ K@2 The this keyword......................................................................................................................KMM
Inter"ace and i#%le#entation................................................................. KGM +lass access................................................................................................ KGL Su##ary.................................................................................................... KGG E&ercises..................................................................................................... KGI
+hoosing co#%osition vs. inheritance........................................................................................... K2I %rotected.................................................................................................... L@@ Incre#ental develo%#ent........................................................................ L@M 4%casting................................................................................................... L@K
:hy !u%casting$O.................................................................................................................... L@L
G= Poly#or%his#................................................................ LKK
4%casting revisited................................................................................... LKL
Eorgetting the ob0ect ty%e.......................................................................................................LK?
)verriding vs. overloading...................................................................... LLH Pit"all= !overriding$ %rivate #ethods..................................................... LLG 6bstract classes and #ethods.............................................................................................. LLI +onstructors and %oly#or%his#........................................................... L?K
)rder o" constructor calls........................................................................................................ L?L Inheritance and "inali1e* ,....................................................................................................... L?H Behavior o" %oly#or%hic #ethods inside constructors.................................................................................................................. L?2
Pure inheritance vs. e&tension................................................................................................LH? 7owncasting and run'ti#e ty%e identi"ication.................................................................................................................... LH3
+o#%aring arrays.................................................................................................................... ??3 6rray ele#ent co#%arisons....................................................................................................??G Sorting an array....................................................................................................................... ?H@ Searching a sorted array.......................................................................................................... ?HK 6rray su##ary........................................................................................................................ ?HH
Iterators...................................................................................................... ?GK +ontainer ta&ono#y................................................................................. ?G3 +ollection "unctionality........................................................................... ?I@ Dist "unctionality.......................................................................................?I?
Making a stack "ro# a DinkedDist..........................................................................................?II Making a Aueue "ro# a DinkedDist......................................................................................... ?I2
)"" by itsel"= 5ando#6ccessEile.................................................................................... 3MH Ty%ical uses o" IF) strea#s..................................................................... 3MG
In%ut strea#s.......................................................................................................................... 3K@ )ut%ut strea#s........................................................................................................................ 3KK 6 bugO6 bugO........................................................................................................................... 3KH Pi%ed strea#s.......................................................................................................................... 3K3
+o#%ression..............................................................................................3L@
Si#%le co#%ression with 8QIP............................................................................................... 3LM Multi"ile storage with Qi%........................................................................................................ 3LK Java 65chives *J65s,.............................................................................................................. 3LH
Making a button........................................................................................ GLL +a%turing an event.................................................................................... GLH Te&t areas................................................................................................... GLI +ontrolling layout..................................................................................... G?@
BorderDayout...........................................................................................................................G?M ElowDayout.............................................................................................................................. G?K 8ridDayout............................................................................................................................... G?L 8ridBagDayout......................................................................................................................... G?? 6bsolute %ositioning................................................................................................................ G?? Bo&Dayout................................................................................................................................ G?H The best a%%roachO.................................................................................................................. G?2
Tool ti%s................................................................................................................................... G32 Te&t "ields................................................................................................................................. G32 Borders..................................................................................................................................... GGK JScrollPanes............................................................................................................................. GGL 6 #ini'editor............................................................................................................................ GGH +heck bo&es.............................................................................................................................. GGG 5adio buttons........................................................................................................................... GG2 +o#bo bo&es *dro%'down lists,.............................................................................................. GI@ Dist bo&es................................................................................................................................. GIK Tabbed %anes........................................................................................................................... GI? Message bo&es.........................................................................................................................GIH Menus...................................................................................................................................... GII Po%'u% #enus.......................................................................................................................... G2H 7rawing.................................................................................................................................... G2G 7ialog Bo&es............................................................................................................................ I@M Eile dialogs..............................................................................................................................I@3 (TMD on Swing co#%onents................................................................................................. I@I Sliders and %rogress bars........................................................................................................IM@ Trees......................................................................................................................................... IMM Tables....................................................................................................................................... IM? Selecting Dook N Eeel............................................................................................................... IMG The cli%board........................................................................................................................... IM2
Su##ary....................................................................................................IH@
E&ercises..................................................................................................... IHM
Priorities..................................................................................................... 2M@
5eading and setting %riorities................................................................................................. 2M@ Thread grou%s.......................................................................................................................... 2MH
Servlets....................................................................................................... 2IL
The basic servlet...................................................................................................................... 2I? Servlets and #ultithreading...................................................................................................2I2 (andling sessions with servlets.............................................................................................. 22@ 5unning the servlet e&a#%les................................................................................................. 22H
+)5B6...................................................................................................... M@MG
+)5B6 "unda#entals............................................................................................................ M@MI 6n e&a#%le............................................................................................................................ M@K@ Java 6%%lets and +)5B6...................................................................................................... M@K3 +)5B6 vs. 5MI.....................................................................................................................M@KG
The 0oin %rocess..................................................................................................................... M@?H The looku% %rocess................................................................................................................ M@?3 Se%aration o" inter"ace and i#%le#entation........................................................................M@?G 6bstracting distributed syste#s...........................................................................................M@?I
5ead'only classes....................................................................................M@II
+reating read'only classes..................................................................................................... M@2@ The drawback to i##utability..............................................................................................M@2M I##utable Strings................................................................................................................. M@2? The String and StringBu""er classes...............................................................................................................M@2G Strings are s%ecial..................................................................................................................MM@K
Passing and using Java ob0ects.............................................................. MMML JCI and Java e&ce%tions......................................................................... MMM3 JCI and threading.................................................................................... MMMG 4sing a %ree&isting code base.................................................................MMMG 6dditional in"or#ation........................................................................... MMMI
7= 5esources..................................................................... MML3
So"tware.................................................................................................... MML3 Books......................................................................................................... MML3
6nalysis N design................................................................................................................... MMLI Python..................................................................................................................................... MM?M My own list o" books .............................................................................................................. MM?M
Inde&................................................................................. MM?L
reface
RSTIJLTP5EE6+ETI@UI suggested to #y brother Todd, who is #aking the lea% "ro# hardware into %rogra##ing, that the ne&t big revolution will be in genetic engineering.
:e ll have #icrobes designed to #ake "ood, "uel, and %lastic; they ll clean u% %ollution and in general allow us to #aster the #ani%ulation o" the %hysical world "or a "raction o" what it costs now. I clai#ed that it would #ake the co#%uter revolution look s#all in co#%arison. RFSURF STIJLTP5EE6+ETIMU Then I reali1ed I was #aking a #istake co##on to science "iction writers= getting lost in the technology *which is o" course easy to do in science "iction,. 6n e&%erienced writer knows that the story is never about the things; it s about the %eo%le. 8enetics will have a very large i#%act on our lives, but I # not so sure it will dwar" the co#%uter revolution *which enables the genetic revolution,9or at least the in"or#ation revolution. In"or#ation is about talking to each other= yes, cars and shoes and es%ecially genetic cures are i#%ortant, but in the end those are 0ust tra%%ings. :hat truly #atters is how we relate to the world. 6nd so #uch o" that is about co##unication.RFSURFSTIJLTP5EE6+ETIKU This book is a case in %oint. 6 #a0ority o" "olks thought I was very bold or a little cra1y to %ut the entire thing u% on the :eb. !:hy would anyone buy itO$ they asked. I" I had been o" a #ore conservative nature I wouldn t have done it, but I really didn t want to write another co#%uter book in the sa#e old way. I didn t know what would ha%%en but it turned out to be the s#artest thing I ve ever done with a book.RFSURF STIJLTP5EE6+ETILU Eor one thing, %eo%le started sending in corrections. This has been an a#a1ing %rocess, because "olks have looked into every nook and cranny and caught both technical and gra##atical errors, and I ve been able to eli#inate bugs o" all sorts that I know would have otherwise sli%%ed through. Peo%le have been si#%ly terri"ic about this, very o"ten saying
!Cow, I don t #ean this in a critical way-$ and then giving #e a collection o" errors I # sure I never would have "ound. I "eel like this has been a kind o" grou% %rocess and it has really #ade the book into so#ething s%ecial.RFSURFSTIJLTP5EE6+ETI?U But then I started hearing !)>, "ine, it s nice you ve %ut u% an electronic version, but I want a %rinted and bound co%y "ro# a real %ublisher.$ I tried very hard to #ake it easy "or everyone to %rint it out in a nice looking "or#at but that didn t ste# the de#and "or the %ublished book. Most %eo%le don t want to read the entire book on screen, and hauling around a shea" o" %a%ers, no #atter how nicely %rinted, didn t a%%eal to the# either. *Plus, I think it s not so chea% in ter#s o" laser %rinter toner., It see#s that the co#%uter revolution won t %ut %ublishers out o" business, a"ter all. (owever, one student suggested this #ay beco#e a #odel "or "uture %ublishing= books will be %ublished on the :eb "irst, and only i" su""icient interest warrants it will the book be %ut on %a%er. +urrently, the great #a0ority o" all books are "inancial "ailures, and %erha%s this new a%%roach could #ake the %ublishing industry #ore %ro"itable.RFSURFSTIJLTP5EE6+ETIHU This book beca#e an enlightening e&%erience "or #e in another way. I originally a%%roached Java as !0ust another %rogra##ing language,$ which in #any senses it is. But as ti#e %assed and I studied it #ore dee%ly, I began to see that the "unda#ental intention o" this language is di""erent "ro# all the other languages I have seen.RFSURF STIJLTP5EE6+ETI3U Progra##ing is about #anaging co#%le&ity= the co#%le&ity o" the %roble# you want to solve, laid u%on the co#%le&ity o" the #achine in which it is solved. Because o" this co#%le&ity, #ost o" our %rogra##ing %ro0ects "ail. 6nd yet, o" all the %rogra##ing languages o" which I a# aware, none o" the# have gone all'out and decided that their #ain design goal would be to conAuer the co#%le&ity o" develo%ing and #aintaining %rogra#s @. )" course, #any language design decisions were #ade with co#%le&ity in #ind, but at so#e %oint there were always so#e other issues that were considered essential to be added into the #i&. Inevitably, those other issues are what cause %rogra##ers to eventually !hit the
@ I take this back on the Knd edition= I believe that the Python language co#es closest to
Thinking in Java
,,,'0ruceEckel'com
wall$ with that language. Eor e&a#%le, +<< had to be backwards' co#%atible with + *to allow easy #igration "or + %rogra##ers,, as well as e""icient. Those are both very use"ul goals and account "or #uch o" the success o" +<<, but they also e&%ose e&tra co#%le&ity that %revents so#e %ro0ects "ro# being "inished *certainly, you can bla#e %rogra##ers and #anage#ent, but i" a language can hel% by catching your #istakes, why shouldn t itO,. 6s another e&a#%le, Visual Basic *VB, was tied to B6SI+, which wasn t really designed to be an e&tensible language, so all the e&tensions %iled u%on VB have %roduced so#e truly horrible and un#aintainable synta&. Perl is backwards'co#%atible with 6wk, Sed, 8re%, and other 4ni& tools it was #eant to re%lace, and as a result is o"ten accused o" %roducing !write'only code$ *that is, a"ter a "ew #onths you can t read it,. )n the other hand, +<<, VB, Perl, and other languages like S#alltalk had so#e o" their design e""orts "ocused on the issue o" co#%le&ity and as a result are re#arkably success"ul in solving certain ty%es o" %roble#s.RFSURFSTIJLTP5EE6+ETIGU :hat has i#%ressed #e #ost as I have co#e to understand Java is what see#s like an un"linching goal o" reducing co#%le&ity $or the rogrammer. 6s i" to say !we don t care about anything e&ce%t reducing the ti#e and di""iculty o" %roducing robust code.$ In the early days, this goal has resulted in code that doesn t run very "ast *although there have been #any %ro#ises #ade about how Auickly Java will so#eday run, but it has indeed %roduced a#a1ing reductions in develo%#ent ti#e; hal" or less o" the ti#e that it takes to create an eAuivalent +<< %rogra#. This result alone can save incredible a#ounts o" ti#e and #oney, but Java doesn t sto% there. It goes on to wra% all the co#%le& tasks that have beco#e i#%ortant, such as #ultithreading and network %rogra##ing, in language "eatures or libraries that can at ti#es #ake those tasks trivial. 6nd "inally, it tackles so#e really big co#%le&ity %roble#s= cross' %lat"or# %rogra#s, dyna#ic code changes, and even security, each o" which can "it on your co#%le&ity s%ectru# anywhere "ro# !i#%edi#ent$ to !show'sto%%er.$ So des%ite the %er"or#ance %roble#s we ve seen, the %ro#ise o" Java is tre#endous= it can #ake us signi"icantly #ore %roductive %rogra##ers.RFSURFSTIJLTP5EE6+ETIIU )ne o" the %laces I see the greatest i#%act "or this is on the :eb. Cetwork %rogra##ing has always been hard, and Java #akes it easy *and the Java language designers are working on #aking it even easier,. Cetwork
%rogra##ing is how we talk to each other #ore e""ectively and chea%er than we ever have with tele%hones *e#ail alone has revolutioni1ed #any businesses,. 6s we talk to each other #ore, a#a1ing things begin to ha%%en, %ossibly #ore a#a1ing even than the %ro#ise o" genetic engineering.RFSURFSTIJLTP5EE6+ETI2U In all ways9creating the %rogra#s, working in tea#s to create the %rogra#s, building user inter"aces so the %rogra#s can co##unicate with the user, running the %rogra#s on di""erent ty%es o" #achines, and easily writing %rogra#s that co##unicate across the Internet9Java increases the co##unication bandwidth bet,een eo le. I think that %erha%s the results o" the co##unication revolution will not be seen "ro# the e""ects o" #oving large Auantities o" bits around; we shall see the true revolution because we will all be able to talk to each other #ore easily= one'on'one, but also in grou%s and, as a %lanet. IVve heard it suggested that the ne&t revolution is the "or#ation o" a kind o" global #ind that results "ro# enough %eo%le and enough interconnectedness. Java #ay or #ay not be the tool that "o#ents that revolution, but at least the %ossibility has #ade #e "eel like IV# doing so#ething #eaning"ul by atte#%ting to teach the language.RFSURFSTIJLTP5EE6+ETIM@U
Thinking in Java
,,,'0ruceEckel'com
broken into two volu#es. 7es%ite this, one o" the things I have atte#%ted to do in this edition is tri# out the %ortions that have beco#e obsolete, or at least nonessential. I "eel co#"ortable doing this because the original #aterial re#ains on the :eb site and the +7 5)M that acco#%anies this book, in the "or# o" the "reely'downloadable "irst edition o" the book *at ,,,'0ruceEckel'com,. I" you want the old stu"", it s still there, and this is a wonder"ul relie" "or an author. Eor e&a#%le, you #ay notice that the original last cha%ter, !Pro0ects,$ is no longer here; two o" the %ro0ects have been integrated into other cha%ters, and the rest were no longer a%%ro%riate. 6lso, the !7esign Pattens$ cha%ter beca#e too big and has been #oved into a book o" its own *also downloadable at the :eb site,. So, by all rights the book should be thinner.RFSURF STIJLTP5EE6+ETIMMU But alas, it is not to be.RFSURFSTIJLTP5EE6+ETIMKU The biggest issue is the continuing develo%#ent o" the Java language itsel", and in %articular the e&%anding 6PIs that %ro#ise to %rovide standard inter"aces "or 0ust about everything you d like to do *and I won t be sur%rised to see the !JToaster$ 6PI eventually a%%ear,. +overing all these 6PIs is obviously beyond the sco%e o" this book and is a task relegated to other authors, but so#e issues cannot be ignored. The biggest o" these include server'side Java *%ri#arily Servlets N Java Server %ages, or JSPs,, which is truly an e&cellent solution to the :orld :ide :eb %roble#, wherein we ve discovered that the various :eb browser %lat"or#s are 0ust not consistent enough to su%%ort client'side %rogra##ing. In addition, there is the whole %roble# o" easily creating a%%lications to interact with databases, transactions, security, and the like, which is involved with Enter%rise Java Beans *EJBs,. These to%ics are wra%%ed into the cha%ter "or#erly called !Cetwork Progra##ing$ and now called !7istributed +o#%uting,$ a sub0ect that is beco#ing essential to everyone. /ou ll also "ind this cha%ter has been e&%anded to include an overview o" Jini *%ronounced !genie,$ and it isn t an acrony#, 0ust a na#e,, which is a cutting'edge technology that allows us to change the way we think about interconnected a%%lications. 6nd o" course the book has been changed to use the Swing 84I library throughout. 6gain, i" you want the old Java [email protected] stu"" you can get it "ro# the "reely' downloadable book at ,,,'0ruceEckel'com *it is also included on this
edition s new +7 5)M, bound into the book; #ore on that a little later,. RFSURFSTIJLTP5EE6+ETIMLU 6side "ro# additional s#all language "eatures added in Java K and corrections #ade throughout the book, the other #a0or change is in the collections cha%ter *2,, which now "ocuses on the Java K collections used throughout the book. I ve also i#%roved that cha%ter to #ore dee%ly go into so#e o" the i#%ortant issues o" collections, in %articular how a hash "unction works *so that you can know how to %ro%erly create one,. There have been other #ove#ents and changes, including a rewrite o" +ha%ter M, and re#oval o" so#e a%%endices and other #aterial that I consider no longer necessary "or the %rinted book, but those are the bulk o" the#. In general, I ve tried to go over everything, re#ove "ro# the K nd edition what is no longer necessary *but which still e&ists in the electronic "irst edition,, include changes, and i#%rove everything I could. 6s the language continues to change9albeit not Auite at the sa#e breakneck %ace as be"ore9there will no doubt be "urther editions o" this book.RF SURFSTIJLTP5EE6+ETIM?U Eor those o" you who still can t stand the si1e o" the book, I do a%ologi1e. Believe it or not, I have worked hard to kee% it s#all. 7es%ite the bulk, I "eel like there #ay be enough alternatives to satis"y you. Eor one thing, the book is available electronically *"ro# the :eb site, and also on the +7 5)M that acco#%anies this book,, so i" you carry your la%to% you can carry the book on that with no e&tra weight. I" you re really into sli##ing down, there are actually Pal# Pilot versions o" the book "loating around. *)ne %erson told #e he would read the book in bed on his Pal# with the backlighting on to kee% "ro# annoying his wi"e. I can only ho%e that it hel%s send hi# to slu#berland., I" you need it on %a%er, I know o" %eo%le who %rint a cha%ter at a ti#e and carry it in their brie"case to read on the train.RFSURFSTIJLTP5EE6+ETIMHU
"ava !
6t this writing, the release o" Sun s Java %evelo ment 6it *J7>, M.L is i##inent, and the %ro%osed changes "or J7> M.? have been %ublici1ed. 6lthough these version nu#bers are still in the !ones,$ the standard way to re"er to any version o" the language that is J7> M.K or greater is to call it !Java K.$ This indicates the very signi"icant changes between !old
Thinking in Java
,,,'0ruceEckel'com
Java$9which had #any warts that I co#%lained about in the "irst edition o" this book9and this #ore #odern and i#%roved version o" the language, which has "ar "ewer warts and #any additions and nice designs. RFSURFSTIJLTP5EE6+ETIM3U This book is written "or Java K. I have the great lu&ury o" getting rid o" all the old stu"" and writing to only the new, i#%roved language because the old in"or#ation still e&ists in the electronic M st edition on the :eb and on the +7 5)M *which is where you can go i" you re stuck using a %re'Java'K version o" the language,. 6lso, because anyone can "reely download the J7> "ro# 0ava.sun.co#, it #eans that by writing to Java K I # not i#%osing a "inancial hardshi% on so#eone by "orcing the# to u%grade.RF SURFSTIJLTP5EE6+ETIMGU There is a bit o" a catch, however. J7> M.L has so#e i#%rove#ents that I d really like to use, but the version o" Java that is currently being released "or Dinu& is J7> M.K.K. Dinu& *see www.Dinu&.org, is a very i#%ortant develo%#ent in con0unction with Java, because it is "ast beco#ing the #ost i#%ortant server %lat"or# out there9"ast, reliable, robust, secure, well'#aintained, and "ree, a true revolution in the history o" co#%uting *I don t think we ve ever seen all o" those "eatures in any tool be"ore,. 6nd Java has "ound a very i#%ortant niche in server'side %rogra##ing in the "or# o" Servlets, a technology that is a huge i#%rove#ent over the traditional +8I %rogra##ing *this is covered in the !7istributed Progra##ing$ cha%ter,.RFSURFSTIJLTP5EE6+ETIMIU So although I would like to only use the very newest "eatures, it s critical that everything co#%iles under Dinu&, and so when you un%ack the source code and co#%ile it under that )S *with the latest J7>, you ll discover that everything will co#%ile. (owever, you will "ind that I ve %ut notes about "eatures in J7> M.L here and there.RFSURF STIJLTP5EE6+ETIM2U
#he CD $OM
6nother bonus with this edition is the +7 5)M that is %ackaged in the back o" the book. I ve resisted %utting +7 5)Ms in the back o" #y books in the %ast because I "elt the e&tra charge "or a "ew >bytes o" source code
on this enor#ous +7 was not 0usti"ied, %re"erring instead to allow %eo%le to download such things "ro# #y :eb site. (owever, you ll soon see that this +7 5)M is di""erent.RFSURFSTIJLTP5EE6+ETIK@U The +7 does contain the source code "ro# the book, but it also contains the book in its entirety, in several electronic "or#ats. My "avorite o" these is the (TMD "or#at, because it is "ast and "ully inde&ed9you 0ust click on an entry in the inde& or table o" contents and you re i##ediately at that %ortion o" the book.RFSURFSTIJLTP5EE6+ETIKMU The bulk o" the L@@< Megabytes o" the +7, however, is a "ull #ulti#edia course called Thinking in C! 9oundations $or C++ & Java' I originally co##issioned +huck 6llison to create this se#inar'on'+7 5)M as a stand'alone %roduct, but decided to include it with the second editions o" both Thinking in C++ and Thinking in Java because o" the consistent e&%erience o" having %eo%le co#e to se#inars without an adeAuate background in +. The thinking a%%arently goes !I # a s#art %rogra##er and I don t ,ant to learn +, but rather +<< or Java, so I ll 0ust ski% + and go directly to +<<FJava.$ 6"ter arriving at the se#inar, it slowly dawns on "olks that the %rereAuisite o" understanding + synta& is there "or a very good reason. By including the +7 5)M with the book, we can ensure that everyone attends a se#inar with adeAuate %re%aration.RFSURF STIJLTP5EE6+ETIKKU The +7 also allows the book to a%%eal to a wider audience. Even though +ha%ter L *+ontrolling %rogra# "low, does cover the "unda#entals o" the %arts o" Java that co#e "ro# +, the +7 is a gentler introduction, and assu#es even less about the student s %rogra##ing background than does the book. It is #y ho%e that by including the +7 #ore %eo%le will be able to be brought into the "old o" Java %rogra##ing. RFSU
Thinking in Java
,,,'0ruceEckel'com
Introduction
RFSTIJLTICT5)TI@UDike any hu#an language, Java %rovides a way to e&%ress conce%ts. I" success"ul, this #ediu# o" e&%ression will be signi"icantly easier and #ore "le&ible than the alternatives as %roble#s grow larger and #ore co#%le&.
/ou can t look at Java as 0ust a collection o" "eatures9so#e o" the "eatures #ake no sense in isolation. /ou can use the su# o" the %arts only i" you are thinking about design, not si#%ly coding. 6nd to understand Java in this way, you #ust understand the %roble#s with it and with %rogra##ing in general. This book discusses %rogra##ing %roble#s, why they are %roble#s, and the a%%roach Java has taken to solve the#. Thus, the set o" "eatures I e&%lain in each cha%ter are based on the way I see a %articular ty%e o" %roble# being solved with the language. In this way I ho%e to #ove you, a little at a ti#e, to the %oint where the Java #indset beco#es your native tongue.RFSURFSTIJLTICT5)TIKLU Throughout, I ll be taking the attitude that you want to build a #odel in your head that allows you to develo% a dee% understanding o" the language; i" you encounter a %u11le you ll be able to "eed it to your #odel and deduce the answer.RFSURFSTIJLTICT5)TIK?U
rere%uisites
This book assu#es that you have so#e %rogra##ing "a#iliarity= you understand that a %rogra# is a collection o" state#ents, the idea o" a subroutineF"unctionF#acro, control state#ents such as !i"$ and loo%ing constructs such as !while,$ etc. (owever, you #ight have learned this in #any %laces, such as %rogra##ing with a #acro language or working with a tool like Perl. 6s long as you ve %rogra##ed to the %oint where you "eel co#"ortable with the basic ideas o" %rogra##ing, you ll be able to work through this book. )" course, the book will be easier "or the + %rogra##ers and #ore so "or the +<< %rogra##ers, but don t count
yoursel" out i" you re not e&%erienced with those languages *but co#e willing to work hard; also, the #ulti#edia +7 that acco#%anies this book will bring you u% to s%eed on the basic + synta& necessary to learn Java,. I ll be introducing the conce%ts o" ob0ect'oriented %rogra##ing *))P, and Java s basic control #echanis#s, so you ll be e&%osed to those, and the "irst e&ercises will involve the basic control'"low state#ents.RFSURF STIJLTICT5)TIKHU 6lthough re"erences will o"ten be #ade to + and +<< language "eatures, these are not intended to be insider co##ents, but instead to hel% all %rogra##ers %ut Java in %ers%ective with those languages, "ro# which, a"ter all, Java is descended. I will atte#%t to #ake these re"erences si#%le and to e&%lain anything that I think a non' +F+<< %rogra##er would not be "a#iliar with.RFSURFSTIJLTICT5)TIK3U
&earning "ava
6t about the sa#e ti#e that #y "irst book <sing C++ *)sborneFMc8raw' (ill, M2I2, ca#e out, I began teaching that language. Teaching %rogra##ing languages has beco#e #y %ro"ession; I ve seen nodding heads, blank "aces, and %u11led e&%ressions in audiences all over the world since M2I2. 6s I began giving in'house training with s#aller grou%s o" %eo%le, I discovered so#ething during the e&ercises. Even those %eo%le who were s#iling and nodding were con"used about #any issues. I "ound out, by chairing the +<< track at the So"tware 7evelo%#ent +on"erence "or a nu#ber o" years *and later the Java track,, that I and other s%eakers tended to give the ty%ical audience too #any to%ics too "ast. So eventually, through both variety in the audience level and the way that I %resented the #aterial, I would end u% losing so#e %ortion o" the audience. Maybe it s asking too #uch, but because I a# one o" those %eo%le resistant to traditional lecturing *and "or #ost %eo%le, I believe, such resistance results "ro# boredo#,, I wanted to try to kee% everyone u% to s%eed.RFSURFSTIJLTICT5)TIKGU Eor a ti#e, I was creating a nu#ber o" di""erent %resentations in "airly short order. Thus, I ended u% learning by e&%eri#ent and iteration *a techniAue that also works well in Java %rogra# design,. Eventually I develo%ed a course using everything I had learned "ro# #y teaching
1=
Thinking in Java
,,,'0ruceEckel'com
e&%erience9one that I would be ha%%y giving "or a long ti#e. It tackles the learning %roble# in discrete, easy'to'digest ste%s, and in a hands'on se#inar *the ideal learning situation, there are e&ercises "ollowing each o" the short lessons. I now give this course in %ublic Java se#inars, which you can "ind out about at ,,,'0ruceEckel'com. *The introductory se#inar is also available as a +7 5)M. In"or#ation is available at the sa#e :eb site.,RFSURFSTIJLTICT5)TIKIU The "eedback that I get "ro# each se#inar hel%s #e change and re"ocus the #aterial until I think it works well as a teaching #ediu#. But this book isn t 0ust se#inar notes9I tried to %ack as #uch in"or#ation as I could within these %ages, and structured it to draw you through onto the ne&t sub0ect. More than anything, the book is designed to serve the solitary reader who is struggling with a new %rogra##ing language.RF SURFSTIJLTICT5)TIK2U
'oals
Dike #y %revious book Thinking in C++, this book has co#e to be structured around the %rocess o" teaching the language. In %articular, #y #otivation is to create so#ething that %rovides #e with a way to teach the language in #y own se#inars. :hen I think o" a cha%ter in the book, I think in ter#s o" what #akes a good lesson during a se#inar. My goal is to get bite'si1ed %ieces that can be taught in a reasonable a#ount o" ti#e, "ollowed by e&ercises that are "easible to acco#%lish in a classroo# situation.RFSURFSTIJLTICT5)TIL@U My goals in this book are to=RFSURFSTIJLTICT5)TILMU
()
Present the #aterial one si#%le ste% at a ti#e so that you can easily digest each conce%t be"ore #oving on. RFSURF STIJLTICT5)TILKU 4se e&a#%les that are as si#%le and short as %ossible. This so#eti#es %revents #e "ro# tackling !real world$ %roble#s, but I ve "ound that beginners are usually ha%%ier when they can understand every detail o" an e&a#%le rather than being i#%ressed by the sco%e o" the %roble# it solves. 6lso, there s a severe li#it to the a#ount o" code that can be absorbed in a classroo# situation.
!)
11
Eor this I will no doubt receive criticis# "or using !toy e&a#%les,$ but I # willing to acce%t that in "avor o" %roducing so#ething %edagogically use"ul. RFSURFSTIJLTICT5)TILLU
*)
+are"ully seAuence the %resentation o" "eatures so that you aren t seeing so#ething that you haven t been e&%osed to. )" course, this isn t always %ossible; in those situations, a brie" introductory descri%tion is given. RFSURFSTIJLTICT5)TIL?U 8ive you what I think is i#%ortant "or you to understand about the language, rather than everything I know. I believe there is an in"or#ation i#%ortance hierarchy, and that there are so#e "acts that 2H %ercent o" %rogra##ers will never need to know and that 0ust con"use %eo%le and adds to their %erce%tion o" the co#%le&ity o" the language. To take an e&a#%le "ro# +, i" you #e#ori1e the o%erator %recedence table *I never did,, you can write clever code. But i" you need to think about it, it will also con"use the readerF #aintainer o" that code. So "orget about %recedence, and use %arentheses when things aren t clear. RFSURF STIJLTICT5)TILHU >ee% each section "ocused enough so that the lecture ti#e9and the ti#e between e&ercise %eriods9is s#all. Cot only does this kee% the audience s #inds #ore active and involved during a hands'on se#inar, but it gives the reader a greater sense o" acco#%lish#ent. RFSURFSTIJLTICT5)TIL3U Provide you with a solid "oundation so that you can understand the issues well enough to #ove on to #ore di""icult coursework and books. RFSURFSTIJLTICT5)TILGU
+)
,)
-)
Online documentation
The Java language and libraries "ro# Sun Microsyste#s *a "ree download, co#e with docu#entation in electronic "or#, readable using a :eb browser, and virtually every third %arty i#%le#entation o" Java has this or an eAuivalent docu#entation syste#. 6l#ost all the books %ublished on Java have du%licated this docu#entation. So you either already have it or you can download it, and unless necessary, this book
12
Thinking in Java
,,,'0ruceEckel'com
will not re%eat that docu#entation because it s usually #uch "aster i" you "ind the class descri%tions with your :eb browser than i" you look the# u% in a book *and the on'line docu#entation is %robably #ore u%'to' date,. This book will %rovide e&tra descri%tions o" the classes only when it s necessary to su%%le#ent the docu#entation so you can understand a %articular e&a#%le.RFSURFSTIJLTICT5)TILIU
Cha.ters
This book was designed with one thing in #ind= the way %eo%le learn the Java language. Se#inar audience "eedback hel%ed #e understand the di""icult %arts that needed illu#ination. In the areas where I got a#bitious and included too #any "eatures all at once, I ca#e to know9 through the %rocess o" %resenting the #aterial9that i" you include a lot o" new "eatures, you need to e&%lain the# all, and this easily co#%ounds the student s con"usion. 6s a result, I ve taken a great deal o" trouble to introduce the "eatures as "ew at a ti#e as %ossible.RFSURF STIJLTICT5)TIL2U The goal, then, is "or each cha%ter to teach a single "eature, or a s#all grou% o" associated "eatures, without relying on additional "eatures. That way you can digest each %iece in the conte&t o" your current knowledge be"ore #oving on.RFSURFSTIJLTICT5)TI?@U (ere is a brie" descri%tion o" the cha%ters contained in the book, which corres%ond to lectures and e&ercise %eriods in #y hands'on se#inars.RF SURFSTIJLTICT5)TI?MU
+ha%ter M=
Introduction to Objects
This cha%ter is an overview o" what ob0ect'oriented %rogra##ing is all about, including the answer to the basic Auestion !:hat s an ob0ectO$, inter"ace vs. i#%le#entation, abstraction and enca%sulation, #essages and "unctions, inheritance and co#%osition, and the all'i#%ortant %oly#or%his#. /ou ll also get an overview o" issues o" ob0ect creation such as constructors, where the ob0ects live, where to %ut the# once they re created, and the #agical garbage collector that cleans u% the ob0ects that are no longer needed.
13
)ther issues will be introduced, including error handling with e&ce%tions, #ultithreading "or res%onsive user inter"aces, and networking and the Internet. /ou ll learn what #akes Java s%ecial, why it s been so success"ul, and about ob0ect'oriented analysis and design.
+ha%ter K=
ver!thing is an Object
This cha%ter #oves you to the %oint where you can write your "irst Java %rogra#, so it #ust give an overview o" the essentials, including the conce%t o" a re$erence to an ob0ect; how to create an ob0ect; an introduction to %ri#itive ty%es and arrays; sco%ing and the way ob0ects are destroyed by the garbage collector; how everything in Java is a new data ty%e *class, and how to create your own classes; "unctions, argu#ents, and return values; na#e visibility and using co#%onents "ro# other libraries; the static keyword; and co##ents and e#bedded docu#entation.RFSURF STIJLTICT5)TI?KU
+ha%ter L=
+ha%ter ?=
14
Thinking in Java
,,,'0ruceEckel'com
by a discussion o" the %rocess o" cleanu%, which is not always as si#%le as it see#s. Cor#ally, you 0ust dro% an ob0ect when you re done with it and the garbage collector eventually co#es along and releases the #e#ory. This %ortion e&%lores the garbage collector and so#e o" its idiosyncrasies. The cha%ter concludes with a closer look at how things are initiali1ed= auto#atic #e#ber initiali1ation, s%eci"ying #e#ber initiali1ation, the order o" initiali1ation, static initiali1ation and array initiali1ation. RFSURF STIJLTICT5)TI??U
+ha%ter H=
+ha%ter 3=
Reusing Classes
The conce%t o" inheritance is standard in virtually all ))P languages. It s a way to take an e&isting class and add to its "unctionality *as well as change it, the sub0ect o" +ha%ter G,. Inheritance is o"ten a way to reuse code by leaving the !base class$ the sa#e, and 0ust %atching things here and there to %roduce what you want. (owever, inheritance isn t the only way to #ake new classes "ro# e&isting ones. /ou can also e#bed an ob0ect inside your new class with com osition. In this cha%ter you ll learn about these two ways to reuse code in Java, and how to a%%ly the#. RFSURFSTIJLTICT5)TI?3U
+ha%ter G=
"ol!#or'his#
)n your own, you #ight take nine #onths to discover and understand %oly#or%his#, a cornerstone o" ))P. Through s#all, si#%le e&a#%les you ll see how to create a "a#ily o"
15
ty%es with inheritance and #ani%ulate ob0ects in that "a#ily through their co##on base class. Java s %oly#or%his# allows you to treat all ob0ects in this "a#ily generically, which #eans the bulk o" your code doesn t rely on s%eci"ic ty%e in"or#ation. This #akes your %rogra#s e&tensible, so building %rogra#s and code #aintenance is easier and chea%er.RFSURFSTIJLTICT5)TI?GU
+ha%ter I=
+ha%ter 2=
17
Thinking in Java
,,,'0ruceEckel'com
+ha%ter M@=
+ha%ter MM=
+ha%ter MK=
18
what 5TTI is "or, how to use it, and how to get rid o" it when it doesn t belong there. In addition, this cha%ter introduces the Java re$lection #echanis#.RFSURFSTIJLTICT5)TIHLU
+ha%ter ML=
+ha%ter M?.
/ulti'le Threads
Java %rovides a built'in "acility to su%%ort #ulti%le concurrent subtasks, called threads, running within a single %rogra#. *4nless you have #ulti%le %rocessors on your #achine, this is only the a earance o" #ulti%le subtasks., 6lthough these can be used anywhere, threads are #ost a%%arent when trying to create a res%onsive user inter"ace so, "or e&a#%le, a user isn t %revented "ro# %ressing a button or entering data while so#e %rocessing is going on. This cha%ter looks at the synta& and se#antics o" #ultithreading in Java. RFSURFSTIJLTICT5)TIHHU
+ha%ter MH=
Distributed Co#'uting
6ll the Java "eatures and libraries see# to really co#e together when you start writing %rogra#s to work across networks. This cha%ter e&%lores co##unication across networks and the Internet, and the classes that Java %rovides to #ake this easier. It introduces the very i#%ortant conce%ts o" Servlets and JSPs *"or server'side %rogra##ing,, along ,ith Java %ata0ase Connectivit) *J7B+,, and -emote Method Invocation *5MI,. Einally, there s an introduction to the new technologies o" JI+I, JavaS aces, and Enter rise Java0eans *EJBs,.RFSURFSTIJLTICT5)TIH3U
1:
Thinking in Java
,,,'0ruceEckel'com
6%%endi& 6=
6%%endi& B=
/0ercises
I ve discovered that si#%le e&ercises are e&ce%tionally use"ul to co#%lete a student s understanding during a se#inar, so you ll "ind a set at the end o" each cha%ter.RFSURFSTIJLTICT5)TI3MU Most e&ercises are designed to be easy enough that they can be "inished in a reasonable a#ount o" ti#e in a classroo# situation while the instructor
1;
observes, #aking sure that all the students are absorbing the #aterial. So#e e&ercises are #ore advanced to %revent boredo# "or e&%erienced students. The #a0ority are designed to be solved in a short ti#e and test and %olish your knowledge. So#e are #ore challenging, but none %resent #a0or challenges. *Presu#ably, you ll "ind those on your own9or #ore likely they ll "ind you,.RFSURFSTIJLTICT5)TI3KU Solutions to selected e&ercises can be "ound in the electronic docu#ent
The Thinking in Java "nnotated Solution @uide, available "or a s#all "ee
"ro# www.BruceEckel.co#.RFSURFSTIJLTICT5)TI3LU
Multimedia CD $OM
There are two #ulti#edia +7s associated with this book. The "irst is bound into the book itsel"= Thinking in C, described at the end o" the %re"ace, which %re%ares you "or the book by bringing you u% to s%eed on the necessary + synta& you need to be able to understand Java.RFSURF STIJLTICT5)TI3?U 6 second Multi#edia +7 5)M is available, which is based on the contents o" the book. This +7 5)M is a se%arate %roduct and contains the entire contents o" the week'long !(ands')n Java$ training se#inar. This is #ore than MH hours o" lectures that I have recorded, synchroni1ed with hundreds o" slides o" in"or#ation. Because the se#inar is based on this book, it is an ideal acco#%ani#ent.RFSURFSTIJLTICT5)TI3HU The +7 5)M contains all the lectures *with the i#%ortant e&ce%tion o" %ersonali1ed attention., "ro# the "ive'day "ull'i##ersion training se#inars. :e believe that it sets a new standard "or Auality.RFSURF STIJLTICT5)TI33U The (ands')n Java +7 5)M is available only by ordering directly "ro# the :eb site ,,,'0ruceEckel'com.RFSURFSTIJLTICT5)TI3GU
1ource code
6ll the source code "or this book is available as co%yrighted "reeware, distributed as a single %ackage, by visiting the :eb site ,,,'0ruceEckel'
2=
Thinking in Java
,,,'0ruceEckel'com
com. To #ake sure that you get the #ost current version, this is the
o""icial site "or distribution o" the code and the electronic version o" the book. /ou can "ind #irrored versions o" the electronic book and the code on other sites *so#e o" these sites are "ound at ,,,'0ruceEckel'com,, but you should check the o""icial site to ensure that the #irrored version is actually the #ost recent edition. /ou #ay distribute the code in classroo# and other educational situations.RFSURFSTIJLTICT5)TI3IU The %ri#ary goal o" the co%yright is to ensure that the source o" the code is %ro%erly cited, and to %revent you "ro# re%ublishing the code in %rint #edia without %er#ission. *6s long as the source is cited, using e&a#%les "ro# the book in #ost #edia is generally not a %roble#.,RFSURF STIJLTICT5)TI32U In each source code "ile you will "ind a re"erence to the "ollowing co%yright notice=RFSURFSTIJLTICT5)TIG@U
//34 3Co"y5ight.t6t Co"yright 7 ''' Bruce Eckel %ource co!e file fro# the n! e!ition of the book 8Thinking in Java.8 0ll rights reserve! E9CEPT as allo:e! by the follo:ing state#ents3 ;ou can freely use this file for your o:n :ork -"ersonal or co##ercial., inclu!ing #o!ifications an! !istribution in e6ecutable for# only. Per#ission is grante! to use this file in classroo# situations, inclu!ing its use in "resentation #aterials, as long as the book 8Thinking in Java8 is cite! as the source. E6ce"t in classroo# situations, you cannot co"y an! !istribute this co!e< instea!, the sole !istribution "oint is htt"3//:::.BruceEckel.co# -an! official #irror sites. :here it is freely available. ;ou cannot re#ove this co"yright an! notice. ;ou cannot !istribute #o!ifie! versions of the source co!e in this "ackage. ;ou cannot use this file in "rinte! #e!ia :ithout the e6"ress "er#ission of the author. Bruce Eckel #akes no re"resentation about the suitability of this soft:are for any "ur"ose. $t is "rovi!e! 8as is8 :ithout e6"ress or i#"lie!
21
:arranty of any kin!, inclu!ing any i#"lie! :arranty of #erchantability, fitness for a "articular "ur"ose or non-infringe#ent. The entire risk as to the =uality an! "erfor#ance of the soft:are is :ith you. Bruce Eckel an! the "ublisher shall not be liable for any !a#ages suffere! by you or any thir! "arty as a result of using or !istributing soft:are. $n no event :ill Bruce Eckel or the "ublisher be liable for any lost revenue, "rofit, or !ata, or for !irect, in!irect, s"ecial, conse=uential, inci!ental, or "unitive !a#ages, ho:ever cause! an! regar!less of the theory of liability, arising out of the use of or inability to use soft:are, even if Bruce Eckel an! the "ublisher have been a!vise! of the "ossibility of such !a#ages. %houl! the soft:are "rove !efective, you assu#e the cost of all necessary servicing, re"air, or correction. $f you think you2ve foun! an error, "lease sub#it the correction using the for# you :ill fin! at :::.BruceEckel.co#. -Please use the sa#e for# for non-co!e errors foun! in the book..
///3>
/ou #ay use the code in your %ro0ects and in the classroo# *including your %resentation #aterials, as long as the co%yright notice that a%%ears in each source "ile is retained.RFSURFSTIJLTICT5)TIGMU
Coding standards
In the te&t o" this book, identi"iers *"unction, variable, and class na#es, are set in bol'. Most keywords are also set in bold, e&ce%t "or those keywords that are used so #uch that the bolding can beco#e tedious, such as !class.$RFSURFSTIJLTICT5)TIGKU I use a %articular coding style "or the e&a#%les in this book. This style "ollows the style that Sun itsel" uses in virtually all o" the code you will "ind at its site *see >ava'sun'com/docs/codeconv/inde*'html,, and see#s to be su%%orted by #ost Java develo%#ent environ#ents. I" you ve read #y other works, you ll also notice that Sun s coding style coincides with
22
Thinking in Java
,,,'0ruceEckel'com
#ine9this %leases #e, although I had nothing to do with it. The sub0ect o" "or#atting style is good "or hours o" hot debate, so I ll 0ust say I # not trying to dictate correct style via #y e&a#%les; I have #y own #otivation "or using the style that I do. Because Java is a "ree'"or# %rogra##ing language, you can continue to use whatever style you re co#"ortable with. RFSURFSTIJLTICT5)TIGLU The %rogra#s in this book are "iles that are included by the word %rocessor in the te&t, directly "ro# co#%iled "iles. Thus, the code "iles %rinted in the book should all work without co#%iler errors. The errors that should cause co#%ile'ti#e error #essages are co##ented out with the co##ent 55= so they can be easily discovered and tested using auto#atic #eans. Errors discovered and re%orted to the author will a%%ear "irst in the distributed source code and later in u%dates o" the book *which will also a%%ear on the :eb site ,,,'0ruceEckel'com,.RF SURFSTIJLTICT5)TIG?U
"ava versions
I generally rely on the Sun i#%le#entation o" Java as a re"erence when deter#ining whether behavior is correct.RFSURFSTIJLTICT5)TIGHU )ver ti#e, Sun has released three #a0or versions o" Java= M.@, M.M and K *which is called version K even though the releases o" the J7> "ro# Sun continue to use the nu#bering sche#e o" M.K, M.L, M.?, etc.,. Version K see#s to "inally bring Java into the %ri#e ti#e, in %articular where user inter"ace tools are concerned. This book "ocuses on and is tested with Java K, although I do so#eti#es #ake concessions to earlier "eatures o" Java K so that the code will co#%ile under Dinu& *via the Dinu& J7> that was available at this writing,.RFSURFSTIJLTICT5)TIG3U I" you need to learn about earlier releases o" the language that are not covered in this edition, the "irst edition o" the book is "reely downloadable at ,,,'0ruceEckel'com and is also contained on the +7 that is bound in with this book.RFSURFSTIJLTICT5)TIGGU )ne thing you ll notice is that, when I do need to #ention earlier versions o" the language, I don t use the sub'revision nu#bers. In this book I will re"er to Java M.@, Java M.M, and Java K only, to guard against ty%ogra%hical
23
/rrors
Co #atter how #any tricks a writer uses to detect errors, so#e always cree% in and these o"ten lea% o"" the %age "or a "resh reader. RFSURF STIJLTICT5)TIIMU There is an error sub#ission "or# linked "ro# the beginning o" each cha%ter in the (TMD version o" this book *and on the +7 5)M bound into the back o" this book, and downloadable "ro# ,,,'0ruceEckel' com, and also on the :eb site itsel", on the %age "or this book. I" you discover anything you believe to be an error, %lease use this "or# to sub#it the error along with your suggested correction. I" necessary, include the original source "ile and note any suggested #odi"ications. /our hel% is a%%reciated.RFSURFSTIJLTICT5)TIIKU
24
Thinking in Java
,,,'0ruceEckel'com
25
Acknowledgements
Eirst, thanks to associates who have worked with #e to give se#inars, %rovide consulting, and develo% teaching %ro0ects= 6ndrea Provaglio, 7ave Bartlett *who also contributed signi"icantly to +ha%ter MH,, Bill Venners, and Darry ) Brien. I a%%reciate your %atience as I continue to try to develo% the best #odel "or inde%endent "olks like us to work together. Thanks to 5ol" 6ndrW >laedtke *Swit1erland,; Martin Vlcek, Martin Byer, Vlada N Pavel Dahoda, Martin the Bear, and (anka *Prague,; and Marco +antu *Italy, "or hosting #e on #y "irst sel"' organi1ed Euro%ean se#inar tour.RFSURFSTIJLTICT5)TIIGU Thanks to the 7oyle Street +ohousing +o##unity "or %utting u% with #e "or the two years that it took #e to write the "irst edition o" this book *and "or %utting u% with #e at all,. Thanks very #uch to >evin and Sonda 7onovan "or subletting their great %lace in gorgeous +rested Butte, +olorado "or the su##er while I worked on the "irst edition o" the book. 6lso thanks to the "riendly residents o" +rested Butte and the 5ocky Mountain Biological Daboratory who #ake #e "eel so welco#e.RFSURF STIJLTICT5)TIIIU Thanks to +laudette Moore at Moore Diterary 6gency "or her tre#endous %atience and %erseverance in getting #e e&actly what I wanted.RFSURF STIJLTICT5)TII2U My "irst two books were %ublished with Je"" Pe%%er as editor at )sborneF Mc8raw'(ill. Je"" a%%eared at the right %lace and the right ti#e at Prentice'(all and has cleared the %ath and #ade all the right things ha%%en to #ake this a very %leasant %ublishing e&%erience. Thanks, Je""9 it #eans a lot to #e.RFSURFSTIJLTICT5)TI2@U I # es%ecially indebted to 8en >iyooka and his co#%any 7igiga#i, who graciously %rovided #y :eb server "or the "irst several years o" #y %resence on the :eb. This was an invaluable learning aid.RFSURF STIJLTICT5)TI2MU
27
Thinking in Java
,,,'0ruceEckel'com
Thanks to +ay (orst#ann *co'author o" Core Java, Prentice'(all, K@@@ A, 7 6rcy S#ith *Sy#antec,, and Paul Ty#a *co'author o" Java Primer Plus, The :aite 8rou%, M223,, "or hel%ing #e clari"y conce%ts in the language.RFSURFSTIJLTICT5)TI2KU Thanks to %eo%le who have s%oken in #y Java track at the So"tware 7evelo%#ent +on"erence, and students in #y se#inars, who ask the Auestions I need to hear in order to #ake the #aterial #ore clear.RFSURF STIJLTICT5)TI2LU S%ecial thanks to Darry and Tina ) Brien, who hel%ed turn #y se#inar into the original .ands/On Java +7 5)M. */ou can "ind out #ore at ,,,'0ruceEckel'com.,RFSURFSTIJLTICT5)TI2?U Dots o" %eo%le sent in corrections and I a# indebted to the# all, but %articular thanks go to *"or the "irst edition,= >evin 5aulerson *"ound tons o" great bugs,, Bob 5esendes *si#%ly incredible,, John Pinto, Joe 7ante, Joe Shar% *all three were "abulous,, 7avid +o#bs *#any gra##ar and clari"ication corrections,, 7r. 5obert Ste%henson, John +ook, Eranklin +hen, Qev 8riner, 7avid >arr, Deander 6. Stroschein, Steve +lark, +harles 6. Dee, 6ustin Maher, 7ennis P. 5oth, 5oAue )liveira, 7ouglas 7unn, 7e0an 5istic, Ceil 8alarneau, 7avid B. Malkovsky, Steve :ilkinson, and a host o" others. Pro". Ir. Marc Meurrens %ut in a great deal o" e""ort to %ublici1e and #ake the electronic version o" the "irst edition o" the book available in Euro%e.RFSURFSTIJLTICT5)TI2HU There have been a s%ate o" s#art technical %eo%le in #y li"e who have beco#e "riends and have also been both in"luential and unusual in that they do yoga and %ractice other "or#s o" s%iritual enhance#ent, which I "ind Auite ins%irational and instructional. They are >raig Brocksch#idt, 8en >iyooka, and 6ndrea Provaglio, *who hel%s in the understanding o" Java and %rogra##ing in general in Italy, and now in the 4nited States as an associate o" the MindView tea#,.RFSURFSTIJLTICT5)TI23U It s not that #uch o" a sur%rise to #e that understanding 7el%hi hel%ed #e understand Java, since there are #any conce%ts and language design decisions in co##on. My 7el%hi "riends %rovided assistance by hel%ing #e gain insight into that #arvelous %rogra##ing environ#ent. They are Marco +antu *another Italian9%erha%s being stee%ed in Datin gives one a%titude "or %rogra##ing languagesO,, Ceil 5ubenking *who used to do
28
the yogaFvegetarianFQen thing until he discovered co#%uters,, and o" course Qack 4rlocker, a long'ti#e %al who# I ve traveled the world with. RFSURFSTIJLTICT5)TI2GU My "riend 5ichard (ale Shaw s insights and su%%ort have been very hel%"ul *and >i# s, too,. 5ichard and I s%ent #any #onths giving se#inars together and trying to work out the %er"ect learning e&%erience "or the attendees. Thanks also to >o6nn Vikoren, Eric Eaurot, Marco Pardi, and the rest o" the cast and crew at MEI. Thanks es%ecially to Tara 6rrowood, who re'ins%ired #e about the %ossibilities o" con"erences.RF SURFSTIJLTICT5)TI2IU The book design, cover design, and cover %hoto were created by #y "riend 7aniel :ill'(arris, noted author and designer * ,,,'Bill/.arris'com,, who used to %lay with rub'on letters in 0unior high school while he awaited the invention o" co#%uters and deskto% %ublishing, and co#%lained o" #e #u#bling over #y algebra %roble#s. (owever, I %roduced the ca#era'ready %ages #ysel", so the ty%esetting errors are #ine. Microso"t X :ord 2G "or :indows was used to write the book and to create ca#era'ready %ages in 6dobe 6crobat; the book was created directly "ro# the 6crobat P7E "iles. *6s a tribute to the electronic age, I ha%%ened to be overseas both ti#es the "inal version o" the book was %roduced9the "irst edition was sent "ro# +a%etown, South 6"rica and the second edition was %osted "ro# Prague,. The body ty%e"ace is @eorgia and the headlines are in Cerdana. The cover ty%e"ace is ITC -ennie Mackintosh'RFSURFSTIJLTICT5)TI22U Thanks to the vendors who created the co#%ilers= Borland, the Blackdown grou% *"or Dinu&,, and o" course, Sun.RFSURF STIJLTICT5)TIM@@U 6 s%ecial thanks to all #y teachers and all #y students *who are #y teachers as well,. The #ost "un writing teacher was 8abrielle 5ico *author o" Briting the +atural Ba), Putna#, M2IL,. I ll always treasure the terri"ic week at Esalen.RFSURFSTIJLTICT5)TIM@MU The su%%orting cast o" "riends includes, but is not li#ited to= 6ndrew Binstock, Steve Sino"sky, J7 (ildebrandt, To# >e""er, Brian McElhinney, Brinkley Barr, Bill 8ates at Midnight Engineering Maga?ine, Darry +onstantine and Ducy Dockwood, 8reg Perry, 7an Putter#an, +hristi
2:
Thinking in Java
,,,'0ruceEckel'com
:est%hal, 8ene :ang, 7ave Mayer, 7avid Intersi#one, 6ndrea 5osen"ield, +laire Sawyers, #ore Italians *Daura Eallai, +orrado, Ilsa, and +ristina 8iusto11i,, +hris and Daura Strand, the 6l#Auists, Brad Jerbic, Marilyn +vitanic, the Mabrys, the (a"lingers, the Pollocks, Peter Vinci, the 5obbins Ea#ilies, the Moelter Ea#ilies *and the McMillans,, Michael :ilk, 7ave Stoner, Daurie 6da#s, the +ranstons, Darry Eogg, Mike and >aren SeAueira, 8ary Ents#inger and 6llison Brody, >evin 7onovan and Sonda Eastlack, +hester and Shannon 6ndersen, Joe Dordi, 7ave and Brenda Bartlett, 7avid Dee, the 5entschlers, the Sudeks, 7ick, Patty, and Dee Eckel, Dynn and Todd, and their "a#ilies. 6nd o" course, Mo# and 7ad.RFSURFSTIJLTICT5)TIM@KU
Internet contributors
Thanks to those who hel%ed #e rewrite the e&a#%les to use the Swing library, and "or other assistance= Jon Shvarts, Tho#as >irsch, 5ahi# 6datia, 5a0esh Jain, 5avi Manthena, Banu 5a0a#ani, Jens Brandt, Citin Shivara#, Malcol# 7avis, and everyone who e&%ressed su%%ort. This really hel%ed #e 0u#%'start the %ro0ect.RFSU
2;
(: Introduction to Ob3ects
RFSTIJLT+(6PTE5MTI@UThe genesis o" the co#%uter revolution was in a #achine. The genesis o" our %rogra##ing languages thus tends to look like that #achine.
But co#%uters are not so #uch #achines as they are #ind a#%li"ication tools *!bicycles "or the #ind,$ as Steve Jobs is "ond o" saying, and a di""erent kind o" e&%ressive #ediu#. 6s a result, the tools are beginning to look less like #achines and #ore like %arts o" our #inds, and also like other "or#s o" e&%ression such as writing, %ainting, scul%ture, ani#ation, and "il##aking. )b0ect'oriented %rogra##ing *))P, is %art o" this #ove#ent toward using the co#%uter as an e&%ressive #ediu#.RFSURF STIJLT+(6PTE5MTIMU This cha%ter will introduce you to the basic conce%ts o" ))P, including an overview o" develo%#ent #ethods. This cha%ter, and this book, assu#e that you have had e&%erience in a %rocedural %rogra##ing language, although not necessarily +. I" you think you need #ore %re%aration in %rogra##ing and the synta& o" + be"ore tackling this book, you should work through the Thinking in C! 9oundations $or C++ and Java training +7 5)M, bound in with this book and also available at ,,,'0ruceEckel' com. RFSURFSTIJLT+(6PTE5MTIKU This cha%ter is background and su%%le#entary #aterial. Many %eo%le do not "eel co#"ortable wading into ob0ect'oriented %rogra##ing without understanding the big %icture "irst. Thus, there are #any conce%ts that are introduced here to give you a solid overview o" ))P. (owever, #any other %eo%le don t get the big %icture conce%ts until they ve seen so#e o" the #echanics "irst; these %eo%le #ay beco#e bogged down and lost without so#e code to get their hands on. I" you re %art o" this latter grou% and are eager to get to the s%eci"ics o" the language, "eel "ree to 0u#% %ast
3=
this cha%ter9ski%%ing it at this %oint will not %revent you "ro# writing %rogra#s or learning the language. (owever, you will want to co#e back here eventually to "ill in your knowledge so you can understand why ob0ects are i#%ortant and how to design with the#.RFSURF STIJLT+(6PTE5MTILU
31
designed to solve, but when you ste% outside o" that do#ain they beco#e awkward. RFSURFSTIJLT+(6PTE5MTIHU The ob0ect'oriented a%%roach goes a ste% "urther by %roviding tools "or the %rogra##er to re%resent ele#ents in the %roble# s%ace. This re%resentation is general enough that the %rogra##er is not constrained to any %articular ty%e o" %roble#. :e re"er to the ele#ents in the %roble# s%ace and their re%resentations in the solution s%ace as !ob0ects.$ *)" course, you will also need other ob0ects that don t have %roble#'s%ace analogs., The idea is that the %rogra# is allowed to ada%t itsel" to the lingo o" the %roble# by adding new ty%es o" ob0ects, so when you read the code describing the solution, you re reading words that also e&%ress the %roble#. This is a #ore "le&ible and %ower"ul language abstraction than what we ve had be"ore. Thus, ))P allows you to describe the %roble# in ter#s o" the %roble#, rather than in ter#s o" the co#%uter where the solution will run. There s still a connection back to the co#%uter, though. Each ob0ect looks Auite a bit like a little co#%uter; it has a state, and it has o%erations that you can ask it to %er"or#. (owever, this doesn t see# like such a bad analogy to ob0ects in the real world9they all have characteristics and behaviors. RFSURFSTIJLT+(6PTE5MTI3U So#e language designers have decided that ob0ect'oriented %rogra##ing by itsel" is not adeAuate to easily solve all %rogra##ing %roble#s, and advocate the co#bination o" various a%%roaches into multi aradigm %rogra##ing languages. @RFSURFSTIJLT+(6PTE5MTIGU 6lan >ay su##ari1ed "ive basic characteristics o" S#alltalk, the "irst success"ul ob0ect'oriented language and one o" the languages u%on which Java is based. These characteristics re%resent a %ure a%%roach to ob0ect' oriented %rogra##ing=RFSURFSTIJLT+(6PTE5MTIIU
4)
32
5)
A rogram is a bunch o! objects telling each other "hat to do by sending messages. To #ake a reAuest o" an
ob0ect, you !send a #essage$ to that ob0ect. More concretely, you can think o" a #essage as a reAuest to call a "unction that belongs to a %articular ob0ect. RFSURFSTIJLT+(6PTE5MTIM@U
6)
Each object has its o"n memory made u o! other objects. Put another way, you create a new kind o" ob0ect by
#aking a %ackage containing e&isting ob0ects. Thus, you can build co#%le&ity in a %rogra# while hiding it behind the si#%licity o" ob0ects. RFSURFSTIJLT+(6PTE5MTIMMU
(7)
Every object has a ty e. 4sing the %arlance, each ob0ect is an instance o" a class, in which !class$ is synony#ous with !ty%e.$ The
#ost i#%ortant distinguishing characteristic o" a class is !:hat #essages can you send to itO$ RFSURFSTIJLT+(6PTE5MTIMKU
(()
All objects o! a articular ty e can receive the same messages. This is actually a loaded state#ent, as you will see
later. Because an ob0ect o" ty%e !circle$ is also an ob0ect o" ty%e !sha%e,$ a circle is guaranteed to acce%t sha%e #essages. This #eans you can write code that talks to sha%es and auto#atically handle anything that "its the descri%tion o" a sha%e. This substitutabilit) is one o" the #ost %ower"ul conce%ts in ))P. RF SURFSTIJLT+(6PTE5MTIMLU
Booch o""ers an even #ore succinct descri%tion o" an ob0ect= "n ob>ect has stateD behavior and identit) This #eans that an ob0ect can have internal data *which gives it state,, #ethods *to %roduce behavior,, and each ob0ect can be uniAuely distinguished "ro# every other ob0ect Y to %ut this in a concrete sense, each ob0ect has a uniAue address in #e#ory@
@ This is actually a bit restrictive, since ob0ects can conceivably e&ist in di""erent #achines and address s%aces, and they can also be stored on disk. In these cases, the identity o" the ob0ect #ust be deter#ined by so#ething other than #e#ory address.
33
34
Since a class describes a set o" ob0ects that have identical characteristics *data ele#ents, and behaviors *"unctionality,, a class is really a data ty%e because a "loating %oint nu#ber, "or e&a#%le, also has a set o" characteristics and behaviors. The di""erence is that a %rogra##er de"ines a class to "it a %roble# rather than being "orced to use an e&isting data ty%e that was designed to re%resent a unit o" storage in a #achine. /ou e&tend the %rogra##ing language by adding new data ty%es s%eci"ic to your needs. The %rogra##ing syste# welco#es the new classes and gives the# all the care and ty%e'checking that it gives to built'in ty%es.RF SURFSTIJLT+(6PTE5MTIMGU The ob0ect'oriented a%%roach is not li#ited to building si#ulations. :hether or not you agree that any %rogra# is a si#ulation o" the syste# you re designing, the use o" ))P techniAues can easily reduce a large set o" %roble#s to a si#%le solution.RFSURFSTIJLT+(6PTE5MTIMIU )nce a class is established, you can #ake as #any ob0ects o" that class as you like, and then #ani%ulate those ob0ects as i" they are the ele#ents that e&ist in the %roble# you are trying to solve. Indeed, one o" the challenges o" ob0ect'oriented %rogra##ing is to create a one'to'one #a%%ing between the ele#ents in the %roble# s%ace and ob0ects in the solution s%ace.RFSURFSTIJLT+(6PTE5MTIM2U But how do you get an ob0ect to do use"ul work "or youO There #ust be a way to #ake a reAuest o" the ob0ect so that it will do so#ething, such as co#%lete a transaction, draw so#ething on the screen, or turn on a switch. 6nd each ob0ect can satis"y only certain reAuests. The reAuests you can #ake o" an ob0ect are de"ined by its inter$aceD and the ty%e is what deter#ines the inter"ace. 6 si#%le e&a#%le #ight be a re%resentation o" a light bulb= RFSURFSTIJLT+(6PTE5MTIK@U
35
37
38
control there s no way to %revent it. Everything s naked to the world.RF SURFSTIJLT+(6PTE5MTIK3U So the "irst reason "or access control is to kee% client %rogra##ers hands o"" %ortions they shouldn t touch9%arts that are necessary "or the internal #achinations o" the data ty%e but not %art o" the inter"ace that users need in order to solve their %articular %roble#s. This is actually a service to users because they can easily see what s i#%ortant to the# and what they can ignore.RFSURFSTIJLT+(6PTE5MTIKGU The second reason "or access control is to allow the library designer to change the internal workings o" the class without worrying about how it will a""ect the client %rogra##er. Eor e&a#%le, you #ight i#%le#ent a %articular class in a si#%le "ashion to ease develo%#ent, and then later discover that you need to rewrite it in order to #ake it run "aster. I" the inter"ace and i#%le#entation are clearly se%arated and %rotected, you can acco#%lish this easily.RFSURFSTIJLT+(6PTE5MTIKIU Java uses three e&%licit keywords to set the boundaries in a class= p*blic, private, and protecte'. Their use and #eaning are Auite straight"orward. These access s eci$iers deter#ine who can use the de"initions that "ollow. p*blic #eans the "ollowing de"initions are available to everyone. The private keyword, on the other hand, #eans that no one can access those de"initions e&ce%t you, the creator o" the ty%e, inside #e#ber "unctions o" that ty%e. private is a brick wall between you and the client %rogra##er. I" so#eone tries to access a private #e#ber, they ll get a co#%ile'ti#e error. protecte' acts like private, with the e&ce%tion that an inheriting class has access to protecte' #e#bers, but not private #e#bers. Inheritance will be introduced shortly.RFSURFSTIJLT+(6PTE5MTIK2U Java also has a !de"ault$ access, which co#es into %lay i" you don t use one o" the a"ore#entioned s%eci"iers. This is so#eti#es called !"riendly$ access because classes can access the "riendly #e#bers o" other classes in the sa#e %ackage, but outside o" the %ackage those sa#e "riendly #e#bers a%%ear to be private.RFSURFSTIJLT+(6PTE5MTIL@U
3:
Car
/ngine
*The above 4MD diagra# indicates co#%osition with the "illed dia#ond, which states there is one car. I will ty%ically use a si#%ler "or#= 0ust a line, without the dia#ond, to indicate an association. @,RFSURF STIJLT+(6PTE5MTILLU +o#%osition co#es with a great deal o" "le&ibility. The #e#ber ob0ects o" your new class are usually %rivate, #aking the# inaccessible to the client %rogra##ers who are using the class. This allows you to change those #e#bers without disturbing e&isting client code. /ou can also change the #e#ber ob0ects at run'ti#e, to dyna#ically change the behavior o" your %rogra#. Inheritance, which is described ne&t, does not have this
@ This is usually enough detail "or #ost diagra#s, and you don t need to get s%eci"ic about whether you re using aggregation or co#%osition.
3;
"le&ibility since the co#%iler #ust %lace co#%ile'ti#e restrictions on classes created with inheritance.RFSURFSTIJLT+(6PTE5MTIL?U Because inheritance is so i#%ortant in ob0ect'oriented %rogra##ing it is o"ten highly e#%hasi1ed, and the new %rogra##er can get the idea that inheritance should be used everywhere. This can result in awkward and overly co#%licated designs. Instead, you should "irst look to co#%osition when creating new classes, since it is si#%ler and #ore "le&ible. I" you take this a%%roach, your designs will be cleaner. )nce you ve had so#e e&%erience, it will be reasonably obvious when you need inheritance.RF SURFSTIJLT+(6PTE5MTILHU
4=
;ase
Derived
*The arrow in the above 4MD diagra# %oints "ro# the derived class to the base class. 6s you will see, there can be #ore than one derived class., RFSURFSTIJLT+(6PTE5MTILIU 6 ty%e does #ore than describe the constraints on a set o" ob0ects; it also has a relationshi% with other ty%es. Two ty%es can have characteristics and behaviors in co##on, but one ty%e #ay contain #ore characteristics than another and #ay also handle #ore #essages *or handle the# di""erently,. Inheritance e&%resses this si#ilarity between ty%es using the conce%t o" base ty%es and derived ty%es. 6 base ty%e contains all o" the characteristics and behaviors that are shared a#ong the ty%es derived "ro# it. /ou create a base ty%e to re%resent the core o" your ideas about so#e ob0ects in your syste#. Ero# the base ty%e, you derive other ty%es to e&%ress the di""erent ways that this core can be reali1ed.RFSURF STIJLT+(6PTE5MTIL2U Eor e&a#%le, a trash'recycling #achine sorts %ieces o" trash. The base ty%e is !trash,$ and each %iece o" trash has a weight, a value, and so on, and can be shredded, #elted, or deco#%osed. Ero# this, #ore s%eci"ic ty%es o" trash are derived that #ay have additional characteristics *a bottle has a color, or behaviors *an alu#inu# can #ay be crushed, a steel can is #agnetic,. In addition, so#e behaviors #ay be di""erent *the value o" %a%er de%ends on its ty%e and condition,. 4sing inheritance, you can build a ty%e hierarchy that e&%resses the %roble# you re trying to solve in ter#s o" its ty%es.RFSURFSTIJLT+(6PTE5MTI?@U 6 second e&a#%le is the classic !sha%e$ e&a#%le, %erha%s used in a co#%uter'aided design syste# or ga#e si#ulation. The base ty%e is !sha%e,$ and each sha%e has a si1e, a color, a %osition, and so on. Each sha%e can be drawn, erased, #oved, colored, etc. Ero# this, s%eci"ic ty%es
41
o" sha%es are derived *inherited,= circle, sAuare, triangle, and so on, each o" which #ay have additional characteristics and behaviors. +ertain sha%es can be "li%%ed, "or e&a#%le. So#e behaviors #ay be di""erent, such as when you want to calculate the area o" a sha%e. The ty%e hierarchy e#bodies both the si#ilarities and di""erences between the sha%es.RF SURFSTIJLT+(6PTE5MTI?MU
$ircle
S%uare
&riangle
+asting the solution in the sa#e ter#s as the %roble# is tre#endously bene"icial because you don t need a lot o" inter#ediate #odels to get "ro# a descri%tion o" the %roble# to a descri%tion o" the solution. :ith ob0ects, the ty%e hierarchy is the %ri#ary #odel, so you go directly "ro# the descri%tion o" the syste# in the real world to the descri%tion o" the syste# in code. Indeed, one o" the di""iculties %eo%le have with ob0ect' oriented design is that it s too si#%le to get "ro# the beginning to the end. 6 #ind trained to look "or co#%le& solutions is o"ten stu#%ed by this si#%licity at "irst.RFSURFSTIJLT+(6PTE5MTI?KU :hen you inherit "ro# an e&isting ty%e, you create a new ty%e. This new ty%e contains not only all the #e#bers o" the e&isting ty%e *although the private ones are hidden away and inaccessible,, but #ore i#%ortant, it du%licates the inter"ace o" the base class. That is, all the #essages you can send to ob0ects o" the base class you can also send to ob0ects o" the derived class. Since we know the ty%e o" a class by the #essages we can send to it, this #eans that the derived class is the same t) e as the base
42
43
$ircle
S%uare
6lthough inheritance #ay so#eti#es i#%ly *es%ecially in Java, where the keyword that indicates inheritance is e4ten's, that you are going to add new "unctions to the inter"ace, that s not necessarily true. The second and #ore i#%ortant way to di""erentiate your new class is to change the behavior o" an e&isting base'class "unction. This is re"erred to as overriding that "unction.RFSURFSTIJLT+(6PTE5MTI?3U
44
To override a "unction, you si#%ly create a new de"inition "or the "unction in the derived class. /ou re saying, !I # using the sa#e inter"ace "unction here, but I want it to do so#ething di""erent "or #y new ty%e.$RFSURF STIJLT+(6PTE5MTI?GU
45
There are ti#es when you #ust add new inter"ace ele#ents to a derived ty%e, thus e&tending the inter"ace and creating a new ty%e. The new ty%e can still be substituted "or the base ty%e, but the substitution isn t %er"ect because your new "unctions are not accessible "ro# the base ty%e. This can be described as an is/like/a@ relationshi%; the new ty%e has the inter"ace o" the old ty%e but it also contains other "unctions, so you can t really say it s e&actly the sa#e. Eor e&a#%le, consider an air conditioner. Su%%ose your house is wired with all the controls "or cooling; that is, it has an inter"ace that allows you to control cooling. I#agine that the air conditioner breaks down and you re%lace it with a heat %u#%, which can both heat and cool. The heat %u#% is/like/an air conditioner, but it can do #ore. Because the control syste# o" your house is designed only to control cooling, it is restricted to co##unication with the cooling %art o" the new ob0ect. The inter"ace o" the new ob0ect has been e&tended, and the e&isting syste# doesn t know about anything e&ce%t the original inter"ace.RFSURFSTIJLT+(6PTE5MTI?2U
&hermostat lower#em.erature89
Controls
)" course, once you see this design it beco#es clear that the base class !cooling syste#$ is not general enough, and should be rena#ed to !te#%erature control syste#$ so that it can also include heating9at which %oint the substitution %rinci%le will work. (owever, the diagra# above is an e&a#%le o" what can ha%%en in design and in the real world. RFSURF STIJLT+(6PTE5MTIH@U
@ My ter#.
47
:hen you see the substitution %rinci%le it s easy to "eel like this a%%roach *%ure substitution, is the only way to do things, and in "act it is nice i" your design works out that way. But you ll "ind that there are ti#es when it s eAually clear that you #ust add new "unctions to the inter"ace o" a derived class. :ith ins%ection both cases should be reasonably obvious. RFSURFSTIJLT+(6PTE5MTIHMU
48
%rogra##er doesn t ,ant to know what %iece o" code will be e&ecuted; the draw "unction can be a%%lied eAually to a circle, a sAuare, or a triangle, and the ob0ect will e&ecute the %ro%er code de%ending on its s%eci"ic ty%e. I" you don t have to know what %iece o" code will be e&ecuted, then when you add a new subty%e, the code it e&ecutes can be di""erent without reAuiring changes to the "unction call. There"ore, the co#%iler cannot know %recisely what %iece o" code is e&ecuted, so what does it doO Eor e&a#%le, in the "ollowing diagra# the 2ir'-ontroller ob0ect 0ust works with generic 2ir' ob0ects, and does not know what e&act ty%e they are. This is convenient "ro# 2ir'-ontroller s %ers%ective because it doesn t have to write s%ecial code to deter#ine the e&act ty%e o" 2ir' it s working with, or that 2ir' s behavior. So how does it ha%%en that, when moveA B is called while ignoring the s%eci"ic ty%e o" 2ir', the right behavior will occur *a "oose runs, "lies, or swi#s, and a #eng*in runs or swi#s,ORFSURFSTIJLT+(6PTE5MTIH?U
Bird$ontroller re&ocate89 What ha..ens when move89 is calledA Bird move89
(oose move89
'enguin move89
The answer is the %ri#ary twist in ob0ect'oriented %rogra##ing= the co#%iler cannot #ake a "unction call in the traditional sense. The "unction call generated by a non'))P co#%iler causes what is called earl) binding, a ter# you #ay not have heard be"ore because you ve never thought about it any other way. It #eans the co#%iler generates a call to a s%eci"ic "unction na#e, and the linker resolves this call to the absolute address o" the code to be e&ecuted. In ))P, the %rogra# cannot deter#ine the address o" the code until run'ti#e, so so#e other sche#e is necessary when a #essage is sent to a generic ob0ect.RFSURF STIJLT+(6PTE5MTIHHU
4:
To solve the %roble#, ob0ect'oriented languages use the conce%t o" late binding. :hen you send a #essage to an ob0ect, the code being called isn t deter#ined until run'ti#e. The co#%iler does ensure that the "unction e&ists and %er"or#s ty%e checking on the argu#ents and return value *a language in which this isn t true is called ,eakl) t) ed,, but it doesn t know the e&act code to e&ecute.RFSURFSTIJLT+(6PTE5MTIH3U To %er"or# late binding, Java uses a s%ecial bit o" code in lieu o" the absolute call. This code calculates the address o" the "unction body, using in"or#ation stored in the ob0ect *this %rocess is covered in great detail in +ha%ter G,. Thus, each ob0ect can behave di""erently according to the contents o" that s%ecial bit o" code. :hen you send a #essage to an ob0ect, the ob0ect actually does "igure out what to do with that #essage.RF SURFSTIJLT+(6PTE5MTIHGU In so#e languages *+<<, in %articular, you #ust e&%licitly state that you want a "unction to have the "le&ibility o" late'binding %ro%erties. In these languages, by de"ault, #e#ber "unctions are not dyna#ically bound. This caused %roble#s, so in Java dyna#ic binding is the de"ault and you don t need to re#e#ber to add any e&tra keywords in order to get %oly#or%his#.RFSURFSTIJLT+(6PTE5MTIHIU +onsider the sha%e e&a#%le. The "a#ily o" classes *all based on the sa#e uni"or# inter"ace, was diagra##ed earlier in this cha%ter. To de#onstrate %oly#or%his#, we want to write a single %iece o" code that ignores the s%eci"ic details o" ty%e and talks only to the base class. That code is decou led "ro# ty%e's%eci"ic in"or#ation, and thus is si#%ler to write and easier to understand. 6nd, i" a new ty%e9a He4agon, "or e&a#%le9is added through inheritance, the code you write will work 0ust as well "or the new ty%e o" )hape as it did on the e&isting ty%es. Thus, the %rogra# is e*tensible.RFSURFSTIJLT+(6PTE5MTIH2U I" you write a #ethod in Java *as you will soon learn how to do,=RFSURF STIJLT+(6PTE5MTI3@U
4;
This "unction s%eaks to any )hape, so it is inde%endent o" the s%eci"ic ty%e o" ob0ect that it s drawing and erasing. I" in so#e other %art o" the %rogra# we use the 'o)t*ffA B "unction=RFSURF STIJLT+(6PTE5MTI3MU
Circle c ? ne: Circle-.< Triangle t ? ne: Triangle-.< Line l ? ne: Line-.< !o%tuff-c.< !o%tuff-t.< !o%tuff-l.<
The calls to 'o)t*ffA B auto#atically work correctly, regardless o" the e&act ty%e o" the ob0ect. RFSURFSTIJLT+(6PTE5MTI3KU This is actually a %retty a#a1ing trick. +onsider the line=
!o%tuff-c.<
:hat s ha%%ening here is that a -ircle is being %assed into a "unction that s e&%ecting a )hape. Since a -ircle is a )hape it can be treated as one by 'o)t*ffA B. That is, any #essage that 'o)t*ffA B can send to a )hape, a -ircle can acce%t. So it is a co#%letely sa"e and logical thing to do.RFSURFSTIJLT+(6PTE5MTI3LU :e call this %rocess o" treating a derived ty%e as though it were its base ty%e u casting. The na#e cast is used in the sense o" casting into a #old and the u co#es "ro# the way the inheritance diagra# is ty%ically arranged, with the base ty%e at the to% and the derived classes "anning out downward. Thus, casting to a base ty%e is #oving u% the inheritance diagra#= !u%casting.$RFSURFSTIJLT+(6PTE5MTI3?U
Sha e
BC.castingB
$ircle
S%uare
&riangle
5=
6n ob0ect'oriented %rogra# contains so#e u%casting so#ewhere, because that s how you decou%le yoursel" "ro# knowing about the e&act ty%e you re working with. Dook at the code in 'o)t*ffA B=RFSURF STIJLT+(6PTE5MTI3HU
51
the co#%iler %revents the#. This is a tool to en"orce a %articular design. RFSURFSTIJLT+(6PTE5MTI3IU /ou can also use the abstract keyword to describe a #ethod that hasn t been i#%le#ented yet9as a stub indicating !here is an inter"ace "unction "or all ty%es inherited "ro# this class, but at this %oint I don t have any i#%le#entation "or it.$ 6n abstract #ethod #ay be created only inside an abstract class. :hen the class is inherited, that #ethod #ust be i#%le#ented, or the inheriting class beco#es abstract as well. +reating an abstract #ethod allows you to %ut a #ethod in an inter"ace without being "orced to %rovide a %ossibly #eaningless body o" code "or that #ethod.RFSURFSTIJLT+(6PTE5MTI32U The interface keyword takes the conce%t o" an abstract class one ste% "urther by %reventing any "unction de"initions at all. The interface is a very handy and co##only used tool, as it %rovides the %er"ect se%aration o" inter"ace and i#%le#entation. In addition, you can co#bine #any inter"aces together, i" you wish, whereas inheriting "ro# #ulti%le regular classes or abstract classes is not %ossible.RFSURF STIJLT+(6PTE5MTIG@U
52
%riority on the s%eed o" storage allocation and release, and control o" these can be very valuable in so#e situations. (owever, you sacri"ice "le&ibility because you #ust know the e&act Auantity, li"eti#e, and ty%e o" ob0ects while youVre writing the %rogra#. I" you are trying to solve a #ore general %roble# such as co#%uter'aided design, warehouse #anage#ent, or air'tra""ic control, this is too restrictive.RFSURF STIJLT+(6PTE5MTIGKU The second a%%roach is to create ob0ects dyna#ically in a %ool o" #e#ory called the hea%. In this a%%roach, you donVt know until run'ti#e how #any ob0ects you need, what their li"eti#e is, or what their e&act ty%e is. Those are deter#ined at the s%ur o" the #o#ent while the %rogra# is running. I" you need a new ob0ect, you si#%ly #ake it on the hea% at the %oint that you need it. Because the storage is #anaged dyna#ically, at run'ti#e, the a#ount o" ti#e reAuired to allocate storage on the hea% is signi"icantly longer than the ti#e to create storage on the stack. *+reating storage on the stack is o"ten a single asse#bly instruction to #ove the stack %ointer down, and another to #ove it back u%., The dyna#ic a%%roach #akes the generally logical assu#%tion that ob0ects tend to be co#%licated, so the e&tra overhead o" "inding storage and releasing that storage will not have an i#%ortant i#%act on the creation o" an ob0ect. In addition, the greater "le&ibility is essential to solve the general %rogra##ing %roble#.RFSURFSTIJLT+(6PTE5MTIGLU Java uses the second a%%roach, e&clusively @. Every ti#e you want to create an ob0ect, you use the ne( keyword to build a dyna#ic instance o" that ob0ect.RFSURFSTIJLT+(6PTE5MTIG?U ThereVs another issue, however, and thatVs the li"eti#e o" an ob0ect. :ith languages that allow ob0ects to be created on the stack, the co#%iler deter#ines how long the ob0ect lasts and can auto#atically destroy it. (owever, i" you create it on the hea% the co#%iler has no knowledge o" its li"eti#e. In a language like +<<, you #ust deter#ine %rogra##atically when to destroy the ob0ect, which can lead to #e#ory leaks i" you don t do it correctly *and this is a co##on %roble# in +<< %rogra#s,. Java %rovides a "eature called a garbage collector that auto#atically discovers when an ob0ect is no longer in use and destroys it. 6 garbage collector is #uch #ore convenient because it reduces the nu#ber o" issues that you
@ Pri#itive ty%es, which you ll learn about later, are a s%ecial case.
53
#ust track and the code you #ust write. More i#%ortant, the garbage collector %rovides a #uch higher level o" insurance against the insidious %roble# o" #e#ory leaks *which has brought #any a +<< %ro0ect to its knees,.RFSURFSTIJLT+(6PTE5MTIGHU The rest o" this section looks at additional "actors concerning ob0ect li"eti#es and landsca%es.RFSURFSTIJLT+(6PTE5MTIG3U
54
Eortunately, a good ))P language co#es with a set o" containers as %art o" the %ackage. In +<<, it s %art o" the Standard +<< Dibrary and is so#eti#es called the Standard Te#%late Dibrary *STD,. )b0ect Pascal has containers in its Visual +o#%onent Dibrary *V+D,. S#alltalk has a very co#%lete set o" containers. Java also has containers in its standard library. In so#e libraries, a generic container is considered good enough "or all needs, and in others *Java, "or e&a#%le, the library has di""erent ty%es o" containers "or di""erent needs= a vector *called an Array+ist in Java, "or consistent access to all ele#ents, and a linked list "or consistent insertion at all ele#ents, "or e&a#%le, so you can choose the %articular ty%e that "its your needs. +ontainer libraries #ay also include sets, Aueues, hash tables, trees, stacks, etc.RFSURFSTIJLT+(6PTE5MTIG2U 6ll containers have so#e way to %ut things in and get things out; there are usually "unctions to add ele#ents to a container, and others to "etch those ele#ents back out. But "etching ele#ents can be #ore %roble#atic, because a single'selection "unction is restrictive. :hat i" you want to #ani%ulate or co#%are a set o" ele#ents in the container instead o" 0ust oneORFSURFSTIJLT+(6PTE5MTII@U The solution is an iterator, which is an ob0ect whose 0ob is to select the ele#ents within a container and %resent the# to the user o" the iterator. 6s a class, it also %rovides a level o" abstraction. This abstraction can be used to se%arate the details o" the container "ro# the code that s accessing that container. The container, via the iterator, is abstracted to be si#%ly a seAuence. The iterator allows you to traverse that seAuence without worrying about the underlying structure9that is, whether it s an Array+ist, a +inke'+ist, a )tack, or so#ething else. This gives you the "le&ibility to easily change the underlying data structure without disturbing the code in your %rogra#. Java began *in version M.@ and M.M, with a standard iterator, called &n*meration, "or all o" its container classes. Java K has added a #uch #ore co#%lete container library that contains an iterator called Iterator that does #ore than the older &n*meration.RFSURFSTIJLT+(6PTE5MTIIMU Ero# a design stand%oint, all you really want is a seAuence that can be #ani%ulated to solve your %roble#. I" a single ty%e o" seAuence satis"ied all o" your needs, there d be no reason to have di""erent kinds. There are two reasons that you need a choice o" containers. Eirst, containers
55
%rovide di""erent ty%es o" inter"aces and e&ternal behavior. 6 stack has a di""erent inter"ace and behavior than that o" a Aueue, which is di""erent "ro# that o" a set or a list. )ne o" these #ight %rovide a #ore "le&ible solution to your %roble# than the other. Second, di""erent containers have di""erent e""iciencies "or certain o%erations. The best e&a#%le is an Array+ist and a +inke'+ist. Both are si#%le seAuences that can have identical inter"aces and e&ternal behaviors. But certain o%erations can have radically di""erent costs. 5ando#ly accessing ele#ents in an Array+ist is a constant'ti#e o%eration; it takes the sa#e a#ount o" ti#e regardless o" the ele#ent you select. (owever, in a +inke'+ist it is e&%ensive to #ove through the list to rando#ly select an ele#ent, and it takes longer to "ind an ele#ent that is "urther down the list. )n the other hand, i" you want to insert an ele#ent in the #iddle o" a seAuence, it s #uch chea%er in a +inke'+ist than in an Array+ist. These and other o%erations have di""erent e""iciencies de%ending on the underlying structure o" the seAuence. In the design %hase, you #ight start with a +inke'+ist and, when tuning "or %er"or#ance, change to an Array+ist. Because o" the abstraction via iterators, you can change "ro# one to the other with #ini#al i#%act on your code.RFSURF STIJLT+(6PTE5MTIIKU In the end, re#e#ber that a container is only a storage cabinet to %ut ob0ects in. I" that cabinet solves all o" your needs, it doesn t really #atter how it is i#%le#ented *a basic conce%t with #ost ty%es o" ob0ects,. I" you re working in a %rogra##ing environ#ent that has built'in overhead due to other "actors, then the cost di""erence between an Array+ist and a +inke'+ist #ight not #atter. /ou #ight need only one ty%e o" seAuence. /ou can even i#agine the !%er"ect$ container abstraction, which can auto#atically change its underlying i#%le#entation according to the way it is used.RFSURFSTIJLT+(6PTE5MTIILU
57
58
es%ecially i#%ortant with syste# level o%erations, such as e&ce%tion handling, and to allow greater "le&ibility in %rogra##ing.RFSURF STIJLT+(6PTE5MTIIIU
5:
described shortly. :hen you "etch ob0ect re"erences "ro# a container, though, you #ust have so#e way to re#e#ber e&actly what they are so you can %er"or# a %ro%er downcast.RFSURFSTIJLT+(6PTE5MTI2LU 7owncasting and the run'ti#e checks reAuire e&tra ti#e "or the running %rogra#, and e&tra e""ort "ro# the %rogra##er. :ouldn t it #ake sense to so#ehow create the container so that it knows the ty%es that it holds, eli#inating the need "or the downcast and a %ossible #istakeO The solution is %ara#eteri1ed ty%es, which are classes that the co#%iler can auto#atically custo#i1e to work with %articular ty%es. Eor e&a#%le, with a %ara#eteri1ed container, the co#%iler could custo#i1e that container so that it would acce%t only Sha%es and "etch only Sha%es.RFSURF STIJLT+(6PTE5MTI2?U Para#eteri1ed ty%es are an i#%ortant %art o" +<<, %artly because +<< has no singly rooted hierarchy. In +<<, the keyword that i#%le#ents %ara#eteri1ed ty%es is !te#%late.$ Java currently has no %ara#eteri1ed ty%es since it is %ossible "or it to get by9however awkwardly9using the singly rooted hierarchy. (owever, a current %ro%osal "or %ara#eteri1ed ty%es uses a synta& that is strikingly si#ilar to +<< te#%lates.RFSURF STIJLT+(6PTE5MTI2HU
5;
air'tra""ic'control 1one. Eor cleanu%, si#%ly delete the a%%ro%riate air%lane ob0ect when a %lane leaves the 1one.RFSURF STIJLT+(6PTE5MTI2GU But %erha%s you have so#e other syste# to record data about the %lanes; %erha%s data that doesn t reAuire such i##ediate attention as the #ain controller "unction. Maybe it s a record o" the "light %lans o" all the s#all %lanes that leave the air%ort. So you have a second container o" s#all %lanes, and whenever you create a %lane ob0ect you also %ut it in this second container i" it s a s#all %lane. Then so#e background %rocess %er"or#s o%erations on the ob0ects in this container during idle #o#ents. RFSURFSTIJLT+(6PTE5MTI2IU Cow the %roble# is #ore di""icult= how can you %ossibly know when to destroy the ob0ectsO :hen you re done with the ob0ect, so#e other %art o" the syste# #ight not be. This sa#e %roble# can arise in a nu#ber o" other situations, and in %rogra##ing syste#s *such as +<<, in which you #ust e&%licitly delete an ob0ect when you re done with it this can beco#e Auite co#%le&.RFSURFSTIJLT+(6PTE5MTI22U :ith Java, the garbage collector is designed to take care o" the %roble# o" releasing the #e#ory *although this doesn t include other as%ects o" cleaning u% an ob0ect,. The garbage collector !knows$ when an ob0ect is no longer in use, and it then auto#atically releases the #e#ory "or that ob0ect. This *co#bined with the "act that all ob0ects are inherited "ro# the single root class .b8ect and that you can create ob0ects only one way, on the hea%, #akes the %rocess o" %rogra##ing in Java #uch si#%ler than %rogra##ing in +<<. /ou have "ar "ewer decisions to #ake and hurdles to overco#e.RFSURFSTIJLT+(6PTE5MTIM@@U
7=
e""icient way to allocate storage "or ob0ects and to "ree that storage. +reating ob0ects on the hea% can be #uch #ore e&%ensive. 6lways inheriting "ro# a base class and #aking all "unction calls %oly#or%hic also e&acts a s#all toll. But the garbage collector is a %articular %roble# because you never Auite know when it s going to start u% or how long it will take. This #eans that there s an inconsistency in the rate o" e&ecution o" a Java %rogra#, so you can t use it in certain situations, such as when the rate o" e&ecution o" a %rogra# is uni"or#ly critical. *These are generally called real ti#e %rogra#s, although not all real ti#e %rogra##ing %roble#s are this stringent.,RFSURF STIJLT+(6PTE5MTIM@MU The designers o" the +<< language, trying to woo + %rogra##ers *and #ost success"ully, at that,, did not want to add any "eatures to the language that would i#%act the s%eed or the use o" +<< in any situation where %rogra##ers #ight otherwise choose +. This goal was reali1ed, but at the %rice o" greater co#%le&ity when %rogra##ing in +<<. Java is si#%ler than +<<, but the trade'o"" is in e""iciency and so#eti#es a%%licability. Eor a signi"icant %ortion o" %rogra##ing %roble#s, however, Java is the su%erior choice.RFSURFSTIJLT+(6PTE5MTIM@KU
71
ob0ect that is !thrown$ "ro# the site o" the error and can be !caught$ by an a%%ro%riate e&ce%tion handler designed to handle that %articular ty%e o" error. It s as i" e&ce%tion handling is a di""erent, %arallel %ath o" e&ecution that can be taken when things go wrong. 6nd because it uses a se%arate e&ecution %ath, it doesn t need to inter"ere with your nor#ally e&ecuting code. This #akes that code si#%ler to write since you aren t constantly "orced to check "or errors. In addition, a thrown e&ce%tion is unlike an error value that s returned "ro# a "unction or a "lag that s set by a "unction in order to indicate an error condition9these can be ignored. 6n e&ce%tion cannot be ignored, so it s guaranteed to be dealt with at so#e %oint. Einally, e&ce%tions %rovide a way to reliably recover "ro# a bad situation. Instead o" 0ust e&iting you are o"ten able to set things right and restore the e&ecution o" a %rogra#, which %roduces #uch #ore robust %rogra#s.RFSURFSTIJLT+(6PTE5MTIM@?U Java s e&ce%tion handling stands out a#ong %rogra##ing languages, because in Java, e&ce%tion handling was wired in "ro# the beginning and you re "orced to use it. I" you don t write your code to %ro%erly handle e&ce%tions, you ll get a co#%ile'ti#e error #essage. This guaranteed consistency #akes error handling #uch easier.RFSURF STIJLT+(6PTE5MTIM@HU It s worth noting that e&ce%tion handling isn t an ob0ect'oriented "eature, although in ob0ect'oriented languages the e&ce%tion is nor#ally re%resented with an ob0ect. E&ce%tion handling e&isted be"ore ob0ect' oriented languages.RFSURFSTIJLT+(6PTE5MTIM@3U
Multithreading
6 "unda#ental conce%t in co#%uter %rogra##ing is the idea o" handling #ore than one task at a ti#e. Many %rogra##ing %roble#s reAuire that the %rogra# be able to sto% what it s doing, deal with so#e other %roble#, and then return to the #ain %rocess. The solution has been a%%roached in #any ways. Initially, %rogra##ers with low'level knowledge o" the #achine wrote interru%t service routines and the sus%ension o" the #ain %rocess was initiated through a hardware interru%t. 6lthough this worked well, it was di""icult and non%ortable, so
72
it #ade #oving a %rogra# to a new ty%e o" #achine slow and e&%ensive. RFSURFSTIJLT+(6PTE5MTIM@GU So#eti#es interru%ts are necessary "or handling ti#e'critical tasks, but there s a large class o" %roble#s in which you re si#%ly trying to %artition the %roble# into se%arately running %ieces so that the whole %rogra# can be #ore res%onsive. :ithin a %rogra#, these se%arately running %ieces are called threads, and the general conce%t is called multithreading' 6 co##on e&a#%le o" #ultithreading is the user inter"ace. By using threads, a user can %ress a button and get a Auick res%onse rather than being "orced to wait until the %rogra# "inishes its current task.RFSURF STIJLT+(6PTE5MTIM@IU )rdinarily, threads are 0ust a way to allocate the ti#e o" a single %rocessor. But i" the o%erating syste# su%%orts #ulti%le %rocessors, each thread can be assigned to a di""erent %rocessor and they can truly run in %arallel. )ne o" the convenient "eatures o" #ultithreading at the language level is that the %rogra##er doesn t need to worry about whether there are #any %rocessors or 0ust one. The %rogra# is logically divided into threads and i" the #achine has #ore than one %rocessor then the %rogra# runs "aster, without any s%ecial ad0ust#ents.RFSURF STIJLT+(6PTE5MTIM@2U 6ll this #akes threading sound %retty si#%le. There is a catch= shared resources. I" you have #ore than one thread running that s e&%ecting to access the sa#e resource you have a %roble#. Eor e&a#%le, two %rocesses can t si#ultaneously send in"or#ation to a %rinter. To solve the %roble#, resources that can be shared, such as the %rinter, #ust be locked while they are being used. So a thread locks a resource, co#%letes its task, and then releases the lock so that so#eone else can use the resource.RFSURF STIJLT+(6PTE5MTIMM@U Java s threading is built into the language, which #akes a co#%licated sub0ect #uch si#%ler. The threading is su%%orted on an ob0ect level, so one thread o" e&ecution is re%resented by one ob0ect. Java also %rovides li#ited resource locking. It can lock the #e#ory o" any ob0ect *which is, a"ter all, one kind o" shared resource, so that only one thread can use it at a ti#e. This is acco#%lished with the synchroni7e' keyword. )ther ty%es o" resources #ust be locked e&%licitly by the %rogra##er, ty%ically
73
by creating an ob0ect to re%resent the lock that all threads #ust check be"ore accessing that resource.RFSURFSTIJLT+(6PTE5MTIMMMU
ersistence
:hen you create an ob0ect, it e&ists "or as long as you need it, but under no circu#stances does it e&ist when the %rogra# ter#inates. :hile this #akes sense at "irst, there are situations in which it would be incredibly use"ul i" an ob0ect could e&ist and hold its in"or#ation even while the %rogra# wasn t running. Then the ne&t ti#e you started the %rogra#, the ob0ect would be there and it would have the sa#e in"or#ation it had the %revious ti#e the %rogra# was running. )" course, you can get a si#ilar e""ect by writing the in"or#ation to a "ile or to a database, but in the s%irit o" #aking everything an ob0ect it would be Auite convenient to be able to declare an ob0ect %ersistent and have all the details taken care o" "or you. RFSURFSTIJLT+(6PTE5MTIMMKU Java %rovides su%%ort "or !lightweight %ersistence,$ which #eans that you can easily store ob0ects on disk and later retrieve the#. The reason it s !lightweight$ is that you re still "orced to #ake e&%licit calls to do the storage and retrieval. In addition, JavaS%aces *described in +ha%ter MH, %rovide "or a kind o" %ersistent storage o" ob0ects. In so#e "uture release #ore co#%lete su%%ort "or %ersistence #ight a%%ear.RFSURF STIJLT+(6PTE5MTIMMLU
74
ClientD1erver com.uting
The %ri#ary idea o" a clientFserver syste# is that you have a central re%ository o" in"or#ation9so#e kind o" data, o"ten in a database9that you want to distribute on de#and to so#e set o" %eo%le or #achines. 6 key to the clientFserver conce%t is that the re%ository o" in"or#ation is centrally located so that it can be changed and so that those changes will %ro%agate out to the in"or#ation consu#ers. Taken together, the in"or#ation re%ository, the so"tware that distributes the in"or#ation, and the #achine*s, where the in"or#ation and so"tware reside is called the server. The so"tware that resides on the re#ote #achine, co##unicates with the server, "etches the in"or#ation, %rocesses it, and then dis%lays it on the re#ote #achine is called the client'RFSURF STIJLT+(6PTE5MTIMM3U The basic conce%t o" clientFserver co#%uting, then, is not so co#%licated. The %roble#s arise because you have a single server trying to serve #any clients at once. 8enerally, a database #anage#ent syste# is involved so the designer !balances$ the layout o" data into tables "or o%ti#al use. In addition, syste#s o"ten allow a client to insert new in"or#ation into a server. This #eans you #ust ensure that one client s new data doesn t walk over another client s new data, or that data isn t lost in the %rocess o" adding it to the database. *This is called transaction %rocessing., 6s client so"tware changes, it #ust be built, debugged, and installed on the client #achines, which turns out to be #ore co#%licated and e&%ensive than you #ight think. It s es%ecially %roble#atic to su%%ort #ulti%le ty%es o" co#%uters and o%erating syste#s. Einally, there s the all'i#%ortant %er"or#ance issue= you #ight have hundreds o" clients #aking reAuests o" your server at any one ti#e, and so any s#all delay is crucial. To
75
#ini#i1e latency, %rogra##ers work hard to o""load %rocessing tasks, o"ten to the client #achine, but so#eti#es to other #achines at the server site, using so'called middle,are' *Middleware is also used to i#%rove #aintainability.,RFSURFSTIJLT+(6PTE5MTIMMGU The si#%le idea o" distributing in"or#ation to %eo%le has so #any layers o" co#%le&ity in i#%le#enting it that the whole %roble# can see# ho%elessly enig#atic. 6nd yet it s crucial= clientFserver co#%uting accounts "or roughly hal" o" all %rogra##ing activities. It s res%onsible "or everything "ro# taking orders and credit'card transactions to the distribution o" any kind o" data9stock #arket, scienti"ic, govern#ent, you na#e it. :hat we ve co#e u% with in the %ast is individual solutions to individual %roble#s, inventing a new solution each ti#e. These were hard to create and hard to use, and the user had to learn a new inter"ace "or each one. The entire clientFserver %roble# needs to be solved in a big way.RFSURFSTIJLT+(6PTE5MTIMMIU
77
by the de#ands %laced on the#. They weren t %articularly interactive, and tended to clog u% both the server and the Internet because any ti#e you needed to do so#ething that reAuired %rogra##ing you had to send in"or#ation back to the server to be %rocessed. It could take #any seconds or #inutes to "ind out you had #iss%elled so#ething in your reAuest. Since the browser was 0ust a viewer it couldn t %er"or# even the si#%lest co#%uting tasks. *)n the other hand, it was sa"e, since it couldn t e&ecute any %rogra#s on your local #achine that #ight contain bugs or viruses.,RFSURFSTIJLT+(6PTE5MTIMKMU To solve this %roble#, di""erent a%%roaches have been taken. To begin with, gra%hics standards have been enhanced to allow better ani#ation and video within browsers. The re#ainder o" the %roble# can be solved only by incor%orating the ability to run %rogra#s on the client end, under the browser. This is called client'side %rogra##ing.RFSURF STIJLT+(6PTE5MTIMKKU
Client@side .rogramming
The :eb s initial server'browser design %rovided "or interactive content, but the interactivity was co#%letely %rovided by the server. The server %roduced static %ages "or the client browser, which would si#%ly inter%ret and dis%lay the#. Basic (TMD contains si#%le #echanis#s "or data gathering= te&t'entry bo&es, check bo&es, radio bo&es, lists and dro%' down lists, as well as a button that can only be %rogra##ed to reset the data on the "or# or !sub#it$ the data on the "or# back to the server. This sub#ission %asses through the +o##on 8ateway Inter"ace *+8I, %rovided on all :eb servers. The te&t within the sub#ission tells +8I what to do with it. The #ost co##on action is to run a %rogra# located on the server in a directory that s ty%ically called !cgi'bin.$ *I" you watch the address window at the to% o" your browser when you %ush a button on a :eb %age, you can so#eti#es see !cgi'bin$ within all the gobbledygook there., These %rogra#s can be written in #ost languages. Perl is a co##on choice because it is designed "or te&t #ani%ulation and is inter%reted, so it can be installed on any server regardless o" %rocessor or o%erating syste#.RFSURFSTIJLT+(6PTE5MTIMKLU Many %ower"ul :eb sites today are built strictly on +8I, and you can in "act do nearly anything with it. (owever, :eb sites built on +8I
78
%rogra#s can ra%idly beco#e overly co#%licated to #aintain, and there is also the %roble# o" res%onse ti#e. The res%onse o" a +8I %rogra# de%ends on how #uch data #ust be sent, as well as the load on both the server and the Internet. *)n to% o" this, starting a +8I %rogra# tends to be slow., The initial designers o" the :eb did not "oresee how ra%idly this bandwidth would be e&hausted "or the kinds o" a%%lications %eo%le develo%ed. Eor e&a#%le, any sort o" dyna#ic gra%hing is nearly i#%ossible to %er"or# with consistency because a 8IE "ile #ust be created and #oved "ro# the server to the client "or each version o" the gra%h. 6nd you ve no doubt had direct e&%erience with so#ething as si#%le as validating the data on an in%ut "or#. /ou %ress the sub#it button on a %age; the data is shi%%ed back to the server; the server starts a +8I %rogra# that discovers an error, "or#ats an (TMD %age in"or#ing you o" the error, and then sends the %age back to you; you #ust then back u% a %age and try again. Cot only is this slow, it s inelegant.RFSURF STIJLT+(6PTE5MTIMK?U The solution is client'side %rogra##ing. Most #achines that run :eb browsers are %ower"ul engines ca%able o" doing vast work, and with the original static (TMD a%%roach they are sitting there, 0ust idly waiting "or the server to dish u% the ne&t %age. +lient'side %rogra##ing #eans that the :eb browser is harnessed to do whatever work it can, and the result "or the user is a #uch s%eedier and #ore interactive e&%erience at your :eb site.RFSURFSTIJLT+(6PTE5MTIMKHU The %roble# with discussions o" client'side %rogra##ing is that they aren t very di""erent "ro# discussions o" %rogra##ing in general. The %ara#eters are al#ost the sa#e, but the %lat"or# is di""erent= a :eb browser is like a li#ited o%erating syste#. In the end, you #ust still %rogra#, and this accounts "or the di11ying array o" %roble#s and solutions %roduced by client'side %rogra##ing. The rest o" this section %rovides an overview o" the issues and a%%roaches in client'side %rogra##ing.RFSURFSTIJLT+(6PTE5MTIMK3U
lug@ins
)ne o" the #ost signi"icant ste%s "orward in client'side %rogra##ing is the develo%#ent o" the %lug'in. This is a way "or a %rogra##er to add new "unctionality to the browser by downloading a %iece o" code that
7:
%lugs itsel" into the a%%ro%riate s%ot in the browser. It tells the browser !"ro# now on you can %er"or# this new activity.$ */ou need to download the %lug'in only once., So#e "ast and %ower"ul behavior is added to browsers via %lug'ins, but writing a %lug'in is not a trivial task, and isn t so#ething you d want to do as %art o" the %rocess o" building a %articular site. The value o" the %lug'in "or client'side %rogra##ing is that it allows an e&%ert %rogra##er to develo% a new language and add that language to a browser without the %er#ission o" the browser #anu"acturer. Thus, %lug'ins %rovide a !back door$ that allows the creation o" new client'side %rogra##ing languages *although not all languages are i#%le#ented as %lug'ins,.RFSURFSTIJLT+(6PTE5MTIMKGU
1cri.ting languages
Plug'ins resulted in an e&%losion o" scri%ting languages. :ith a scri%ting language you e#bed the source code "or your client'side %rogra# directly into the (TMD %age, and the %lug'in that inter%rets that language is auto#atically activated while the (TMD %age is being dis%layed. Scri%ting languages tend to be reasonably easy to understand and, because they are si#%ly te&t that is %art o" an (TMD %age, they load very Auickly as %art o" the single server hit reAuired to %rocure that %age. The trade'o"" is that your code is e&%osed "or everyone to see *and steal,. 8enerally, however, you aren t doing a#a1ingly so%histicated things with scri%ting languages so this is not too #uch o" a hardshi%.RFSURF STIJLT+(6PTE5MTIMKIU This %oints out that the scri%ting languages used inside :eb browsers are really intended to solve s%eci"ic ty%es o" %roble#s, %ri#arily the creation o" richer and #ore interactive gra%hical user inter"aces *84Is,. (owever, a scri%ting language #ight solve I@ %ercent o" the %roble#s encountered in client'side %rogra##ing. /our %roble#s #ight very well "it co#%letely within that I@ %ercent, and since scri%ting languages can allow easier and "aster develo%#ent, you should %robably consider a scri%ting language be"ore looking at a #ore involved solution such as Java or 6ctiveZ %rogra##ing.RFSURFSTIJLT+(6PTE5MTIMK2U The #ost co##only discussed browser scri%ting languages are JavaScri%t *which has nothing to do with Java; it s na#ed that way 0ust to grab so#e o" Java s #arketing #o#entu#,, VBScri%t *which looks like
7;
Visual Basic,, and TclFTk, which co#es "ro# the %o%ular cross'%lat"or# 84I'building language. There are others out there, and no doubt #ore in develo%#ent.RFSURFSTIJLT+(6PTE5MTIML@U JavaScri%t is %robably the #ost co##only su%%orted. It co#es built into both Cetsca%e Cavigator and the Microso"t Internet E&%lorer *IE,. In addition, there are %robably #ore JavaScri%t books available than there are "or the other browser languages, and so#e tools auto#atically create %ages using JavaScri%t. (owever, i" you re already "luent in Visual Basic or TclFTk, you ll be #ore %roductive using those scri%ting languages rather than learning a new one. */ou ll have your hands "ull dealing with the :eb issues already., RFSURFSTIJLT+(6PTE5MTIMLMU
"ava
I" a scri%ting language can solve I@ %ercent o" the client'side %rogra##ing %roble#s, what about the other K@ %ercent9the !really hard stu""O$ The #ost %o%ular solution today is Java. Cot only is it a %ower"ul %rogra##ing language built to be secure, cross'%lat"or#, and international, but Java is being continually e&tended to %rovide language "eatures and libraries that elegantly handle %roble#s that are di""icult in traditional %rogra##ing languages, such as #ultithreading, database access, network %rogra##ing, and distributed co#%uting. Java allows client'side %rogra##ing via the a let.RFSURF STIJLT+(6PTE5MTIMLKU 6n a%%let is a #ini'%rogra# that will run only under a :eb browser. The a%%let is downloaded auto#atically as %art o" a :eb %age *0ust as, "or e&a#%le, a gra%hic is auto#atically downloaded,. :hen the a%%let is activated it e&ecutes a %rogra#. This is %art o" its beauty9it %rovides you with a way to auto#atically distribute the client so"tware "ro# the server at the ti#e the user needs the client so"tware, and no sooner. The user gets the latest version o" the client so"tware without "ail and without di""icult reinstallation. Because o" the way Java is designed, the %rogra##er needs to create only a single %rogra#, and that %rogra# auto#atically works with all co#%uters that have browsers with built'in Java inter%reters. *This sa"ely includes the vast #a0ority o" #achines., Since Java is a "ull'"ledged %rogra##ing language, you can do as #uch work as %ossible on the client be"ore and a"ter #aking reAuests o" the
8=
server. Eor e&a#%le, you won t need to send a reAuest "or# across the Internet to discover that you ve gotten a date or so#e other %ara#eter wrong, and your client co#%uter can Auickly do the work o" %lotting data instead o" waiting "or the server to #ake a %lot and shi% a gra%hic i#age back to you. Cot only do you get the i##ediate win o" s%eed and res%onsiveness, but the general network tra""ic and load on servers can be reduced, %reventing the entire Internet "ro# slowing down.RFSURF STIJLT+(6PTE5MTIMLLU )ne advantage a Java a%%let has over a scri%ted %rogra# is that it s in co#%iled "or#, so the source code isn t available to the client. )n the other hand, a Java a%%let can be deco#%iled without too #uch trouble, but hiding your code is o"ten not an i#%ortant issue. Two other "actors can be i#%ortant. 6s you will see later in this book, a co#%iled Java a%%let can co#%rise #any #odules and take #ulti%le server !hits$ *accesses, to download. *In Java M.M and higher this is #ini#i1ed by Java archives, called J65 "iles, that allow all the reAuired #odules to be %ackaged together and co#%ressed "or a single download., 6 scri%ted %rogra# will 0ust be integrated into the :eb %age as %art o" its te&t *and will generally be s#aller and reduce server hits,. This could be i#%ortant to the res%onsiveness o" your :eb site. 6nother "actor is the all' i#%ortant learning curve. 5egardless o" what you ve heard, Java is not a trivial language to learn. I" you re a Visual Basic %rogra##er, #oving to VBScri%t will be your "astest solution, and since it will %robably solve #ost ty%ical clientFserver %roble#s you #ight be hard %ressed to 0usti"y learning Java. I" you re e&%erienced with a scri%ting language you will certainly bene"it "ro# looking at JavaScri%t or VBScri%t be"ore co##itting to Java, since they #ight "it your needs handily and you ll be #ore %roductive sooner.RFSURFSTIJLT+(6PTE5MTIML?U
ActiveE
To so#e degree, the co#%etitor to Java is Microso"t s 6ctiveZ, although it takes a co#%letely di""erent a%%roach. 6ctiveZ was originally a :indows' only solution, although it is now being develo%ed via an inde%endent consortiu# to beco#e cross'%lat"or#. E""ectively, 6ctiveZ says !i" your %rogra# connects to its environ#ent 0ust so, it can be dro%%ed into a :eb %age and run under a browser that su%%orts 6ctiveZ.$ *IE directly su%%orts 6ctiveZ and Cetsca%e does so using a %lug'in., Thus, 6ctiveZ
81
does not constrain you to a %articular language. I", "or e&a#%le, you re already an e&%erienced :indows %rogra##er using a language such as +<<, Visual Basic, or Borland s 7el%hi, you can create 6ctiveZ co#%onents with al#ost no changes to your %rogra##ing knowledge. 6ctiveZ also %rovides a %ath "or the use o" legacy code in your :eb %ages. RFSURFSTIJLT+(6PTE5MTIMLHU
1ecurit:
6uto#atically downloading and running %rogra#s across the Internet can sound like a virus'builder s drea#. 6ctiveZ es%ecially brings u% the thorny issue o" security in client'side %rogra##ing. I" you click on a :eb site, you #ight auto#atically download any nu#ber o" things along with the (TMD %age= 8IE "iles, scri%t code, co#%iled Java code, and 6ctiveZ co#%onents. So#e o" these are benign; 8IE "iles can t do any har#, and scri%ting languages are generally li#ited in what they can do. Java was also designed to run its a%%lets within a !sandbo&$ o" sa"ety, which %revents it "ro# writing to disk or accessing #e#ory outside the sandbo&. RFSURFSTIJLT+(6PTE5MTIML3U 6ctiveZ is at the o%%osite end o" the s%ectru#. Progra##ing with 6ctiveZ is like %rogra##ing :indows9you can do anything you want. So i" you click on a %age that downloads an 6ctiveZ co#%onent, that co#%onent #ight cause da#age to the "iles on your disk. )" course, %rogra#s that you load onto your co#%uter that are not restricted to running inside a :eb browser can do the sa#e thing. Viruses downloaded "ro# Bulletin'Board Syste#s *BBSs, have long been a %roble#, but the s%eed o" the Internet a#%li"ies the di""iculty.RFSURF STIJLT+(6PTE5MTIMLGU The solution see#s to be !digital signatures,$ whereby code is veri"ied to show who the author is. This is based on the idea that a virus works because its creator can be anony#ous, so i" you re#ove the anony#ity individuals will be "orced to be res%onsible "or their actions. This see#s like a good %lan because it allows %rogra#s to be #uch #ore "unctional, and I sus%ect it will eli#inate #alicious #ischie". I", however, a %rogra# has an unintentional destructive bug it will still cause %roble#s.RFSURF STIJLT+(6PTE5MTIMLIU
82
The Java a%%roach is to %revent these %roble#s "ro# occurring, via the sandbo&. The Java inter%reter that lives on your local :eb browser e&a#ines the a%%let "or any untoward instructions as the a%%let is being loaded. In %articular, the a%%let cannot write "iles to disk or erase "iles *one o" the #ainstays o" viruses,. 6%%lets are generally considered to be sa"e, and since this is essential "or reliable clientFserver syste#s, any bugs in the Java language that allow viruses are ra%idly re%aired. *It s worth noting that the browser so"tware actually en"orces these security restrictions, and so#e browsers allow you to select di""erent security levels to %rovide varying degrees o" access to your syste#.,RFSURF STIJLT+(6PTE5MTIML2U /ou #ight be ske%tical o" this rather draconian restriction against writing "iles to your local disk. Eor e&a#%le, you #ay want to build a local database or save data "or later use o""line. The initial vision see#ed to be that eventually everyone would get online to do anything i#%ortant, but that was soon seen to be i#%ractical *although low'cost !Internet a%%liances$ #ight so#eday satis"y the needs o" a signi"icant seg#ent o" users,. The solution is the !signed a%%let$ that uses %ublic'key encry%tion to veri"y that an a%%let does indeed co#e "ro# where it clai#s it does. 6 signed a%%let can still trash your disk, but the theory is that since you can now hold the a%%let creator accountable they won t do vicious things. Java %rovides a "ra#ework "or digital signatures so that you will eventually be able to allow an a%%let to ste% outside the sandbo& i" necessary.RFSURFSTIJLT+(6PTE5MTIM?@U 7igital signatures have #issed an i#%ortant issue, which is the s%eed that %eo%le #ove around on the Internet. I" you download a buggy %rogra# and it does so#ething untoward, how long will it be be"ore you discover the da#ageO It could be days or even weeks. By then, how will you track down the %rogra# that s done itO 6nd what good will it do you at that %ointORFSURFSTIJLT+(6PTE5MTIM?MU
83
%roble# o" #ulti%le ty%es o" client co#%uters, as well as the di""iculty o" installing new client so"tware, both o" which are handily solved with :eb browsers and client'side %rogra##ing. :hen :eb technology is used "or an in"or#ation network that is restricted to a %articular co#%any, it is re"erred to as an intranet. Intranets %rovide #uch greater security than the Internet, since you can %hysically control access to the servers within your co#%any. In ter#s o" training, it see#s that once %eo%le understand the general conce%t o" a browser it s #uch easier "or the# to deal with di""erences in the way %ages and a%%lets look, so the learning curve "or new kinds o" syste#s see#s to be reduced.RFSURF STIJLT+(6PTE5MTIM?KU The security %roble# brings us to one o" the divisions that see#s to be auto#atically "or#ing in the world o" client'side %rogra##ing. I" your %rogra# is running on the Internet, you don t know what %lat"or# it will be working under, and you want to be e&tra care"ul that you don t disse#inate buggy code. /ou need so#ething cross'%lat"or# and secure, like a scri%ting language or Java. RFSURFSTIJLT+(6PTE5MTIM?LU I" you re running on an intranet, you #ight have a di""erent set o" constraints. It s not unco##on that your #achines could all be IntelF :indows %lat"or#s. )n an intranet, you re res%onsible "or the Auality o" your own code and can re%air bugs when they re discovered. In addition, you #ight already have a body o" legacy code that you ve been using in a #ore traditional clientFserver a%%roach, whereby you #ust %hysically install client %rogra#s every ti#e you do an u%grade. The ti#e wasted in installing u%grades is the #ost co#%elling reason to #ove to browsers, because u%grades are invisible and auto#atic. I" you are involved in such an intranet, the #ost sensible a%%roach to take is the shortest %ath that allows you to use your e&isting code base, rather than trying to recode your %rogra#s in a new language.RFSURFSTIJLT+(6PTE5MTIM??U :hen "aced with this bewildering array o" solutions to the client'side %rogra##ing %roble#, the best %lan o" attack is a cost'bene"it analysis. +onsider the constraints o" your %roble# and what would be the shortest %ath to your solution. Since client'side %rogra##ing is still %rogra##ing, it s always a good idea to take the "astest develo%#ent a%%roach "or your %articular situation. This is an aggressive stance to
84
%re%are "or inevitable encounters with the %roble#s o" %rogra# develo%#ent.RFSURFSTIJLT+(6PTE5MTIM?HU
1erver@side .rogramming
This whole discussion has ignored the issue o" server'side %rogra##ing. :hat ha%%ens when you #ake a reAuest o" a serverO Most o" the ti#e the reAuest is si#%ly !send #e this "ile.$ /our browser then inter%rets the "ile in so#e a%%ro%riate "ashion= as an (TMD %age, a gra%hic i#age, a Java a%%let, a scri%t %rogra#, etc. 6 #ore co#%licated reAuest to a server generally involves a database transaction. 6 co##on scenario involves a reAuest "or a co#%le& database search, which the server then "or#ats into an (TMD %age and sends to you as the result. *)" course, i" the client has #ore intelligence via Java or a scri%ting language, the raw data can be sent and "or#atted at the client end, which will be "aster and less load on the server., )r you #ight want to register your na#e in a database when you 0oin a grou% or %lace an order, which will involve changes to that database. These database reAuests #ust be %rocessed via so#e code on the server side, which is generally re"erred to as server'side %rogra##ing. Traditionally, server'side %rogra##ing has been %er"or#ed using Perl and +8I scri%ts, but #ore so%histicated syste#s have been a%%earing. These include Java'based :eb servers that allow you to %er"or# all your server'side %rogra##ing in Java by writing what are called servlets. Servlets and their o""s%ring, JSPs, are two o" the #ost co#%elling reasons that co#%anies who develo% :eb sites are #oving to Java, es%ecially because they eli#inate the %roble#s o" dealing with di""erently abled browsers. RFSURFSTIJLT+(6PTE5MTIM?3U
85
but also its %rogra##ability. 6s you ll see throughout this book, Java has #any "eatures that allow you to create robust %rogra#s in a shorter %eriod than with %revious %rogra##ing languages.RFSURF STIJLT+(6PTE5MTIM?GU Be aware that this is a #i&ed blessing. /ou %ay "or the i#%rove#ents through slower e&ecution s%eed *although there is signi"icant work going on in this area9J7> M.L, in %articular, introduces the so'called !hots%ot$ %er"or#ance i#%rove#ents,. Dike any language, Java has built'in li#itations that #ight #ake it ina%%ro%riate to solve certain ty%es o" %rogra##ing %roble#s. Java is a ra%idly evolving language, however, and as each new release co#es out it beco#es #ore and #ore attractive "or solving larger sets o" %roble#s.RFSURFSTIJLT+(6PTE5MTIM?IU
87
than you could handle using si#%le #ethodologies with %rocedural languages.RFSURFSTIJLT+(6PTE5MTIMHMU It s also i#%ortant to reali1e that the ter# !#ethodology$ is o"ten too grand and %ro#ises too #uch. :hatever you do now when you design and write a %rogra# is a #ethod ology. It #ay be your own #ethod ology, and you #ay not be conscious o" doing it, but it is a %rocess you go through as you create. I" it is an e""ective %rocess, it #ay need only a s#all tune'u% to work with Java. I" you are not satis"ied with your %roductivity and the way your %rogra#s turn out, you #ay want to consider ado%ting a "or#al #ethod ology, or choosing %ieces "ro# a#ong the #any "or#al #ethod ologies.F/GHF/GTIJ3IC."PTE-1II152H :hile you re going through the develo%#ent %rocess, the #ost i#%ortant issue is this= 7on t get lost. It s easy to do. Most o" the analysis and design #ethod oligies are intended to solve the largest o" %roble#s. 5e#e#ber that #ost %ro0ects don t "it into that category, so you can usually have success"ul analysis and design with a relatively s#all subset o" what a #ethod ology reco##ends @. But so#e sort o" %rocess, no #atter how li#ited, will generally get you on your way in a #uch better "ashion than si#%ly beginning to code.RFSURFSTIJLT+(6PTE5MTIMHLU It s also easy to get stuck, to "all into !analysis %aralysis,$ where you "eel like you can t #ove "orward because you haven t nailed down every little detail at the current stage. 5e#e#ber, no #atter how #uch analysis you do, there are so#e things about a syste# that won t reveal the#selves until design ti#e, and #ore things that won t reveal the#selves until you re coding, or not even until a %rogra# is u% and running. Because o" this, it s crucial to #ove "airly Auickly through analysis and design, and to i#%le#ent a test o" the %ro%osed syste#.RFSURF STIJLT+(6PTE5MTIMH?U This %oint is worth e#%hasi1ing. Because o" the history we ve had with %rocedural languages, it is co##endable that a tea# will want to %roceed care"ully and understand every #inute detail be"ore #oving to design and i#%le#entation. +ertainly, when creating a 7atabase Manage#ent Syste# *D4/*,, it %ays to understand a custo#er s needs thoroughly.
@ 6n e&cellent e&a#%le o" this is <M( %istilled, Knd edition, by Martin Eowler *6ddison' :esley K@@@,, which reduces the so#eti#es'overwhel#ing 4MD %rocess to a #anageable subset.
88
But a 7BMS is in a class o" %roble#s that is very well'%osed and well' understood; in #any such %rogra#s, the database structure is the %roble# to be tackled. The class o" %rogra##ing %roble# discussed in this cha%ter is o" the !wild'card$ *#y ter#, variety, in which the solution isn t si#%ly re'"or#ing a well'known solution, but instead involves one or #ore !wild'card "actors$9ele#ents "or which there is no well'understood %revious solution, and "or which research is necessary @. 6tte#%ting to thoroughly analy1e a wild'card %roble# be"ore #oving into design and i#%le#entation results in analysis %aralysis because you don t have enough in"or#ation to solve this kind o" %roble# during the analysis %hase. Solving such a %roble# reAuires iteration through the whole cycle, and that reAuires risk'taking behavior *which #akes sense, because you re trying to do so#ething new and the %otential rewards are higher,. It #ay see# like the risk is co#%ounded by !rushing$ into a %reli#inary i#%le#entation, but it can instead reduce the risk in a wild'card %ro0ect because you re "inding out early whether a %articular a%%roach to the %roble# is viable. Product develo%#ent is risk #anage#ent.RFSURF STIJLT+(6PTE5MTIMHHU It s o"ten %ro%osed that you !build one to throw away.$ :ith ))P, you #ay still throw art o" it away, but because code is enca%sulated into classes, during the "irst %ass you will inevitably %roduce so#e use"ul class designs and develo% so#e worthwhile ideas about the syste# design that do not need to be thrown away. Thus, the "irst ra%id %ass at a %roble# not only %roduces critical in"or#ation "or the ne&t analysis, design, and i#%le#entation %ass, it also creates a code "oundation.RFSURF STIJLT+(6PTE5MTIMH3U That said, i" you re looking at a #ethodology that contains tre#endous detail and suggests #any ste%s and docu#ents, it s still di""icult to know when to sto%. >ee% in #ind what you re trying to discover=RFSURF STIJLT+(6PTE5MTIMHGU
(!)
:hat are the ob0ectsO *(ow do you %artition your %ro0ect into its co#%onent %artsO,
@ My rule o" thu#b "or esti#ating such %ro0ects= I" there s #ore than one wild card, don t even try to %lan how long it s going to take or how #uch it will cost until you ve created a working %rototy%e. There are too #any degrees o" "reedo#.
8:
(*)
:hat are their inter"acesO *:hat #essages do you need to send to each ob0ectO,
I" you co#e u% with nothing #ore than the ob0ects and their inter"aces, then you can write a %rogra#. Eor various reasons you #ight need #ore descri%tions and docu#ents than this, but you can t get away with any less.RFSURFSTIJLT+(6PTE5MTIMHIU The %rocess can be undertaken in "ive %hases, and a Phase @ that is 0ust the initial co##it#ent to using so#e kind o" structure.RFSURF STIJLT+(6PTE5MTIMH2U
8;
start coding, you still so#ehow go through the subseAuent %hases while asking and answering certain Auestions.RFSURF STIJLT+(6PTE5MTIM3KU
:=
or syste#,. The syste# s%eci"ication is a to%'level e&%loration into the %roble# and in so#e sense a discovery o" whether it can be done and how long it will take. Since both o" these will reAuire consensus a#ong %eo%le *and because they will usually change over ti#e,, I think it s best to kee% the# as bare as %ossible9ideally, to lists and basic diagra#s9to save ti#e. /ou #ight have other constraints that reAuire you to e&%and the# into bigger docu#ents, but by kee%ing the initial docu#ent s#all and concise, it can be created in a "ew sessions o" grou% brainstor#ing with a leader who dyna#ically creates the descri%tion. This not only solicits in%ut "ro# everyone, it also "osters initial buy'in and agree#ent by everyone on the tea#. Perha%s #ost i#%ortantly, it can kick o"" a %ro0ect with a lot o" enthusias#.RFSURFSTIJLT+(6PTE5MTIM3HU It s necessary to stay "ocused on the heart o" what you re trying to acco#%lish in this %hase= deter#ine what the syste# is su%%osed to do. The #ost valuable tool "or this is a collection o" what are called !use cases. $ 4se cases identi"y key "eatures in the syste# that will reveal so#e o" the "unda#ental classes you ll be using. These are essentially descri%tive answers to Auestions like @=RFSURFSTIJLT+(6PTE5MTIM33U
!:ho will use this syste#O$ !:hat can those actors do with the syste#O$ !(ow does this actor do that with this syste#O$ !(ow else #ight this work i" so#eone else were doing this, or i" the sa#e actor had a di""erent ob0ectiveO$ *to reveal variations, !:hat %roble#s #ight ha%%en while doing this with the syste#O $ *to reveal e&ce%tions,
I" you are designing an auto'teller, "or e&a#%le, the use case "or a %articular as%ect o" the "unctionality o" the syste# is able to describe what the auto'teller does in every %ossible situation. Each o" these !situations$ is re"erred to as a scenario, and a use case can be considered a collection o" scenarios. /ou can think o" a scenario as a Auestion that starts with= !:hat does the syste# do i"-O$ Eor e&a#%le, !:hat does the auto'teller do i" a custo#er has 0ust de%osited a check within the last K? hours, and there s not enough in the account without the check having cleared to %rovide a desired withdrawalO$ RFSURFSTIJLT+(6PTE5MTIM3GU
@ Thanks "or hel% "ro# Ja#es ( Jarrett.
:1
4se case diagra#s are intentionally si#%le to %revent you "ro# getting bogged down in syste# i#%le#entation details %re#aturely=
;ank
Make De.osit Make Withdrawal
Cses
#eller
Customer
A#M
Each stick %erson re%resents an !actor,$ which is ty%ically a hu#an or so#e other kind o" "ree agent. *These can even be other co#%uter syste#s, as is the case with !6TM.$, The bo& re%resents the boundary o" your syste#. The elli%ses re%resent the use cases, which are descri%tions o" valuable work that can be %er"or#ed with the syste#. The lines between the actors and the use cases re%resent the interactions.RFSURF STIJLT+(6PTE5MTIM3IU It doesn t #atter how the syste# is actually i#%le#ented, as long as it looks like this to the user.RFSURFSTIJLT+(6PTE5MTIM32U 6 use case does not need to be terribly co#%le&, even i" the underlying syste# is co#%le&. It is only intended to show the syste# as it a%%ears to the user. Eor e&a#%le=RFSURFSTIJLT+(6PTE5MTIMG@U
'reenhouse
Maintain 'rowing #em.erature
'ardener
:2
The use cases %roduce the reAuire#ents s%eci"ications by deter#ining all the interactions that the user #ay have with the syste#. /ou try to discover a "ull set o" use cases "or your syste#, and once you ve done that you have the core o" what the syste# is su%%osed to do. The nice thing about "ocusing on use cases is that they always bring you back to the essentials and kee% you "ro# dri"ting o"" into issues that aren t critical "or getting the 0ob done. That is, i" you have a "ull set o" use cases, you can describe your syste# and #ove on to the ne&t %hase. /ou %robably won t get it all "igured out %er"ectly on the "irst try, but that s )>. Everything will reveal itsel" in ti#e, and i" you de#and a %er"ect syste# s%eci"ication at this %oint you ll get stuck.RFSURFSTIJLT+(6PTE5MTIMGMU I" you do get stuck, you can kick'start this %hase by using a rough a%%ro&i#ation tool= describe the syste# in a "ew %aragra%hs and then look "or nouns and verbs. The nouns can suggest actors, conte&t o" the use case *e.g., !lobby$,, or arti"acts #ani%ulated in the use case. Verbs can suggest interactions between actors and use cases, and s%eci"y ste%s within the use case. /ou ll also discover that nouns and verbs %roduce ob0ects and #essages during the design %hase *and note that use cases describe interactions between subsyste#s, so the !noun and verb$ techniAue can be used only as a brainstor#ing tool as it does not generate use cases, D.RFSURFSTIJLT+(6PTE5MTIMGKU The boundary between a use case and an actor can %oint out the e&istence o" a user inter"ace, but it does not de"ine such a user inter"ace. Eor a %rocess o" de"ining and creating user inter"aces, see So$t,are $or <se by Darry +onstantine and Ducy Dockwood, *6ddison':esley Dong#an, M222, or go to ,,,'9or<se'com.RFSURFSTIJLT+(6PTE5MTIMGLU 6lthough it s a black art, at this %oint so#e kind o" basic scheduling is i#%ortant. /ou now have an overview o" what you re building, so you ll %robably be able to get so#e idea o" how long it will take. 6 lot o" "actors co#e into %lay here. I" you esti#ate a long schedule then the co#%any #ight decide not to build it *and thus use their resources on so#ething #ore reasonable9that s a good thing,. )r a #anager #ight have already decided how long the %ro0ect should take and will try to in"luence your
@ More in"or#ation on use cases can be "ound in " l)ing <se Cases by Schneider N :inters *6ddison':esley M22I, and <se Case %riven Ob>ect Modeling ,ith <M( by 5osenberg *6ddison':esley M222,.
:3
esti#ate. But it s best to have an honest schedule "ro# the beginning and deal with the tough decisions early. There have been a lot o" atte#%ts to co#e u% with accurate scheduling techniAues *#uch like techniAues to %redict the stock #arket,, but %robably the best a%%roach is to rely on your e&%erience and intuition. 8et a gut "eeling "or how long it will really take, then double that and add M@ %ercent. /our gut "eeling is %robably correct; you can get so#ething working in that ti#e. The !doubling$ will turn that into so#ething decent, and the M@ %ercent will deal with the "inal %olishing and details @. (owever you want to e&%lain it, and regardless o" the #oans and #ani%ulations that ha%%en when you reveal such a schedule, it 0ust see#s to work out that way.RFSURF STIJLT+(6PTE5MTIMG?U
(+)
The na#e o" the class. It s i#%ortant that this na#e ca%ture the essence o" what the class does, so that it #akes sense at a glance. RFSURFSTIJLT+(6PTE5MTIMG3U The !res%onsibilities$ o" the class= what it should do. This can ty%ically be su##ari1ed by 0ust stating the na#es o" the #e#ber "unctions *since those na#es should be descri%tive in a good design,, but it does not %reclude other notes. I" you need to seed the %rocess, look at the %roble# "ro# a la1y %rogra##er s stand%oint= :hat ob0ects would you like to #agically a%%ear to solve your %roble#O RFSURFSTIJLT+(6PTE5MTIMGGU
(,)
@ My %ersonal take on this has changed lately. 7oubling and adding M@ %ercent will give you a reasonably accurate esti#ate *assu#ing there are not too #any wild'card "actors,, but you still have to work Auite diligently to "inish in that ti#e. I" you want ti#e to really #ake it elegant and to en0oy yoursel" in the %rocess, the correct #ulti%lier is #ore like three or "our ti#es, I believe.
:4
(-)
The !collaborations$ o" the class= what other classes does it interact withO !Interact$ is an intentionally broad ter#; it could #ean aggregation or si#%ly that so#e other ob0ect e&ists that will %er"or# services "or an ob0ect o" the class. +ollaborations should also consider the audience "or this class. Eor e&a#%le, i" you create a class Firecracker, who is going to observe it, a -hemist or a )pectatorO The "or#er will want to know what che#icals go into the construction, and the latter will res%ond to the colors and sha%es released when it e&%lodes. RFSURF STIJLT+(6PTE5MTIMGIU
/ou #ay "eel like the cards should be bigger because o" all the in"or#ation you d like to get on the#, but they are intentionally s#all, not only to kee% your classes s#all but also to kee% you "ro# getting into too #uch detail too early. I" you can t "it all you need to know about a class on a s#all card, the class is too co#%le& *either you re getting too detailed, or you should create #ore than one class,. The ideal class should be understood at a glance. The idea o" +5+ cards is to assist you in co#ing u% with a "irst cut o" the design so that you can get the big %icture and then re"ine your design.RFSURFSTIJLT+(6PTE5MTIMG2U )ne o" the great bene"its o" +5+ cards is in co##unication. It s best done real ti#e, in a grou%, without co#%uters. Each %erson takes res%onsibility "or several classes *which at "irst have no na#es or other in"or#ation,. /ou run a live si#ulation by solving one scenario at a ti#e, deciding which #essages are sent to the various ob0ects to satis"y each scenario. 6s you go through this %rocess, you discover the classes that you need along with their res%onsibilities and collaborations, and you "ill out the cards as you do this. :hen you ve #oved through all the use cases, you should have a "airly co#%lete "irst cut o" your design.RFSURF STIJLT+(6PTE5MTIMI@U Be"ore I began using +5+ cards, the #ost success"ul consulting e&%eriences I had when co#ing u% with an initial design involved standing in "ront o" a tea#9who hadn t built an ))P %ro0ect be"ore9and drawing ob0ects on a whiteboard. :e talked about how the ob0ects should co##unicate with each other, and erased so#e o" the# and re%laced the# with other ob0ects. E""ectively, I was #anaging all the !+5+ cards$ on the whiteboard. The tea# *who knew what the %ro0ect was su%%osed
:5
to do, actually created the design; they !owned$ the design rather than having it given to the#. 6ll I was doing was guiding the %rocess by asking the right Auestions, trying out the assu#%tions, and taking the "eedback "ro# the tea# to #odi"y those assu#%tions. The true beauty o" the %rocess was that the tea# learned how to do ob0ect'oriented design not by reviewing abstract e&a#%les, but by working on the one design that was #ost interesting to the# at that #o#ent= theirs.RFSURF STIJLT+(6PTE5MTIMIMU )nce you ve co#e u% with a set o" +5+ cards, you #ay want to create a #ore "or#al descri%tion o" your design using 4MD @. /ou don t need to use 4MD, but it can be hel%"ul, es%ecially i" you want to %ut u% a diagra# on the wall "or everyone to %onder, which is a good idea. 6n alternative to 4MD is a te&tual descri%tion o" the ob0ects and their inter"aces, or, de%ending on your %rogra##ing language, the code itsel" @.RFSURF STIJLT+(6PTE5MTIMIKU 4MD also %rovides an additional diagra##ing notation "or describing the dyna#ic #odel o" your syste#. This is hel%"ul in situations in which the state transitions o" a syste# or subsyste# are do#inant enough that they need their own diagra#s *such as in a control syste#,. /ou #ay also need to describe the data structures, "or syste#s or subsyste#s in which data is a do#inant "actor *such as a database,.RFSURFSTIJLT+(6PTE5MTIMILU /ou ll know you re done with Phase K when you have described the ob0ects and their inter"aces. :ell, #ost o" the#9there are usually a "ew that sli% through the cracks and don t #ake the#selves known until Phase L. But that s )>. 6ll you are concerned with is that you eventually discover all o" your ob0ects. It s nice to discover the# early in the %rocess, but ))P %rovides enough structure so that it s not so bad i" you discover the# later. In "act, the design o" an ob0ect tends to ha%%en in "ive stages, throughout the %rocess o" %rogra# develo%#ent.RFSURF STIJLT+(6PTE5MTIMI?U
@ Eor starters, I reco##end the a"ore#entioned <M( %istilled, Knd edition. @ Python *www.Python.org, is o"ten used as !e&ecutable %seudocode.$
:7
). Object discovery. This stage occurs during the initial analysis o" a
%rogra#. )b0ects #ay be discovered by looking "or e&ternal "actors and boundaries, du%lication o" ele#ents in the syste#, and the s#allest conce%tual units. So#e ob0ects are obvious i" you already have a set o" class libraries. +o##onality between classes suggesting base classes and inheritance #ay a%%ear right away, or later in the design %rocess.RFSURF STIJLT+(6PTE5MTIMI3U
:8
o"ten end u% with "eatures that are !solutions in search o" a %roble#.$ In E*treme Programming %ractice, the best answer to a "eature that is not absolutely essential to solve the %roble# at hand is !you re not going to need it.$ .. Object reuse. This is the real stress test "or a class. I" so#eone tries
to reuse it in an entirely new situation, they ll %robably discover so#e shortco#ings. 6s you change a class to ada%t to #ore new %rogra#s, the general %rinci%les o" the class will beco#e clearer, until you have a truly reusable ty%e. (owever, don t e&%ect #ost ob0ects "ro# a syste# design to be reusable9it is %er"ectly acce%table "or the bulk o" your ob0ects to be syste#'s%eci"ic. 5eusable ty%es tend to be less co##on, and they #ust solve #ore general %roble#s in order to be reusable.RFSURF STIJLT+(6PTE5MTIM2@U
(4)
Det a s%eci"ic %roble# generate a class, then let the class grow and #ature during the solution o" other %roble#s. RFSURF STIJLT+(6PTE5MTIM2KU 5e#e#ber, discovering the classes you need *and their inter"aces, is the #a0ority o" the syste# design. I" you already had those classes, this would be an easy %ro0ect. RFSURF STIJLT+(6PTE5MTIM2LU 7on t "orce yoursel" to know everything at the beginning; learn as you go. This will ha%%en anyway. RFSURF STIJLT+(6PTE5MTIM2?U Start %rogra##ing; get so#ething working so you can %rove or dis%rove your design. 7on t "ear that you ll end u% with %rocedural'style s%aghetti code9classes %artition the %roble# and hel% control anarchy and entro%y. Bad classes do not break good classes. RFSURFSTIJLT+(6PTE5MTIM2HU
(5)
(6)
!7)
::
!()
6lways kee% it si#%le. Dittle clean ob0ects with obvious utility are better than big co#%licated inter"aces. :hen decision %oints co#e u%, use an )cca# s 5a1or a%%roach= +onsider the choices and select the one that is si#%lest, because si#%le classes are al#ost always best. Start s#all and si#%le, and you can e&%and the class inter"ace when you understand it better. 6s ti#e goes on, it s di""icult to re#ove ele#ents "ro# a class. RFSURF STIJLT+(6PTE5MTIM23U
:;
(ow big is an iterationO Ideally, each iteration lasts one to three weeks *this can vary based on the i#%le#entation language,. 6t the end o" that %eriod, you have an integrated, tested syste# with #ore "unctionality than it had be"ore. But what s %articularly interesting is the basis "or the iteration= a single use case. Each use case is a %ackage o" related "unctionality that you build into the syste# all at once, during one iteration. Cot only does this give you a better idea o" what the sco%e o" a use case should be, but it also gives #ore validation to the idea o" a use case, since the conce%t isn t discarded a"ter analysis and design, but instead it is a "unda#ental unit o" develo%#ent throughout the so"tware' building %rocess. RFSURFSTIJLT+(6PTE5MTIK@MU /ou sto% iterating when you achieve target "unctionality or an e&ternal deadline arrives and the custo#er can be satis"ied with the current version. *5e#e#ber, so"tware is a subscri%tion business., Because the %rocess is iterative, you have #any o%%ortunities to shi% a %roduct rather than a single end%oint; o%en'source %ro0ects work e&clusively in an iterative, high'"eedback environ#ent, which is %recisely what #akes the# success"ul.RFSURFSTIJLT+(6PTE5MTIK@KU 6n iterative develo%#ent %rocess is valuable "or #any reasons. /ou can reveal and resolve critical risks early, the custo#ers have a#%le o%%ortunity to change their #inds, %rogra##er satis"action is higher, and the %ro0ect can be steered with #ore %recision. But an additional i#%ortant bene"it is the "eedback to the stakeholders, who can see by the current state o" the %roduct e&actly where everything lies. This #ay reduce or eli#inate the need "or #ind'nu#bing status #eetings and increase the con"idence and su%%ort "ro# the stakeholders.RFSURF STIJLT+(6PTE5MTIK@LU
hase ,: /volution
This is the %oint in the develo%#ent cycle that has traditionally been called !#aintenance,$ a catch'all ter# that can #ean everything "ro# !getting it to work the way it was really su%%osed to in the "irst %lace$ to !adding "eatures that the custo#er "orgot to #ention$ to the #ore traditional !"i&ing the bugs that show u%$ and !adding new "eatures as the need arises.$ So #any #isconce%tions have been a%%lied to the ter# !#aintenance$ that it has taken on a slightly deceiving Auality, %artly
;=
because it suggests that you ve actually built a %ristine %rogra# and all you need to do is change %arts, oil it, and kee% it "ro# rusting. Perha%s there s a better ter# to describe what s going on.RFSURF STIJLT+(6PTE5MTIK@?U I ll use the ter# evolution@. That is, !/ou won t get it right the "irst ti#e, so give yoursel" the latitude to learn and to go back and #ake changes.$ /ou #ight need to #ake a lot o" changes as you learn and understand the %roble# #ore dee%ly. The elegance you ll %roduce i" you evolve until you get it right will %ay o"", both in the short and the long ter#. Evolution is where your %rogra# goes "ro# good to great, and where those issues that you didn t really understand in the "irst %ass beco#e clear. It s also where your classes can evolve "ro# single'%ro0ect usage to reusable resources.RF SURFSTIJLT+(6PTE5MTIK@HU :hat it #eans to !get it right$ isn t 0ust that the %rogra# works according to the reAuire#ents and the use cases. It also #eans that the internal structure o" the code #akes sense to you, and "eels like it "its together well, with no awkward synta&, oversi1ed ob0ects, or ungainly e&%osed bits o" code. In addition, you #ust have so#e sense that the %rogra# structure will survive the changes that it will inevitably go through during its li"eti#e, and that those changes can be #ade easily and cleanly. This is no s#all "eat. /ou #ust not only understand what you re building, but also how the %rogra# will evolve *what I call the vector o$ change,. Eortunately, ob0ect'oriented %rogra##ing languages are %articularly ade%t at su%%orting this kind o" continuing #odi"ication9the boundaries created by the ob0ects are what tend to kee% the structure "ro# breaking down. They also allow you to #ake changes9ones that would see# drastic in a %rocedural %rogra#9without causing earthAuakes throughout your code. In "act, su%%ort "or evolution #ight be the #ost i#%ortant bene"it o" ))P.RFSURFSTIJLT+(6PTE5MTIK@3U :ith evolution, you create so#ething that at least a%%ro&i#ates what you think you re building, and then you kick the tires, co#%are it to your reAuire#ents, and see where it "alls short. Then you can go back and "i& it by redesigning and rei#%le#enting the %ortions o" the %rogra# that
@ 6t least one as%ect o" evolution is covered in Martin Eowler s book -e$actoring! im roving the design o$ e*isting code *6ddison':esley M222,, which uses Java e&a#%les e&clusively.
;1
didn t work right @. /ou #ight actually need to solve the %roble#, or an as%ect o" the %roble#, several ti#es be"ore you hit on the right solution. *6 study o" %esign Patterns is usually hel%"ul here. /ou can "ind in"or#ation in Thinking in Patterns ,ith Java, downloadable at ,,,' 0ruceEckel'com.,RFSURFSTIJLT+(6PTE5MTIK@GU Evolution also occurs when you build a syste#, see that it #atches your reAuire#ents, and then discover it wasn t actually what you wanted. :hen you see the syste# in o%eration, you "ind that you really wanted to solve a di""erent %roble#. I" you think this kind o" evolution is going to ha%%en, then you owe it to yoursel" to build your "irst version as Auickly as %ossible so you can "ind out i" it is indeed what you want.RFSURF STIJLT+(6PTE5MTIK@IU Perha%s the #ost i#%ortant thing to re#e#ber is that by de"ault9by de"inition, really9i" you #odi"y a class, its su%er' and subclasses will still "unction. /ou need not "ear #odi"ication *es%ecially i" you have a built'in set o" unit tests to veri"y the correctness o" your #odi"ications,. Modi"ication won t necessarily break the %rogra#, and any change in the outco#e will be li#ited to subclasses andFor s%eci"ic collaborators o" the class you change.RFSURFSTIJLT+(6PTE5MTIK@2U
;2
here suggests a #iddle %ath9a sliding scale. 4se an a%%roach that "its your needs *and your %ersonality,. Co #atter how #ini#al you choose to #ake it, some kind o" %lan will #ake a big i#%rove#ent in your %ro0ect as o%%osed to no %lan at all. 5e#e#ber that, by #ost esti#ates, over H@ %ercent o" %ro0ects "ail *so#e esti#ates go u% to G@ %ercent.,. RFSURF STIJLT+(6PTE5MTIKM@U By "ollowing a %lan9%re"erably one that is si#%le and brie"9and co#ing u% with design structure be"ore coding, you ll discover that things "all together "ar #ore easily than i" you dive in and start hacking. /ou ll also reali1e a great deal o" satis"action. It s #y e&%erience that co#ing u% with an elegant solution is dee%ly satis"ying at an entirely di""erent level; it "eels closer to art than technology. 6nd elegance always %ays o""; it s not a "rivolous %ursuit. Cot only does it give you a %rogra# that s easier to build and debug, but it s also easier to understand and #aintain, and that s where the "inancial value lies.RFSURFSTIJLT+(6PTE5MTIKMMU
/0treme .rogramming
I have studied analysis and design techniAues, on and o"", since I was in graduate school. The conce%t o" E*treme Programming *ZP, is the #ost radical, and delight"ul, that I ve seen. /ou can "ind it chronicled in E*treme Programming E* lained by >ent Beck *6ddison':esley, K@@@, and on the :eb at ,,,'* rogramming'com.RFSURF STIJLT+(6PTE5MTIKMKU ZP is both a %hiloso%hy about %rogra##ing work and a set o" guidelines to do it. So#e o" these guidelines are re"lected in other recent #ethodologies, but the two #ost i#%ortant and distinct contributions, in #y o%inion, are !write tests "irst$ and !%air %rogra##ing.$ 6lthough he argues strongly "or the whole %rocess, Beck %oints out that i" you ado%t only these two %ractices you ll greatly i#%rove your %roductivity and reliability.RFSURFSTIJLT+(6PTE5MTIKMLU
;3
a low %riority, and %eo%le who s%eciali1e in it have not been given a lot o" status and have o"ten even been cordoned o"" in a base#ent, away "ro# the !real %rogra##ers.$ Test tea#s have res%onded in kind, going so "ar as to wear black clothing and cackling with glee whenever they break so#ething *to be honest, I ve had this "eeling #ysel" when breaking co#%ilers,.RFSURFSTIJLT+(6PTE5MTIKM?U ZP co#%letely revolutioni1es the conce%t o" testing by giving it eAual *or even greater, %riority than the code. In "act, you write the tests be$ore you write the code that will be tested, and the tests stay with the code "orever. The tests #ust be e&ecuted success"ully every ti#e you do an integration o" the %ro0ect *which is o"ten, so#eti#es #ore than once a day,.RFSURF STIJLT+(6PTE5MTIKMHU :riting tests "irst has two e&tre#ely i#%ortant e""ects.RFSURF STIJLT+(6PTE5MTIKM3U Eirst, it "orces a clear de"inition o" the inter"ace o" a class. I ve o"ten suggested that %eo%le !i#agine the %er"ect class to solve a %articular %roble#$ as a tool when trying to design the syste#. The ZP testing strategy goes "urther than that9it s%eci"ies e&actly what the class #ust look like, to the consu#er o" that class, and e&actly how the class #ust behave. In no uncertain ter#s. /ou can write all the %rose, or create all the diagra#s you want, describing how a class should behave and what it looks like, but nothing is as real as a set o" tests. The "or#er is a wish list, but the tests are a contract that is en"orced by the co#%iler and the running %rogra#. It s hard to i#agine a #ore concrete descri%tion o" a class than the tests.RFSURFSTIJLT+(6PTE5MTIKMGU :hile creating the tests, you are "orced to co#%letely think out the class and will o"ten discover needed "unctionality that #ight be #issed during the thought e&%eri#ents o" 4MD diagra#s, +5+ cards, use cases, etc. RF SURFSTIJLT+(6PTE5MTIKMIU The second i#%ortant e""ect o" writing the tests "irst co#es "ro# running the tests every ti#e you do a build o" your so"tware. This activity gives you the other hal" o" the testing that s %er"or#ed by the co#%iler. I" you look at the evolution o" %rogra##ing languages "ro# this %ers%ective, you ll see that the real i#%rove#ents in the technology have actually revolved around testing. 6sse#bly language checked only "or synta&, but
;4
+ i#%osed so#e se#antic restrictions, and these %revented you "ro# #aking certain ty%es o" #istakes. ))P languages i#%ose even #ore se#antic restrictions, which i" you think about it are actually "or#s o" testing. !Is this data ty%e being used %ro%erlyO$ and !Is this "unction being called %ro%erlyO$ are the kinds o" tests that are being %er"or#ed by the co#%iler or run'ti#e syste#. :e ve seen the results o" having these tests built into the language= %eo%le have been able to write #ore co#%le& syste#s, and get the# to work, with #uch less ti#e and e""ort. I ve %u11led over why this is, but now I reali1e it s the tests= you do so#ething wrong, and the sa"ety net o" the built'in tests tells you there s a %roble# and %oints you to where it is. RFSURFSTIJLT+(6PTE5MTIKM2U But the built'in testing a""orded by the design o" the language can only go so "ar. 6t so#e %oint, )ou #ust ste% in and add the rest o" the tests that %roduce a "ull suite *in coo%eration with the co#%iler and run'ti#e syste#, that veri"ies all o" your %rogra#. 6nd, 0ust like having a co#%iler watching over your shoulder, wouldn t you want these tests hel%ing you right "ro# the beginningO That s why you write the# "irst, and run the# auto#atically with every build o" your syste#. /our tests beco#e an e&tension o" the sa"ety net %rovided by the language. RFSURF STIJLT+(6PTE5MTIKK@U )ne o" the things that I ve discovered about the use o" #ore and #ore %ower"ul %rogra##ing languages is that I a# e#boldened to try #ore bra1en e&%eri#ents, because I know that the language will kee% #e "ro# wasting #y ti#e chasing bugs. The ZP test sche#e does the sa#e thing "or your entire %ro0ect. Because you know your tests will always catch any %roble#s that you introduce *and you regularly add any new tests as you think o" the#,, you can #ake big changes when you need to without worrying that you ll throw the whole %ro0ect into co#%lete disarray. This is incredibly %ower"ul. RFSURFSTIJLT+(6PTE5MTIKKMU
air .rogramming
Pair %rogra##ing goes against the rugged individualis# that we ve been indoctrinated into "ro# the beginning, through school *where we succeed or "ail on our own, and working with our neighbors is considered !cheating$,, and #edia, es%ecially (ollywood #ovies in which the hero is
;5
usually "ighting against #indless con"or#ity @. Progra##ers, too, are considered %aragons o" individuality9!cowboy coders$ as Darry +onstantine likes to say. 6nd yet ZP, which is itsel" battling against conventional thinking, says that code should be written with two %eo%le %er workstation. 6nd that this should be done in an area with a grou% o" workstations, without the barriers that the "acilities'design %eo%le are so "ond o". In "act, Beck says that the "irst task o" converting to ZP is to arrive with screwdrivers and 6llen wrenches and take a%art everything that gets in the way. @ *This will reAuire a #anager who can de"lect the ire o" the "acilities de%art#ent., RFSURFSTIJLT+(6PTE5MTIKKKU The value o" %air %rogra##ing is that one %erson is actually doing the coding while the other is thinking about it. The thinker kee%s the big %icture in #ind9not only the %icture o" the %roble# at hand, but the guidelines o" ZP. I" two %eo%le are working, it s less likely that one o" the# will get away with saying, !I don t want to write the tests "irst,$ "or e&a#%le. 6nd i" the coder gets stuck, they can swa% %laces. I" both o" the# get stuck, their #usings #ay be overheard by so#eone else in the work area who can contribute. :orking in %airs kee%s things "lowing and on track. Probably #ore i#%ortant, it #akes %rogra##ing a lot #ore social and "un. RFSURFSTIJLT+(6PTE5MTIKKLU I ve begun using %air %rogra##ing during the e&ercise %eriods in so#e o" #y se#inars and it see#s to signi"icantly i#%rove everyone s e&%erience. RFSURFSTIJLT+(6PTE5MTIKK?U
;7
designed to aid you as #uch as %ossible, while hindering you as little as %ossible with arbitrary rules or any reAuire#ent that you use a %articular set o" "eatures. Java is designed to be %ractical; Java language design decisions were based on %roviding the #a&i#u# bene"its to the %rogra##er. RFSURFSTIJLT+(6PTE5MTIKKHU
/rror handling
Error handling in + is a notorious %roble#, and one that is o"ten ignored 9"inger'crossing is usually involved. I" you re building a large, co#%le&
;8
%rogra#, there s nothing worse than having an error buried so#ewhere with no clue as to where it ca#e "ro#. Java e*ce tion handling is a way to guarantee that an error is noticed, and that so#ething ha%%ens as a result. RFSURFSTIJLT+(6PTE5MTIKK2U
;:
Switching an entire co#%any will o" course introduce certain grou% dyna#ics, but it will hel% at each ste% to re#e#ber how one %erson would do it. RFSURFSTIJLT+(6PTE5MTIKLKU
'uidelines
(ere are so#e guidelines to consider when #aking the transition to ))P and Java= RFSURFSTIJLT+(6PTE5MTIKLLU
() #raining
The "irst ste% is so#e "or# o" education. 5e#e#ber the co#%any s invest#ent in code, and try not to throw everything into disarray "or si& to nine #onths while everyone %u11les over how inter"aces work. Pick a s#all grou% "or indoctrination, %re"erably one co#%osed o" %eo%le who are curious, work well together, and can "unction as their own su%%ort network while they re learning Java. 6n alternative a%%roach that is so#eti#es suggested is the education o" all co#%any levels at once, including overview courses "or strategic #anagers as well as design and %rogra##ing courses "or %ro0ect builders. This is es%ecially good "or s#aller co#%anies #aking "unda#ental shi"ts in the way they do things, or at the division level o" larger co#%anies. Because the cost is higher, however, so#e #ay choose to start with %ro0ect'level training, do a %ilot %ro0ect *%ossibly with an outside #entor,, and let the %ro0ect tea# beco#e the teachers "or the rest o" the co#%any. RFSURFSTIJLT+(6PTE5MTIKL?U
!) &ow@risk .ro3ect
Try a low'risk %ro0ect "irst and allow "or #istakes. )nce you ve gained so#e e&%erience, you can either seed other %ro0ects "ro# #e#bers o" this "irst tea# or use the tea# #e#bers as an ))P technical su%%ort sta"". This "irst %ro0ect #ay not work right the "irst ti#e, so it should not be #ission'critical "or the co#%any. It should be si#%le, sel"'contained, and instructive; this #eans that it should involve creating classes that will be #eaning"ul to the other %rogra##ers in the co#%any when they get their turn to learn Java. RFSURFSTIJLT+(6PTE5MTIKLHU
;;
Management obstacles
I" you re a #anager, your 0ob is to acAuire resources "or your tea#, to overco#e barriers to your tea# s success, and in general to try to %rovide the #ost %roductive and en0oyable environ#ent so your tea# is #ost likely to %er"or# those #iracles that are always being asked o" you.
1==
Moving to Java "alls in all three o" these categories, and it would be wonder"ul i" it didn t cost you anything as well. 6lthough #oving to Java #ay be chea%er9de%ending on your constraints9than the ))P alternatives "or a tea# o" + %rogra##ers *and %robably "or %rogra##ers in other %rocedural languages,, it isn t "ree, and there are obstacles you should be aware o" be"ore trying to sell the #ove to Java within your co#%any and e#barking on the #ove itsel". RFSURF STIJLT+(6PTE5MTIKL2U
1tartu. costs
The cost o" #oving to Java is #ore than 0ust the acAuisition o" Java co#%ilers *the Sun Java co#%iler is "ree, so this is hardly an obstacle,. /our #ediu#' and long'ter# costs will be #ini#i1ed i" you invest in training *and %ossibly #entoring "or your "irst %ro0ect, and also i" you identi"y and %urchase class libraries that solve your %roble# rather than trying to build those libraries yoursel". These are hard'#oney costs that #ust be "actored into a realistic %ro%osal. In addition, there are the hidden costs in loss o" %roductivity while learning a new language and %ossibly a new %rogra##ing environ#ent. Training and #entoring can certainly #ini#i1e these, but tea# #e#bers #ust overco#e their own struggles to understand the new technology. 7uring this %rocess they will #ake #ore #istakes *this is a "eature, because acknowledged #istakes are the "astest %ath to learning, and be less %roductive. Even then, with so#e ty%es o" %rogra##ing %roble#s, the right classes, and the right develo%#ent environ#ent, it s %ossible to be #ore %roductive while you re learning Java *even considering that you re #aking #ore #istakes and writing "ewer lines o" code %er day, than i" you d stayed with +. RF SURFSTIJLT+(6PTE5MTIK?@U
erformance issues
6 co##on Auestion is, !7oesn t ))P auto#atically #ake #y %rogra#s a lot bigger and slowerO$ The answer is, !It de%ends.$ The e&tra sa"ety "eatures in Java have traditionally e&tracted a %er"or#ance %enalty over a language like +<<. Technologies such as !hots%ot$ and co#%ilation technologies have i#%roved the s%eed signi"icantly in #ost cases, and e""orts continue toward higher %er"or#ance. RFSURF STIJLT+(6PTE5MTIK?MU
1=1
:hen your "ocus is on ra%id %rototy%ing, you can throw together co#%onents as "ast as %ossible while ignoring e""iciency issues. I" you re using any third'%arty libraries, these are usually already o%ti#i1ed by their vendors; in any case it s not an issue while you re in ra%id' develo%#ent #ode. :hen you have a syste# that you like, i" it s s#all and "ast enough, then you re done. I" not, you begin tuning with a %ro"iling tool, looking "irst "or s%eedu%s that can be done by rewriting s#all %ortions o" code. I" that doesn t hel%, you look "or #odi"ications that can be #ade in the underlying i#%le#entation so no code that uses a %articular class needs to be changed. )nly i" nothing else solves the %roble# do you need to change the design. The "act that %er"or#ance is so critical in that %ortion o" the design is an indicator that it #ust be %art o" the %ri#ary design criteria. /ou have the bene"it o" "inding this out early using ra%id develo%#ent. I" you "ind a "unction that is a %articular bottleneck, you can rewrite it in +F+<< using Java s native methods, the sub0ect o" 6%%endi& B. RFSURF STIJLT+(6PTE5MTIK?KU
1=2
+<<, we ve seen steady i#%rove#ents but no dra#atic breakthroughs. 6lso, there see#s to be a continuing interest in +<<, so I don t think that language is going away any ti#e soon. *Danguages see# to hang around. S%eaking at one o" #y !Inter#ediateF6dvanced Java Se#inars,$ 6llen (olub asserted that the two #ost co##only used languages are 5e&& and +)B)D, in that order., RFSURFSTIJLT+(6PTE5MTIK??U I # beginning to think that the strength o" Java lies in a slightly di""erent arena than that o" +<<. +<< is a language that doesn t try to "it a #old. +ertainly it has been ada%ted in a nu#ber o" ways to solve %articular %roble#s. So#e +<< tools co#bine libraries, co#%onent #odels, and code'generation tools to solve the %roble# o" develo%ing windowed end' user a%%lications *"or Microso"t :indows,. 6nd yet, what do the vast #a0ority o" :indows develo%ers useO Microso"t s Visual Basic *VB,. This des%ite the "act that VB %roduces the kind o" code that beco#es un#anageable when the %rogra# is only a "ew %ages long *and synta& that can be %ositively #ysti"ying,. 6s success"ul and %o%ular as VB is, it s not a very good e&a#%le o" language design. It would be nice to have the ease and %ower o" VB without the resulting un#anageable code. 6nd that s where I think Java will shine= as the !ne&t VB.$ /ou #ay or #ay not shudder to hear this, but think about it= so #uch o" Java is intended to #ake it easy "or the %rogra##er to solve a%%lication'level %roble#s like networking and cross'%lat"or# 4I, and yet it has a language design that allows the creation o" very large and "le&ible bodies o" code. 6dd to this the "act that Java has the #ost robust ty%e checking and error handling syste#s I ve ever seen in a language and you have the #akings o" a signi"icant lea% "orward in %rogra##ing %roductivity. RFSURF STIJLT+(6PTE5MTIK?HU Should you use Java instead o" +<< "or your %ro0ectO )ther than :eb a%%lets, there are two issues to consider. Eirst, i" you want to use a lot o" e&isting +<< libraries *and you ll certainly get a lot o" %roductivity gains there,, or i" you have an e&isting + or +<< code base, Java #ight slow your develo%#ent down rather than s%eeding it u%. RFSURF STIJLT+(6PTE5MTIK?3U I" you re develo%ing all your code %ri#arily "ro# scratch, then the si#%licity o" Java over +<< will signi"icantly shorten your develo%#ent ti#e9the anecdotal evidence *stories "ro# +<< tea#s that I ve talked to
1=3
who have switched to Java, suggests a doubling o" develo%#ent s%eed over +<<. I" Java %er"or#ance doesn t #atter or you can so#ehow co#%ensate "or it, sheer ti#e'to'#arket issues #ake it di""icult to choose +<< over Java. RFSURFSTIJLT+(6PTE5MTIK?GU The biggest issue is %er"or#ance. Inter%reted Java has been slow, even K@ to H@ ti#es slower than + in the original Java inter%reters. This has i#%roved greatly over ti#e, but it will still re#ain an i#%ortant nu#ber. +o#%uters are about s%eed; i" it wasn t signi"icantly "aster to do so#ething on a co#%uter then you d do it by hand. *I ve even heard it suggested that you start with Java, to gain the short develo%#ent ti#e, then use a tool and su%%ort libraries to translate your code to +<<, i" you need "aster e&ecution s%eed., RFSURFSTIJLT+(6PTE5MTIK?IU The key to #aking Java "easible "or #ost develo%#ent %ro0ects is the a%%earance o" s%eed i#%rove#ents like so'called !0ust'in ti#e$ *JIT, co#%ilers, Sun s own !hots%ot$ technology, and even native code co#%ilers. )" course, native code co#%ilers will eli#inate the touted cross'%lat"or# e&ecution o" the co#%iled %rogra#s, but they will also bring the s%eed o" the e&ecutable closer to that o" + and +<<. 6nd cross' co#%iling a %rogra# in Java should be a lot easier than doing so in + or +<<. *In theory, you 0ust reco#%ile, but that %ro#ise has been #ade be"ore "or other languages., RFSURFSTIJLT+(6PTE5MTIK?2U /ou can "ind co#%arisons o" Java and +<< and observations about Java realities in the a%%endices o" the "irst edition o" this book *6vailable on this book s acco#%anying +7 5)M, as well as at ,,,'0ruceEckel'comA. RFSURFSTIJLT+(6PTE5MTIKH@U
1ummar:
This cha%ter atte#%ts to give you a "eel "or the broad issues o" ob0ect' oriented %rogra##ing and Java, including why ))P is di""erent, and why Java in %articular is di""erent, conce%ts o" ))P #ethodologies, and "inally the kinds o" issues you will encounter when #oving your own co#%any to ))P and Java. RFSURFSTIJLT+(6PTE5MTIKHMU ))P and Java #ay not be "or everyone. It s i#%ortant to evaluate your own needs and decide whether Java will o%ti#ally satis"y those needs, or
1=4
i" you #ight be better o"" with another %rogra##ing syste# *including the one you re currently using,. I" you know that your needs will be very s%eciali1ed "or the "oreseeable "uture and i" you have s%eci"ic constraints that #ay not be satis"ied by Java, then you owe it to yoursel" to investigate the alternatives @. Even i" you eventually choose Java as your language, you ll at least understand what the o%tions were and have a clear vision o" why you took that direction. RFSURF STIJLT+(6PTE5MTIKHKU /ou know what a %rocedural %rogra# looks like= data de"initions and "unction calls. To "ind the #eaning o" such a %rogra# you have to work a little, looking through the "unction calls and low'level conce%ts to create a #odel in your #ind. This is the reason we need inter#ediate re%resentations when designing %rocedural %rogra#s9by the#selves, these %rogra#s tend to be con"using because the ter#s o" e&%ression are oriented #ore toward the co#%uter than to the %roble# you re solving. RFSURFSTIJLT+(6PTE5MTIKHLU Because Java adds #any new conce%ts on to% o" what you "ind in a %rocedural language, your natural assu#%tion #ay be that the mainA B in a Java %rogra# will be "ar #ore co#%licated than "or the eAuivalent + %rogra#. (ere, you ll be %leasantly sur%rised= 6 well'written Java %rogra# is generally "ar si#%ler and #uch easier to understand than the eAuivalent + %rogra#. :hat you ll see are the de"initions o" the ob0ects that re%resent conce%ts in your %roble# s%ace *rather than the issues o" the co#%uter re%resentation, and #essages sent to those ob0ects to re%resent the activities in that s%ace. )ne o" the delights o" ob0ect' oriented %rogra##ing is that, with a well'designed %rogra#, it s easy to understand the code by reading it. 4sually there s a lot less code as well, because #any o" your %roble#s will be solved by reusing e&isting library code. RFSU
1=5
!: /ver:thing is an Ob3ect
RFSTIJLT+(6PTE5KTI@U6lthough it is based on +<<, Java is #ore o" a !%ure$ ob0ect'oriented language.
Both +<< and Java are hybrid languages, but in Java the designers "elt that the hybridi1ation was not as i#%ortant as it was in +<<. 6 hybrid language allows #ulti%le %rogra##ing styles; the reason +<< is hybrid is to su%%ort backward co#%atibility with the + language. Because +<< is a su%erset o" the + language, it includes #any o" that language s undesirable "eatures, which can #ake so#e as%ects o" +<< overly co#%licated. RFSURFSTIJLT+(6PTE5KTIMU The Java language assu#es that you want to do only ob0ect'oriented %rogra##ing. This #eans that be"ore you can begin you #ust shi"t your #indset into an ob0ect'oriented world *unless it s already there, ' The bene"it o" this initial e""ort is the ability to %rogra# in a language that is si#%ler to learn and to use than #any other ))P languages. In this cha%ter we ll see the basic co#%onents o" a Java %rogra# and we ll learn that everything in Java is an ob0ect, even a Java %rogra#. RFSURF STIJLT+(6PTE5KTIKU
1=7
+<<, that #ust be treated with a s%ecial synta&O RFSURF STIJLT+(6PTE5KTILU 6ll this is si#%li"ied in Java. /ou treat everything as an ob0ect, so there is a single consistent synta& that you use everywhere. 6lthough you treat everything as an ob0ect, the identi"ier you #ani%ulate is actually a !re"erence$ to an ob0ect @. /ou #ight i#agine this scene as a television *the ob0ect, with your re#ote control *the re"erence,. 6s long as you re holding this re"erence, you have a connection to the television, but when so#eone says !change the channel$ or !lower the volu#e,$ what you re #ani%ulating is the re"erence, which in turn #odi"ies the ob0ect. I" you want to #ove around the roo# and still control the television, you take the re#oteFre"erence with you, not the television. RFSURF STIJLT+(6PTE5KTI?U 6lso, the re#ote control can stand on its own, with no television. That is, 0ust because you have a re"erence doesn t #ean there s necessarily an ob0ect connected to it. So i" you want to hold a word or sentence, you create a )tring re"erence= F/GHF/GTIJ3IC."PTE-2II5H
%tring s<
But here you ve created onl) the re"erence, not an ob0ect. I" you decided to send a #essage to s at this %oint, you ll get an error *at run'ti#e, because s isn t actually attached to anything *there s no television,. 6 sa"er %ractice, then, is always to initiali1e a re"erence when you create it= RFSURFSTIJLT+(6PTE5KTI3U
@ This can be a "lash%oint. There are those who say !clearly, it s a %ointer,$ but this %resu#es an underlying i#%le#entation. 6lso, Java re"erences are #uch #ore akin to +<< re"erences than %ointers in their synta&. In the "irst edition o" this book, I chose to invent a new ter#, !handle,$ because +<< re"erences and Java re"erences have so#e i#%ortant di""erences. I was co#ing out o" +<< and did not want to con"use the +<< %rogra##ers who# I assu#ed would be the largest audience "or Java. In the Knd edition, I decided that !re"erence$ was the #ore co##only used ter#, and that anyone changing "ro# +<< would have a lot #ore to co%e with than the ter#inology o" re"erences, so they #ight as well 0u#% in with both "eet. (owever, there are %eo%le who disagree even with the ter# !re"erence.$ I read in one book where it was !co#%letely wrong to say that Java su%%orts %ass by re"erence,$ because Java ob0ect identi"iers *according to that author, are actuall) !ob0ect re"erences.$ 6nd *he goes on, everything is actuall) %ass by value. So you re not %assing by re"erence, you re !%assing an ob0ect re"erence by value.$ )ne could argue "or the %recision o" such convoluted e&%lanations, but I think #y a%%roach si#%li"ies the understanding o" the conce%t without hurting anything *well, the language lawyers #ay clai# that I # lying to you, but I ll say that I # %roviding an a%%ro%riate abstraction.,
1=8
%tring s ? 8as!f8<
(owever, this uses a s%ecial Java "eature= strings can be initiali1ed with Auoted te&t. Cor#ally, you #ust use a #ore general ty%e o" initiali1ation "or ob0ects. F/GHF/GTIJ3IC."PTE-2II8H
!!)
1=:
!*)
!+)
!,)
)tatic storage. !Static$ is used here in the sense o" !in a "i&ed
location$ *although it s also in 56M,. Static storage contains data that is available "or the entire ti#e a %rogra# is running. /ou can use the static keyword to s%eci"y that a %articular ele#ent o" an ob0ect is static, but Java ob0ects the#selves are never %laced in static storage. RFSURFSTIJLT+(6PTE5KTIMHU
!-)
1=;
!4)
)i7 e
9 M3' bit I' bit
1inim* m
9 4nicode @ 'MKI
1a4im*m
9 4nicode K M3' M <MKG
11=
)i7 e
M3' bit LK' bit 3?' bit LK' bit 3?' bit 9
1inim* m
'K MH 'K LM 'K 3L IEEEGH? IEEEGH? 9
1a4im*m
<K MH9M <K LM9M <K 3L9M IEEEGH? IEEEGH? 9
6ll nu#eric ty%es are signed, so don t go looking "or unsigned ty%es. RF SURFSTIJLT+(6PTE5KTIK@U The si1e o" the boolean ty%e is not e&%licitly de"ined; it is only s%eci"ied to be able to take the literal values tr*e or false. The %ri#itive data ty%es also have !wra%%er$ classes "or the#. That #eans that i" you want to #ake a non%ri#itive ob0ect on the hea% to re%resent that %ri#itive ty%e, you use the associated wra%%er. Eor e&a#%le= RFSURFSTIJLT+(6PTE5KTIKMU
>[email protected] numbers
Java includes two classes "or %er"or#ing high'%recision arith#etic=
2igInteger and 2ig ecimal. 6lthough these a%%ro&i#ately "it into the
sa#e category as the !wra%%er$ classes, neither one has a %ri#itive analogue. RFSURFSTIJLT+(6PTE5KTIKLU
111
Both classes have #ethods that %rovide analogues "or the o%erations that you %er"or# on %ri#itive ty%es. That is, you can do anything with a 2igInteger or 2ig ecimal that you can with an int or float, it s 0ust that you #ust use #ethod calls instead o" o%erators. 6lso, since there s #ore involved, the o%erations will be slower. /ou re e&changing s%eed "or accuracy. RFSURFSTIJLT+(6PTE5KTIK?U
2igInteger su%%orts arbitrary'%recision integers. This #eans that you can accurately re%resent integral values o" any si1e without losing any in"or#ation during o%erations. RFSURFSTIJLT+(6PTE5KTIKHU 2ig ecimal is "or arbitrary'%recision "i&ed'%oint nu#bers; you can use these "or accurate #onetary calculations, "or e&a#%le. RFSURF STIJLT+(6PTE5KTIK3U
+onsult your online docu#entation "or details about the constructors and #ethods you can call "or these two classes. RFSURF STIJLT+(6PTE5KTIKGU
Arra:s in "ava
Virtually all %rogra##ing languages su%%ort arrays. 4sing arrays in + and +<< is %erilous because those arrays are only blocks o" #e#ory. I" a %rogra# accesses the array outside o" its #e#ory block or uses the #e#ory be"ore initiali1ation *co##on %rogra##ing errors, there will be un%redictable results. RFSURFSTIJLT+(6PTE5KTIKIU )ne o" the %ri#ary goals o" Java is sa"ety, so #any o" the %roble#s that %lague %rogra##ers in + and +<< are not re%eated in Java. 6 Java array is guaranteed to be initiali1ed and cannot be accessed outside o" its range. The range checking co#es at the %rice o" having a s#all a#ount o" #e#ory overhead on each array as well as veri"ying the inde& at run'ti#e, but the assu#%tion is that the sa"ety and increased %roductivity is worth the e&%ense. RFSURFSTIJLT+(6PTE5KTIK2U :hen you create an array o" ob0ects, you are really creating an array o" re"erences, and each o" those re"erences is auto#atically initiali1ed to a s%ecial value with its own keyword= n*ll. :hen Java sees n*ll, it recogni1es that the re"erence in Auestion isn t %ointing to an ob0ect. /ou #ust assign an ob0ect to each re"erence be"ore you use it, and i" you try to
112
use a re"erence that s still n*ll, the %roble# will be re%orted at run'ti#e. Thus, ty%ical array errors are %revented in Java. RFSURF STIJLT+(6PTE5KTIL@U /ou can also create an array o" %ri#itives. 6gain, the co#%iler guarantees initiali1ation because it 1eroes the #e#ory "or that array. RFSURF STIJLT+(6PTE5KTILMU 6rrays will be covered in detail in later cha%ters. RFSURF STIJLT+(6PTE5KTILKU
1co.ing
Most %rocedural languages have the conce%t o" sco e. This deter#ines both the visibility and li"eti#e o" the na#es de"ined within that sco%e. In +, +<<, and Java, sco%e is deter#ined by the %lace#ent o" curly braces EF. So "or e&a#%le= RFSURFSTIJLT+(6PTE5KTIL?U
@ int 6 ? ( /B only 6 @ int = ? /B both A /B only 6 /B = Eout A < available B/ C+< 6 D = available B/ available B/ of sco"eF B/
113
6 variable de"ined within a sco%e is available only to the end o" that sco%e. RFSURFSTIJLT+(6PTE5KTILHU Indentation #akes Java code easier to read. Since Java is a "ree'"or# language, the e&tra s%aces, tabs, and carriage returns do not a""ect the resulting %rogra#. RFSURFSTIJLT+(6PTE5KTIL3U Cote that you cannot do the "ollowing, even though it is legal in + and +<<=
1co.e of ob3ects
Java ob0ects do not have the sa#e li"eti#es as %ri#itives. :hen you create a Java ob0ect using ne(, it hangs around %ast the end o" the sco%e. Thus i" you use=
114
vanish in Java. The hardest %roble#s see# to occur in +<< because you don t get any hel% "ro# the language in #aking sure that the ob0ects are available when they re needed. 6nd #ore i#%ortant, in +<< you #ust #ake sure that you destroy the ob0ects when you re done with the#. RF SURFSTIJLT+(6PTE5KTIL2U That brings u% an interesting Auestion. I" Java leaves the ob0ects lying around, what kee%s the# "ro# "illing u% #e#ory and halting your %rogra#O This is e&actly the kind o" %roble# that would occur in +<<. This is where a bit o" #agic ha%%ens. Java has a garbage collector, which looks at all the ob0ects that were created with ne( and "igures out which ones are not being re"erenced any#ore. Then it releases the #e#ory "or those ob0ects, so the #e#ory can be used "or new ob0ects. This #eans that you never need to worry about reclai#ing #e#ory yoursel". /ou si#%ly create ob0ects, and when you no longer need the# they will go away by the#selves. This eli#inates a certain class o" %rogra##ing %roble#= the so'called !#e#ory leak,$ in which a %rogra##er "orgets to release #e#ory. RFSURFSTIJLT+(6PTE5KTI?@U
115
In AType/ame, the class body consists only o" a co##ent *the stars and slashes and what is inside, which will be discussed later in this cha%ter,, so there is not too #uch that you can do with it. In "act, you cannot tell it to do #uch o" anything *that is, you cannot send it any interesting #essages, until you de"ine so#e #ethods "or it. RFSURF STIJLT+(6PTE5KTI?KU
117
na#e o" the ob0ect re"erence, "ollowed by a %eriod *dot,, "ollowed by the na#e o" the #e#ber inside the ob0ect= RFSURFSTIJLT+(6PTE5KTI?3U
obHect5eference.#e#ber
Eor e&a#%le= RFSURFSTIJLT+(6PTE5KTI?GU
#yPlane.leftTank.ca"acity ? (''<
The ata.nly class cannot do #uch o" anything e&ce%t hold data, because it has no #e#ber "unctions *#ethods,. To understand how those work, you #ust "irst understand arguments and return values, which will be described shortly. RFSURFSTIJLT+(6PTE5KTI?2U
#rimitive type boolean char byte short int long float 'o*ble
Cote care"ully that the de"ault values are what Java guarantees when the variable is used as a member o$ a class. This ensures that #e#ber variables o" %ri#itive ty%es will always be initiali1ed *so#ething +<<
118
doesn t do,, reducing a source o" bugs. (owever, this initial value #ay not be correct or even legal "or the %rogra# you are writing. It s best to always e&%licitly initiali1e your variables. RFSURFSTIJLT+(6PTE5KTIH@U This guarantee doesn t a%%ly to !local$ variables9those that are not "ields o" a class. Thus, i" within a "unction de"inition you have=
int 6<
Then 4 will get so#e arbitrary value *as in + and +<<,; it will not auto#atically be initiali1ed to 1ero. /ou are res%onsible "or assigning an a%%ro%riate value be"ore you use 4. I" you "orget, Java de"initely i#%roves on +<<= you get a co#%ile'ti#e error telling you the variable #ight not have been initiali1ed. *Many +<< co#%ilers will warn you about uninitiali1ed variables, but in Java these are errors., RFSURF STIJLT+(6PTE5KTIHMU
11:
The return ty%e is the ty%e o" the value that %o%s out o" the #ethod a"ter you call it. The argu#ent list gives the ty%es and na#es "or the in"or#ation you want to %ass into the #ethod. The #ethod na#e and argu#ent list together uniAuely identi"y the #ethod. RFSURF STIJLT+(6PTE5KTIH?U Methods in Java can be created only as %art o" a class. 6 #ethod can be called only "or an ob0ect, @ and that ob0ect #ust be able to %er"or# that #ethod call. I" you try to call the wrong #ethod "or an ob0ect, you ll get an error #essage at co#%ile'ti#e. /ou call a #ethod "or an ob0ect by na#ing the ob0ect "ollowed by a %eriod *dot,, "ollowed by the na#e o" the #ethod and its argu#ent list, like this= ob8ect/ame!metho'/ameAarg>, argI, argJB. Eor e&a#%le, su%%ose you have a #ethod fA B that takes no argu#ents and returns a value o" ty%e int. Then, i" you have an ob0ect called a "or which fA B can be called, you can say this=
int 6 ? a.f-.<
The ty%e o" the return value #ust be co#%atible with the ty%e o" 4. RF SURFSTIJLT+(6PTE5KTIHHU This act o" calling a #ethod is co##only re"erred to as sending a message to an ob>ect. In the above e&a#%le, the #essage is fA B and the ob0ect is a. )b0ect'oriented %rogra##ing is o"ten su##ari1ed as si#%ly !sending #essages to ob0ects.$ RFSURFSTIJLT+(6PTE5KTIH3U
11;
re"erence #ust be correct, however. I" the argu#ent is su%%osed to be a )tring, what you %ass in #ust be a string. RFSURF STIJLT+(6PTE5KTIHGU +onsider a #ethod that takes a )tring as its argu#ent. (ere is the de"inition, which #ust be %laced within a class de"inition "or it to be co#%iled=
boolean flag-. @ return true< A float naturalLogBase-. @ return voi! nothing-. @ return< A voi! nothing -. @A
.*(1f< A
:hen the return ty%e is voi', then the ret*rn keyword is used only to e&it the #ethod, and is there"ore unnecessary when you reach the end o" the #ethod. /ou can return "ro# a #ethod at any %oint, but i" you ve given a non' voi' return ty%e then the co#%iler will "orce you *with error #essages, to return the a%%ro%riate ty%e o" value regardless o" where you return. RFSURFSTIJLT+(6PTE5KTI3@U
12=
6t this %oint, it can look like a %rogra# is 0ust a bunch o" ob0ects with #ethods that take other ob0ects as argu#ents and send #essages to those other ob0ects. That is indeed #uch o" what goes on, but in the "ollowing cha%ter you ll learn how to do the detailed low'level work by #aking decisions within a #ethod. Eor this cha%ter, sending #essages will su""ice. RFSURFSTIJLT+(6PTE5KTI3MU
2ame visibilit:
6 %roble# in any %rogra##ing language is the control o" na#es. I" you use a na#e in one #odule o" the %rogra#, and another %rogra##er uses the sa#e na#e in another #odule, how do you distinguish one na#e "ro# another and %revent the two na#es "ro# !clashingO$ In + this is a %articular %roble# because a %rogra# is o"ten an un#anageable sea o" na#es. +<< classes *on which Java classes are based, nest "unctions within classes so they cannot clash with "unction na#es nested within other classes. (owever, +<< still allowed global data and global "unctions, so clashing was still %ossible. To solve this %roble#, +<< introduced names aces using additional keywords. RFSURF STIJLT+(6PTE5KTI3LU Java was able to avoid all o" this by taking a "resh a%%roach. To %roduce an una#biguous na#e "or a library, the s%eci"ier used is not unlike an Internet do#ain na#e. In "act, the Java creators want you to use your Internet do#ain na#e in reverse since those are guaranteed to be uniAue. Since #y do#ain na#e is 2r*ce&ckel!com, #y utility library o" "oibles would be na#ed com!br*ceeckel!*tility!foibles. 6"ter your reversed do#ain na#e, the dots are intended to re%resent subdirectories. RFSURF STIJLT+(6PTE5KTI3?U In Java M.@ and Java M.M the do#ain e&tensions com, e'*, org, net, etc., were ca%itali1ed by convention, so the library would a%%ear= -.1! br*ceeckel!*tility!foibles. Partway through the develo%#ent o" Java
121
K, however, it was discovered that this caused %roble#s, and so now the entire %ackage na#e is lowercase. RFSURFSTIJLT+(6PTE5KTI3HU This #echanis# #eans that all o" your "iles auto#atically live in their own na#es%aces, and each class within a "ile #ust have a uniAue identi"ier. So you do not need to learn s%ecial language "eatures to solve this %roble#9the language takes care o" it "or you. RFSURF STIJLT+(6PTE5KTI33U
i#"ort Hava.util.0rrayList<
122
to tell the co#%iler that you want to use Java s Array+ist class. (owever, *til contains a nu#ber o" classes and you #ight want to use several o" the# without declaring the# all e&%licitly. This is easily acco#%lished by using [K to indicate a wild card=
i#"ort Hava.util.B<
It is #ore co##on to i#%ort a collection o" classes in this #anner than to i#%ort classes individually. RFSURFSTIJLT+(6PTE5KTIG@U
123
whole, and not "or any %articular ob0ects o" the class. So#eti#es the Java literature uses these ter#s too. RFSURFSTIJLT+(6PTE5KTIGLU To #ake a data #e#ber or #ethod static, you si#%ly %lace the keyword be"ore the de"inition. Eor e&a#%le, the "ollowing %roduces a static data #e#ber and initiali1es it= RFSURFSTIJLT+(6PTE5KTIG?U
%taticTest.iKK<
The LL o%erator incre#ents the variable. 6t this %oint, both st>!i and stI!i will have the value ?I. RFSURFSTIJLT+(6PTE5KTIGIU Si#ilar logic a%%lies to static #ethods. /ou can re"er to a static #ethod either through an ob0ect as you can with any #ethod, or with the s%ecial additional synta& -lass/ame!metho'A B. /ou de"ine a static #ethod in a si#ilar way= RFSURFSTIJLT+(6PTE5KTIG2U
124
/ou can see that the )taticF*n #ethod incrA B incre#ents the static data i. /ou can call incrA B in the ty%ical way, through an ob0ect= RFSURF STIJLT+(6PTE5KTII@U
%taticLun.incr-.<
:hile static, when a%%lied to a data #e#ber, de"initely changes the way the data is created *one "or each class vs. the non' static one "or each ob0ect,, when a%%lied to a #ethod it s not so dra#atic. 6n i#%ortant use o" static "or #ethods is to allow you to call that #ethod without creating an ob0ect. This is essential, as we will see, in de"ining the mainA B #ethod that is the entry %oint "or running an a%%lication. RFSURF STIJLT+(6PTE5KTIIKU Dike any #ethod, a static #ethod can create or use na#ed ob0ects o" its ty%e, so a static #ethod is o"ten used as a !she%herd$ "or a "lock o" instances o" its own ty%e. RFSURFSTIJLT+(6PTE5KTIILU
// MelloDate.Hava
@ So#e %rogra##ing environ#ents will "lash %rogra#s u% on the screen and close the# be"ore youVve had a chance to see the results. /ou can %ut in the "ollowing bit o" code at the end o" mainA B to %ause the out%ut=
try @ %yste#.in.rea!-.< A catch-E6ce"tion e. @A This will %ause the out%ut until you %ress !Enter$ *or any other key,. This code involves conce%ts that will not be introduced until #uch later in the book, so you won t understand it until then, but it will do the trick.
125
i#"ort Hava.util.B< "ublic class MelloDate @ "ublic static voi! #ain-%tringNO args. @ %yste#.out."rintln-8Mello, it2s3 8.< %yste#.out."rintln-ne: Date-..< A A
6t the beginning o" each %rogra# "ile, you #ust %lace the import state#ent to bring in any e&tra classes you ll need "or the code in that "ile. Cote that I say !e&tra;$ that s because there s a certain library o" classes that are auto#atically brought into every Java "ile= 8ava!lang. Start u% your :eb browser and look at the docu#entation "ro# Sun. *I" you haven t downloaded it "ro# >ava'sun'com or otherwise installed the Java docu#entation, do so now,. I" you look at the list o" the %ackages, you ll see all the di""erent class libraries that co#e with Java. Select 8ava!lang. This will bring u% a list o" all the classes that are %art o" that library. Since 8ava!lang is i#%licitly included in every Java code "ile, these classes are auto#atically available. There s no ate class listed in 8ava!lang, which #eans you #ust i#%ort another library to use that. I" you don t know the library where a %articular class is, or i" you want to see all o" the classes, you can select !Tree$ in the Java docu#entation. Cow you can "ind every single class that co#es with Java. Then you can use the browser s !"ind$ "unction to "ind ate. :hen you do you ll see it listed as 8ava!*til! ate, which lets you know that it s in the *til library and that you #ust import 8ava!*til!K in order to use ate. RFSURFSTIJLT+(6PTE5KTIIHU I" you go back to the beginning, select 8ava!lang and then )ystem, you ll see that the )ystem class has several "ields, and i" you select o*t you ll discover that it s a static #rint)tream ob0ect. Since it s static you don t need to create anything. The o*t ob0ect is always there and you can 0ust use it. :hat you can do with this o*t ob0ect is deter#ined by the ty%e it is= a #rint)tream. +onveniently, #rint)tream is shown in the descri%tion as a hy%erlink, so i" you click on that you ll see a list o" all the #ethods you can call "or #rint)tream. There are Auite a "ew and these will be covered later in this book. Eor now all we re interested in is printlnA B, which in e""ect #eans !%rint what I # giving you out to the console and end with a new line.$ Thus, in any Java %rogra# you write
127
you can say )ystem!o*t!printlnAMthingsMB whenever you want to %rint so#ething to the console. RFSURFSTIJLT+(6PTE5KTII3U The na#e o" the class is the sa#e as the na#e o" the "ile. :hen you re creating a stand'alone %rogra# such as this one, one o" the classes in the "ile #ust have the sa#e na#e as the "ile. *The co#%iler co#%lains i" you don t do this., That class #ust contain a #ethod called mainA B with the signature shown= RFSURFSTIJLT+(6PTE5KTIIGU
%yste#.out."rintln-ne: Date-..<
+onsider the argu#ent= a ate ob0ect is being created 0ust to send its value to printlnA B. 6s soon as this state#ent is "inished, that ate is unnecessary, and the garbage collector can co#e along and get it anyti#e. :e don t need to worry about cleaning it u%. RFSURF STIJLT+(6PTE5KTI2@U
128
downloading and installing the J7> "or your %articular %lat"or#. RFSURF STIJLT+(6PTE5KTI2KU )nce the J7> is installed, and you ve set u% your co#%uter s %ath in"or#ation so that it will "ind 8avac and 8ava, download and un%ack the source code "or this book *you can "ind it on the +7 5)M that s bound in with this book, or at ,,,'0ruceEckel'com,. This will create a subdirectory "or each cha%ter in this book. Move to subdirectory cDI and ty%e= RFSURFSTIJLT+(6PTE5KTI2LU
Havac MelloDate.Hava
This co##and should %roduce no res%onse. I" you get any kind o" an error #essage it #eans you haven t installed the J7> %ro%erly and you need to investigate those %roble#s. RFSURFSTIJLT+(6PTE5KTI2?U )n the other hand, i" you 0ust get your co##and %ro#%t back, you can ty%e=
Hava MelloDate
and you ll get the #essage and the date as out%ut. RFSURF STIJLT+(6PTE5KTI2HU This is the %rocess you can use to co#%ile and run each o" the %rogra#s in this book. (owever, you will see that the source code "or this book also has a "ile called makefile in each cha%ter, and this contains !#ake$ co##ands "or auto#atically building the "iles "or that cha%ter. See this book s :eb %age at ,,,'0ruceEckel'com "or details on how to use the #ake"iles. RFSURFSTIJLT+(6PTE5KTI23U
12:
%rogra##ers will begin each line o" a continued co##ent with a K, so you ll o"ten see=
Comment documentation
)ne o" the thought"ul %arts o" the Java language is that the designers didn t consider writing code to be the only i#%ortant activity9they also thought about docu#enting it. Possibly the biggest %roble# with docu#enting code has been #aintaining that docu#entation. I" the docu#entation and the code are se%arate, it beco#es a hassle to change the docu#entation every ti#e you change the code. The solution see#s si#%le= link the code to the docu#entation. The easiest way to do this is to %ut everything in the sa#e "ile. To co#%lete the %icture, however, you need a s%ecial co##ent synta& to #ark s%ecial docu#entation, and a tool to e&tract those co##ents and %ut the# in a use"ul "or#. This is what Java has done. RFSURFSTIJLT+(6PTE5KTI22U The tool to e&tract the co##ents is called >avadoc' It uses so#e o" the technology "ro# the Java co#%iler to look "or s%ecial co##ent tags you %ut in your %rogra#s. It not only e&tracts the in"or#ation #arked by these tags, but it also %ulls out the class na#e or #ethod na#e that
12;
ad0oins the co##ent. This way you can get away with the #ini#al a#ount o" work to generate decent %rogra# docu#entation. RFSURF STIJLT+(6PTE5KTIM@@U The out%ut o" 0avadoc is an (TMD "ile that you can view with your :eb browser. This tool allows you to create and #aintain a single source "ile and auto#atically generate use"ul docu#entation. Because o" 0avadoc we have a standard "or creating docu#entation, and it s easy enough that we can e&%ect or even de#and docu#entation with all Java libraries. RFSURF STIJLT+(6PTE5KTIM@MU
1:nta0
6ll o" the 0avadoc co##ands occur only within 5KK co##ents. The co##ents end with K5 as usual. There are two %ri#ary ways to use 0avadoc= e#bed (TMD, or use !doc tags.$ 7oc tags are co##ands that start with a [ 9 and are %laced at the beginning o" a co##ent line. *6 leading [K , however, is ignored., RFSURFSTIJLT+(6PTE5KTIM@KU There are three !ty%es$ o" co##ent docu#entation, which corres%ond to the ele#ent the co##ent %recedes= class, variable, or #ethod. That is, a class co##ent a%%ears right be"ore the de"inition o" a class; a variable co##ent a%%ears right in "ront o" the de"inition o" a variable, and a #ethod co##ent a%%ears right in "ront o" the de"inition o" a #ethod. 6s a si#%le e&a#%le= RFSURFSTIJLT+(6PTE5KTIM@LU
/BB 0 class co##ent B/ "ublic class !ocTest @ /BB 0 variable co##ent B/ "ublic int i< /BB 0 #etho! co##ent B/ "ublic voi! f-. @A A
Cote that 0avadoc will %rocess co##ent docu#entation "or only p*blic and protecte' #e#bers. +o##ents "or private and !"riendly$ #e#bers *see +ha%ter H, are ignored and you ll see no out%ut. *(owever, you can use the 6private "lag to include private #e#bers as well., This #akes sense, since only p*blic and protecte' #e#bers are available outside the "ile, which is the client %rogra##er s %ers%ective. (owever,
13=
all class co##ents are included in the out%ut. RFSURF STIJLT+(6PTE5KTIM@?U The out%ut "or the above code is an (TMD "ile that has the sa#e standard "or#at as all the rest o" the Java docu#entation, so users will be co#"ortable with the "or#at and can easily navigate your classes. It s worth entering the above code, sending it through 0avadoc and viewing the resulting (TMD "ile to see the results. RFSURF STIJLT+(6PTE5KTIM@HU
/mbedded >#M&
Javadoc %asses (TMD co##ands through to the generated (TMD docu#ent. This allows you "ull use o" (TMD; however, the %ri#ary #otive is to let you "or#at code, such as= RFSURF STIJLT+(6PTE5KTIM@3U
/BB B ;ou can Pe#QevenP/e#Q insert a list3 B PolQ B PliQ $te# one B PliQ $te# t:o B PliQ $te# three B P/olQ B/
Cote that within the docu#entation co##ent, asterisks at the beginning o" a line are thrown away by 0avadoc, along with leading s%aces. Javadoc re"or#ats everything so that it con"or#s to the standard docu#entation a%%earance. 7on t use headings such as Nh>O or NhrO as e#bedded
131
(TMD because 0avadoc inserts its own headings and yours will inter"ere with the#. RFSURFSTIJLT+(6PTE5KTIM@IU 6ll ty%es o" co##ent docu#entation9class, variable, and #ethod9can su%%ort e#bedded (TMD. RFSURFSTIJLT+(6PTE5KTIM@2U
Iversion
This is o" the "or#=
Rversion version-infor#ation
in which version6information is any signi"icant in"or#ation you see "it to include. :hen the 6version "lag is %laced on the 0avadoc co##and line, the version in"or#ation will be called out s%ecially in the generated (TMD docu#entation. RFSURFSTIJLT+(6PTE5KTIMMLU
132
Iauthor
This is o" the "or#=
Rauthor author-infor#ation
in which a*thor6information is, %resu#ably, your na#e, but it could also include your e#ail address or any other a%%ro%riate in"or#ation. :hen the 6a*thor "lag is %laced on the 0avadoc co##and line, the author in"or#ation will be called out s%ecially in the generated (TMD docu#entation. RFSURFSTIJLT+(6PTE5KTIMM?U /ou can have #ulti%le author tags "or a list o" authors, but they #ust be %laced consecutively. 6ll the author in"or#ation will be lu#%ed together into a single %aragra%h in the generated (TMD. RFSURF STIJLT+(6PTE5KTIMMHU
Isince
This tag allows you to indicate the version o" this code that began using a %articular "eature. /ou ll see it a%%earing in the (TMD Java docu#entation to indicate what version o" the J7> is used. RFSURF STIJLT+(6PTE5KTIMM3U
I.aram
This is o" the "or#=
133
in which parameter6name is the identi"ier in the %ara#eter list, and 'escription is te&t that can continue on subseAuent lines. The descri%tion is considered "inished when a new docu#entation tag is encountered. /ou can have any nu#ber o" these, %resu#ably one "or each %ara#eter. RFSURFSTIJLT+(6PTE5KTIMM2U
Ireturn
This is o" the "or#=
Rreturn description
in which 'escription gives you the #eaning o" the return value. It can continue on subseAuent lines. RFSURFSTIJLT+(6PTE5KTIMK@U
Ithrows
E&ce%tions will be de#onstrated in +ha%ter M@, but brie"ly they are ob0ects that can be !thrown$ out o" a #ethod i" that #ethod "ails. 6lthough only one e&ce%tion ob0ect can e#erge when you call a #ethod, a %articular #ethod #ight %roduce any nu#ber o" di""erent ty%es o" e&ce%tions, all o" which need descri%tions. So the "or# "or the e&ce%tion tag is=
Ide.recated
This is used to tag "eatures that were su%erseded by an i#%roved "eature. The de%recated tag is a suggestion that you no longer use this %articular "eature, since so#eti#e in the "uture it is likely to be re#oved. 6 #ethod that is #arked 9'eprecate' causes the co#%iler to issue a warning i" it is used. RFSURFSTIJLT+(6PTE5KTIMKKU
134
Documentation e0am.le
(ere is the "irst Java %rogra# again, this ti#e with docu#entation co##ents added=
//3 c' 3MelloDate.Hava i#"ort Hava.util.B< /BB The first Thinking in Java e6a#"le "rogra#. B Dis"lays a string an! to!ay2s !ate. B Rauthor Bruce Eckel B Rauthor :::.BruceEckel.co# B Rversion .' B/ "ublic class MelloDate @ /BB %ole entry "oint to class D a""lication B R"ara# args array of string argu#ents B Rreturn &o return value B Re6ce"tion e6ce"tions &o e6ce"tions thro:n B/ "ublic static voi! #ain-%tringNO args. @ %yste#.out."rintln-8Mello, it2s3 8.< %yste#.out."rintln-ne: Date-..< A A ///3>
The "irst line o" the "ile uses #y own techniAue o" %utting a [< as a s%ecial #arker "or the co##ent line containing the source "ile na#e. That line contains the %ath in"or#ation to the "ile *in this case, cDI indicates +ha%ter K, "ollowed by the "ile na#e @. The last line also "inishes with a co##ent, and this one indicates the end o" the source code listing, which allows it to be auto#atically e&tracted "ro# the te&t o" this book and checked with a co#%iler. RFSURFSTIJLT+(6PTE5KTIMKLU
@ 6 tool that I created using Python *see www.Python.org, uses this in"or#ation to e&tract the code "iles, %ut the# in a%%ro%riate subdirectories, and create #ake"iles.
135
Coding st:le
The uno""icial standard in Java is to ca%itali1e the "irst letter o" a class na#e. I" the class na#e consists o" several words, they are run together *that is, you don t use underscores to se%arate the na#es,, and the "irst letter o" each e#bedded word is ca%itali1ed, such as= RFSURF STIJLT+(6PTE5KTIMK?U
1ummar:
In this cha%ter you have seen enough o" Java %rogra##ing to understand how to write a si#%le %rogra#, and you have gotten an overview o" the language and so#e o" its basic ideas. (owever, the e&a#%les so "ar have all been o" the "or# !do this, then do that, then do so#ething else.$ :hat i" you want the %rogra# to #ake choices, such as !i" the result o" doing this is red, do that; i" not, then do so#ething else$O The su%%ort in Java
137
"or this "unda#ental %rogra##ing activity will be covered in the ne&t cha%ter. RFSURFSTIJLT+(6PTE5KTIMKIU
/0ercises
Solutions to selected e&ercises can be "ound in the electronic docu#entThe Thinking in Java "nnotated Solution @uide, available "or a s#all "ee "ro# ,,,'0ruceEckel'com.
*) Turn the
ata.nly code "rag#ents into a %rogra# that co#%iles and runs. RFSURFSTIJLT+(6PTE5KTIMLMU ata.nly are
assigned to and %rinted in mainA B. RFSURF STIJLT+(6PTE5KTIMLKU
138
6) Eind the code "or the second version o" Hello ate!8ava, which is
the si#%le co##ent docu#entation e&a#%le. E&ecute 8ava'oc on the "ile and view the results with your :eb browser. RFSURF STIJLT+(6PTE5KTIMLGU
(7) Turn 'ocTest into a "ile that co#%iles and then run it through
8ava'oc. Veri"y the resulting docu#entation with your :eb
browser. RFSURFSTIJLT+(6PTE5KTIMLIU
(() 6dd an (TMD list o" ite#s to the docu#entation in E&ercise M@.
RFSURFSTIJLT+(6PTE5KTIML2U
13:
13;
generate the side e""ect, but you should kee% in #ind that the value %roduced is available "or your use 0ust as in o%erators without side e""ects. RFSURFSTIJLT+(6PTE5LTI?U 6l#ost all o%erators work only with %ri#itives. The e&ce%tions are GP , [PP and [=P , which work with all ob0ects *and are a %oint o" con"usion "or ob0ects,. In addition, the )tring class su%%orts [L and [LP . RFSURF STIJLT+(6PTE5LTIHU
recedence
)%erator %recedence de"ines how an e&%ression evaluates when several o%erators are %resent. Java has s%eci"ic rules that deter#ine the order o" evaluation. The easiest one to re#e#ber is that #ulti%lication and division ha%%en be"ore addition and subtraction. Progra##ers o"ten "orget the other %recedence rules, so you should use %arentheses to #ake the order o" evaluation e&%licit. Eor e&a#%le= RFSURF STIJLT+(6PTE5LTI3U
0 a ? 9 6 K ; y -
K TU<
has a very di""erent #eaning "ro# the sa#e state#ent with a %articular grou%ing o" %arentheses= RFSURFSTIJLT+(6PTE5LTIGU
0 a ? 9 6 K -; y -
./-
K TU.<
Assignment
6ssign#ent is %er"or#ed with the o%erator \. It #eans !take the value o" the right'hand side *o"ten called the rvalue, and co%y it into the le"t'hand side *o"ten called the lvalue,. 6n rvalue is any constant, variable or e&%ression that can %roduce a value, but an lvalue #ust be a distinct, na#ed variable. *That is, there #ust be a %hysical s%ace to store a value., Eor instance, you can assign a constant value to a variable * A P QR,, but you cannot assign anything to constant value9it cannot be an lvalue. */ou can t say Q P AR., RFSURFSTIJLT+(6PTE5LTIIU 6ssign#ent o" %ri#itives is Auite straight"orward. Since the %ri#itive holds the actual value and not a re"erence to an ob0ect, when you assign %ri#itives you co%y the contents "ro# one %lace to another. Eor e&a#%le,
14=
Thinking in Java
,,,'0ruceEckel'com
i" you say A P 2 "or %ri#itives, then the contents o" 2 are co%ied into A. I" you then go on to #odi"y A, 2 is naturally una""ected by this #odi"ication. 6s a %rogra##er, this is what you ve co#e to e&%ect "or #ost situations. RFSURFSTIJLT+(6PTE5LTI2U :hen you assign ob0ects, however, things change. :henever you #ani%ulate an ob0ect, what you re #ani%ulating is the re"erence, so when you assign !"ro# one ob0ect to another$ you re actually co%ying a re"erence "ro# one %lace to another. This #eans that i" you say - P "or ob0ects, you end u% with both - and %ointing to the ob0ect that, originally, only %ointed to. The "ollowing e&a#%le will de#onstrate this. RFSURFSTIJLT+(6PTE5LTIM@U (ere s the e&a#%le=
//3 c')30ssign#ent.Hava // 0ssign#ent :ith obHects is a bit tricky. class &u#ber @ int i< A "ublic class 0ssign#ent @ "ublic static voi! #ain-%tringNO &u#ber n( ? ne: &u#ber-.< &u#ber n ? ne: &u#ber-.< n(.i ? C< n .i ? I*< %yste#.out."rintln-8(3 n(.i3 8 8, n .i3 8 K n .i.< n( ? n < %yste#.out."rintln-8 3 n(.i3 8 8, n .i3 8 K n .i.< n(.i ? *< %yste#.out."rintln-8)3 n(.i3 8 8, n .i3 8 K n .i.< A A ///3> args. @
The /*mber class is si#%le, and two instances o" it * n> and nI, are created within mainA B. The i value within each /*mber is given a
141
di""erent value, and then nI is assigned to n>, and n> is changed. In #any %rogra##ing languages you would e&%ect n> and nI to be inde%endent at all ti#es, but because you ve assigned a re"erence here s the out%ut you ll see= RFSURFSTIJLT+(6PTE5LTIMMU
n(.i ? n .i<
This retains the two se%arate ob0ects instead o" tossing one and tying n> and nI to the sa#e ob0ect, but you ll soon reali1e that #ani%ulating the "ields within ob0ects is #essy and goes against good ob0ect'oriented design %rinci%les. This is a nontrivial to%ic, so it is le"t "or 6%%endi& 6, which is devoted to aliasing. In the #eanti#e, you should kee% in #ind that assign#ent "or ob0ects can add sur%rises. RFSURF STIJLT+(6PTE5LTIM?U
//3 c')3PassGbHect.Hava // Passing obHects to #etho!s #ay not be :hat // you2re use! to. class Letter @ char c< A
142
Thinking in Java
,,,'0ruceEckel'com
"ublic class PassGbHect @ static voi! f-Letter y. @ y.c ? 2U2< A "ublic static voi! #ain-%tringNO args. @ Letter 6 ? ne: Letter-.< 6.c ? 2a2< %yste#.out."rintln-8(3 6.c3 8 K 6.c.< f-6.< %yste#.out."rintln-8 3 6.c3 8 K 6.c.< A A ///3>
In #any %rogra##ing languages, the #ethod fA B would a%%ear to be #aking a co%y o" its argu#ent +etter y inside the sco%e o" the #ethod. But once again a re"erence is being %assed so the line RFSURF STIJLT+(6PTE5LTIMHU
y.c ? 2U2<
is actually changing the ob0ect outside o" fA B. The out%ut shows this= RF SURFSTIJLT+(6PTE5LTIM3U
(3 6.c3 a 3 6.c3 U
6liasing and its solution is a co#%le& issue and, although you #ust wait until 6%%endi& 6 "or all the answers, you should be aware o" it at this %oint so you can watch "or %it"alls. RFSURFSTIJLT+(6PTE5LTIMGU
Mathematical o.erators
The basic #athe#atical o%erators are the sa#e as the ones available in #ost %rogra##ing languages= addition * L,, subtraction * 6,, division * 5,, #ulti%lication * K, and #odulus * S, which %roduces the re#ainder "ro# integer division,. Integer division truncates, rather than rounds, the result. RFSURFSTIJLT+(6PTE5LTIMIU Java also uses a shorthand notation to %er"or# an o%eration and an assign#ent at the sa#e ti#e. This is denoted by an o%erator "ollowed by an eAual sign, and is consistent with all the o%erators in the language
143
*whenever it #akes sense,. Eor e&a#%le, to add ? to the variable 4 and assign the result to 4, use= 4 LP Q. RFSURFSTIJLT+(6PTE5LTIM2U This e&a#%le shows the use o" the #athe#atical o%erators=
//3 c')3JathG"s.Hava // De#onstrates the #athe#atical o"erators. i#"ort Hava.util.B< "ublic class JathG"s @ // Create a shorthan! to save ty"ing3 static voi! "rt-%tring s. @ %yste#.out."rintln-s.< A // shorthan! to "rint a string an! an int3 static voi! "$nt-%tring s, int i. @ "rt-s K 8 ? 8 K i.< A // shorthan! to "rint a string an! a float3 static voi! "Llt-%tring s, float f. @ "rt-s K 8 ? 8 K f.< A "ublic static voi! #ain-%tringNO args. @ // Create a ran!o# nu#ber generator, // see!s :ith current ti#e by !efault3 5an!o# ran! ? ne: 5an!o#-.< int i, H, k< // 2V2 li#its #a6i#u# value to CC3 H ? ran!.ne6t$nt-. V (''< k ? ran!.ne6t$nt-. V (''< "$nt-8H8,H.< "$nt-8k8,k.< i ? H K k< "$nt-8H K k8, i.< i ? H - k< "$nt-8H - k8, i.< i ? k / H< "$nt-8k / H8, i.< i ? k B H< "$nt-8k B H8, i.< i ? k V H< "$nt-8k V H8, i.< H V? k< "$nt-8H V? k8, H.< // Lloating-"oint nu#ber tests3 float u,v,:< // a""lies to !oubles, too v ? ran!.ne6tLloat-.< : ? ran!.ne6tLloat-.<
144
Thinking in Java
,,,'0ruceEckel'com
"Llt-8v8, v.< "Llt-8:8, :.< u ? v K :< "Llt-8v K :8, u.< u ? v - :< "Llt-8v - :8, u.< u ? v B :< "Llt-8v B :8, u.< u ? v / :< "Llt-8v / :8, u.< // the follo:ing also :orks for // char, byte, short, int, long, // an! !ouble3 u K? v< "Llt-8u K? v8, u.< u -? v< "Llt-8u -? v8, u.< u B? v< "Llt-8u B? v8, u.< u /? v< "Llt-8u /? v8, u.< A A ///3>
The "irst thing you will see are so#e shorthand #ethods "or %rinting= the
prtA B #ethod %rints a )tring, the pIntA B %rints a )tring "ollowed by an int and the pFltA B %rints a )tring "ollowed by a float. )" course, they all ulti#ately end u% using )ystem!o*t!printlnA B. RFSURF
STIJLT+(6PTE5LTIK@U To generate nu#bers, the %rogra# "irst creates a $an'om ob0ect. Because no argu#ents are %assed during creation, Java uses the current ti#e as a seed "or the rando# nu#ber generator. The %rogra# generates a nu#ber o" di""erent ty%es o" rando# nu#bers with the $an'om ob0ect si#%ly by calling di""erent the #ethods= ne4tIntA B, ne4t+ongA B, and ne4tFloatA B *you can also call ne4t+ongA B or ne4t o*bleA B,. RF SURFSTIJLT+(6PTE5LTIKMU The #odulus o%erator, when used with the result o" the rando# nu#ber generator, li#its the result to an u%%er bound o" the o%erand #inus one *22 in this case,. RFSURFSTIJLT+(6PTE5LTIKKU
6 ? -a<
145
has an obvious #eaning. The co#%iler is able to "igure out= RFSURF STIJLT+(6PTE5LTIK?U
6 ? a B -b<
but the reader #ight get con"used, so it is clearer to say= RFSURF STIJLT+(6PTE5LTIKHU
6 ? a B --b.<
The unary #inus %roduces the negative o" the value. 4nary %lus %rovides sy##etry with unary #inus, although it doesn t have any e""ect. RFSURF STIJLT+(6PTE5LTIK3U
//3 c')30uto$nc.Hava
147
Thinking in Java
,,,'0ruceEckel'com
// De#onstrates the KK an! -- o"erators. "ublic class 0uto$nc @ "ublic static voi! #ain-%tringNO args. @ int i ? (< "rt-8i 3 8 K i.< "rt-8KKi 3 8 K KKi.< // Pre-incre#ent "rt-8iKK 3 8 K iKK.< // Post-incre#ent "rt-8i 3 8 K i.< "rt-8--i 3 8 K --i.< // Pre-!ecre#ent "rt-8i-- 3 8 K i--.< // Post-!ecre#ent "rt-8i 3 8 K i.< A static voi! "rt-%tring s. @ %yste#.out."rintln-s.< A A ///3>
The out%ut "or this %rogra# is= RFSURFSTIJLT+(6PTE5LTIL@U
( 3 3 ) 3 3 (
/ou can see that "or the %re"i& "or# you get the value a"ter the o%eration has been %er"or#ed, but with the %ost"i& "or# you get the value be"ore the o%eration is %er"or#ed. These are the only o%erators *other than those involving assign#ent, that have side e""ects. *That is, they change the o%erand rather than using 0ust its value., RFSURF STIJLT+(6PTE5LTILMU The incre#ent o%erator is one e&%lanation "or the na#e +<<, i#%lying !one ste% beyond +.$ In an early Java s%eech, Bill Joy *one o" the creators,, said that !Java\+<<''$ *+ %lus %lus #inus #inus,, suggesting that Java is +<< with the unnecessary hard %arts re#oved and there"ore a #uch si#%ler language. 6s you %rogress in this book you ll see that #any
148
%arts are si#%ler, and yet Java isn t that #uch easier than +<<. RFSURF STIJLT+(6PTE5LTILKU
$elational o.erators
5elational o%erators generate a boolean result. They evaluate the relationshi% between the values o" the o%erands. 6 relational e&%ression %roduces tr*e i" the relationshi% is true, and false i" the relationshi% is untrue. The relational o%erators are less than *R,, greater than *U,, less than or eAual to *R\,, greater than or eAual to *U\,, eAuivalent *\\, and not eAuivalent *.\,. EAuivalence and noneAuivalence work s with all built' in data ty%es, but the other co#%arisons won t work with ty%e boolean. RFSURFSTIJLT+(6PTE5LTILLU
//3 c')3E=uivalence.Hava "ublic class E=uivalence @ "ublic static voi! #ain-%tringNO args. @ $nteger n( ? ne: $nteger-I*.< $nteger n ? ne: $nteger-I*.< %yste#.out."rintln-n( ?? n .< %yste#.out."rintln-n( 4? n .< A A ///3>
The e&%ression )ystem!o*t!printlnAn> PP nIB will %rint the result o" the boolean co#%arison within it. Surely the out%ut should be tr*e and then false, since both Integer ob0ects are the sa#e. But while the contents o" the ob0ects are the sa#e, the re"erences are not the sa#e and the o%erators PP and =P co#%are ob0ect re"erences. So the out%ut is actually false and then tr*e. Caturally, this sur%rises %eo%le at "irst. RF SURFSTIJLT+(6PTE5LTILHU
14:
Thinking in Java
,,,'0ruceEckel'com
:hat i" you want to co#%are the actual contents o" an ob0ect "or eAuivalenceO /ou #ust use the s%ecial #ethod eC*alsA B that e&ists "or all ob0ects *not %ri#itives, which work "ine with PP and =P,. (ere s how it s used= RFSURFSTIJLT+(6PTE5LTIL3U
//3 c')3E=ualsJetho!.Hava "ublic class E=ualsJetho! @ "ublic static voi! #ain-%tringNO args. @ $nteger n( ? ne: $nteger-I*.< $nteger n ? ne: $nteger-I*.< %yste#.out."rintln-n(.e=uals-n ..< A A ///3>
The result will be tr*e, as you would e&%ect. 6h, but it s not as si#%le as that. I" you create your own class, like this= RFSURF STIJLT+(6PTE5LTILGU
//3 c')3E=ualsJetho! .Hava class Walue @ int i< A "ublic class E=ualsJetho! @ "ublic static voi! #ain-%tringNO args. @ Walue v( ? ne: Walue-.< Walue v ? ne: Walue-.< v(.i ? v .i ? (''< %yste#.out."rintln-v(.e=uals-v ..< A A ///3>
you re back to sAuare one= the result is false. This is because the de"ault behavior o" eC*alsA B is to co#%are re"erences. So unless you override eC*alsA B in your new class you won t get the desired behavior. 4n"ortunately, you won t learn about overriding until +ha%ter G, but being aware o" the way eC*alsA B behaves #ight save you so#e grie" in the #eanti#e. RFSURFSTIJLT+(6PTE5LTILIU
14;
Most o" the Java library classes i#%le#ent eC*alsA B so that it co#%ares the contents o" ob0ects instead o" their re"erences. RFSURF STIJLT+(6PTE5LTIL2U
&ogical o.erators
Each o" The the logical o%erators 6C7 *NN,, )5 *]], and C)T *., %roduce s a boolean value o" tr*e or false based on the logical relationshi% o" its argu#ents. This e&a#%le uses the relational and logical o%erators= RFSURFSTIJLT+(6PTE5LTI?@U //3 c')3Bool.Hava // 5elational an! logical o"erators. i#"ort Hava.util.B< "ublic class Bool @ "ublic static voi! #ain-%tringNO args. @ 5an!o# ran! ? ne: 5an!o#-.< int i ? ran!.ne6t$nt-. V (''< int H ? ran!.ne6t$nt-. V (''< "rt-8i ? 8 K i.< "rt-8H ? 8 K H.< "rt-8i Q H is 8 K -i Q H..< "rt-8i P H is 8 K -i P H..< "rt-8i Q? H is 8 K -i Q? H..< "rt-8i P? H is 8 K -i P? H..< "rt-8i ?? H is 8 K -i ?? H..< "rt-8i 4? H is 8 K -i 4? H..< // Treating an int as a boolean is // not legal Java //4 "rt-8i DD H is 8 K -i DD H..< //4 "rt-8i XX H is 8 K -i XX H..< //4 "rt-84i is 8 K 4i.< "rt-8-i P ('. DD -H P ('. is 8 K --i P ('. DD -H P ('.. .< "rt-8-i P ('. XX -H P ('. is 8 K --i P ('. XX -H P ('.. .< A
15=
Thinking in Java
,,,'0ruceEckel'com
i ? 1, H ? I i Q H is true i P H is false i Q? H is true i P? H is false i ?? H is false i 4? H is true -i P ('. DD -H P ('. is false -i P ('. XX -H P ('. is true
Cote that a boolean value is auto#atically converted to an a%%ro%riate te&t "or# i" it s used where a )tring is e&%ected. RFSURF STIJLT+(6PTE5LTI?KU /ou can re%lace the de"inition "or int in the above %rogra# with any other %ri#itive data ty%e e&ce%t boolean. Be aware, however, that the co#%arison o" "loating'%oint nu#bers is very strict. 6 nu#ber that is the tiniest "raction di""erent "ro# another nu#ber is still !not eAual.$ 6 nu#ber that is the tiniest bit above 1ero is still non1ero. RFSURF STIJLT+(6PTE5LTI?LU
1hort@circuiting
:hen dealing with logical o%erators you run into a %heno#enon called !short circuiting.$ This #eans that the e&%ression will be evaluated only until the truth or "alsehood o" the entire e&%ression can be una#biguously deter#ined. 6s a result, all the %arts o" a logical
151
//3 c')3%hortCircuit.Hava // De#onstrates short-circuiting behavior. // :ith logical o"erators. "ublic class %hortCircuit @ static boolean test(-int val. @ %yste#.out."rintln-8test(-8 K val K 8.8.< %yste#.out."rintln-8result3 8 K -val P (..< return val P (< A static boolean test -int val. @ %yste#.out."rintln-8test -8 K val K 8.8.< %yste#.out."rintln-8result3 8 K -val P ..< return val P < A static boolean test)-int val. @ %yste#.out."rintln-8test)-8 K val K 8.8.< %yste#.out."rintln-8result3 8 K -val P )..< return val P )< A "ublic static voi! #ain-%tringNO args. @ if-test(-'. DD test - . DD test)- .. %yste#.out."rintln-8e6"ression is true8.< else %yste#.out."rintln-8e6"ression is false8.< A A ///3>
Each test %er"or#s a co#%arison against the argu#ent and returns true or "alse. It also %rints in"or#ation to show you that it s being called. The tests are used in the e&%ression= RFSURFSTIJLT+(6PTE5LTI??U
152
Thinking in Java
,,,'0ruceEckel'com
;itwise o.erators
The bitwise o%erators allow you to #ani%ulate individual bits in an integral %ri#itive data ty%e. Bitwise o%erators %er"or# boolean algebra on the corres%onding bits in the two argu#ents to %roduce the result. RF SURFSTIJLT+(6PTE5LTI?GU The bitwise o%erators co#e "ro# + s low'level orientation; you were o"ten #ani%ulating hardware directly and had to set the bits in hardware registers. Java was originally designed to be e#bedded in TV set'to% bo&es, so this low'level orientation still #ade sense. (owever, you %robably won t use the bitwise o%erators #uch. RFSURF STIJLT+(6PTE5LTI?IU The bitwise 6C7 o%erator * ,, %roduces a one in the out%ut bit i" both in%ut bits are one; otherwise it %roduces a 1ero. The bitwise )5 o%erator * T, %roduces a one in the out%ut bit i" either in%ut bit is a one and %roduces a 1ero only i" both in%ut bits are 1ero. The bitwise EZ+D4SIVE )5, or Z)5 * U,, %roduces a one in the out%ut bit i" one or the other in%ut bit is a one, but not both. The bitwise C)T * V, also called the ones com lement o%erator, is a unary o%erator; it takes only one argu#ent. *6ll other bitwise o%erators are binary o%erators., Bitwise C)T %roduces the o%%osite o" the in%ut bit9a one i" the in%ut bit is 1ero, a 1ero i" the in%ut bit is one. RFSURFSTIJLT+(6PTE5LTI?2U The bitwise o%erators and logical o%erators use the sa#e characters, so it is hel%"ul to have a #ne#onic device to hel% you re#e#ber the
153
#eanings= since bits are !s#all,$ there is only one character in the bitwise o%erators. RFSURFSTIJLT+(6PTE5LTIH@U Bitwise o%erators can be co#bined with the P sign to unite the o%eration and assign#ent= ,P, TP and UP are all legiti#ate. *Since V is a unary o%erator it cannot be co#bined with the P sign., RFSURF STIJLT+(6PTE5LTIHMU The boolean ty%e is treated as a one'bit value so it is so#ewhat di""erent. /ou can %er"or# a bitwise 6C7, )5 and Z)5, but you can t %er"or# a bitwise C)T *%resu#ably to %revent con"usion with the logical C)T,. Eor booleans the bitwise o%erators have the sa#e e""ect as the logical o%erators e&ce%t that they do not short circuit. 6lso, bitwise o%erations on booleans include an Z)5 logical o%erator that is not included under the list o" !logical$ o%erators. /ou re %revented "ro# using booleans in shi"t e&%ressions, which is described ne&t. RFSURF STIJLT+(6PTE5LTIHKU
1hift o.erators
The shi"t o%erators also #ani%ulate bits. They can be used solely with %ri#itive, integral ty%es. The le"t'shi"t o%erator * NN, %roduces the o%erand to the le"t o" the o%erator shi"ted to the le"t by the nu#ber o" bits s%eci"ied a"ter the o%erator *inserting 1eroes at the lower'order bits,. The signed right'shi"t o%erator * OO, %roduces the o%erand to the le"t o" the o%erator shi"ted to the right by the nu#ber o" bits s%eci"ied a"ter the o%erator. The signed right shi"t OO uses sign e*tension= i" the value is %ositive, 1eroes are inserted at the higher'order bits; i" the value is negative, ones are inserted at the higher'order bits. Java has also added the unsigned right shi"t OOO, which uses ?ero e*tension= regardless o" the sign, 1eroes are inserted at the higher'order bits. This o%erator does not e&ist in + or +<<. F/GHF/GTIJ3IC."PTE-3II53H I" you shi"t a char, byte, or short, it will be %ro#oted to int be"ore the shi"t takes %lace, and the result will be an int. )nly the "ive low'order bits o" the right'hand side will be used. This %revents you "ro# shi"ting #ore than the nu#ber o" bits in an int. I" you re o%erating on a long, you ll get a long result. )nly the si& low'order bits o" the right'hand side will be
154
Thinking in Java
,,,'0ruceEckel'com
used so you can t shi"t #ore than the nu#ber o" bits in a long. RFSURF STIJLT+(6PTE5LTIH?U Shi"ts can be co#bined with the eAual sign * NNP or OOP or OOOP,. The lvalue is re%laced by the lvalue shi"ted by the rvalue. There is a %roble#, however, with the unsigned right shi"t co#bined with assign#ent. I" you use it with byte or short you don t get the correct results. Instead, these are %ro#oted to int and right shi"ted, but then truncated as they are assigned back into their variables, so you get 6> in those cases. The "ollowing e&a#%le de#onstrates this= RFSURFSTIJLT+(6PTE5LTIHHU
//3 c')3Y5%hift.Hava // Test of unsigne! right shift. "ublic class Y5%hift @ "ublic static voi! #ain-%tringNO args. @ int i ? -(< i QQQ? ('< %yste#.out."rintln-i.< long l ? -(< l QQQ? ('< %yste#.out."rintln-l.< short s ? -(< s QQQ? ('< %yste#.out."rintln-s.< byte b ? -(< b QQQ? ('< %yste#.out."rintln-b.< b ? -(< %yste#.out."rintln-bQQQ('.< A A ///3>
In the last line, the resulting value is not assigned back into b, but is %rinted directly and so the correct behavior occurs. RFSURF STIJLT+(6PTE5LTIH3U (ere s an e&a#%le that de#onstrates the use o" all the o%erators involving bits=
155
i#"ort Hava.util.B< "ublic class BitJani"ulation @ "ublic static voi! #ain-%tringNO args. @ 5an!o# ran! ? ne: 5an!o#-.< int i ? ran!.ne6t$nt-.< int H ? ran!.ne6t$nt-.< "Bin$nt-8-(8, -(.< "Bin$nt-8K(8, K(.< int #a6"os ? (I*I1)+I*< "Bin$nt-8#a6"os8, #a6"os.< int #a6neg ? - (I*I1)+I1< "Bin$nt-8#a6neg8, #a6neg.< "Bin$nt-8i8, i.< "Bin$nt-8>i8, >i.< "Bin$nt-8-i8, -i.< "Bin$nt-8H8, H.< "Bin$nt-8i D H8, i D H.< "Bin$nt-8i X H8, i X H.< "Bin$nt-8i Z H8, i Z H.< "Bin$nt-8i PP ,8, i PP ,.< "Bin$nt-8i QQ ,8, i QQ ,.< "Bin$nt-8->i. QQ ,8, ->i. QQ ,.< "Bin$nt-8i QQQ ,8, i QQQ ,.< "Bin$nt-8->i. QQQ ,8, ->i. QQQ ,.< long l ? ran!.ne6tLong-.< long # ? ran!.ne6tLong-.< "BinLong-8-(L8, -(L.< "BinLong-8K(L8, K(L.< long ll ? C ))* ')+1,I**,1'*L< "BinLong-8#a6"os8, ll.< long lln ? -C ))* ')+1,I**,1'1L< "BinLong-8#a6neg8, lln.< "BinLong-8l8, l.< "BinLong-8>l8, >l.< "BinLong-8-l8, -l.< "BinLong-8#8, #.< "BinLong-8l D #8, l D #.< "BinLong-8l X #8, l X #.< "BinLong-8l Z #8, l Z #.<
157
Thinking in Java
,,,'0ruceEckel'com
"BinLong-8l PP ,8, l PP ,.< "BinLong-8l QQ ,8, l QQ ,.< "BinLong-8->l. QQ ,8, ->l. QQ ,.< "BinLong-8l QQQ ,8, l QQQ ,.< "BinLong-8->l. QQQ ,8, ->l. QQQ ,.< A static voi! "Bin$nt-%tring s, int i. @ %yste#.out."rintlns K 8, int3 8 K i K 8, binary3 8.< %yste#.out."rint-8 8.< for-int H ? )(< H Q?'< H--. if---( PP H. D i. 4? '. %yste#.out."rint-8(8.< else %yste#.out."rint-8'8.< %yste#.out."rintln-.< A static voi! "BinLong-%tring s, long l. @ %yste#.out."rintlns K 8, long3 8 K l K 8, binary3 8.< %yste#.out."rint-8 8.< for-int i ? +)< i Q?'< i--. if---(L PP i. D l. 4? '. %yste#.out."rint-8(8.< else %yste#.out."rint-8'8.< %yste#.out."rintln-.< A A ///3>
The two #ethods at the end, p2inIntA B and p2in+ongA B take an int or a long, res%ectively, and %rint it out in binary "or#at along with a descri%tive string. /ou can ignore the i#%le#entation o" these "or now. RFSURFSTIJLT+(6PTE5LTIHGU /ou ll note the use o" )ystem!o*t!printA B instead o" )ystem!o*t! printlnA B. The printA B #ethod does not e#it a new line, so it allows you to out%ut a line in %ieces. RFSURFSTIJLT+(6PTE5LTIHIU 6s well as de#onstrating the e""ect o" all the bitwise o%erators "or int and long, this e&a#%le also shows the #ini#u#, #a&i#u#, <M and 'M values
158
"or int and long so you can see what they look like. Cote that the high bit re%resents the sign= @ #eans %ositive and M #eans negative. The out%ut "or the int %ortion looks like this=
-(, int3 -(, binary3 (((((((((((((((((((((((((((((((( K(, int3 (, binary3 '''''''''''''''''''''''''''''''( #a6"os, int3 (I*I1)+I*, binary3 '((((((((((((((((((((((((((((((( #a6neg, int3 - (I*I1)+I1, binary3 (''''''''''''''''''''''''''''''' i, int3 ,C'1(*(+, binary3 ''''''(((''''('(('''''(((((('('' >i, int3 -,C'1(*(*, binary3 (((((('''(((('(''(((((''''''('(( -i, int3 -,C'1(*(+, binary3 (((((('''(((('(''(((((''''''(('' H, int3 (C11,'C,+, binary3 ''''('(((('(('('''(((''(('''(('' i D H, int3 ,1* '+II, binary3 ''''''(((''''''''''''''((''''('' i X H, int3 (CC ( ' 1, binary3 ''''('(((('(((((('((('(((((((('' i Z H, int3 (I'IC()1I, binary3 ''''(''''('(((((('((('(''((((''' i PP ,, int3 (1C'+(IC( , binary3 '(((''''('(('''''(((((('(''''''' i QQ ,, int3 (1I+)'), binary3 '''''''''''(((''''('(('''''((((( ->i. QQ ,, int3 -(1I+)'I, binary3 ((((((((((('''(((('(''(((((''''' i QQQ ,, int3 (1I+)'), binary3 '''''''''''(((''''('(('''''((((( ->i. QQQ ,, int3 () )*(I I, binary3 '''''(((((('''(((('(''((((('''''
The binary re%resentation o" the nu#bers is re"erred to as signed t,oJs com lement. RFSURFSTIJLT+(6PTE5LTIH2U
15:
Thinking in Java
,,,'0ruceEckel'com
15;
o%erator Y it s generally warranted when you re setting a variable to one o" two values. RFSURFSTIJLT+(6PTE5LTI3HU
String o.erator F
There s one s%ecial usage o" an o%erator in Java= the L o%erator can be used to concatenate strings, as you ve already seen. It see#s a natural use o" the L even though it doesn t "it with the traditional way that L is used. This ca%ability see#ed like a good idea in +<<, so o erator overloading was added to +<< to allow the +<< %rogra##er to add #eanings to al#ost any o%erator. 4n"ortunately, o%erator overloading co#bined with so#e o" the other restrictions in +<< turns out to be a "airly co#%licated "eature "or %rogra##ers to design into their classes. 6lthough o%erator overloading would have been #uch si#%ler to i#%le#ent in Java than it was in +<<, this "eature was still considered too co#%le&, so Java %rogra##ers cannot i#%le#ent their own overloaded o%erators as +<< %rogra##ers can. RFSURFSTIJLT+(6PTE5LTI3GU The use o" the )tring L has so#e interesting behavior. I" an e&%ression begins with a )tring, then all o%erands that "ollow #ust be )trings *re#e#ber that the co#%iler will turn a Auoted seAuence o" characters into a )tring,= RFSURFSTIJLT+(6PTE5LTI3IU
%yste#.out."rintln-6 K s%tring.<
Java will turn 4 into a )tring. RFSURFSTIJLT+(6PTE5LTI32U
17=
Thinking in Java
,,,'0ruceEckel'com
:hile-6 ? y. @ // .... A
The %rogra##er was trying to test "or eAuivalence * PP, rather than do an assign#ent. In + and +<< the result o" this assign#ent will always be tr*e i" y is non1ero, and you ll %robably get an in"inite loo%. In Java, the result o" this e&%ression is not a boolean, and the co#%iler e&%ects a boolean and won t convert "ro# an int, so it will conveniently give you a co#%ile'ti#e error and catch the %roble# be"ore you ever try to run the %rogra#. So the %it"all never ha%%ens in Java. *The only ti#e you won t get a co#%ile'ti#e error is when 4 and y are boolean, in which case 4 P y is a legal e&%ression, and in the above case, %robably an error., RFSURF STIJLT+(6PTE5LTIGMU 6 si#ilar %roble# in + and +<< is using bitwise 6C7 and )5 instead o" the logical versions. Bitwise 6C7 and )5 use one o" the characters * , or T, while logical 6C7 and )5 use two * ,, and TT,. Just as with P and PP, it s easy to ty%e 0ust one character instead o" two. In Java, the co#%iler again %revents this because it won t let you cavalierly use one ty%e where it doesn t belong. RFSURFSTIJLT+(6PTE5LTIGKU
Casting o.erators
The word cast is used in the sense o" !casting into a #old.$ Java will auto#atically change one ty%e o" data into another when a%%ro%riate. Eor instance, i" you assign an integral value to a "loating'%oint variable, the co#%iler will auto#atically convert the int to a float. +asting allows you
171
to #ake this ty%e conversion e&%licit, or to "orce it when it wouldn t nor#ally ha%%en. RFSURFSTIJLT+(6PTE5LTIGLU To %er"or# a cast, %ut the desired data ty%e *including all #odi"iers, inside %arentheses to the le"t o" any value. (ere s an e&a#%le=
172
Thinking in Java
,,,'0ruceEckel'com
&iterals
)rdinarily when you insert a literal value into a %rogra# the co#%iler knows e&actly what ty%e to #ake it. So#eti#es, however, the ty%e is a#biguous. :hen this ha%%ens you #ust guide the co#%iler by adding so#e e&tra in"or#ation in the "or# o" characters associated with the literal value. The "ollowing code shows these characters= RFSURF STIJLT+(6PTE5LTIGGU
//3 c')3Literals.Hava "ublic class Literals @ char c ? '6ffff< // #a6 char he6 value byte b ? '6*f< // #a6 byte he6 value short s ? '6*fff< // #a6 short he6 value int i( ? '6 f< // Me6a!eci#al -lo:ercase. int i ? '9 L< // Me6a!eci#al -u""ercase. int i) ? '(**< // Gctal -lea!ing Uero. // Me6 an! Gct also :ork :ith long. long n( ? ''L< // long suffi6 long n ? ''l< // long suffi6 long n) ? ''< //4 long l+- ''.< // not allo:e! float f( ? (< float f ? (L< // float suffi6 float f) ? (f< // float suffi6 float fI ? (e-I,f< // (' to the "o:er float f, ? (eKCf< // float suffi6 !ouble !( ? (!< // !ouble suffi6 !ouble ! ? (D< // !ouble suffi6 !ouble !) ? I*eI*!< // (' to the "o:er A ///3>
(e&adeci#al *base M3,, which works with all the integral data ty%es, is denoted by a leading D4 or DX "ollowed by @92 and a9" either in u%%er or lowercase. I" you try to initiali1e a variable with a value bigger than it can hold *regardless o" the nu#erical "or# o" the value,, the co#%iler will give you an error #essage. Cotice in the above code the #a&i#u# %ossible he&adeci#al values "or char, byte, and short. I" you e&ceed these, the co#%iler will auto#atically #ake the value an int and tell you
173
that you need a narrowing cast "or the assign#ent. /ou ll know you ve ste%%ed over the line. RFSURFSTIJLT+(6PTE5LTIGIU )ctal *base I, is denoted by a leading 1ero in the nu#ber and digits "ro# @'G. There is no literal re%resentation "or binary nu#bers in +, +<< or Java. RFSURFSTIJLT+(6PTE5LTIG2U 6 trailing character a"ter a literal value establishes its ty%e. 4%%er or lowercase + #eans long, u%%er or lowercase F #eans float and u%%er or lowercase #eans 'o*ble. N5WON5WTIJJX-HA#T&$JXIYDO E&%onents use a notation that I ve always "ound rather dis#aying= >!J? e6QZf. In science and engineering, [e re"ers to the base o" natural logarith#s, a%%ro&i#ately K.GMI. *6 #ore %recise 'o*ble value is available in Java as 1ath!&., This is used in e&%onentiation e&%ressions such as M.L2 & e'?G, which #eans M.L2 & K.GMI '?G. (owever, when E)5T56C was invented they decided that e would naturally #ean !ten to the %ower, $ which is an odd decision because E)5T56C was designed "or science and engineering and one would think its designers would be sensitive about introducing such an a#biguity. @ 6t any rate, this custo# was "ollowed in +, +<< and now Java. So i" you re used to thinking in ter#s o" e as the base o" natural logarith#s, you #ust do a #ental translation when you see an e&%ression such as >!J? e6QZf in Java; it #eans M.L2 & M@ '?G. N5WON5WTIJJX-HA#T&$JXIY>O Cote that you don t need to use the trailing character when the co#%iler can "igure out the a%%ro%riate ty%e. :ith RFSURF STIJLT+(6PTE5LTIIKU
long n) ?
''<
@ John >irkha# writes, !I started co#%uting in M23K using E)5T56C II on an IBM M3K@. 6t that ti#e, and throughout the M23@s and into the M2G@s, E)5T56C was an all u%%ercase language. This %robably started because #any o" the early in%ut devices were old telety%e units that used H bit Baudot code, which had no lowercase ca%ability. The [E in the e&%onential notation was also always u%%er case and was never con"used with the natural logarith# base [e , which is always lowercase. The [E si#%ly stood "or e&%onential, which was "or the base o" the nu#ber syste# used9usually M@. 6t the ti#e octal was also widely used by %rogra##ers. 6lthough I never saw it used, i" I had seen an octal nu#ber in e&%onential notation I would have considered it to be base I. The "irst ti#e I re#e#ber seeing an e&%onential using a lowercase [e was in the late M2G@s and I also "ound it con"using. The %roble# arose as lowercase cre%t into E)5T56C, not at its beginning. :e actually had "unctions to use i" you really wanted to use the natural logarith# base, but they were all u%%ercase.$
174
Thinking in Java
,,,'0ruceEckel'com
there s no a#biguity, so an + a"ter the K@@ would be su%er"luous. (owever, with RFSURFSTIJLT+(6PTE5LTIILU
romotion
/ou ll discover that i" you %er"or# any #athe#atical or bitwise o%erations on %ri#itive data ty%es that are s#aller than an int *that is, char, byte, or short,, those values will be %ro#oted to int be"ore %er"or#ing the o%erations, and the resulting value will be o" ty%e int. So i" you want to assign back into the s#aller ty%e, you #ust use a cast. *6nd, since you re assigning back into a s#aller ty%e, you #ight be losing in"or#ation., In general, the largest data ty%e in an e&%ression is the one that deter#ines the si1e o" the result o" that e&%ression; i" you #ulti%ly a float and a 'o*ble, the result will be 'o*ble; i" you add an int and a long, the result will be long. RFSURFSTIJLT+(6PTE5LTIIHU
175
recedence revisited
4%on hearing #e co#%lain about the co#%le&ity o" re#e#bering o%erator %recedence during one o" #y se#inars, a student suggested a #ne#onic that is si#ultaneously a co##entary= !4lcer 6ddicts 5eally Dike + 6 lot.$
1nemon ic
4lcer 6ddicts 5eally Dike + 6 Dot
.perator type
4nary 6rith#etic *and shi"t, 5elational Dogical *and bitwise, +onditional *ternary, 6ssign#ent
)" course, with the shi"t and bitwise o%erators distributed around the table it is not a %er"ect #ne#onic, but "or non'bit o%erations it works.
A com.endium of o.erators
The "ollowing e&a#%le shows which %ri#itive data ty%es can be used with %articular o%erators. Basically, it is the sa#e e&a#%le re%eated over and over, but using di""erent %ri#itive data ty%es. The "ile will co#%ile without error because the lines that would cause errors are co##ented out with a 55=. RFSURFSTIJLT+(6PTE5LTIIIU
//3 c')30llG"s.Hava // Tests all the o"erators on all the // "ri#itive !ata ty"es to sho: :hich // ones are acce"te! by the Java co#"iler. "ublic class 0llG"s @ // To acce"t the results of a boolean test3 voi! f-boolean b. @A voi! boolTest-boolean 6, boolean y. @ // 0rith#etic o"erators3
177
Thinking in Java
,,,'0ruceEckel'com
//4 6 ? 6 B y< //4 6 ? 6 / y< //4 6 ? 6 V y< //4 6 ? 6 K y< //4 6 ? 6 - y< //4 6KK< //4 6--< //4 6 ? Ky< //4 6 ? -y< // 5elational an! logical3 //4 f-6 Q y.< //4 f-6 Q? y.< //4 f-6 P y.< //4 f-6 P? y.< f-6 ?? y.< f-6 4? y.< f-4y.< 6 ? 6 DD y< 6 ? 6 XX y< // Bit:ise o"erators3 //4 6 ? >y< 6 ? 6 D y< 6 ? 6 X y< 6 ? 6 Z y< //4 6 ? 6 PP (< //4 6 ? 6 QQ (< //4 6 ? 6 QQQ (< // Co#"oun! assign#ent3 //4 6 K? y< //4 6 -? y< //4 6 B? y< //4 6 /? y< //4 6 V? y< //4 6 PP? (< //4 6 QQ? (< //4 6 QQQ? (< 6 D? y< 6 Z? y< 6 X? y< // Casting3 //4 char c ? -char.6<
178
byte B ? -byte.6< short s ? -short.6< int i ? -int.6< long l ? -long.6< float f ? -float.6< !ouble ! ? -!ouble.6<
A voi! charTest-char 6, char y. @ // 0rith#etic o"erators3 6 ? -char.-6 B y.< 6 ? -char.-6 / y.< 6 ? -char.-6 V y.< 6 ? -char.-6 K y.< 6 ? -char.-6 - y.< 6KK< 6--< 6 ? -char.Ky< 6 ? -char.-y< // 5elational an! logical3 f-6 Q y.< f-6 Q? y.< f-6 P y.< f-6 P? y.< f-6 ?? y.< f-6 4? y.< //4 f-46.< //4 f-6 DD y.< //4 f-6 XX y.< // Bit:ise o"erators3 6? -char.>y< 6 ? -char.-6 D y.< 6 ? -char.-6 X y.< 6 ? -char.-6 Z y.< 6 ? -char.-6 PP (.< 6 ? -char.-6 QQ (.< 6 ? -char.-6 QQQ (.< // Co#"oun! assign#ent3 6 K? y< 6 -? y< 6 B? y< 6 /? y<
17:
Thinking in Java
,,,'0ruceEckel'com
6 V? y< 6 PP? (< 6 QQ? (< 6 QQQ? (< 6 D? y< 6 Z? y< 6 X? y< // Casting3 //4 boolean b ? -boolean.6< byte B ? -byte.6< short s ? -short.6< int i ? -int.6< long l ? -long.6< float f ? -float.6< !ouble ! ? -!ouble.6< A voi! byteTest-byte 6, byte y. @ // 0rith#etic o"erators3 6 ? -byte.-6B y.< 6 ? -byte.-6 / y.< 6 ? -byte.-6 V y.< 6 ? -byte.-6 K y.< 6 ? -byte.-6 - y.< 6KK< 6--< 6 ? -byte.K y< 6 ? -byte.- y< // 5elational an! logical3 f-6 Q y.< f-6 Q? y.< f-6 P y.< f-6 P? y.< f-6 ?? y.< f-6 4? y.< //4 f-46.< //4 f-6 DD y.< //4 f-6 XX y.< // Bit:ise o"erators3 6 ? -byte.>y< 6 ? -byte.-6 D y.< 6 ? -byte.-6 X y.<
17;
6 ? -byte.-6 Z y.< 6 ? -byte.-6 PP (.< 6 ? -byte.-6 QQ (.< 6 ? -byte.-6 QQQ (.< // Co#"oun! assign#ent3 6 K? y< 6 -? y< 6 B? y< 6 /? y< 6 V? y< 6 PP? (< 6 QQ? (< 6 QQQ? (< 6 D? y< 6 Z? y< 6 X? y< // Casting3 //4 boolean b ? -boolean.6< char c ? -char.6< short s ? -short.6< int i ? -int.6< long l ? -long.6< float f ? -float.6< !ouble ! ? -!ouble.6< A voi! shortTest-short 6, short y. @ // 0rith#etic o"erators3 6 ? -short.-6 B y.< 6 ? -short.-6 / y.< 6 ? -short.-6 V y.< 6 ? -short.-6 K y.< 6 ? -short.-6 - y.< 6KK< 6--< 6 ? -short.Ky< 6 ? -short.-y< // 5elational an! logical3 f-6 Q y.< f-6 Q? y.< f-6 P y.< f-6 P? y.<
18=
Thinking in Java
,,,'0ruceEckel'com
f-6 ?? y.< f-6 4? y.< //4 f-46.< //4 f-6 DD y.< //4 f-6 XX y.< // Bit:ise o"erators3 6 ? -short.>y< 6 ? -short.-6 D y.< 6 ? -short.-6 X y.< 6 ? -short.-6 Z y.< 6 ? -short.-6 PP (.< 6 ? -short.-6 QQ (.< 6 ? -short.-6 QQQ (.< // Co#"oun! assign#ent3 6 K? y< 6 -? y< 6 B? y< 6 /? y< 6 V? y< 6 PP? (< 6 QQ? (< 6 QQQ? (< 6 D? y< 6 Z? y< 6 X? y< // Casting3 //4 boolean b ? -boolean.6< char c ? -char.6< byte B ? -byte.6< int i ? -int.6< long l ? -long.6< float f ? -float.6< !ouble ! ? -!ouble.6< A voi! intTest-int 6, int y. @ // 0rith#etic o"erators3 6 ? 6 B y< 6 ? 6 / y< 6 ? 6 V y< 6 ? 6 K y< 6 ? 6 - y<
181
6KK< 6--< 6 ? Ky< 6 ? -y< // 5elational an! logical3 f-6 Q y.< f-6 Q? y.< f-6 P y.< f-6 P? y.< f-6 ?? y.< f-6 4? y.< //4 f-46.< //4 f-6 DD y.< //4 f-6 XX y.< // Bit:ise o"erators3 6 ? >y< 6 ? 6 D y< 6 ? 6 X y< 6 ? 6 Z y< 6 ? 6 PP (< 6 ? 6 QQ (< 6 ? 6 QQQ (< // Co#"oun! assign#ent3 6 K? y< 6 -? y< 6 B? y< 6 /? y< 6 V? y< 6 PP? (< 6 QQ? (< 6 QQQ? (< 6 D? y< 6 Z? y< 6 X? y< // Casting3 //4 boolean b ? -boolean.6< char c ? -char.6< byte B ? -byte.6< short s ? -short.6< long l ? -long.6< float f ? -float.6<
182
Thinking in Java
,,,'0ruceEckel'com
!ouble ! ? -!ouble.6< A voi! longTest-long 6, long y. @ // 0rith#etic o"erators3 6 ? 6 B y< 6 ? 6 / y< 6 ? 6 V y< 6 ? 6 K y< 6 ? 6 - y< 6KK< 6--< 6 ? Ky< 6 ? -y< // 5elational an! logical3 f-6 Q y.< f-6 Q? y.< f-6 P y.< f-6 P? y.< f-6 ?? y.< f-6 4? y.< //4 f-46.< //4 f-6 DD y.< //4 f-6 XX y.< // Bit:ise o"erators3 6 ? >y< 6 ? 6 D y< 6 ? 6 X y< 6 ? 6 Z y< 6 ? 6 PP (< 6 ? 6 QQ (< 6 ? 6 QQQ (< // Co#"oun! assign#ent3 6 K? y< 6 -? y< 6 B? y< 6 /? y< 6 V? y< 6 PP? (< 6 QQ? (< 6 QQQ? (< 6 D? y<
183
6 Z? y< 6 X? y< // Casting3 //4 boolean b ? -boolean.6< char c ? -char.6< byte B ? -byte.6< short s ? -short.6< int i ? -int.6< float f ? -float.6< !ouble ! ? -!ouble.6< A voi! floatTest-float 6, float y. @ // 0rith#etic o"erators3 6 ? 6 B y< 6 ? 6 / y< 6 ? 6 V y< 6 ? 6 K y< 6 ? 6 - y< 6KK< 6--< 6 ? Ky< 6 ? -y< // 5elational an! logical3 f-6 Q y.< f-6 Q? y.< f-6 P y.< f-6 P? y.< f-6 ?? y.< f-6 4? y.< //4 f-46.< //4 f-6 DD y.< //4 f-6 XX y.< // Bit:ise o"erators3 //4 6 ? >y< //4 6 ? 6 D y< //4 6 ? 6 X y< //4 6 ? 6 Z y< //4 6 ? 6 PP (< //4 6 ? 6 QQ (< //4 6 ? 6 QQQ (< // Co#"oun! assign#ent3
184
Thinking in Java
,,,'0ruceEckel'com
6 K? y< 6 -? y< 6 B? y< 6 /? y< 6 V? y< //4 6 PP? (< //4 6 QQ? (< //4 6 QQQ? (< //4 6 D? y< //4 6 Z? y< //4 6 X? y< // Casting3 //4 boolean b ? -boolean.6< char c ? -char.6< byte B ? -byte.6< short s ? -short.6< int i ? -int.6< long l ? -long.6< !ouble ! ? -!ouble.6< A voi! !oubleTest-!ouble 6, !ouble y. @ // 0rith#etic o"erators3 6 ? 6 B y< 6 ? 6 / y< 6 ? 6 V y< 6 ? 6 K y< 6 ? 6 - y< 6KK< 6--< 6 ? Ky< 6 ? -y< // 5elational an! logical3 f-6 Q y.< f-6 Q? y.< f-6 P y.< f-6 P? y.< f-6 ?? y.< f-6 4? y.< //4 f-46.< //4 f-6 DD y.< //4 f-6 XX y.<
185
// Bit:ise o"erators3 //4 6 ? >y< //4 6 ? 6 D y< //4 6 ? 6 X y< //4 6 ? 6 Z y< //4 6 ? 6 PP (< //4 6 ? 6 QQ (< //4 6 ? 6 QQQ (< // Co#"oun! assign#ent3 6 K? y< 6 -? y< 6 B? y< 6 /? y< 6 V? y< //4 6 PP? (< //4 6 QQ? (< //4 6 QQQ? (< //4 6 D? y< //4 6 Z? y< //4 6 X? y< // Casting3 //4 boolean b ? -boolean.6< char c ? -char.6< byte B ? -byte.6< short s ? -short.6< int i ? -int.6< long l ? -long.6< float f ? -float.6< A A ///3>
Cote that boolean is Auite li#ited. /ou can assign to it the values tr*e and false, and you can test it "or truth or "alsehood, but you cannot add booleans or %er"or# any other ty%e o" o%eration on the#. RFSURF STIJLT+(6PTE5LTII2U In char, byte, and short you can see the e""ect o" %ro#otion with the arith#etic o%erators. Each arith#etic o%eration on any o" those ty%es results in an int result, which #ust be e&%licitly cast back to the original ty%e *a narrowing conversion that #ight lose in"or#ation, to assign back to that ty%e. :ith int values, however, you do not need to cast, because
187
Thinking in Java
,,,'0ruceEckel'com
everything is already an int. 7on t be lulled into thinking everything is sa"e, though. I" you #ulti%ly two ints that are big enough, you ll over"low the result. The "ollowing e&a#%le de#onstrates this= RFSURF STIJLT+(6PTE5LTI2@U
//3 c')3Gverflo:.Hava // %ur"rise4 Java lets you overflo:. "ublic class Gverflo: @ "ublic static voi! #ain-%tringNO args. @ int big ? '6*fffffff< // #a6 int value "rt-8big ? 8 K big.< int bigger ? big B I< "rt-8bigger ? 8 K bigger.< A static voi! "rt-%tring s. @ %yste#.out."rintln-s.< A A ///3>
The out%ut o" this is=
188
/0ecution control
Java uses all o" + s e&ecution control state#ents, so i" you ve %rogra##ed with + or +<< then #ost o" what you see will be "a#iliar. Most %rocedural %rogra##ing languages have so#e kind o" control state#ents, and there is o"ten overla% a#ong languages. In Java, the keywords include if6else, (hile, 'o6(hile, for, and a selection state#ent called s(itch. Java does not, however, su%%ort the #uch'#aligned goto *which can still be the #ost e&%edient way to solve certain ty%es o" %roble#s,. /ou can still do a goto'like 0u#%, but it is #uch #ore constrained than a ty%ical goto. RFSURFSTIJLT+(6PTE5LTI2?U
if@else
The if6else state#ent is %robably the #ost basic way to control %rogra# "low. The else is o%tional, so you can use if in two "or#s=
if(Boolean-e6"ression) state#ent
or
18:
Thinking in Java
,,,'0ruceEckel'com
state#ent
The conditional #ust %roduce a boolean result. The statement #eans either a si#%le state#ent ter#inated by a se#icolon or a co#%ound state#ent, which is a grou% o" si#%le state#ents enclosed in braces. 6ny ti#e the word ! statement$ is used, it always i#%lies that the state#ent can be si#%le or co#%ound. RFSURFSTIJLT+(6PTE5LTI23U 6s an e&a#%le o" if6else, here is a testA B #ethod that will tell you whether a guess is above, below, or eAuivalent to a target nu#ber=
//3 c')3$fElse.Hava "ublic class $fElse @ static int test-int testval, int target. @ int result ? '< if-testval Q target. result ? K(< else if-testval P target. result ? -(< else result ? '< // Jatch return result< A "ublic static voi! #ain-%tringNO args. @ %yste#.out."rintln-test-(', ,..< %yste#.out."rintln-test-,, ('..< %yste#.out."rintln-test-,, ,..< A A ///3> It is conventional to indent the body o" a control "low state#ent so the reader #ight easily deter#ine where it begins and ends.
return
The ret*rn keyword has two %ur%oses= it s%eci"ies what value a #ethod will return *i" it doesn t have a voi' return value, and it causes that value to be returned i##ediately. The testA B #ethod above can be rewritten to take advantage o" this= RFSURFSTIJLT+(6PTE5LTI2GU
18;
static int test-int testval, int target. @ int result ? '< if-testval Q target. return K(< else if-testval P target. return -(< else return '< // Jatch A "ublic static voi! #ain-%tringNO args. @ %yste#.out."rintln-test-(', ,..< %yste#.out."rintln-test-,, ('..< %yste#.out."rintln-test-,, ,..< A A ///3>
There s no need "or else because the #ethod will not continue a"ter e&ecuting a ret*rn. RFSURFSTIJLT+(6PTE5LTI2IU
Iteration
(hile, 'o6(hile and for control loo%ing and are so#eti#es classi"ied as iteration statements. 6 statement re%eats until the controlling 0oolean' e* ression evaluates to "alse. The "or# "or a (hile loo% is while(Boolean-e6"ression) state#ent
The 0oolean/e* ression is evaluated once at the beginning o" the loo% and again be"ore each "urther iteration o" the statement. RFSURF STIJLT+(6PTE5LTI22U (ere s a si#%le e&a#%le that generates rando# nu#bers until a %articular condition is #et=
//3 c')3\hileTest.Hava // De#onstrates the :hile loo". "ublic class \hileTest @ "ublic static voi! #ain-%tringNO args. @ !ouble r ? '< :hile-r P '.CC!. @
1:=
Thinking in Java
,,,'0ruceEckel'com
do@while
The "or# "or 'o6(hile is
do state#ent while(Boolean-e6"ression);
The sole di""erence between (hile and 'o6(hile is that the state#ent o" the 'o6(hile always e&ecutes at least once, even i" the e&%ression evaluates to "alse the "irst ti#e. In a (hile, i" the conditional is "alse the "irst ti#e the state#ent never e&ecutes. In %ractice, 'o6(hile is less co##on than (hile. RFSURFSTIJLT+(6PTE5LTIM@MU
for
6 for loo% %er"or#s initiali1ation be"ore the "irst iteration. Then it %er"or#s conditional testing and, at the end o" each iteration, so#e "or# o" !ste%%ing.$ The "or# o" the for loo% is=
1:1
for loo%s are usually used "or !counting$ tasks= //3 c')3ListCharacters.Hava // De#onstrates 8for8 loo" by listing // all the 0%C$$ characters. "ublic class ListCharacters @ "ublic static voi! #ain-%tringNO args. @ for- char c ? '< c P ( 1< cKK. if -c 4? + . // 0&%$ Clear screen %yste#.out."rintln8value3 8 K -int.c K 8 character3 8 K c.< A A ///3>
Cote that the variable c is de"ined at the %oint where it is used, inside the control e&%ression o" the for loo%, rather than at the beginning o" the block denoted by the o%en curly brace. The sco%e o" c is the e&%ression controlled by the for. RFSURFSTIJLT+(6PTE5LTIM@LU Traditional %rocedural languages like + reAuire that all variables be de"ined at the beginning o" a block so when the co#%iler creates a block it can allocate s%ace "or those variables. In Java and +<< you can s%read your variable declarations throughout the block, de"ining the# at the %oint that you need the#. This allows a #ore natural coding style and #akes code easier to understand. RFSURFSTIJLT+(6PTE5LTIM@?U /ou can de"ine #ulti%le variables within a for state#ent, but they #ust be o" the sa#e ty%e=
for-int i ? ', H ? (< i P (' DD H 4? ((< iKK, HKK. /B bo!y of for loo" B/<
The int de"inition in the for state#ent covers both i and 8. The ability to de"ine variables in the control e&%ression is li#ited to the for loo%. /ou cannot use this a%%roach with any o" the other selection or iteration state#ents. RFSURFSTIJLT+(6PTE5LTIM@HU
1:2
Thinking in Java
,,,'0ruceEckel'com
//3 c')3Co##aG"erator.Hava "ublic class Co##aG"erator @ "ublic static voi! #ain-%tringNO args. @ for-int i ? (, H ? i K ('< i P ,< iKK, H ? i B . @ %yste#.out."rintln-8i? 8 K i K 8 H? 8 K H.< A A A ///3>
(ere s the out%ut= RFSURFSTIJLT+(6PTE5LTIM@3U
i? ( H? (( i? H? I i? ) H? + i? I H? 1
/ou can see that in both the initiali1ation and ste% %ortions the state#ents are evaluated in seAuential order. 6lso, the initiali1ation %ortion can have any nu#ber o" de"initions o$ one t) e. RFSURF STIJLT+(6PTE5LTIM@GU
1:3
This %rogra# shows e&a#%les o" break and contin*e within for and
(hile loo%s= //3 c')3Break0n!Continue.Hava // De#onstrates break an! continue key:or!s. "ublic class Break0n!Continue @ "ublic static voi! #ain-%tringNO args. @ for-int i ? '< i P (''< iKK. @ if-i ?? *I. break< // Gut of for loo" if-i V C 4? '. continue< // &e6t iteration %yste#.out."rintln-i.< A int i ? '< // 0n 8infinite loo"83 :hile-true. @ iKK< int H ? i B *< if-H ?? ( +C. break< // Gut of loo" if-i V (' 4? '. continue< // To" of loo" %yste#.out."rintln-i.< A A A ///3>
In the for loo% the value o" i never gets to M@@ because the break state#ent breaks out o" the loo% when i is G?. Cor#ally, you d use a break like this only i" you didn t know when the ter#inating condition was going to occur. The contin*e state#ent causes e&ecution to go back to the to% o" the iteration loo% *thus incre#enting i, whenever i is not evenly divisible by 2. :hen it is, the value is %rinted. RFSURF STIJLT+(6PTE5LTIM@2U The second %ortion shows an !in"inite loo%$ that would, in theory, continue "orever. (owever, inside the loo% there is a break state#ent that will break out o" the loo%. In addition, you ll see that the contin*e #oves back to the to% o" the loo% without co#%leting the re#ainder. *Thus %rinting ha%%ens in the second loo% only when the value o" i is divisible by M@., The out%ut is=
'
1:4
Thinking in Java
,,,'0ruceEckel'com
WTIJJX-HA#T&$JXI>>JO
1:5
6lthough goto is a reserved word in Java, it is not used in the language; Java has no goto. (owever, it does have so#ething that looks a bit like a 0u#% tied in with the break and contin*e keywords. It s not a 0u#% but rather a way to break out o" an iteration state#ent. The reason it s o"ten thrown in with discussions o" goto is because it uses the sa#e #echanis#= a label. RFSURFSTIJLT+(6PTE5LTIMM?U 6 label is an identi"ier "ollowed by a colon, like this=
label(3
The onl) %lace a label is use"ul in Java is right be"ore an iteration state#ent. 6nd that #eans right be"ore9it does no good to %ut any other state#ent between the label and the iteration. 6nd the sole reason to %ut a label be"ore an iteration is i" you re going to nest another iteration or a switch inside it. That s because the break and contin*e keywords will nor#ally interru%t only the current loo%, but when used with a label they ll interru%t the loo%s u% to where the label e&ists= RFSURF STIJLT+(6PTE5LTIMMHU
label(3 outer-iteration @ inner-iteration @ //] break< // ( //] continue< // //] continue label(< // ) //] break label(< // I A A
In case M, the break breaks out o" the inner iteration and you end u% in the outer iteration. In case K, the contin*e #oves back to the beginning o" the inner iteration. But in case L, the contin*e label> breaks out o" the inner iteration and the outer iteration, all the way back to label>. Then it does in "act continue the iteration, but starting at the outer iteration. In case ?, the break label> also breaks all the way out to
1:7
Thinking in Java
,,,'0ruceEckel'com
label>, but it does not re'enter the iteration. It actually does break out o"
both iterations. RFSURFSTIJLT+(6PTE5LTIMM3U (ere is an e&a#%le using for loo%s=
//3 c')3Labele!Lor.Hava // Java^s 8labele! for8 loo". "ublic class Labele!Lor @ "ublic static voi! #ain-%tringNO args. @ int i ? '< outer3 // Can2t have state#ents here for-< true <. @ // infinite loo" inner3 // Can2t have state#ents here for-< i P ('< iKK. @ "rt-8i ? 8 K i.< if-i ?? . @ "rt-8continue8.< continue< A if-i ?? ). @ "rt-8break8.< iKK< // Gther:ise i never // gets incre#ente!. break< A if-i ?? *. @ "rt-8continue outer8.< iKK< // Gther:ise i never // gets incre#ente!. continue outer< A if-i ?? 1. @ "rt-8break outer8.< break outer< A for-int k ? '< k P ,< kKK. @ if-k ?? ). @ "rt-8continue inner8.< continue inner< A
1:8
A A A // Can2t break or continue // to labels here A static voi! "rt-%tring s. @ %yste#.out."rintln-s.< A A ///3>
This uses the prtA B #ethod that has been de"ined in the other e&a#%les. RFSURFSTIJLT+(6PTE5LTIMMGU Cote that break breaks out o" the for loo%, and that the incre#ent' e&%ression doesn t occur until the end o" the %ass through the for loo%. Since break ski%s the incre#ent e&%ression, the incre#ent is %er"or#ed directly in the case o" i PP J. The contin*e o*ter state#ent in the case o" i PP Z also goes to the to% o" the loo% and also ski%s the incre#ent, so it too is incre#ented directly. RFSURFSTIJLT+(6PTE5LTIMMIU (ere is the out%ut=
i ? ' continue inner i ? ( continue inner i ? continue i ? ) break i ? I continue inner i ? , continue inner i ? + continue inner i ? * continue outer i ? 1 break outer
1::
Thinking in Java
,,,'0ruceEckel'com
I" not "or the break o*ter state#ent, there would be no way to get out o" the outer loo% "ro# within an inner loo%, since break by itsel" can break out o" only the inner#ost loo%. *The sa#e is true "or contin*e., RFSURF STIJLT+(6PTE5LTIMM2U )" course, in the cases where breaking out o" a loo% will also e&it the #ethod, you can si#%ly use a ret*rn. RFSURFSTIJLT+(6PTE5LTIMK@U (ere is a de#onstration o" labeled break and contin*e state#ents with (hile loo%s=
//3 c')3Labele!\hile.Hava // Java2s 8labele! :hile8 loo". "ublic class Labele!\hile @ "ublic static voi! #ain-%tringNO args. @ int i ? '< outer3 :hile-true. @ "rt-8Guter :hile loo"8.< :hile-true. @ iKK< "rt-8i ? 8 K i.< if-i ?? (. @ "rt-8continue8.< continue< A if-i ?? ). @ "rt-8continue outer8.< continue outer< A if-i ?? ,. @ "rt-8break8.< break< A if-i ?? *. @ "rt-8break outer8.< break outer< A A A
1:;
6 %lain contin*e goes to the to% o" the inner#ost loo% and continues. 6 labeled contin*e goes to the label and re'enters the loo% right a"ter that label. 6 break !dro%s out o" the botto#$ o" the loo%. 6 labeled break dro%s out o" the botto# o" the end o" the loo% denoted by the label.
Guter :hile loo" i ? ( continue i ? i ? ) continue outer Guter :hile loo" i ? I i ? , break Guter :hile loo" i ? + i ? * break outer
It s i#%ortant to re#e#ber that the onl) reason to use labels in Java is when you have nested loo%s and you want to break or contin*e through #ore than one nested level. RFSURFSTIJLT+(6PTE5LTIMKLU In 7i0kstra s !goto considered har#"ul$ %a%er, what he s%eci"ically ob0ected to was the labels, not the goto. (e observed that the nu#ber o"
1;=
Thinking in Java
,,,'0ruceEckel'com
bugs see#s to increase with the nu#ber o" labels in a %rogra#. Dabels and gotos #ake %rogra#s di""icult to analy1e statically, since it introduces cycles in the %rogra# e&ecution gra%h. Cote that Java labels don t su""er "ro# this %roble#, since they are constrained in their %lace#ent and can t be used to trans"er control in an ad hoc #anner. It s also interesting to note that this is a case where a language "eature is #ade #ore use"ul by restricting the %ower o" the state#ent. RFSURFSTIJLT+(6PTE5LTIMK?U
switch
The s(itch is so#eti#es classi"ied as a selection statement. The s(itch state#ent selects "ro# a#ong %ieces o" code based on the value o" an integral e&%ression. Its "or# is= RFSURFSTIJLT+(6PTE5LTIMKHU
switch(integral-selector) { case integral-value( : state#ent; case integral-value : state#ent; case integral-value) : state#ent; case integral-valueI : state#ent; case integral-value, : state#ent; // ... default: state#ent; A
Integral/selector is an e&%ression that %roduces an integral value. The s(itch co#%ares the result o" integral/selector to each integral/value. I" it "inds a #atch, the corres%onding statement *si#%le or co#%ound, e&ecutes. I" no #atch occurs, the 'efa*lt statement e&ecutes. RFSURF STIJLT+(6PTE5LTIMK3U /ou will notice in the above de"inition that each case ends with a break, which causes e&ecution to 0u#% to the end o" the s(itch body. This is the conventional way to build a s(itch state#ent, but the break is o%tional. I" it is #issing, the code "or the "ollowing case state#ents e&ecute until a break is encountered. 6lthough you don t usually want this kind o" behavior, it can be use"ul to an e&%erienced %rogra##er. Cote the last state#ent, "ollowing the 'efa*lt, doesn t have a break because the e&ecution 0ust "alls through to where the break would have taken it anyway. /ou could %ut a break at the end o" the 'efa*lt state#ent with
1;1
no har# i" you considered it i#%ortant "or style s sake. RFSURF STIJLT+(6PTE5LTIMKGU The s(itch state#ent is a clean way to i#%le#ent #ulti'way selection *i. e., selecting "ro# a#ong a nu#ber o" di""erent e&ecution %aths,, but it reAuires a selector that evaluates to an integral value such as int or char. I" you want to use, "or e&a#%le, a string or a "loating'%oint nu#ber as a selector, it won t work in a s(itch state#ent. Eor non'integral ty%es, you #ust use a series o" if state#ents. RFSURFSTIJLT+(6PTE5LTIMKIU (ere s an e&a#%le that creates letters rando#ly and deter#ines whether they re vowels or consonants= RFSURFSTIJLT+(6PTE5LTIMK2U
//3 c')3Wo:els0n!Consonants.Hava // De#onstrates the s:itch state#ent. "ublic class Wo:els0n!Consonants @ "ublic static voi! #ain-%tringNO args. @ for-int i ? '< i P (''< iKK. @ char c ? -char.-Jath.ran!o#-. B + K 2a2.< %yste#.out."rint-c K 83 8.< s:itch-c. @ case 2a23 case 2e23 case 2i23 case 2o23 case 2u23 %yste#.out."rintln-8vo:el8.< break< case 2y23 case 2:23 %yste#.out."rintln8%o#eti#es a vo:el8.< break< !efault3 %yste#.out."rintln-8consonant8.< A A A A ///3>
1;2
Thinking in Java
,,,'0ruceEckel'com
Since 1ath!ran'omA B generates a value between @ and M, you need only #ulti%ly it by the u%%er bound o" the range o" nu#bers you want to %roduce *K3 "or the letters in the al%habet, and add an o""set to establish the lower bound. RFSURFSTIJLT+(6PTE5LTIML@U 6lthough it a%%ears you re switching on a character here, the s(itch state#ent is actually using the integral value o" the character. The singly' Auoted characters in the case state#ents also %roduce integral values that are used "or co#%arison. RFSURFSTIJLT+(6PTE5LTIMLMU Cotice how the cases can be !stacked$ on to% o" each other to %rovide #ulti%le #atches "or a %articular %iece o" code. /ou should also be aware that it s essential to %ut the break state#ent at the end o" a %articular case, otherwise control will si#%ly dro% through and continue %rocessing on the ne&t case. RFSURFSTIJLT+(6PTE5LTIMLKU
Calculation details
The state#ent= char c ? -char.-Jath.ran!o#-. B + K 2a2.<
deserves a closer look. 1ath!ran'omA B %roduces a 'o*ble, so the value K3 is converted to a 'o*ble to %er"or# the #ulti%lication, which also %roduces a 'o*ble. This #eans that Ga; #ust be converted to a 'o*ble to %er"or# the addition. The 'o*ble result is turned back into a char with a cast. RFSURFSTIJLT+(6PTE5LTIMLLU :hat does the cast to char doO That is, i" you have the value K2.G and you cast it to a char, is the resulting value L@ or K2O The answer to this can be seen in this e&a#%le= RFSURFSTIJLT+(6PTE5LTIML?U
//3 c')3Casting&u#bers.Hava // \hat ha""ens :hen you cast a float // or !ouble to an integral value[ "ublic class Casting&u#bers @ "ublic static voi! #ain-%tringNO args. @ !ouble above ? '.*, belo: ? '.I< %yste#.out."rintln-8above3 8 K above.<
1;3
%yste#.out."rintln-8belo:3 8 K belo:.< %yste#.out."rintln8-int.above3 8 K -int.above.< %yste#.out."rintln8-int.belo:3 8 K -int.belo:.< %yste#.out."rintln8-char.-2a2 K above.3 8 K -char.-2a2 K above..< %yste#.out."rintln8-char.-2a2 K belo:.3 8 K -char.-2a2 K belo:..< A A ///3>
The out%ut is= RFSURFSTIJLT+(6PTE5LTIMLHU
above3 '.* belo:3 '.I -int.above3 ' -int.belo:3 ' -char.-2a2 K above.3 a -char.-2a2 K belo:.3 a
So the answer is that casting "ro# a float or 'o*ble to an integral value always truncates. RFSURFSTIJLT+(6PTE5LTIML3U 6 second Auestion concerns 1ath!ran'omA B. 7oes it %roduce a value "ro# 1ero to one, inclusive or e&clusive o" the value [M O In #ath lingo, is it *@,M,, or _@,M`, or *@,M` or _@,M,O *The sAuare bracket #eans !includes$ whereas the %arenthesis #eans !doesn t include.$, 6gain, a test %rogra# #ight %rovide the answer= RFSURFSTIJLT+(6PTE5LTIMLGU
//3 c')35an!o#Boun!s.Hava // Does Jath.ran!o#-. "ro!uce '.' an! (.'[ "ublic class 5an!o#Boun!s @ static voi! usage-. @ %yste#.out."rintln-8Ysage3 _n_t8 K 85an!o#Boun!s lo:er_n_t8 K 85an!o#Boun!s u""er8.< %yste#.e6it-(.< A
1;4
Thinking in Java
,,,'0ruceEckel'com
"ublic static voi! #ain-%tringNO args. @ if-args.length 4? (. usage-.< if-argsN'O.e=uals-8lo:er8.. @ :hile-Jath.ran!o#-. 4? '.'. < // `ee" trying %yste#.out."rintln-8Pro!uce! '.'48.< A else if-argsN'O.e=uals-8u""er8.. @ :hile-Jath.ran!o#-. 4? (.'. < // `ee" trying %yste#.out."rintln-8Pro!uce! (.'48.< A else usage-.< A A ///3>
To run the %rogra#, you ty%e a co##and line o" either= RFSURF STIJLT+(6PTE5LTIMLIU
1;5
likelihood o" reaching any one value e&%eri#entally #ight e&ceed the li"eti#e o" one co#%uter, or even one e&%eri#enter. It turns out that @.@ is included in the out%ut o" 1ath!ran'omA B. )r, in #ath lingo, it is _@,M,. RFSURFSTIJLT+(6PTE5LTIML2U
1ummar:
This cha%ter concludes the study o" "unda#ental "eatures that a%%ear in #ost %rogra##ing languages= calculation, o%erator %recedence, ty%e casting, and selection and iteration. Cow you re ready to begin taking ste%s that #ove you closer to the world o" ob0ect'oriented %rogra##ing. The ne&t cha%ter will cover the i#%ortant issues o" initiali1ation and cleanu% o" ob0ects, "ollowed in the subseAuent cha%ter by the essential conce%t o" i#%le#entation hiding. RFSURFSTIJLT+(6PTE5LTIM?@U
/0ercises
Solutions to selected e&ercises can be "ound in the electronic docu#entThe Thinking in Java "nnotated Solution @uide, available "or a s#all "ee "ro# ,,,'0ruceEckel'com.
(,) Ero# the sections labeled !i"'else$ and !return$, %ut the #ethods
testA B and testIA B into a working %rogra#. #odi"y the two test A B #ethods so that testval is tested to see i" it is within the range between *and including, the argu#ents begin and en'. RFSURF
STIJLT+(6PTE5LTIM?LU
(-) :rite a %rogra# that %rints values "ro# one to M@@. RFSURF
STIJLT+(6PTE5LTIM??U
1;7
Thinking in Java
,,,'0ruceEckel'com
(4) Modi"y E&ercise ? so that the %rogra# e&its by using the break
keyword at value ?G. Try using ret*rn instead. RFSURF STIJLT+(6PTE5LTIM?HU
(5) :rite a "unction that takes two )tring argu#ents, and uses all
the boolean co#%arisons to co#%are the two )trings and %rint the results. Eor the PP and =P, also %er"or# the eC*alsA B test. In mainA B, call your "unction with so#e di""erent )tring ob0ects. RF SURFSTIJLT+(6PTE5LTIM?3U
(6) :rite a %rogra# that generates KH rando# int values. Eor each
value, use an if'else state#ent to classi"y it as greater than, less than or eAual to a second rando#ly'generated value. RFSURF STIJLT+(6PTE5LTIM?GU
!() :rite a %rogra# that uses two nested for loo%s and the #odulus
o%erator * S, to detect and %rint %ri#e nu#bers *integral nu#bers that are not evenly divisible by any other nu#bers e&ce%t "or the#selves and M,. RFSURFSTIJLT+(6PTE5LTIM?2U
!!) +reate a s(itch state#ent that %rints a #essage "or each case,
and %ut the s(itch inside a for loo% that tries each case. Put a break a"ter each case and test it, then re#ove the breaks and see what ha%%ens. RFSU
1;8
+: Initiali?ation L Cleanu.
RFSTIJLT+(6PTE5?TI@U6s the co#%uter revolution %rogresses, !unsa"e$ %rogra##ing has beco#e one o" the #a0or cul%rits that #akes %rogra##ing e&%ensive.
Two o" these sa"ety issues are initiali?ation and cleanu . Many + bugs occur when the %rogra##er "orgets to initiali1e a variable. This is es%ecially true with libraries when users don t know how to initiali1e a library co#%onent, or even that they #ust. +leanu% is a s%ecial %roble# because it s easy to "orget about an ele#ent when you re done with it, since it no longer concerns you. Thus, the resources used by that ele#ent are retained and you can easily end u% running out o" resources *#ost notably, #e#ory,. RFSURFSTIJLT+(6PTE5?TIMU +<< introduced the conce%t o" a constructor, a s%ecial #ethod auto#atically called when an ob0ect is created. Java also ado%ted the constructor, and in addition has a garbage collector that auto#atically releases #e#ory resources when they re no longer being used. This cha%ter e&a#ines the issues o" initiali1ation and cleanu%, and their su%%ort in Java. RFSURFSTIJLT+(6PTE5?TIKU
1;:
Java, the class designer can guarantee initiali1ation o" every ob0ect by %roviding a s%ecial #ethod called a constructor. I" a class has a constructor, Java auto#atically calls that constructor when an ob0ect is created, be"ore users can even get their hands on it. So initiali1ation is guaranteed. RFSURFSTIJLT+(6PTE5?TILU The ne&t challenge is what to na#e this #ethod. There are two issues. The "irst is that any na#e you use could clash with a na#e you #ight like to use as a #e#ber in the class. The second is that because the co#%iler is res%onsible "or calling the constructor, it #ust always know which #ethod to call. The +<< solution see#s the easiest and #ost logical, so it s also used in Java= the na#e o" the constructor is the sa#e as the na#e o" the class. It #akes sense that such a #ethod will be called auto#atically on initiali1ation. RFSURFSTIJLT+(6PTE5?TI?U (ere s a si#%le class with a constructor=
//3 c'I3%i#"leConstructor.Hava // De#onstration of a si#"le constructor. class 5ock @ 5ock-. @ // This is the constructor %yste#.out."rintln-8Creating 5ock8.< A A "ublic class %i#"leConstructor @ "ublic static voi! #ain-%tringNO args. @ for-int i ? '< i P ('< iKK. ne: 5ock-.< A A ///3>
Cow, when an ob0ect is created= RFSURFSTIJLT+(6PTE5?TIHU
ne: 5ock-.<
storage is allocated and the constructor is called. It is guaranteed that the ob0ect will be %ro%erly initiali1ed be"ore you can get your hands on it. RF SURFSTIJLT+(6PTE5?TI3U
1;;
Cote that the coding style o" #aking the "irst letter o" all #ethods lowercase does not a%%ly to constructors, since the na#e o" the constructor #ust #atch the na#e o" the class e*actl). RFSURF STIJLT+(6PTE5?TIGU Dike any #ethod, the constructor can have argu#ents to allow you to s%eci"y ho, an ob0ect is created. The above e&a#%le can easily be changed so the constructor takes an argu#ent=
//3 c'I3%i#"leConstructor .Hava // Constructors can have argu#ents. class 5ock @ 5ock -int i. @ %yste#.out."rintln8Creating 5ock nu#ber 8 K i.< A A "ublic class %i#"leConstructor @ "ublic static voi! #ain-%tringNO args. @ for-int i ? '< i P ('< iKK. ne: 5ock -i.< A A ///3>
+onstructor argu#ents %rovide you with a way to %rovide %ara#eters "or the initiali1ation o" an ob0ect. Eor e&a#%le, i" the class Tree has a constructor that takes a single integer argu#ent denoting the height o" the tree, you would create a Tree ob0ect like this= RFSURF STIJLT+(6PTE5?TIIU
// ( -foot tree
I" TreeAintB is your only constructor, then the co#%iler won t let you create a Tree ob0ect any other way. RFSURFSTIJLT+(6PTE5?TI2U +onstructors eli#inate a large class o" %roble#s and #ake the code easier to read. In the %receding code "rag#ent, "or e&a#%le, you don t see an e&%licit call to so#e initiali7eA B #ethod that is conce%tually se%arate "ro# de"inition. In Java, de"inition and initiali1ation are uni"ied conce%ts 9you can t have one without the other. RFSURFSTIJLT+(6PTE5?TIM@U
2==
The constructor is an unusual ty%e o" #ethod because it has no return value. This is distinctly di""erent "ro# a voi' return value, in which the #ethod returns nothing but you still have the o%tion to #ake it return so#ething else. +onstructors return nothing and you don t have an o%tion. I" there was a return value, and i" you could select your own, the co#%iler would so#ehow need to know what to do with that return value. RFSURFSTIJLT+(6PTE5?TIMMU
Method overloading
)ne o" the i#%ortant "eatures in any %rogra##ing language is the use o" na#es. :hen you create an ob0ect, you give a na#e to a region o" storage. 6 #ethod is a na#e "or an action. By using na#es to describe your syste#, you create a %rogra# that is easier "or %eo%le to understand and change. It s a lot like writing %rose9the goal is to co##unicate with your readers. RFSURFSTIJLT+(6PTE5?TIMKU /ou re"er to all ob0ects and #ethods by using na#es. :ell'chosen na#es #ake it easier "or you and others to understand your code. RFSURF STIJLT+(6PTE5?TIMLU 6 %roble# arises when #a%%ing the conce%t o" nuance in hu#an language onto a %rogra##ing language. )"ten, the sa#e word e&%resses a nu#ber o" di""erent #eanings9it s overloaded. This is use"ul, es%ecially when it co#es to trivial di""erences. /ou say !wash the shirt,$ !wash the car,$ and !wash the dog.$ It would be silly to be "orced to say, !shirt:ash the shirt,$ !car:ash the car,$ and !dog:ash the dog$ 0ust so the listener doesn t need to #ake any distinction about the action %er"or#ed. Most hu#an languages are redundant, so even i" you #iss a "ew words, you can still deter#ine the #eaning. :e don t need uniAue identi"iers9we can deduce #eaning "ro# conte&t. RFSURFSTIJLT+(6PTE5?TIM?U Most %rogra##ing languages *+ in %articular, reAuire you to have a uniAue identi"ier "or each "unction. So you could not have one "unction called printA B "or %rinting integers and another called printA B "or %rinting "loats9each "unction reAuires a uniAue na#e. RFSURF STIJLT+(6PTE5?TIMHU
2=1
In Java *and +<<,, another "actor "orces the overloading o" #ethod na#es= the constructor. Because the constructor s na#e is %redeter#ined by the na#e o" the class, there can be only one constructor na#e. But what i" you want to create an ob0ect in #ore than one wayO Eor e&a#%le, su%%ose you build a class that can initiali1e itsel" in a standard way or by reading in"or#ation "ro# a "ile. /ou need two constructors, one that takes no argu#ents *the de$ault constructor, also called the no/arg constructor,, and one that takes a )tring as an argu#ent, which is the na#e o" the "ile "ro# which to initiali1e the ob0ect. Both are constructors, so they #ust have the sa#e na#e9the na#e o" the class. Thus, method overloading is essential to allow the sa#e #ethod na#e to be used with di""erent argu#ent ty%es. 6nd although #ethod overloading is a #ust "or constructors, it s a general convenience and can be used with any #ethod. RFSURFSTIJLT+(6PTE5?TIM3U (ere s an e&a#%le that shows both overloaded constructors and overloaded ordinary #ethods=
//3 c'I3Gverloa!ing.Hava // De#onstration of both constructor // an! or!inary #etho! overloa!ing. i#"ort Hava.util.B< class Tree @ int height< Tree-. @ "rt-8Planting a see!ling8.< height ? '< A Tree-int i. @ "rt-8Creating ne: Tree that is 8 K i K 8 feet tall8.< height ? i< A voi! info-. @ "rt-8Tree is 8 K height K 8 feet tall8.< A voi! info-%tring s. @ "rt-s K 83 Tree is 8
2=2
K height K 8 feet tall8.< A static voi! "rt-%tring s. @ %yste#.out."rintln-s.< A A "ublic class Gverloa!ing @ "ublic static voi! #ain-%tringNO args. @ for-int i ? '< i P ,< iKK. @ Tree t ? ne: Tree-i.< t.info-.< t.info-8overloa!e! #etho!8.< A // Gverloa!e! constructor3 ne: Tree-.< A A ///3>
6 Tree ob0ect can be created either as a seedling, with no argu#ent, or as a %lant grown in a nursery, with an e&isting height. To su%%ort this, there are two constructors, one that takes no argu#ents *we call constructors that take no argu#ents de$ault constructors@, and one that takes the e&isting height. RFSURFSTIJLT+(6PTE5?TIMGU /ou #ight also want to call the infoA B #ethod in #ore than one way. Eor e&a#%le, with a )tring argu#ent i" you have an e&tra #essage you want %rinted, and without i" you have nothing #ore to say. It would see# strange to give two se%arate na#es to what is obviously the sa#e conce%t. Eortunately, #ethod overloading allows you to use the sa#e na#e "or both. RFSURFSTIJLT+(6PTE5?TIMIU
2=3
I" you think about this "or a second, it #akes sense= how else could a %rogra##er tell the di""erence between two #ethods that have the sa#e na#e, other than by the ty%es o" their argu#entsO RFSURF STIJLT+(6PTE5?TIK@U Even di""erences in the ordering o" argu#ents are su""icient to distinguish two #ethods= *6lthough you don t nor#ally want to take this a%%roach, as it %roduces di""icult'to'#aintain code., RFSURF STIJLT+(6PTE5?TIKMU
//3 c'I3Gverloa!ingGr!er.Hava // Gverloa!ing base! on the or!er of // the argu#ents. "ublic class Gverloa!ingGr!er @ static voi! "rint-%tring s, int i. @ %yste#.out."rintln8%tring3 8 K s K 8, int3 8 K i.< A static voi! "rint-int i, %tring s. @ %yste#.out."rintln8int3 8 K i K 8, %tring3 8 K s.< A "ublic static voi! #ain-%tringNO args. @ "rint-8%tring first8, ((.< "rint-CC, 8$nt first8.< A A ///3>
The two printA B #ethods have identical argu#ents, but the order is di""erent, and that s what #akes the# distinct. RFSURF STIJLT+(6PTE5?TIKKU
2=4
//3 c'I3Pri#itiveGverloa!ing.Hava // Pro#otion of "ri#itives an! overloa!ing. "ublic class Pri#itiveGverloa!ing @ // boolean can2t be auto#atically converte! static voi! "rt-%tring s. @ %yste#.out."rintln-s.< A voi! voi! voi! voi! voi! voi! voi! voi! voi! voi! voi! voi! voi! voi! voi! voi! voi! voi! voi! voi! voi! voi! f(-char 6. @ "rt-8f(-char.8.< A f(-byte 6. @ "rt-8f(-byte.8.< A f(-short 6. @ "rt-8f(-short.8.< A f(-int 6. @ "rt-8f(-int.8.< A f(-long 6. @ "rt-8f(-long.8.< A f(-float 6. @ "rt-8f(-float.8.< A f(-!ouble 6. @ "rt-8f(-!ouble.8.< A f f f f f f -byte 6. @ "rt-8f -byte.8.< A -short 6. @ "rt-8f -short.8.< A -int 6. @ "rt-8f -int.8.< A -long 6. @ "rt-8f -long.8.< A -float 6. @ "rt-8f -float.8.< A -!ouble 6. @ "rt-8f -!ouble.8.< A
f)-short 6. @ "rt-8f)-short.8.< A f)-int 6. @ "rt-8f)-int.8.< A f)-long 6. @ "rt-8f)-long.8.< A f)-float 6. @ "rt-8f)-float.8.< A f)-!ouble 6. @ "rt-8f)-!ouble.8.< A fI-int 6. @ "rt-8fI-int.8.< A fI-long 6. @ "rt-8fI-long.8.< A fI-float 6. @ "rt-8fI-float.8.< A fI-!ouble 6. @ "rt-8fI-!ouble.8.< A
voi! f,-long 6. @ "rt-8f,-long.8.< A voi! f,-float 6. @ "rt-8f,-float.8.< A voi! f,-!ouble 6. @ "rt-8f,-!ouble.8.< A voi! f+-float 6. @ "rt-8f+-float.8.< A voi! f+-!ouble 6. @ "rt-8f+-!ouble.8.< A
2=5
voi! f*-!ouble 6. @ "rt-8f*-!ouble.8.< A voi! testConstWal-. @ "rt-8Testing :ith ,8.< f(-,.<f -,.<f)-,.<fI-,.<f,-,.<f+-,.<f*-,.< A voi! testChar-. @ char 6 ? 262< "rt-8char argu#ent38.< f(-6.<f -6.<f)-6.<fI-6.<f,-6.<f+-6.<f*-6.< A voi! testByte-. @ byte 6 ? '< "rt-8byte argu#ent38.< f(-6.<f -6.<f)-6.<fI-6.<f,-6.<f+-6.<f*-6.< A voi! test%hort-. @ short 6 ? '< "rt-8short argu#ent38.< f(-6.<f -6.<f)-6.<fI-6.<f,-6.<f+-6.<f*-6.< A voi! test$nt-. @ int 6 ? '< "rt-8int argu#ent38.< f(-6.<f -6.<f)-6.<fI-6.<f,-6.<f+-6.<f*-6.< A voi! testLong-. @ long 6 ? '< "rt-8long argu#ent38.< f(-6.<f -6.<f)-6.<fI-6.<f,-6.<f+-6.<f*-6.< A voi! testLloat-. @ float 6 ? '< "rt-8float argu#ent38.< f(-6.<f -6.<f)-6.<fI-6.<f,-6.<f+-6.<f*-6.< A voi! testDouble-. @ !ouble 6 ? '< "rt-8!ouble argu#ent38.< f(-6.<f -6.<f)-6.<fI-6.<f,-6.<f+-6.<f*-6.<
2=7
A "ublic static voi! #ain-%tringNO args. @ Pri#itiveGverloa!ing " ? ne: Pri#itiveGverloa!ing-.< ".testConstWal-.< ".testChar-.< ".testByte-.< ".test%hort-.< ".test$nt-.< ".testLong-.< ".testLloat-.< ".testDouble-.< A A ///3>
I" you view the out%ut o" this %rogra#, you ll see that the constant value H is treated as an int, so i" an overloaded #ethod is available that takes an int it is used. In all other cases, i" you have a data ty%e that is s#aller than the argu#ent in the #ethod, that data ty%e is %ro#oted. char %roduces a slightly di""erent e""ect, since i" it doesn t "ind an e&act char #atch, it is %ro#oted to int. RFSURFSTIJLT+(6PTE5?TIKLU :hat ha%%ens i" your argu#ent is bigger than the argu#ent e&%ected by the overloaded #ethodO 6 #odi"ication o" the above %rogra# gives the answer=
//3 c'I3De#otion.Hava // De#otion of "ri#itives an! overloa!ing. "ublic class De#otion @ static voi! "rt-%tring s. @ %yste#.out."rintln-s.< A voi! voi! voi! voi! voi! voi! voi! f(-char 6. @ "rt-8f(-char.8.< A f(-byte 6. @ "rt-8f(-byte.8.< A f(-short 6. @ "rt-8f(-short.8.< A f(-int 6. @ "rt-8f(-int.8.< A f(-long 6. @ "rt-8f(-long.8.< A f(-float 6. @ "rt-8f(-float.8.< A f(-!ouble 6. @ "rt-8f(-!ouble.8.< A
2=8
voi! voi! voi! voi! voi! voi! voi! voi! voi! voi! voi! voi! voi! voi! voi!
f f f f f f
-char 6. @ "rt-8f -char.8.< A -byte 6. @ "rt-8f -byte.8.< A -short 6. @ "rt-8f -short.8.< A -int 6. @ "rt-8f -int.8.< A -long 6. @ "rt-8f -long.8.< A -float 6. @ "rt-8f -float.8.< A
f)-char 6. @ "rt-8f)-char.8.< A f)-byte 6. @ "rt-8f)-byte.8.< A f)-short 6. @ "rt-8f)-short.8.< A f)-int 6. @ "rt-8f)-int.8.< A f)-long 6. @ "rt-8f)-long.8.< A fI-char 6. @ "rt-8fI-char.8.< A fI-byte 6. @ "rt-8fI-byte.8.< A fI-short 6. @ "rt-8fI-short.8.< A fI-int 6. @ "rt-8fI-int.8.< A
voi! f,-char 6. @ "rt-8f,-char.8.< A voi! f,-byte 6. @ "rt-8f,-byte.8.< A voi! f,-short 6. @ "rt-8f,-short.8.< A voi! f+-char 6. @ "rt-8f+-char.8.< A voi! f+-byte 6. @ "rt-8f+-byte.8.< A voi! f*-char 6. @ "rt-8f*-char.8.< A voi! testDouble-. @ !ouble 6 ? '< "rt-8!ouble argu#ent38.< f(-6.<f --float.6.<f)--long.6.<fI--int.6.< f,--short.6.<f+--byte.6.<f*--char.6.< A "ublic static voi! #ain-%tringNO args. @ De#otion " ? ne: De#otion-.< ".testDouble-.< A A ///3>
2=:
(ere, the #ethods take narrower %ri#itive values. I" your argu#ent is wider then you #ust cast to the necessary ty%e using the ty%e na#e in %arentheses. I" you don t do this, the co#%iler will issue an error #essage. RFSURFSTIJLT+(6PTE5?TIK?U /ou should be aware that this is a narro,ing conversionD which #eans you #ight lose in"or#ation during the cast. This is why the co#%iler "orces you to do it9to "lag the narrowing conversion. RFSURF STIJLT+(6PTE5?TIKHU
f-.<
how can Java deter#ine which fA B should be calledO 6nd how could so#eone reading the code see itO Because o" this sort o" %roble#, you cannot use return value ty%es to distinguish overloaded #ethods. RFSURF STIJLT+(6PTE5?TIKIU
Default constructors
6s #entioned %reviously, a de"ault constructor *a.k.a. a !no'arg$ constructor, is one without argu#ents, used to create a !vanilla ob0ect.$ I" you create a class that has no constructors, the co#%iler will
2=;
auto#atically create a de"ault constructor "or you. Eor e&a#%le= RFSURF STIJLT+(6PTE5?TIK2U
//3 c'I3DefaultConstructor.Hava class Bir! @ int i< A "ublic class DefaultConstructor @ "ublic static voi! #ain-%tringNO args. @ Bir! nc ? ne: Bir!-.< // !efault4 A A ///3>
The line RFSURFSTIJLT+(6PTE5?TIL@U
ne: Bir!-.<
creates a new ob0ect and calls the de"ault constructor, even though one was not e&%licitly de"ined. :ithout it we would have no #ethod to call to build our ob0ect. (owever, i" you de"ine any constructors *with or without argu#ents,, the co#%iler will not synthesi1e one "or you= RFSURF STIJLT+(6PTE5?TILMU
ne: Bush-.<
the co#%iler will co#%lain that it cannot "ind a constructor that #atches. It s as i" when you don t %ut in any constructors, the co#%iler says !/ou are bound to need some constructor, so let #e #ake one "or you.$ But i" you write a constructor, the co#%iler says !/ou ve written a constructor so you know what you re doing; i" you didn t %ut in a de"ault it s because you #eant to leave it out.$ RFSURFSTIJLT+(6PTE5?TILLU
21=
class Banana @ voi! f-int i. @ /B ... B/ A A Banana a ? ne: Banana-., b ? ne: Banana-.< a.f-(.< b.f- .<
I" there s only one #ethod called fA B, how can that #ethod know whether it s being called "or the ob0ect a or bO RFSURFSTIJLT+(6PTE5?TILHU To allow you to write the code in a convenient ob0ect'oriented synta& in which you !send a #essage to an ob0ect,$ the co#%iler does so#e undercover work "or you. There s a secret "irst argu#ent %assed to the #ethod fA B, and that argu#ent is the re"erence to the ob0ect that s being #ani%ulated. So the two #ethod calls above beco#e so#ething like= RF SURFSTIJLT+(6PTE5?TIL3U
211
//3 c'I3Leaf.Hava // %i#"le use of the 8this8 key:or!. "ublic class Leaf @ int i ? '< Leaf incre#ent-. @ iKK< return this< A voi! "rint-. @ %yste#.out."rintln-8i ? 8 K i.< A "ublic static voi! #ain-%tringNO args. @ Leaf 6 ? ne: Leaf-.< 6.incre#ent-..incre#ent-..incre#ent-.."rint-.< A A ///3>
Because incrementA B returns the re"erence to the current ob0ect via the this keyword, #ulti%le o%erations can easily be %er"or#ed on the sa#e ob0ect. RFSURFSTIJLT+(6PTE5?TI?@U
212
when you give it an argu#ent list= it #akes an e&%licit call to the constructor that #atches that argu#ent list. Thus you have a straight"orward way to call other constructors= RFSURF STIJLT+(6PTE5?TI?KU
//3 c'I3Llo:er.Hava // Calling constructors :ith 8this.8 "ublic class Llo:er @ int "etalCount ? '< %tring s ? ne: %tring-8null8.< Llo:er-int "etals. @ "etalCount ? "etals< %yste#.out."rintln8Constructor :/ int arg only, "etalCount? 8 K "etalCount.< A Llo:er-%tring ss. @ %yste#.out."rintln8Constructor :/ %tring arg only, s?8 K ss.< s ? ss< A Llo:er-%tring s, int "etals. @ this-"etals.< //4 this-s.< // Can2t call t:o4 this.s ? s< // 0nother use of 8this8 %yste#.out."rintln-8%tring D int args8.< A Llo:er-. @ this-8hi8, I*.< %yste#.out."rintln8!efault constructor -no args.8.< A voi! "rint-. @ //4 this-((.< // &ot insi!e non-constructor4 %yste#.out."rintln8"etalCount ? 8 K "etalCount K 8 s ? 8K s.< A "ublic static voi! #ain-%tringNO args. @ Llo:er 6 ? ne: Llo:er-.< 6."rint-.<
213
A A ///3>
The constructor Flo(erA)tring s, int petalsB shows that, while you can call one constructor using this, you cannot call two. In addition, the constructor call #ust be the "irst thing you do or you ll get a co#%iler error #essage. RFSURFSTIJLT+(6PTE5?TI?LU This e&a#%le also shows another way you ll see this used. Since the na#e o" the argu#ent s and the na#e o" the #e#ber data s are the sa#e, there s an a#biguity. /ou can resolve it by saying this!s to re"er to the #e#ber data. /ou ll o"ten see this "or# used in Java code, and it s used in nu#erous %laces in this book. RFSURFSTIJLT+(6PTE5?TI??U In printA B you can see that the co#%iler won t let you call a constructor "ro# inside any #ethod other than a constructor. RFSURF STIJLT+(6PTE5?TI?HU
static #ethod. Then, via the re"erence *which is now e""ectively this,, you can call non' static #ethods and access non'static "ields. But ty%ically i" you want to do so#ething like this you ll 0ust #ake an ordinary, non'static #ethod.
214
they are !%ro%er ))P$ should be le"t to the theoreticians. Indeed, even S#alltalk has the eAuivalent in its !class #ethods.$ F/GHF/
GTIJ3IC."PTE-4II48H
215
an ob0ect, you #ust %er"or# that activity yoursel". Java has no destructor or si#ilar conce%t, so you #ust create an ordinary #ethod to %er"or# this cleanu%. Eor e&a#%le, su%%ose in the %rocess o" creating your ob0ect it draws itsel" on the screen. I" you don t e&%licitly erase its i#age "ro# the screen, it #ight never get cleaned u%. I" you %ut so#e kind o" erasing "unctionality inside finali7eA B, then i" an ob0ect is garbage'collected, the i#age will "irst be re#oved "ro# the screen, but i" it isn t, the i#age will re#ain. So a second %oint to re#e#ber is= RFSURF STIJLT+(6PTE5?TIH@U
217
cases, in which your ob0ect can allocate so#e storage in so#e way other than creating an ob0ect. But, you #ight observe, everything in Java is an ob0ect so how can this beO RFSURFSTIJLT+(6PTE5?TIH?U It would see# that finali7eA B is in %lace because o" the %ossibility that you ll do so#ething +'like by allocating #e#ory using a #echanis# other than the nor#al one in Java. This can ha%%en %ri#arily through native methods, which are a way to call non'Java code "ro# Java. *Cative #ethods are discussed in 6%%endi& B., + and +<< are the only languages currently su%%orted by native #ethods, but since they can call sub%rogra#s in other languages, you can e""ectively call anything. Inside the non'Java code, + s mallocA B "a#ily o" "unctions #ight be called to allocate storage, and unless you call freeA B that storage will not be released, causing a #e#ory leak. )" course, freeA B is a + and +<< "unction, so you d need to call it in a native #ethod inside your finali7e A B. RFSURFSTIJLT+(6PTE5?TIHHU 6"ter reading this, you %robably get the idea that you won t use finali7e A B #uch. /ou re correct; it is not the a%%ro%riate %lace "or nor#al cleanu% to occur. So where should nor#al cleanu% be %er"or#edO RF SURFSTIJLT+(6PTE5?TIH3U
218
In contrast, Java doesn t allow you to create local ob0ects9you #ust always use ne(. But in Java, there s no !delete$ to call to release the ob0ect since the garbage collector releases the storage "or you. So "ro# a si#%listic stand%oint you could say that because o" garbage collection, Java has no destructor. /ou ll see as this book %rogresses, however, that the %resence o" a garbage collector does not re#ove the need "or or utility o" destructors. *6nd you should never call finali7eA B directly, so that s not an a%%ro%riate avenue "or a solution., I" you want so#e kind o" cleanu% %er"or#ed other than storage release you #ust still e&%licitly call an a%%ro%riate #ethod in Java, which is the eAuivalent o" a +<< destructor without the convenience. RFSURFSTIJLT+(6PTE5?TIHIU )ne o" the things finali7eA B can be use"ul "or is observing the %rocess o" garbage collection. The "ollowing e&a#%le shows you what s going on and su##ari1es the %revious descri%tions o" garbage collection=
//3 c'I3aarbage.Hava // De#onstration of the garbage // collector an! finaliUation class Chair @ static boolean gcrun ? false< static boolean f ? false< static int create! ? '< static int finaliUe! ? '< int i< Chair-. @ i ? KKcreate!< if-create! ?? I*. %yste#.out."rintln-8Create! I*8.< A "ublic voi! finaliUe-. @ if-4gcrun. @ // The first ti#e finaliUe-. is calle!3 gcrun ? true< %yste#.out."rintln8Beginning to finaliUe after 8 K create! K 8 Chairs have been create!8.< A if-i ?? I*. @ %yste#.out."rintln-
21:
8LinaliUing Chair SI*, 8 K 8%etting flag to sto" Chair creation8.< f ? true< A finaliUe!KK< if-finaliUe! Q? create!. %yste#.out."rintln80ll 8 K finaliUe! K 8 finaliUe!8.< A A "ublic class aarbage @ "ublic static voi! #ain-%tringNO args. @ // 0s long as the flag hasn2t been set, // #ake Chairs an! %trings3 :hile-4Chair.f. @ ne: Chair-.< ne: %tring-8To take u" s"ace8.< A %yste#.out."rintln80fter all Chairs have been create!3_n8 K 8total create! ? 8 K Chair.create! K 8, total finaliUe! ? 8 K Chair.finaliUe!.< // G"tional argu#ents force garbage // collection D finaliUation3 if-args.length Q '. @ if-argsN'O.e=uals-8gc8. XX argsN'O.e=uals-8all8.. @ %yste#.out."rintln-8gc-.38.< %yste#.gc-.< A if-argsN'O.e=uals-8finaliUe8. XX argsN'O.e=uals-8all8.. @ %yste#.out."rintln-8runLinaliUation-.38.< %yste#.runLinaliUation-.< A A %yste#.out."rintln-8bye48.< A A ///3>
21;
The above %rogra# creates #any -hair ob0ects, and at so#e %oint a"ter the garbage collector begins running, the %rogra# sto%s creating -hairs. Since the garbage collector can run at any ti#e, you don t know e&actly when it will start u%, so there s a "lag called gcr*n to indicate whether the garbage collector has started running yet. 6 second "lag f is a way "or -hair to tell the mainA B loo% that it should sto% #aking ob0ects. Both o" these "lags are set within finali7eA B, which is called during garbage collection. RFSURFSTIJLT+(6PTE5?TIH2U Two other static variables, create' and finali7e', kee% track o" the nu#ber o" -hairs created versus the nu#ber that get "inali1ed by the garbage collector. Einally, each -hair has its own *non' static, int i so it can kee% track o" what nu#ber it is. :hen -hair nu#ber ?G is "inali1ed, the "lag is set to tr*e to bring the %rocess o" -hair creation to a sto%. RF SURFSTIJLT+(6PTE5?TI3@U 6ll this ha%%ens in mainA B, in the loo%
22=
The behavior o" this %rogra# and the version in the "irst edition o" this book shows that the whole issue o" garbage collection and "inali1ation has been evolving, with #uch o" the evolution ha%%ening behind closed doors. In "act, by the ti#e you read this, the behavior o" the %rogra# #ay have changed once again. RFSURFSTIJLT+(6PTE5?TI3?U I" )ystem!gcA B is called, then "inali1ation ha%%ens to all the ob0ects. This was not necessarily the case with %revious i#%le#entations o" the J7>, although the docu#entation clai#ed otherwise. In addition, you ll see that it doesn t see# to #ake any di""erence whether )ystem! r*nFinali7ationA B is called. RFSURFSTIJLT+(6PTE5?TI3HU (owever, you will see that only i" )ystem!gcA B is called a"ter all the ob0ects are created and discarded will all the "inali1ers be called. I" you do not call )ystem!gcA B, then only so#e o" the ob0ects will be "inali1ed. In Java M.M, a #ethod )ystem!r*nFinali7ers.n&4itA B was introduced that caused %rogra#s to run all the "inali1ers as they e&ited, but the design turned out to be buggy and the #ethod was de%recated. This is yet another clue that the Java designers were thrashing about trying to solve the garbage collection and "inali1ation %roble#. :e can only ho%e that things have been worked out in Java K. RFSURFSTIJLT+(6PTE5?TI33U The %receding %rogra# shows that the %ro#ise that "inali1ers will always be run holds true, but only i" you e&%licitly "orce it to ha%%en yoursel". I" you don t cause )ystem!gcA B to be called, you ll get an out%ut like this=
Create! I* Beginning to finaliUe create! LinaliUing Chair SI*, creation 0fter all Chairs have total create! ? )11(, bye4
after )I1+ Chairs have been %etting flag to sto" Chair been create!3 total finaliUe! ? +1I
Thus, not all "inali1ers get called by the ti#e the %rogra# co#%letes. I" )ystem!gcA B is called, it will "inali1e and destroy all the ob0ects that are no longer in use u% to that %oint. RFSURFSTIJLT+(6PTE5?TI3GU 5e#e#ber that neither garbage collection nor "inali1ation is guaranteed. I" the Java Virtual Machine *JVM, isn t close to running out o" #e#ory,
221
then it will *wisely, not waste ti#e recovering #e#ory through garbage collection. RFSURFSTIJLT+(6PTE5?TI3IU
//3 c'I3DeathCon!ition.Hava // Ysing finaliUe-. to !etect an obHect that // hasn2t been "ro"erly cleane! u". class Book @ boolean checke!Gut ? false< Book-boolean checkGut. @ checke!Gut ? checkGut< A voi! check$n-. @ checke!Gut ? false< A
@ 6 ter# coined by Bill Venners *www.arti#a.co#, during a se#inar that he and I were giving together.
222
"ublic voi! finaliUe-. @ if-checke!Gut. %yste#.out."rintln-8Error3 checke! out8.< A A "ublic class DeathCon!ition @ "ublic static voi! #ain-%tringNO args. @ Book novel ? ne: Book-true.< // Pro"er cleanu"3 novel.check$n-.< // Dro" the reference, forget to clean u"3 ne: Book-true.< // Lorce garbage collection D finaliUation3 %yste#.gc-.< A A ///3>
The death condition is that all 2ook ob0ects are su%%osed to be checked in be"ore they are garbage'collected, but in mainA B a %rogra##er error doesn t check in one o" the books. :ithout finali7eA B to veri"y the death condition, this could be a di""icult bug to "ind. RFSURF STIJLT+(6PTE5?TIGMU Cote that )ystem!gcA B is used to "orce "inali1ation *and you should do this during %rogra# develo%#ent to s%eed debugging,. But even i" it isn t, it s highly %robable that the errant 2ook will eventually be discovered through re%eated e&ecutions o" the %rogra# *assu#ing the %rogra# allocates enough storage to cause the garbage collector to e&ecute,. RF SURFSTIJLT+(6PTE5?TIGKU
223
ob0ects in Java can be nearly as "ast as creating storage on the stack in other languages. RFSURFSTIJLT+(6PTE5?TIGLU Eor e&a#%le, you can think o" the +<< hea% as a yard where each ob0ect stakes out its own %iece o" tur". This real estate can beco#e abandoned so#eti#e later and #ust be reused. In so#e JVMs, the Java hea% is Auite di""erent; it s #ore like a conveyor belt that #oves "orward every ti#e you allocate a new ob0ect. This #eans that ob0ect storage allocation is re#arkably ra%id. The !hea% %ointer$ is si#%ly #oved "orward into virgin territory, so it s e""ectively the sa#e as +<< s stack allocation. *)" course, there s a little e&tra overhead "or bookkee%ing but it s nothing like searching "or storage., RFSURFSTIJLT+(6PTE5?TIG?U Cow you #ight observe that the hea% isn t in "act a conveyor belt, and i" you treat it that way you ll eventually start %aging #e#ory a lot *which is a big %er"or#ance hit, and later run out. The trick is that the garbage collector ste%s in and while it collects the garbage it co#%acts all the ob0ects in the hea% so that you ve e""ectively #oved the !hea% %ointer$ closer to the beginning o" the conveyor belt and "urther away "ro# a %age "ault. The garbage collector rearranges things and #akes it %ossible "or the high's%eed, in"inite'"ree'hea% #odel to be used while allocating storage. RFSURFSTIJLT+(6PTE5?TIGHU To understand how this works, you need to get a little better idea o" the way the di""erent garbage collector *8+, sche#es work. 6 si#%le but slow 8+ techniAue is re"erence counting. This #eans that each ob0ect contains a re"erence counter, and every ti#e a re"erence is attached to an ob0ect the re"erence count is increased. Every ti#e a re"erence goes out o" sco%e or is set to n*ll, the re"erence count is decreased. Thus, #anaging re"erence counts is a s#all but constant overhead that ha%%ens throughout the li"eti#e o" your %rogra#. The garbage collector #oves through the entire list o" ob0ects and when it "inds one with a re"erence count o" 1ero it releases that storage. The one drawback is that i" ob0ects circularly re"er to each other they can have non1ero re"erence counts while still being garbage. Docating such sel"'re"erential grou%s reAuires signi"icant e&tra work "or the garbage collector. 5e"erence counting is co##only used to e&%lain one kind o" garbage collection but it doesn t see# to be used in any JVM i#%le#entations. RFSURF STIJLT+(6PTE5?TIG3U
224
In "aster sche#es, garbage collection is not based on re"erence counting. Instead, it is based on the idea that any nondead ob0ect #ust ulti#ately be traceable back to a re"erence that lives either on the stack or in static storage. The chain #ight go through several layers o" ob0ects. Thus, i" you start in the stack and the static storage area and walk through all the re"erences you ll "ind all the live ob0ects. Eor each re"erence that you "ind, you #ust trace into the ob0ect that it %oints to and then "ollow all the re"erences in that ob0ect, tracing into the ob0ects they %oint to, etc., until you ve #oved through the entire web that originated with the re"erence on the stack or in static storage. Each ob0ect that you #ove through #ust still be alive. Cote that there is no %roble# with detached sel"'re"erential grou%s9these are si#%ly not "ound, and are there"ore auto#atically garbage. RFSURFSTIJLT+(6PTE5?TIGGU In the a%%roach described here, the JVM uses an ada tive garbage' collection sche#e, and what it does with the live ob0ects that it locates de%ends on the variant currently being used. )ne o" these variants is sto /and/co ). This #eans that9"or reasons that will beco#e a%%arent9 the %rogra# is "irst sto%%ed *this is not a background collection sche#e,. Then, each live ob0ect that is "ound is co%ied "ro# one hea% to another, leaving behind all the garbage. In addition, as the ob0ects are co%ied into the new hea% they are %acked end'to'end, thus co#%acting the new hea% *and allowing new storage to si#%ly be reeled o"" the end as %reviously described,. RFSURFSTIJLT+(6PTE5?TIGIU )" course, when an ob0ect is #oved "ro# one %lace to another, all re"erences that %oint at *i.e., that re$erence, the ob0ect #ust be changed. The re"erence that goes "ro# the hea% or the static storage area to the ob0ect can be changed right away, but there can be other re"erences %ointing to this ob0ect that will be encountered later during the !walk.$ These are "i&ed u% as they are "ound *you could i#agine a table that #a%s old addresses to new ones,. RFSURFSTIJLT+(6PTE5?TIG2U There are two issues that #ake these so'called !co%y collectors$ ine""icient. The "irst is the idea that you have two hea%s and you slosh all the #e#ory back and "orth between these two se%arate hea%s, #aintaining twice as #uch #e#ory as you actually need. So#e JVMs deal with this by allocating the hea% in chunks as needed and si#%ly co%ying "ro# one chunk to another. RFSURFSTIJLT+(6PTE5?TII@U
225
The second issue is the co%ying. )nce your %rogra# beco#es stable it #ight be generating little or no garbage. 7es%ite that, a co%y collector will still co%y all the #e#ory "ro# one %lace to another, which is waste"ul. To %revent this, so#e JVMs detect that no new garbage is being generated and switch to a di""erent sche#e *this is the !ada%tive$ %art,. This other sche#e is called mark and s,ee , and it s what earlier versions o" Sun s JVM used all the ti#e. Eor general use, #ark and swee% is "airly slow, but when you know you re generating little or no garbage it s "ast. RFSURF STIJLT+(6PTE5?TIIMU Mark and swee% "ollows the sa#e logic o" starting "ro# the stack and static storage and tracing through all the re"erences to "ind live ob0ects. (owever, each ti#e it "inds a live ob0ect that ob0ect is #arked by setting a "lag in it, but the ob0ect isn t collected yet. )nly when the #arking %rocess is "inished does the swee% occur. 7uring the swee%, the dead ob0ects are released. (owever, no co%ying ha%%ens, so i" the collector chooses to co#%act a "rag#ented hea% it does so by shu""ling ob0ects around. RF SURFSTIJLT+(6PTE5?TIIKU The !sto%'and'co%y$ re"ers to the idea that this ty%e o" garbage collection is not done in the background; instead, the %rogra# is sto%%ed while the 8+ occurs. In the Sun literature you ll "ind #any re"erences to garbage collection as a low'%riority background %rocess, but it turns out that the 8+ was not i#%le#ented that way, at least in earlier versions o" the Sun JVM. Instead, the Sun garbage collector ran when #e#ory got low. In addition, #ark'and'swee% reAuires that the %rogra# be sto%%ed. RFSURF STIJLT+(6PTE5?TIILU 6s %reviously #entioned, in the JVM described here #e#ory is allocated in big blocks. I" you allocate a large ob0ect, it gets its own block. Strict sto%'and'co%y reAuires co%ying every live ob0ect "ro# the source hea% to a new hea% be"ore you could "ree the old one, which translates to lots o" #e#ory. :ith blocks, the 8+ can ty%ically use dead blocks to co%y ob0ects to as it collects. Each block has a generation count to kee% track o" whether it s alive. In the nor#al case, only the blocks created since the last 8+ are co#%acted; all other blocks get their generation count bu#%ed i" they have been re"erenced "ro# so#ewhere. This handles the nor#al case o" lots o" short'lived te#%orary ob0ects. Periodically, a "ull swee% is #ade9large ob0ects are still not co%ied *0ust get their generation
227
count bu#%ed, and blocks containing s#all ob0ects are co%ied and co#%acted. The JVM #onitors the e""iciency o" 8+ and i" it beco#es a waste o" ti#e because all ob0ects are long'lived then it switches to #ark' and'swee%. Si#ilarly, the JVM kee%s track o" how success"ul #ark'and' swee% is, and i" the hea% starts to beco#e "rag#ented it switches back to sto%'and'co%y. This is where the !ada%tive$ %art co#es in, so you end u% with a #outh"ul= !ada%tive generational sto%'and'co%y #ark'and'swee%.$ RFSURFSTIJLT+(6PTE5?TII?U There are a nu#ber o" additional s%eedu%s %ossible in a JVM. 6n es%ecially i#%ortant one involves the o%eration o" the loader and Just'In' Ti#e *JIT, co#%iler. :hen a class #ust be loaded *ty%ically, the "irst ti#e you want to create an ob0ect o" that class,, the !class "ile is located and the byte codes "or that class are brought into #e#ory. 6t this %oint, one a%%roach is to si#%ly JIT all the code, but this has two drawbacks= it takes a little #ore ti#e, which, co#%ounded throughout the li"e o" the %rogra#, can add u%; and it increases the si1e o" the e&ecutable *byte codes are signi"icantly #ore co#%act than e&%anded JIT code, and this #ight cause %aging, which de"initely slows down a %rogra#. 6n alternative a%%roach is la?) evaluationD which #eans that the code is not JIT co#%iled until necessary. Thus, code that never gets e&ecuted #ight never get JIT co#%iled. RFSURFSTIJLT+(6PTE5?TIIHU
Member initiali?ation
Java goes out o" its way to guarantee that variables are %ro%erly initiali1ed be"ore they are used. In the case o" variables that are de"ined locally to a #ethod, this guarantee co#es in the "or# o" a co#%ile'ti#e error. So i" you say= RFSURFSTIJLT+(6PTE5?TII3U
228
have covered that u%. Eorcing the %rogra##er to %rovide an initiali1ation value is #ore likely to catch a bug. RFSURFSTIJLT+(6PTE5?TIIGU I" a %ri#itive is a data #e#ber o" a class, however, things are a bit di""erent. Since any #ethod can initiali1e or use that data, it #ight not be %ractical to "orce the user to initiali1e it to its a%%ro%riate value be"ore the data is used. (owever, it s unsa"e to leave it with a garbage value, so each %ri#itive data #e#ber o" a class is guaranteed to get an initial value. Those values can be seen here= RFSURFSTIJLT+(6PTE5?TIIIU
//3 c'I3$nitialWalues.Hava // %ho:s !efault initial values. class Jeasure#ent @ boolean t< char c< byte b< short s< int i< long l< float f< !ouble !< voi! "rint-. @ %yste#.out."rintln8Data ty"e $nitial value_n8 K 8boolean 8 K t K 8_n8 K 8char N8 K c K 8O 8K -int.c K8_n8K 8byte 8 K b K 8_n8 K 8short 8 K s K 8_n8 K 8int 8 K i K 8_n8 K 8long 8 K l K 8_n8 K 8float 8 K f K 8_n8 K 8!ouble 8 K !.< A A "ublic class $nitialWalues @ "ublic static voi! #ain-%tringNO args. @ Jeasure#ent ! ? ne: Jeasure#ent-.< !."rint-.< /B $n this case you coul! also say3
22:
Data ty"e boolean char byte short int long float !ouble
$nitial value false N O ' ' ' ' ' '.' '.'
The char value is a 1ero, which %rints as a s%ace. RFSURF STIJLT+(6PTE5?TII2U /ou ll see later that when you de"ine an ob0ect re"erence inside a class without initiali1ing it to a new ob0ect, that re"erence is given a s%ecial value o" n*ll *which is a Java keyword,. RFSURF STIJLT+(6PTE5?TI2@U /ou can see that even though the values are not s%eci"ied, they auto#atically get initiali1ed. So at least there s no threat o" working with uninitiali1ed variables. RFSURFSTIJLT+(6PTE5?TI2MU
1.ecif:ing initiali?ation
:hat ha%%ens i" you want to give a variable an initial valueO )ne direct way to do this is si#%ly to assign the value at the %oint you de"ine the variable in the class. *Cotice you cannot do this in +<<, although +<< novices always try., (ere the "ield de"initions in class 1eas*rement are changed to %rovide initial values=
class Jeasure#ent @ boolean b ? true< char c ? 262< byte B ? I*< short s ? '6ff<
22;
23=
This is one %lace in which the co#%iler, a%%ro%riately, does co#%lain about "orward re"erencing, since this has to do with the order o" initiali1ation and not the way the %rogra# is co#%iled. RFSURF STIJLT+(6PTE5?TI23U This a%%roach to initiali1ation is si#%le and straight"orward. It has the li#itation that ever) ob0ect o" ty%e 1eas*rement will get these sa#e initiali1ation values. So#eti#es this is e&actly what you need, but at other ti#es you need #ore "le&ibility. RFSURFSTIJLT+(6PTE5?TI2GU
Constructor initiali?ation
The constructor can be used to %er"or# initiali1ation, and this gives you greater "le&ibility in your %rogra##ing since you can call #ethods and %er"or# actions at run'ti#e to deter#ine the initial values. There s one thing to kee% in #ind, however= you aren t %recluding the auto#atic initiali1ation, which ha%%ens be"ore the constructor is entered. So, "or e&a#%le, i" you say=
Order of initiali?ation
:ithin a class, the order o" initiali1ation is deter#ined by the order that the variables are de"ined within the class. The variable de"initions #ay be scattered throughout and in between #ethod de"initions, but the
@ In contrast, +<< has the constructor initiali?er list that causes initiali1ation to occur be"ore entering the constructor body, and is en"orced "or ob0ects. See Thinking in C++D 2nd edition *available on this book s +7 5)M and at ,,,'0ruceEckel'com,.
231
variables are initiali1ed be"ore any #ethods can be called9even the constructor. Eor e&a#%le= RFSURFSTIJLT+(6PTE5?TI22U
//3 c'I3Gr!erGf$nitialiUation.Hava // De#onstrates initialiUation or!er. // \hen the constructor is calle! to create a // Tag obHect, you2ll see a #essage3 class Tag @ Tag-int #arker. @ %yste#.out."rintln-8Tag-8 K #arker K 8.8.< A A class Car! @ Tag t( ? ne: Tag-(.< // Before constructor Car!-. @ // $n!icate :e2re in the constructor3 %yste#.out."rintln-8Car!-.8.< t) ? ne: Tag-)).< // 5einitialiUe t) A Tag t ? ne: Tag- .< // 0fter constructor voi! f-. @ %yste#.out."rintln-8f-.8.< A Tag t) ? ne: Tag-).< // 0t en! A "ublic class Gr!erGf$nitialiUation @ "ublic static voi! #ain-%tringNO args. @ Car! t ? ne: Car!-.< t.f-.< // %ho:s that construction is !one A A ///3>
In -ar', the de"initions o" the Tag ob0ects are intentionally scattered about to %rove that they ll all get initiali1ed be"ore the constructor is entered or anything else can ha%%en. In addition, tJ is reinitiali1ed inside the constructor. The out%ut is= RFSURFSTIJLT+(6PTE5?TIM@@U
Tag-(. Tag- .
232
//3 c'I3%tatic$nitialiUation.Hava // %"ecifying initial values in a // class !efinition. class Bo:l @ Bo:l-int #arker. @ %yste#.out."rintln-8Bo:l-8 K #arker K 8.8.< A voi! f-int #arker. @ %yste#.out."rintln-8f-8 K #arker K 8.8.< A A class Table @ static Bo:l b( ? ne: Bo:l-(.< Table-. @
233
%yste#.out."rintln-8Table-.8.< b .f-(.< A voi! f -int #arker. @ %yste#.out."rintln-8f -8 K #arker K 8.8.< A static Bo:l b ? ne: Bo:l- .< A class Cu"boar! @ Bo:l b) ? ne: Bo:l-).< static Bo:l bI ? ne: Bo:l-I.< Cu"boar!-. @ %yste#.out."rintln-8Cu"boar!-.8.< bI.f- .< A voi! f)-int #arker. @ %yste#.out."rintln-8f)-8 K #arker K 8.8.< A static Bo:l b, ? ne: Bo:l-,.< A "ublic class %tatic$nitialiUation @ "ublic static voi! #ain-%tringNO args. @ %yste#.out."rintln8Creating ne: Cu"boar!-. in #ain8.< ne: Cu"boar!-.< %yste#.out."rintln8Creating ne: Cu"boar!-. in #ain8.< ne: Cu"boar!-.< t .f -(.< t).f)-(.< A static Table t ? ne: Table-.< static Cu"boar! t) ? ne: Cu"boar!-.< A ///3> 2o(l allows you to view the creation o" a class, and Table and -*pboar' create static #e#bers o" 2o(l scattered through their class de"initions. Cote that -*pboar' creates a non' static 2o(l bJ %rior to
234
the static de"initions. The out%ut shows what ha%%ens= RFSURF STIJLT+(6PTE5?TIM@?U
Bo:l-(. Bo:l- . Table-. f-(. Bo:l-I. Bo:l-,. Bo:l-). Cu"boar!-. f- . Creating ne: Cu"boar!-. in #ain Bo:l-). Cu"boar!-. f- . Creating ne: Cu"boar!-. in #ain Bo:l-). Cu"boar!-. f- . f -(. f)-(.
The static initiali1ation occurs only i" it s necessary. I" you don t create a Table ob0ect and you never re"er to Table!b> or Table!bI, the static 2o(l b> and bI will never be created. (owever, they are initiali1ed only when the $irst Table ob0ect is created *or the "irst static access occurs,. 6"ter that, the static ob0ects are not reinitiali1ed. RFSURF STIJLT+(6PTE5?TIM@HU The order o" initiali1ation is statics "irst, i" they haven t already been initiali1ed by a %revious ob0ect creation, and then the non' static ob0ects. /ou can see the evidence o" this in the out%ut. RFSURF STIJLT+(6PTE5?TIM@3U It s hel%"ul to su##ari1e the %rocess o" creating an ob0ect. +onsider a class called og= RFSURFSTIJLT+(6PTE5?TIM@GU
*!)
The "irst ti#e an ob0ect o" ty%e og is created, or the "irst ti#e a static #ethod or static "ield o" class og is accessed, the Java
235
inter%reter #ust locate og!class, which it does by searching through the class%ath. RFSURFSTIJLT+(6PTE5?TIM@IU
**)
6s og!class is loaded *creating a -lass ob0ect, which you ll learn about later,, all o" its static initiali1ers are run. Thus, static initiali1ation takes %lace only once, as the -lass ob0ect is loaded "or the "irst ti#e. RFSURFSTIJLT+(6PTE5?TIM@2U :hen you create a ne( ogA B, the construction %rocess "or a og ob0ect "irst allocates enough storage "or a og ob0ect on the hea%. RFSURFSTIJLT+(6PTE5?TIMM@U This storage is wi%ed to 1ero, auto#atically setting all the %ri#itives in that og ob0ect to their de"ault values *1ero "or nu#bers and the eAuivalent "or boolean and char, and the re"erences to n*ll. RFSURFSTIJLT+(6PTE5?TIMMMU 6ny initiali1ations that occur at the %oint o" "ield de"inition are e&ecuted. RFSURFSTIJLT+(6PTE5?TIMMKU +onstructors are e&ecuted. 6s you shall see in +ha%ter 3, this #ight actually involve a "air a#ount o" activity, es%ecially when inheritance is involved. RFSURFSTIJLT+(6PTE5?TIMMLU
*+)
*,)
*-) *4)
237
//3 c'I3E6"licit%tatic.Hava // E6"licit static initialiUation // :ith the 8static8 clause. class Cu" @ Cu"-int #arker. @ %yste#.out."rintln-8Cu"-8 K #arker K 8.8.< A voi! f-int #arker. @ %yste#.out."rintln-8f-8 K #arker K 8.8.< A A class Cu"s @ static Cu" c(< static Cu" c < static @ c( ? ne: Cu"-(.< c ? ne: Cu"- .< A Cu"s-. @ %yste#.out."rintln-8Cu"s-.8.< A A "ublic class E6"licit%tatic @ "ublic static voi! #ain-%tringNO args. @ %yste#.out."rintln-8$nsi!e #ain-.8.< Cu"s.c(.f-CC.< // -(. A // static Cu"s 6 ? ne: Cu"s-.< // - . // static Cu"s y ? ne: Cu"s-.< // - . A ///3>
The static initiali1ers "or -*ps run when either the access o" the static ob0ect c> occurs on the line #arked *M,, or i" line *M, is co##ented out and the lines #arked *K, are unco##ented. I" both *M, and *K, are co##ented out, the static initiali1ation "or -*ps never occurs. 6lso, it doesn t #atter i" one or both o" the lines #arked *K, are unco##ented; the static initiali1ation only occurs once. RFSURF STIJLT+(6PTE5?TIMM3U
238
//3 c'I3Jugs.Hava // Java 8$nstance $nitialiUation.8 class Jug @ Jug-int #arker. @ %yste#.out."rintln-8Jug-8 K #arker K 8.8.< A voi! f-int #arker. @ %yste#.out."rintln-8f-8 K #arker K 8.8.< A A "ublic class Jugs @ Jug c(< Jug c < @ c( ? ne: Jug-(.< c ? ne: Jug- .< %yste#.out."rintln-8c( D c initialiUe!8.< A Jugs-. @ %yste#.out."rintln-8Jugs-.8.< A "ublic static voi! #ain-%tringNO args. @ %yste#.out."rintln-8$nsi!e #ain-.8.< Jugs 6 ? ne: Jugs-.< A A ///3>
/ou can see that the instance initiali1ation clause= RFSURF STIJLT+(6PTE5?TIMMGU
23:
looks e&actly like the static initiali1ation clause e&ce%t "or the #issing
static keyword. This synta& is necessary to su%%ort the initiali1ation o" anon)mous inner classes *see +ha%ter I,. RFSURF
STIJLT+(6PTE5?TIMMIU
Arra: initiali?ation
Initiali1ing arrays in + is error'%rone and tedious. +<< uses aggregate initiali?ation to #ake it #uch sa"er @. Java has no !aggregates$ like +<<, since everything is an ob0ect in Java. It does have arrays, and these are su%%orted with array initiali1ation. RFSURFSTIJLT+(6PTE5?TIMM2U 6n array is si#%ly a seAuence o" either ob0ects or %ri#itives, all the sa#e ty%e and %ackaged together under one identi"ier na#e. 6rrays are de"ined and used with the sAuare'brackets inde*ing o erator ] ^. To de"ine an array you si#%ly "ollow your ty%e na#e with e#%ty sAuare brackets= RF SURFSTIJLT+(6PTE5?TIMK@U
intNO a(<
/ou can also %ut the sAuare brackets a"ter the identi"ier to %roduce e&actly the sa#e #eaning= RFSURFSTIJLT+(6PTE5?TIMKMU
int a(NO<
This con"or#s to e&%ectations "ro# + and +<< %rogra##ers. The "or#er style, however, is %robably a #ore sensible synta&, since it says that the ty%e is !an int array.$ That style will be used in this book. RFSURF STIJLT+(6PTE5?TIMKKU The co#%iler doesn t allow you to tell it how big the array is. This brings us back to that issue o" !re"erences.$ 6ll that you have at this %oint is a re"erence to an array, and there s been no s%ace allocated "or the array. To create storage "or the array you #ust write an initiali1ation e&%ression. Eor arrays, initiali1ation can a%%ear anywhere in your code, but you can also use a s%ecial kind o" initiali1ation e&%ression that #ust occur at the %oint where the array is created. This s%ecial initiali1ation is a set o"
@ See Thinking in C++D 2nd edition "or a co#%lete descri%tion o" +<< aggregate initiali1ation.
23;
values surrounded by curly braces. The storage allocation *the eAuivalent o" using ne(, is taken care o" by the co#%iler in this case. Eor e&a#%le= RFSURFSTIJLT+(6PTE5?TIMKLU
intNO a( ? @ (,
, ), I, , A<
So why would you ever de"ine an array re"erence without an arrayO RF SURFSTIJLT+(6PTE5?TIMK?U
intNO a <
:ell, it s %ossible to assign one array to another in Java, so you can say= RFSURFSTIJLT+(6PTE5?TIMKHU
? a(<
//3 c'I30rrays.Hava // 0rrays of "ri#itives. "ublic class 0rrays @ "ublic static voi! #ain-%tringNO args. @ intNO a( ? @ (, , ), I, , A< intNO a < a ? a(< for-int i ? '< i P a .length< iKK. a NiOKK< for-int i ? '< i P a(.length< iKK. %yste#.out."rintln8a(N8 K i K 8O ? 8 K a(NiO.< A A ///3>
/ou can see that a> is given an initiali1ation value while aI is not; aI is assigned later9in this case, to another array. RFSURF STIJLT+(6PTE5?TIMKGU There s so#ething new here= all arrays have an intrinsic #e#ber *whether they re arrays o" ob0ects or arrays o" %ri#itives, that you can Auery9but not change9to tell you how #any ele#ents there are in the array. This #e#ber is length. Since arrays in Java, like + and +<<, start
24=
counting "ro# ele#ent 1ero, the largest ele#ent you can inde& is length 6 >. I" you go out o" bounds, + and +<< Auietly acce%t this and allow you to sto#% all over your #e#ory, which is the source o" #any in"a#ous bugs. (owever, Java %rotects you against such %roble#s by causing a run'ti#e error *an e*ce tion, the sub0ect o" +ha%ter M@, i" you ste% out o" bounds. )" course, checking every array access costs ti#e and code and there s no way to turn it o"", which #eans that array accesses #ight be a source o" ine""iciency in your %rogra# i" they occur at a critical 0uncture. Eor Internet security and %rogra##er %roductivity, the Java designers thought that this was a worthwhile trade'o"". RFSURF STIJLT+(6PTE5?TIMKIU :hat i" you don t know how #any ele#ents you re going to need in your array while you re writing the %rogra#O /ou si#%ly use ne( to create the ele#ents in the array. (ere, ne( works even though it s creating an array o" %ri#itives * ne( won t create a nonarray %ri#itive,= RFSURF STIJLT+(6PTE5?TIMK2U
//3 c'I30rray&e:.Hava // Creating arrays :ith ne:. i#"ort Hava.util.B< "ublic class 0rray&e: @ static 5an!o# ran! ? ne: 5an!o#-.< static int "5an!-int #o!. @ return Jath.abs-ran!.ne6t$nt-.. V #o! K (< A "ublic static voi! #ain-%tringNO args. @ intNO a< a ? ne: intN"5an!- '.O< %yste#.out."rintln8length of a ? 8 K a.length.< for-int i ? '< i P a.length< iKK. %yste#.out."rintln8aN8 K i K 8O ? 8 K aNiO.< A A ///3>
Since the si1e o" the array is chosen at rando# *using the p$an'A B #ethod,, it s clear that array creation is actually ha%%ening at run'ti#e. In addition, you ll see "ro# the out%ut o" this %rogra# that array ele#ents
241
o" %ri#itive ty%es are auto#atically initiali1ed to !e#%ty$ values. *Eor nu#erics and char, this is 1ero, and "or boolean, it s false., RFSURF STIJLT+(6PTE5?TIML@U )" course, the array could also have been de"ined and initiali1ed in the sa#e state#ent=
//3 c'I30rrayClassGbH.Hava // Creating an array of non"ri#itive obHects. i#"ort Hava.util.B< "ublic class 0rrayClassGbH @ static 5an!o# ran! ? ne: 5an!o#-.< static int "5an!-int #o!. @ return Jath.abs-ran!.ne6t$nt-.. V #o! K (< A "ublic static voi! #ain-%tringNO args. @ $ntegerNO a ? ne: $ntegerN"5an!- '.O< %yste#.out."rintln8length of a ? 8 K a.length.< for-int i ? '< i P a.length< iKK. @ aNiO ? ne: $nteger-"5an!-,''..< %yste#.out."rintln8aN8 K i K 8O ? 8 K aNiO.< A A A ///3>
(ere, even a"ter ne( is called to create the array= RFSURF STIJLT+(6PTE5?TIMLKU
242
it s only an array o" re"erences, and not until the re"erence itsel" is initiali1ed by creating a new Integer ob0ect is the initiali1ation co#%lete= RFSURFSTIJLT+(6PTE5?TIMLLU
//3 c'I30rray$nit.Hava // 0rray initialiUation. "ublic class 0rray$nit @ "ublic static voi! #ain-%tringNO args. @ $ntegerNO a ? @ ne: $nteger-(., ne: $nteger- ., ne: $nteger-)., A< $ntegerNO b ? ne: $ntegerNO @ ne: $nteger-(., ne: $nteger- ., ne: $nteger-)., A< A A ///3>
This is use"ul at ti#es, but it s #ore li#ited since the si1e o" the array is deter#ined at co#%ile'ti#e. The "inal co##a in the list o" initiali1ers is o%tional. *This "eature #akes "or easier #aintenance o" long lists., RF SURFSTIJLT+(6PTE5?TIML3U
243
The second "or# o" array initiali1ation %rovides a convenient synta& to create and call #ethods that can %roduce the sa#e e""ect as + s variable argument lists *known as !varargs$ in +,. These can include unknown Auantity o" argu#ents as well as unknown ty%es. Since all classes are ulti#ately inherited "ro# the co##on root class .b8ect *a sub0ect you will learn #ore about as this book %rogresses,, you can create a #ethod that takes an array o" .b8ect and call it like this= RFSURF STIJLT+(6PTE5?TIMLGU
//3 c'I3War0rgs.Hava // Ysing the array synta6 to create // variable argu#ent lists. class 0 @ int i< A "ublic class War0rgs @ static voi! f-GbHectNO 6. @ for-int i ? '< i P 6.length< iKK. %yste#.out."rintln-6NiO.< A "ublic static voi! #ain-%tringNO args. @ f-ne: GbHectNO @ ne: $nteger-I*., ne: War0rgs-., ne: Lloat-).(I., ne: Double-((.((. A.< f-ne: GbHectNO @8one8, 8t:o8, 8three8 A.< f-ne: GbHectNO @ne: 0-., ne: 0-., ne: 0-.A.< A A ///3>
6t this %oint, there s not #uch you can do with these unknown ob0ects, and this %rogra# uses the auto#atic )tring conversion to do so#ething use"ul with each .b8ect. In +ha%ter MK, which covers run/time t) e identi$ication *5TTI,, you ll learn how to discover the e&act ty%e o" such ob0ects so that you can do so#ething #ore interesting with the#. RFSURF STIJLT+(6PTE5?TIMLIU
Multidimensional arra:s
Java allows you to easily create #ultidi#ensional arrays=
//3 c'I3JultiDi#0rray.Hava
244
// Creating #ulti!i#ensional arrays. i#"ort Hava.util.B< "ublic class JultiDi#0rray @ static 5an!o# ran! ? ne: 5an!o#-.< static int "5an!-int #o!. @ return Jath.abs-ran!.ne6t$nt-.. V #o! K (< A static voi! "rt-%tring s. @ %yste#.out."rintln-s.< A "ublic static voi! #ain-%tringNO args. @ intNONO a( ? @ @ (, , ), A, @ I, ,, +, A, A< for-int i ? '< i P a(.length< iKK. for-int H ? '< H P a(NiO.length< HKK. "rt-8a(N8 K i K 8ON8 K H K 8O ? 8 K a(NiONHO.< // )-D array :ith fi6e! length3 intNONONO a ? ne: intN ON ONIO< for-int i ? '< i P a .length< iKK. for-int H ? '< H P a NiO.length< HKK. for-int k ? '< k P a NiONHO.length< kKK. "rt-8a N8 K i K 8ON8 K H K 8ON8 K k K 8O ? 8 K a NiONHONkO.< // )-D array :ith varie!-length vectors3 intNONONO a) ? ne: intN"5an!-*.ONONO< for-int i ? '< i P a).length< iKK. @ a)NiO ? ne: intN"5an!-,.ONO< for-int H ? '< H P a)NiO.length< HKK. a)NiONHO ? ne: intN"5an!-,.O< A for-int i ? '< i P a).length< iKK. for-int H ? '< H P a)NiO.length< HKK. for-int k ? '< k P a)NiONHO.length< kKK. "rt-8a)N8 K i K 8ON8 K
245
H K 8ON8 K k K 8O ? 8 K a)NiONHONkO.< // 0rray of non"ri#itive obHects3 $ntegerNONO aI ? @ @ ne: $nteger-(., ne: $nteger- .A, @ ne: $nteger-)., ne: $nteger-I.A, @ ne: $nteger-,., ne: $nteger-+.A, A< for-int i ? '< i P aI.length< iKK. for-int H ? '< H P aINiO.length< HKK. "rt-8aIN8 K i K 8ON8 K H K 8O ? 8 K aINiONHO.< $ntegerNONO a,< a, ? ne: $ntegerN)ONO< for-int i ? '< i P a,.length< iKK. @ a,NiO ? ne: $ntegerN)O< for-int H ? '< H P a,NiO.length< HKK. a,NiONHO ? ne: $nteger-iBH.< A for-int i ? '< i P a,.length< iKK. for-int H ? '< H P a,NiO.length< HKK. "rt-8a,N8 K i K 8ON8 K H K 8O ? 8 K a,NiONHO.< A A ///3>
The code used "or %rinting uses length so that it doesn t de%end on "i&ed array si1es. RFSURFSTIJLT+(6PTE5?TIML2U The "irst e&a#%le shows a #ultidi#ensional array o" %ri#itives. /ou deli#it each vector in the array with curly braces=
intNONO a( ? @ @ (, , ), A, @ I, ,, +, A, A<
Each set o" sAuare brackets #oves you into the ne&t level o" the array. RF SURFSTIJLT+(6PTE5?TIM?@U The second e&a#%le shows a three'di#ensional array allocated with ne(. (ere, the whole array is allocated at once=
247
intNONONO a
But the third e&a#%le shows that each vector in the arrays that #ake u% the #atri& can be o" any length=
intNONONO a) ? ne: intN"5an!-*.ONONO< for-int i ? '< i P a).length< iKK. @ a)NiO ? ne: intN"5an!-,.ONO< for-int H ? '< H P a)NiO.length< HKK. a)NiONHO ? ne: intN"5an!-,.O< A
The "irst ne( creates an array with a rando#'length "irst ele#ent and the rest undeter#ined. The second ne( inside the for loo% "ills out the ele#ents but leaves the third inde& undeter#ined until you hit the third ne(. RFSURFSTIJLT+(6PTE5?TIM?MU /ou will see "ro# the out%ut that array values are auto#atically initiali1ed to 1ero i" you don t give the# an e&%licit initiali1ation value. /ou can deal with arrays o" non%ri#itive ob0ects in a si#ilar "ashion, which is shown in the "ourth e&a#%le, de#onstrating the ability to collect #any ne( e&%ressions with curly braces=
$ntegerNONO aI ? @ @ ne: $nteger-(., ne: $nteger- .A, @ ne: $nteger-)., ne: $nteger-I.A, @ ne: $nteger-,., ne: $nteger-+.A, A<
The "i"th e&a#%le shows how an array o" non%ri#itive ob0ects can be built u% %iece by %iece=
$ntegerNONO a,< a, ? ne: $ntegerN)ONO< for-int i ? '< i P a,.length< iKK. @ a,NiO ? ne: $ntegerN)O< for-int H ? '< H P a,NiO.length< HKK. a,NiONHO ? ne: $nteger-iBH.< A
The iK8 is 0ust to %ut an interesting value into the Integer. RFSURF STIJLT+(6PTE5?TIM?KU
248
1ummar:
This see#ingly elaborate #echanis# "or initiali1ation, the constructor, should give you a strong hint about the critical i#%ortance %laced on initiali1ation in the language. 6s Stroustru% was designing +<<, one o" the "irst observations he #ade about %roductivity in + was that i#%ro%er initiali1ation o" variables causes a signi"icant %ortion o" %rogra##ing %roble#s. These kinds o" bugs are hard to "ind, and si#ilar issues a%%ly to i#%ro%er cleanu%. Because constructors allow you to guarantee %ro%er initiali1ation and cleanu% *the co#%iler will not allow an ob0ect to be created without the %ro%er constructor calls,, you get co#%lete control and sa"ety. RFSURFSTIJLT+(6PTE5?TIM?LU In +<<, destruction is Auite i#%ortant because ob0ects created with ne( #ust be e&%licitly destroyed. In Java, the garbage collector auto#atically releases the #e#ory "or all ob0ects, so the eAuivalent cleanu% #ethod in Java isn t necessary #uch o" the ti#e. In cases where you don t need destructor'like behavior, Java s garbage collector greatly si#%li"ies %rogra##ing, and adds #uch'needed sa"ety in #anaging #e#ory. So#e garbage collectors can even clean u% other resources like gra%hics and "ile handles. (owever, the garbage collector does add a run'ti#e cost, the e&%ense o" which is di""icult to %ut into %ers%ective because o" the overall slowness o" Java inter%reters at this writing. 6s this changes, we ll be able to discover i" the overhead o" the garbage collector will %reclude the use o" Java "or certain ty%es o" %rogra#s. *)ne o" the issues is the un%redictability o" the garbage collector., RFSURF STIJLT+(6PTE5?TIM??U Because o" the guarantee that all ob0ects will be constructed, there s actually #ore to the constructor than what is shown here. In %articular, when you create new classes using either com osition or inheritance the guarantee o" construction also holds, and so#e additional synta& is necessary to su%%ort this. /ou ll learn about co#%osition, inheritance, and how they a""ect constructors in "uture cha%ters. RFSURF STIJLT+(6PTE5?TIM?HU
24:
/0ercises
Solutions to selected e&ercises can be "ound in the electronic docu#entThe Thinking in Java "nnotated Solution @uide, available "or a s#all "ee "ro# ,,,'0ruceEckel'com.
!,) +reate an array o" ob0ect re"erences o" the class you created in
E&ercise K, but don t actually create ob0ects to assign into the array. :hen you run the %rogra#, notice whether the initiali1ation #essages "ro# the constructor calls are %rinted. RF SURFSTIJLT+(6PTE5?TIM?IU
!4) +reate an array o" )tring ob0ects and assign a string to each
ele#ent. Print the array using a for loo%. RFSURF STIJLT+(6PTE5?TIMH@U
og with an overloaded barkA B #ethod. This #ethod should be overloaded based on various %ri#itive data ty%es, and %rint di""erent ty%es o" barking, howling, etc., de%ending on which overloaded version is called. :rite a mainA B that calls all the di""erent versions. RFSURF STIJLT+(6PTE5?TIMHMU
two argu#ents *o" two di""erent ty%es,, but in reversed order relative to each other. Veri"y that this works. RFSURF STIJLT+(6PTE5?TIMHKU
!6) Modi"y E&ercise 3 so that two o" the overloaded #ethods have
*7) +reate a class without a constructor, and then create an ob0ect o"
that class in mainA B to veri"y that the de"ault constructor is auto#atically synthesi1ed. RFSURFSTIJLT+(6PTE5?TIMHLU
24;
*() +reate a class with two #ethods. :ithin the "irst #ethod, call the
second #ethod twice= the "irst ti#e without using this, and the second ti#e using this. RFSURFSTIJLT+(6PTE5?TIMH?U
*,) +reate a class called Tank that can be "illed and e#%tied, and
has a death condition that it #ust be e#%ty when the ob0ect is cleaned u%. :rite a finali7eA B that veri"ies this death condition. In mainA B, test the %ossible scenarios that can occur when your Tank is used. RFSURFSTIJLT+(6PTE5?TIMHIU
*-) +reate a class containing an int and a char that are not
initiali1ed, and %rint their values to veri"y that Java %er"or#s de"ault initiali1ation. RFSURFSTIJLT+(6PTE5?TIMH2U
*5) +reate a class with a )tring "ield that is initiali1ed at the %oint o"
de"inition, and another one that is initiali1ed by the constructor. :hat is the di""erence between the two a%%roachesO RFSURF STIJLT+(6PTE5?TIM3MU
*6) +reate a class with a static )tring "ield that is initiali1ed at the
%oint o" de"inition, and another one that is initiali1ed by the static block. 6dd a static #ethod that %rints both "ields and de#onstrates that they are both initiali1ed be"ore they are used. RFSURFSTIJLT+(6PTE5?TIM3KU
25=
251
252
the #ethods that you want the client %rogra##er to use. This is e&actly right, even though it s o"ten counterintuitive "or %eo%le who %rogra# in other languages *es%ecially +, and are used to accessing everything without restriction. By the end o" this cha%ter you should be convinced o" the value o" access control in Java. RFSURFSTIJLT+(6PTE5HTILU The conce%t o" a library o" co#%onents and the control over who can access the co#%onents o" that library is not co#%lete, however. There s still the Auestion o" how the co#%onents are bundled together into a cohesive library unit. This is controlled with the package keyword in Java, and the access s%eci"iers are a""ected by whether a class is in the sa#e %ackage or in a se%arate %ackage. So to begin this cha%ter, you ll learn how library co#%onents are %laced into %ackages. Then you ll be able to understand the co#%lete #eaning o" the access s%eci"iers. RFSURF STIJLT+(6PTE5HTI?U
i#"ort Hava.util.B<
This brings in the entire utility library that s %art o" the standard Java distribution. Since, "or e&a#%le, the class Array+ist is in 8ava!*til, you can now either s%eci"y the "ull na#e 8ava!*til!Array+ist *which you can do without the import state#ent,, or you can si#%ly say Array+ist *because o" the import,. RFSURFSTIJLT+(6PTE5HTIHU I" you want to bring in a single class, you can na#e that class in the import state#ent
i#"ort Hava.util.0rrayList<
Cow you can use Array+ist with no Auali"ication. (owever, none o" the other classes in 8ava!*til are available. RFSURFSTIJLT+(6PTE5HTI3U
253
The reason "or all this i#%orting is to %rovide a #echanis# to #anage ! na#e s%aces.$ The na#es o" all your class #e#bers are insulated "ro# each other. 6 #ethod fA B inside a class A will not clash with an fA B that has the sa#e signature *argu#ent list, in class 2. But what about the class na#esO Su%%ose you create a stack class that is installed on a #achine that already has a stack class that s written by so#eone elseO :ith Java on the Internet, this can ha%%en without the user knowing it, since classes can get downloaded auto#atically in the %rocess o" running a Java %rogra#. RFSURFSTIJLT+(6PTE5HTIGU This %otential clashing o" na#es is why it s i#%ortant to have co#%lete control over the na#e s%aces in Java, and to be able to create a co#%letely uniAue na#e regardless o" the constraints o" the Internet. RF SURFSTIJLT+(6PTE5HTIIU So "ar, #ost o" the e&a#%les in this book have e&isted in a single "ile and have been designed "or local use, and haven t bothered with %ackage na#es. *In this case the class na#e is %laced in the !de"ault %ackage.$, This is certainly an o%tion, and "or si#%licity s sake this a%%roach will be used whenever %ossible throughout the rest o" this book. (owever, i" you re %lanning to create libraries or %rogra#s that are "riendly to other Java %rogra#s on the sa#e #achine, you #ust think about %reventing class na#e clashes. RFSURFSTIJLT+(6PTE5HTI2U :hen you create a source'code "ile "or Java, it s co##only called a
com ilation unit *so#eti#es a translation unit,. Each co#%ilation unit #ust have a na#e ending in !8ava, and inside the co#%ilation unit there can be a p*blic class that #ust have the sa#e na#e as the "ile *including ca%itali1ation, but e&cluding the !8ava "ilena#e e&tension,. There can be only one p*blic class in each co#%ilation unit, otherwise the co#%iler
will co#%lain. The rest o" the classes in that co#%ilation unit, i" there are any, are hidden "ro# the world outside that %ackage because they re not p*blic, and they co#%rise !su%%ort$ classes "or the #ain p*blic class. RFSURFSTIJLT+(6PTE5HTIM@U :hen you co#%ile a !8ava "ile you get an out%ut "ile with e&actly the sa#e na#e but an e&tension o" !class $or each class in the !8ava "ile. Thus you can end u% with Auite a "ew !class "iles "ro# a s#all nu#ber o" !8ava "iles. I" you ve %rogra##ed with a co#%iled language, you #ight be used
254
to the co#%iler s%itting out an inter#ediate "or# *usually an !ob0$ "ile, that is then %ackaged together with others o" its kind using a linker *to create an e&ecutable "ile, or a librarian *to create a library,. That s not how Java works. 6 working %rogra# is a bunch o" !class "iles, which can be %ackaged and co#%ressed into a J65 "ile *using Java s 8ar archiver,. The Java inter%reter is res%onsible "or "inding, loading, and inter%reting these "iles @. RFSURFSTIJLT+(6PTE5HTIMMU 6 library is also a bunch o" these class "iles. Each "ile has one class that is p*blic *you re not "orced to have a p*blic class, but it s ty%ical,, so there s one co#%onent "or each "ile. I" you want to say that all these co#%onents *that are in their own se%arate !8ava and !class "iles, belong together, that s where the package keyword co#es in. RFSURF STIJLT+(6PTE5HTIMKU :hen you say=
"ackage #y"ackage<
at the beginning o" a "ile *i" you use a package state#ent, it must a%%ear as the "irst nonco##ent in the "ile,, you re stating that this co#%ilation unit is %art o" a library na#ed mypackage. )r, %ut another way, you re saying that the p*blic class na#e within this co#%ilation unit is under the u#brella o" the na#e mypackage, and i" anyone wants to use the na#e they #ust either "ully s%eci"y the na#e or use the import keyword in co#bination with mypackage *using the choices given %reviously,. Cote that the convention "or Java %ackage na#es is to use all lowercase letters, even "or inter#ediate words. RFSURFSTIJLT+(6PTE5HTIMLU Eor e&a#%le, su%%ose the na#e o" the "ile is 1y-lass!8ava. This #eans there can be one and only one p*blic class in that "ile, and the na#e o" that class #ust be 1y-lass *including the ca%itali1ation,=
255
to #ake the na#e or na#es in mypackage available. The alternative is to give the "ully Auali"ied na#e=
257
"abricate an unlikely co#bination *such as your "irst and last na#e, to create uniAue %ackage na#es. I" you ve decided to start %ublishing Java code it s worth the relatively s#all e""ort to get a do#ain na#e. RFSURF STIJLT+(6PTE5HTIM3U The second %art o" this trick is resolving the package na#e into a directory on your #achine, so when the Java %rogra# runs and it needs to load the !class "ile *which it does dyna#ically, at the %oint in the %rogra# where it needs to create an ob0ect o" that %articular class, or the "irst ti#e you access a static #e#ber o" the class,, it can locate the directory where the !class "ile resides. RFSURFSTIJLT+(6PTE5HTIMGU The Java inter%reter %roceeds as "ollows. Eirst, it "inds the environ#ent variable +D6SSP6T( *set via the o%erating syste#, so#eti#es by the installation %rogra# that installs Java or a Java'based tool on your #achine,. +D6SSP6T( contains one or #ore directories that are used as roots "or a search "or !class "iles. Starting at that root, the inter%reter will take the %ackage na#e and re%lace each dot with a slash to generate a %ath na#e "ro# the +D6SSP6T( root *so package foo!bar!ba7 beco#es fooHbarHba7 or foo5bar5ba7 or %ossibly so#ething else, de%ending on your o%erating syste#,. This is then concatenated to the various entries in the +D6SSP6T(. That s where it looks "or the !class "ile with the na#e corres%onding to the class you re trying to create. *It also searches so#e standard directories relative to where the Java inter%reter resides,. RFSURFSTIJLT+(6PTE5HTIMIU To understand this, consider #y do#ain na#e, which is br*ceeckel! com. By reversing this, com!br*ceeckel establishes #y uniAue global na#e "or #y classes. *The co#, edu, org, etc., e&tension was "or#erly ca%itali1ed in Java %ackages, but this was changed in Java K so the entire %ackage na#e is lowercase., I can "urther subdivide this by deciding that I want to create a library na#ed simple, so I ll end u% with a %ackage na#e=
"ackage co#.bruceeckel.si#"le<
Cow this %ackage na#e can be used as an u#brella na#e s%ace "or the "ollowing two "iles= RFSURFSTIJLT+(6PTE5HTIM2U
//3 co#3bruceeckel3si#"le3Wector.Hava
258
// Creating a "ackage. "ackage co#.bruceeckel.si#"le< "ublic class Wector @ "ublic Wector-. @ %yste#.out."rintln8co#.bruceeckel. si#"leutil.Wector8.< A A ///3>
:hen you create your own %ackages, you ll discover that the package state#ent #ust be the "irst nonco##ent code in the "ile. The second "ile looks #uch the sa#e= RFSURFSTIJLT+(6PTE5HTIK@U
//3 co#3bruceeckel3si#"le3List.Hava // Creating a "ackage. "ackage co#.bruceeckel.si#"le< "ublic class List @ "ublic List-. @ %yste#.out."rintln8co#.bruceeckel. si#"leutil.List8.< A A ///3>
Both o" these "iles are %laced in the subdirectory on #y syste#= RFSURF STIJLT+(6PTE5HTIKMU
C3_DGC_JavaT_co#_bruceeckel_si#"le
I" you walk back through this, you can see the %ackage na#e com! br*ceeckel!simple, but what about the "irst %ortion o" the %athO That s taken care o" in the +D6SSP6T( environ#ent variable, which is, on #y #achine= RFSURFSTIJLT+(6PTE5HTIKKU
CL0%%P0TM?.<D3_J0W0_L$B<C3_DGC_JavaT
/ou can see that the +D6SSP6T( can contain a nu#ber o" alternative search %aths. RFSURFSTIJLT+(6PTE5HTIKLU There s a variation when using J65 "iles, however. /ou #ust %ut the na#e o" the J65 "ile in the class%ath, not 0ust the %ath where it s located. So "or a J65 na#ed grape!8ar your class%ath would include=
25:
CL0%%P0TM?.<D3_J0W0_L$B<C3_flavors_gra"e.Har
)nce the class%ath is set u% %ro%erly, the "ollowing "ile can be %laced in any directory=
//3 c',3LibTest.Hava // Yses the library. i#"ort co#.bruceeckel.si#"le.B< "ublic class LibTest @ "ublic static voi! #ain-%tringNO args. @ Wector v ? ne: Wector-.< List l ? ne: List-.< A A ///3>
:hen the co#%iler encounters the import state#ent, it begins searching at the directories s%eci"ied by +D6SSP6T(, looking "or subdirectory co# bbruceeckelbsi#%le, then seeking the co#%iled "iles o" the a%%ro%riate na#es * Vector!class "or Vector and +ist!class "or +ist,. Cote that both the classes and the desired #ethods in Vector and +ist #ust be p*blic. RFSURFSTIJLT+(6PTE5HTIK?U Setting the +D6SSP6T( has been such a trial "or beginning Java users *it was "or #e, when I started, that Sun #ade the J7> in Java K a bit s#arter. /ou ll "ind that, when you install it, even i" you don t set a +D6SSP6T( you ll be able to co#%ile and run basic Java %rogra#s. To co#%ile and run the source'code %ackage "or this book *available on the +7 5)M %ackaged with this book, or at ,,,'0ruceEckel'com,, however, you will need to #ake so#e #odi"ications to your +D6SSP6T( *these are e&%lained in the source'code %ackage,. RFSURFSTIJLT+(6PTE5HTIKHU
Collisions
:hat ha%%ens i" two libraries are i#%orted via B and they include the sa#e na#esO Eor e&a#%le, su%%ose a %rogra# does this=
25;
causes the collision, everything is )>9this is good because otherwise you #ight end u% doing a lot o" ty%ing to %revent collisions that would never ha%%en. RFSURFSTIJLT+(6PTE5HTIK3U The collision does occur i" you now try to #ake a Vector=
//3 co#3bruceeckel3tools3P.Hava // The P.rint D P.rintln shorthan!. "ackage co#.bruceeckel.tools< "ublic class P @ "ublic static voi! rint-%tring s. @ %yste#.out."rint-s.< A "ublic static voi! rintln-%tring s. @ %yste#.out."rintln-s.< A A ///3>
/ou can use this shorthand to %rint a )tring either with a newline * #! rintlnA B, or without a newline * #!rintA B,. RFSURF STIJLT+(6PTE5HTIKIU
27=
/ou can guess that the location o" this "ile #ust be in a directory that starts at one o" the +D6SSP6T( locations, then continues com5 br*ceeckel5tools. 6"ter co#%iling, the #!class "ile can be used anywhere on your syste# with an import state#ent=
//3 c',3ToolTest.Hava // Yses the tools library. i#"ort co#.bruceeckel.tools.B< "ublic class ToolTest @ "ublic static voi! #ain-%tringNO args. @ P.rintln-80vailable fro# no: on48.< P.rintln-88 K (''.< // Lorce it to be a %tring P.rintln-88 K (''L.< P.rintln-88 K ).(I(,C.< A A ///3>
Cotice that all ob0ects can easily be "orced into )tring re%resentations by %utting the# in a )tring e&%ression; in the above case, starting the e&%ression with an e#%ty )tring does the trick. But this brings u% an interesting observation. I" you call )ystem!o*t!printlnA>DDB, it works without casting it to a )tring. :ith so#e e&tra overloading, you can get the # class to do this as well *this is an e&ercise at the end o" this cha%ter,. RFSURFSTIJLT+(6PTE5HTIK2U So "ro# now on, whenever you co#e u% with a use"ul new utility, you can add it to the tools directory. *)r to your own %ersonal *til or tools directory., RFSURFSTIJLT+(6PTE5HTIL@U
271
(owever, there are other valuable uses "or conditional co#%ilation. 6 very co##on use is "or debugging code. The debugging "eatures are enabled during develo%#ent, and disabled in the shi%%ing %roduct. 6llen (olub * ,,,'holub'com, ca#e u% with the idea o" using %ackages to #i#ic conditional co#%ilation. (e used this to create a Java version o" + s very use"ul assertion mechanism, whereby you can say !this should be true$ or !this should be "alse$ and i" the state#ent doesn t agree with your assertion you ll "ind out about it. Such a tool is Auite hel%"ul during debugging. RFSURFSTIJLT+(6PTE5HTILKU (ere is the class that you ll use "or debugging=
//3 co#3bruceeckel3tools3!ebug30ssert.Hava // 0ssertion tool for !ebugging. "ackage co#.bruceeckel.tools.!ebug< "ublic class 0ssert @ "rivate static voi! "err-%tring #sg. @ %yste#.err."rintln-#sg.< A "ublic final static voi! isbtrue-boolean e6". @ if-4e6". "err-80ssertion faile!8.< A "ublic final static voi! isbfalse-boolean e6".@ if-e6". "err-80ssertion faile!8.< A "ublic final static voi! isbtrue-boolean e6", %tring #sg. @ if-4e6". "err-80ssertion faile!3 8 K #sg.< A "ublic final static voi! isbfalse-boolean e6", %tring #sg. @ if-e6". "err-80ssertion faile!3 8 K #sg.< A A ///3>
This class si#%ly enca%sulates Boolean tests, which %rint error #essages i" they "ail. In +ha%ter M@, you ll learn about a #ore so%histicated tool "or dealing with errors called e*ce tion handling, but the perrA B #ethod will work "ine in the #eanti#e. RFSURFSTIJLT+(6PTE5HTILLU
272
The out%ut is %rinted to the console standard error strea# by writing to )ystem!err. RFSURFSTIJLT+(6PTE5HTIL?U :hen you want to use this class, you add a line in your %rogra#=
i#"ort co#.bruceeckel.tools.!ebug.B<
To re#ove the assertions so you can shi% the code, a second Assert class is created, but in a di""erent %ackage= RFSURFSTIJLT+(6PTE5HTILHU
//3 co#3bruceeckel3tools30ssert.Hava // Turning off the assertion out"ut // so you can shi" the "rogra#. "ackage co#.bruceeckel.tools< "ublic class 0ssert @ "ublic final static voi! isbtrue-boolean e6".@A "ublic final static voi! isbfalse-boolean e6".@A "ublic final static voi! isbtrue-boolean e6", %tring #sg. @A "ublic final static voi! isbfalse-boolean e6", %tring #sg. @A A ///3>
Cow i" you change the %revious import state#ent to=
i#"ort co#.bruceeckel.tools.B<
The %rogra# will no longer %rint assertions. (ere s an e&a#%le= RFSURF STIJLT+(6PTE5HTIL3U
//3 c',3Test0ssert.Hava // De#onstrating the assertion tool. // Co##ent the follo:ing, an! unco##ent the // subse=uent line to change assertion behavior3 i#"ort co#.bruceeckel.tools.!ebug.B< // i#"ort co#.bruceeckel.tools.B< "ublic class Test0ssert @ "ublic static voi! #ain-%tringNO args. @ 0ssert.isbtrue-- K . ?? ,.< 0ssert.isbfalse--( K (. ?? .< 0ssert.isbtrue-- K . ?? ,, 8 K ?? ,8.<
273
0ssert.isbfalse--( K (. ?? A A ///3>
, 8( K( 4?
8.<
By changing the package that s i#%orted, you change your code "ro# the debug version to the %roduction version. This techniAue can be used "or any kind o" conditional code. RFSURFSTIJLT+(6PTE5HTILGU
ackage caveat
It s worth re#e#bering that anyti#e you create a %ackage, you i#%licitly s%eci"y a directory structure when you give the %ackage a na#e. The %ackage must live in the directory indicated by its na#e, which #ust be a directory that is searchable starting "ro# the +D6SSP6T(. E&%eri#enting with the package keyword can be a bit "rustrating at "irst, because unless you adhere to the %ackage'na#e to directory'%ath rule, you ll get a lot o" #ysterious run'ti#e #essages about not being able to "ind a %articular class, even i" that class is sitting there in the sa#e directory. I" you get a #essage like this, try co##enting out the package state#ent, and i" it runs you ll know where the %roble# lies. RFSURF STIJLT+(6PTE5HTILIU
274
J<riendl:K
:hat i" you give no access s%eci"ier at all, as in all the e&a#%les be"ore this cha%terO The de"ault access has no keyword, but it is co##only re"erred to as !"riendly.$ It #eans that all the other classes in the current %ackage have access to the "riendly #e#ber, but to all the classes outside o" this %ackage the #e#ber a%%ears to be private. Since a co#%ilation unit9a "ile9can belong only to a single %ackage, all the classes within a single co#%ilation unit are auto#atically "riendly with each other. Thus, "riendly ele#ents are also said to have ackage access. RFSURF STIJLT+(6PTE5HTI?MU Eriendly access allows you to grou% related classes together in a %ackage so that they can easily interact with each other. :hen you %ut classes together in a %ackage *thus granting #utual access to their "riendly #e#bers; e.g.i.e., #aking the# !"riends$, you !own$ the code in that %ackage. It #akes sense that only code you own should have "riendly access to other code you own. /ou could say that "riendly access gives a #eaning or a reason "or grou%ing classes together in a %ackage. In #any languages the way you organi1e your de"initions in "iles can be willy'nilly, but in Java you re co#%elled to organi1e the# in a sensible "ashion. In addition, you ll %robably want to e&clude classes that shouldn t have access to the classes being de"ined in the current %ackage. RFSURF STIJLT+(6PTE5HTI?KU The class controls which code has access to its #e#bers. There s no #agic way to !break in.$ +ode "ro# another %ackage can t show u% and say, !(i, I # a "riend o" 2ob s.$ and e&%ect to see the protecte', "riendly, and private #e#bers o" 2ob. The only way to grant access to a #e#ber is to= RFSURFSTIJLT+(6PTE5HTI?LU
*5) *6)
Make the #e#ber p*blic. Then everybody, everywhere, can access it. RFSURFSTIJLT+(6PTE5HTI??U Make the #e#ber "riendly by leaving o"" any access s%eci"ier, and %ut the other classes in the sa#e %ackage. Then the other classes can access the #e#ber. RFSURFSTIJLT+(6PTE5HTI?HU 6s you ll see in +ha%ter 3, when inheritance is introduced, an inherited class can access a protecte' #e#ber as well as a p*blic
+7)
275
#e#ber *but not private #e#bers,. It can access "riendly #e#bers only i" the two classes are in the sa#e %ackage. But don t worry about that now. RFSURFSTIJLT+(6PTE5HTI?3U
+()
Provide !accessorF#utator$ #ethods *also known as !getFset$ #ethods, that read and change the value. This is the #ost civili1ed a%%roach in ter#s o" ))P, and it is "unda#ental to JavaBeans, as you ll see in +ha%ter ML. RFSURFSTIJLT+(6PTE5HTI?GU
//3 c',3!essert3Cookie.Hava // Creates a library. "ackage c',.!essert< "ublic class Cookie @ "ublic Cookie-. @ %yste#.out."rintln-8Cookie constructor8.< A voi! bite-. @ %yste#.out."rintln-8bite8.< A A ///3>
5e#e#ber, -ookie!8ava #ust reside in a subdirectory called 'essert, in a directory under cD@ *indicating +ha%ter H o" this book, that #ust be under one o" the +D6SSP6T( directories. 7on t #ake the #istake o" thinking that Java will always look at the current directory as one o" the starting %oints "or searching. I" you don t have a [! as one o" the %aths in your +D6SSP6T(, Java won t look there. RFSURF STIJLT+(6PTE5HTI?2U Cow i" you create a %rogra# that uses -ookie=
277
"ublic class Dinner @ "ublic Dinner-. @ %yste#.out."rintln-8Dinner constructor8.< A "ublic static voi! #ain-%tringNO args. @ Cookie 6 ? ne: Cookie-.< //4 6.bite-.< // Can2t access A A ///3>
you can create a -ookie ob0ect, since its constructor is p*blic and the class is p*blic. *:e ll look #ore at the conce%t o" a p*blic class later., (owever, the biteA B #e#ber is inaccessible inside inner!8ava since biteA B is "riendly only within %ackage 'essert. RFSURF STIJLT+(6PTE5HTIH@U
//3 c',3Cake.Hava // 0ccesses a class in a // se"arate co#"ilation unit. class Cake @ "ublic static voi! #ain-%tringNO args. @ Pie 6 ? ne: Pie-.< 6.f-.< A A ///3>
In a second "ile, in the sa#e directory=
//3 c',3Pie.Hava // The other class. class Pie @ voi! f-. @ %yste#.out."rintln-8Pie.f-.8.< A A ///3>
278
/ou #ight initially view these as co#%letely "oreign "iles, and yet -ake is able to create a #ie ob0ect and call its fA B #ethod. *Cote that you #ust have [. in your +D6SSP6T( in order "or the "iles to co#%ile., /ou d ty%ically think that #ie and fA B are "riendly and there"ore not available to -ake. They are "riendly9that %art is correct. The reason that they are available in -ake!8ava is because they are in the sa#e directory and have no e&%licit %ackage na#e. Java treats "iles like this as i#%licitly %art o" the !de"ault %ackage$ "or that directory, and there"ore "riendly to all the other "iles in that directory. RFSURFSTIJLT+(6PTE5HTIHMU
27:
"rivate %un!ae-. @A static %un!ae #ake0%un!ae-. @ return ne: %un!ae-.< A A "ublic class $ceCrea# @ "ublic static voi! #ain-%tringNO args. @ //4 %un!ae 6 ? ne: %un!ae-.< %un!ae 6 ? %un!ae.#ake0%un!ae-.< A A ///3>
This shows an e&a#%le in which private co#es in handy= you #ight want to control how an ob0ect is created and %revent so#eone "ro# directly accessing a %articular constructor *or all o" the#,. In the e&a#%le above, you cannot create a )*n'ae ob0ect via its constructor; instead you #ust call the makeA)*n'aeA B #ethod to do it "or you @. RFSURF STIJLT+(6PTE5HTIH?U 6ny #ethod that you re certain is only a !hel%er$ #ethod "or that class can be #ade private, to ensure that you don t accidentally use it elsewhere in the %ackage and thus %rohibit yoursel" "ro# changing or re#oving the #ethod. Making a #ethod private guarantees that you retain this o%tion. RFSURFSTIJLT+(6PTE5HTIHHU The sa#e is true "or a private "ield inside a class. 4nless you #ust e&%ose the underlying i#%le#entation *which is a #uch rarer situation than you #ight think,, you should #ake all "ields private. (owever, 0ust because a re"erence to an ob0ect is private inside a class doesnVt #ean that so#e other ob0ect canVt have a p*blic re"erence to the sa#e ob0ect. *See 6%%endi& 6 "or issues about aliasing., RFSURF STIJLT+(6PTE5HTIH3U
@ There s another e""ect in this case= Since the de"ault constructor is the only one de"ined, and it s private, it will %revent inheritance o" this class. *6 sub0ect that will be introduced in +ha%ter 3.,
27;
//3 c',3ChocolateChi".Hava // Can2t access frien!ly #e#ber // in another class. i#"ort c',.!essert.B< "ublic class ChocolateChi" e6ten!s Cookie @ "ublic ChocolateChi"-. @ %yste#.out."rintln8ChocolateChi" constructor8.< A "ublic static voi! #ain-%tringNO args. @ ChocolateChi" 6 ? ne: ChocolateChi"-.<
28=
"ublic class Cookie @ "ublic Cookie-. @ %yste#.out."rintln-8Cookie constructor8.< A "rotecte! voi! bite-. @ %yste#.out."rintln-8bite8.< A A
then biteA B still has !"riendly$ access within %ackage 'essert, but it is also accessible to anyone inheriting "ro# -ookie. (owever, it is not p*blic.
protecte' also gives %ackage access Y that is, other classes in the sa#e %ackage #ay access protecte'RFSURFSTIJLT+(6PTE5HTIH2U ele#ents.
281
6ccess control %uts boundaries within a data ty%e "or two i#%ortant reasons. The "irst is to establish what the client %rogra##ers can and can t use. /ou can build your internal #echanis#s into the structure without worrying that the client %rogra##ers will accidentally treat the internals as %art o" the inter"ace that they should be using. RFSURF STIJLT+(6PTE5HTI3MU This "eeds directly into the second reason, which is to se%arate the inter"ace "ro# the i#%le#entation. I" the structure is used in a set o" %rogra#s, but client %rogra##ers can t do anything but send #essages to the p*blic inter"ace, then you can change anything that s not p*blic *e.g., !"riendly,$ protecte', or private, without reAuiring #odi"ications to client code. RFSURFSTIJLT+(6PTE5HTI3KU :e re now in the world o" ob0ect'oriented %rogra##ing, where a class is actually describing !a class o" ob0ects,$ as you would describe a class o" "ishes or a class o" birds. 6ny ob0ect belonging to this class will share these characteristics and behaviors. The class is a descri%tion o" the way all ob0ects o" this ty%e will look and act. RFSURFSTIJLT+(6PTE5HTI3LU In the original ))P language, Si#ula'3G, the keyword class was used to describe a new data ty%e. The sa#e keyword has been used "or #ost ob0ect'oriented languages. This is the "ocal %oint o" the whole language= the creation o" new data ty%es that are #ore than 0ust bo&es containing data and #ethods. RFSURFSTIJLT+(6PTE5HTI3?U The class is the "unda#ental ))P conce%t in Java. It is one o" the keywords that will not be set in bold in this book9it beco#es annoying with a word re%eated as o"ten as !class.$ RFSURF STIJLT+(6PTE5HTI3HU Eor clarity, you #ight %re"er a style o" creating classes that %uts the
p*blic #e#bers at the beginning, "ollowed by the protecte', "riendly, and private #e#bers. The advantage is that the user o" the class can
then read down "ro# the to% and see "irst what s i#%ortant to the# *the p*blic #e#bers, because they can be accessed outside the "ile,, and sto% reading when they encounter the non' p*blic #e#bers, which are %art o" the internal i#%le#entation=
"ublic class 9 @
282
"ublic voi! "ub(- . "ublic voi! "ub - . "ublic voi! "ub)- . "rivate voi! "riv("rivate voi! "riv "rivate voi! "riv)"rivate int i< // . . . A
@ @ @ . . .
/B . /B . /B . @ /B @ /B @ /B
. . . . . .
. . . . . .
B/ A B/ A B/ A . B/ A . B/ A . B/ A
This will #ake it only %artially easier to read because the inter"ace and i#%le#entation are still #i&ed together. That is, you still see the source code9the i#%le#entation9because it s right there in the class. In addition, the co##ent docu#entation su%%orted by 0avadoc *described in +ha%ter K, lessens the i#%ortance o" code readability by the client %rogra##er. 7is%laying the inter"ace to the consu#er o" a class is really the 0ob o" the class bro,ser, a tool whose 0ob is to look at all the available classes and show you what you can do with the# *i.e., what #e#bers are available, in a use"ul "ashion. By the ti#e you read this, browsers should be an e&%ected %art o" any good Java develo%#ent tool. RFSURF STIJLT+(6PTE5HTI33U
Class access
In Java, the access s%eci"iers can also be used to deter#ine which classes ,ithin a library will be available to the users o" that library. I" you want a class to be available to a client %rogra##er, you %lace the p*blic keyword so#ewhere be"ore the o%ening brace o" the class body. This controls whether the client %rogra##er can even create an ob0ect o" the class. RFSURFSTIJLT+(6PTE5HTI3GU To control the access o" a class, the s%eci"ier #ust a%%ear be"ore the keyword class. Thus you can say=
i#"ort #ylib.\i!get<
283
or
i#"ort #ylib.B<
(owever, there s an e&tra set o" constraints= RFSURF STIJLT+(6PTE5HTI3IU
+!)
There can be only one p*blic class %er co#%ilation unit *"ile,. The idea is that each co#%ilation unit has a single %ublic inter"ace re%resented by that p*blic class. It can have as #any su%%orting !"riendly$ classes as you want. I" you have #ore than one p*blic class inside a co#%ilation unit, the co#%iler will give you an error #essage. RFSURFSTIJLT+(6PTE5HTI32U The na#e o" the p*blic class #ust e&actly #atch the na#e o" the "ile containing the co#%ilation unit, including ca%itali1ation. So "or 0i'get, the na#e o" the "ile #ust be 0i'get!8ava, not (i'get! 8ava or 0I "&T!8ava. 6gain, you ll get a co#%ile'ti#e error i" they don t agree. RFSURFSTIJLT+(6PTE5HTIG@U It is %ossible, though not ty%ical, to have a co#%ilation unit with no p*blic class at all. In this case, you can na#e the "ile whatever you like. RFSURFSTIJLT+(6PTE5HTIGMU
+*)
++)
:hat i" you ve got a class inside mylib that you re 0ust using to acco#%lish the tasks %er"or#ed by 0i'get or so#e other p*blic class in mylibO /ou don t want to go to the bother o" creating docu#entation "or the client %rogra##er, and you think that so#eti#e later you #ight want to co#%letely change things and ri% out your class altogether, substituting a di""erent one. To give you this "le&ibility, you need to ensure that no client %rogra##ers beco#e de%endent on your %articular i#%le#entation details hidden inside mylib. To acco#%lish this, you 0ust leave the p*blic keyword o"" the class, in which case it beco#es "riendly. *That class can be used only within that %ackage., RFSURF STIJLT+(6PTE5HTIGKU Cote that a class cannot be private *that would #ake it accessible to no one but the class,, or protecte'@. So you have only two choices "or class access= !"riendly$ or p*blic. I" you don t want anyone else to have access
@ 6ctually, an inner class can be %rivate or %rotected, but that s a s%ecial case. These will be introduced in +ha%ter G.
284
to that class, you can #ake all the constructors private, thereby %reventing anyone but you, inside a static #e#ber o" the class, "ro# creating an ob0ect o" that class @. (ere s an e&a#%le=
//3 c',3Lunch.Hava // De#onstrates class access s"ecifiers. // Jake a class effectively "rivate // :ith "rivate constructors3 class %ou" @ "rivate %ou"-. @A // -(. 0llo: creation via static #etho!3 "ublic static %ou" #ake%ou"-. @ return ne: %ou"-.< A // - . Create a static obHect an! // return a reference u"on re=uest. // -The 8%ingleton8 "attern.3 "rivate static %ou" "s( ? ne: %ou"-.< "ublic static %ou" access-. @ return "s(< A "ublic voi! f-. @A A class %an!:ich @ // Yses Lunch voi! f-. @ ne: Lunch-.< A A // Gnly one "ublic class allo:e! "er file3 "ublic class Lunch @ voi! test-. @ // Can2t !o this4 Private constructor3 //4 %ou" "riv( ? ne: %ou"-.< %ou" "riv ? %ou".#ake%ou"-.< %an!:ich f( ? ne: %an!:ich-.< %ou".access-..f-.< A A ///3>
@ /ou can also do it by inheriting *+ha%ter 3, "ro# that class.
285
4% to now, #ost o" the #ethods have been returning either voi' or a %ri#itive ty%e, so the de"inition=
287
%rogra##er can still access that static #e#ber even though they cannot create an ob0ect o" that class. RFSURFSTIJLT+(6PTE5HTIG3U
1ummar:
In any relationshi% it s i#%ortant to have boundaries that are res%ected by all %arties involved. :hen you create a library, you establish a relationshi% with the user o" that library9the client %rogra##er9who is another %rogra##er, but one %utting together an a%%lication or using your library to build a bigger library. RFSURFSTIJLT+(6PTE5HTIGGU :ithout rules, client %rogra##ers can do anything they want with all the #e#bers o" a class, even i" you #ight %re"er they don t directly #ani%ulate so#e o" the #e#bers. Everything s naked to the world. RF SURFSTIJLT+(6PTE5HTIGIU This cha%ter looked at how classes are built to "or# libraries; "irst, the way a grou% o" classes is %ackaged within a library, and second, the way the class controls access to its #e#bers. RFSURF STIJLT+(6PTE5HTIG2U It is esti#ated that a + %rogra##ing %ro0ect begins to break down so#ewhere between H@> and M@@> lines o" code because + has a single !na#e s%ace$ so na#es begin to collide, causing an e&tra #anage#ent overhead. In Java, the package keyword, the %ackage na#ing sche#e, and the import keyword give you co#%lete control over na#es, so the issue o" na#e collision is easily avoided. RFSURF STIJLT+(6PTE5HTII@U There are two reasons "or controlling access to #e#bers. The "irst is to kee% users hands o"" tools that they shouldn t touch; tools that are necessary "or the internal #achinations o" the data ty%e, but not %art o" the inter"ace that users need to solve their %articular %roble#s. So #aking #ethods and "ields private is a service to users because they can easily see what s i#%ortant to the# and what they can ignore. It si#%li"ies their understanding o" the class. RFSURF STIJLT+(6PTE5HTIIMU
288
The second and #ost i#%ortant reason "or access control is to allow the library designer to change the internal workings o" the class without worrying about how it will a""ect the client %rogra##er. /ou #ight build a class one way at "irst, and then discover that restructuring your code will %rovide #uch greater s%eed. I" the inter"ace and i#%le#entation are clearly se%arated and %rotected, you can acco#%lish this without "orcing the user to rewrite their code. RFSURFSTIJLT+(6PTE5HTIIKU 6ccess s%eci"iers in Java give valuable control to the creator o" a class. The users o" the class can clearly see e&actly what they can use and what to ignore. More i#%ortant, though, is the ability to ensure that no user beco#es de%endent on any %art o" the underlying i#%le#entation o" a class. I" you know this as the creator o" the class, you can change the underlying i#%le#entation with the knowledge that no client %rogra##er will be a""ected by the changes because they can t access that %art o" the class. RFSURFSTIJLT+(6PTE5HTIILU :hen you have the ability to change the underlying i#%le#entation, you can not only i#%rove your design later, but you also have the "reedo# to #ake #istakes. Co #atter how care"ully you %lan and design you ll #ake #istakes. >nowing that it s relatively sa"e to #ake these #istakes #eans you ll be #ore e&%eri#ental, you ll learn "aster, and you ll "inish your %ro0ect sooner. RFSURFSTIJLT+(6PTE5HTII?U The %ublic inter"ace to a class is what the user does see, so that is the #ost i#%ortant %art o" the class to get !right$ during analysis and design. Even that allows you so#e leeway "or change. I" you don t get the inter"ace right the "irst ti#e, you can add #ore #ethods, as long as you don t re#ove any that client %rogra##ers have already used in their code. RFSURFSTIJLT+(6PTE5HTIIHU
/0ercises
Solutions to selected e&ercises can be "ound in the electronic docu#entThe Thinking in Java "nnotated Solution @uide, available "or a s#all "ee "ro# ,,,'0ruceEckel'com.
28:
+-) In the section labeled !%ackage= the library unit,$ turn the code
"rag#ents concerning mypackage into a co#%iling and running set o" Java "iles. RFSURFSTIJLT+(6PTE5HTIIGU
+4) In the section labeled !+ollisions,$ take the code "rag#ents and
turn the# into a %rogra#, and veri"y that collisions do in "act occur. RFSURFSTIJLT+(6PTE5HTIIIU
+5) 8enerali1e the class # de"ined in this cha%ter by adding all the
overloaded versions o" rintA B and rintlnA B necessary to handle all the di""erent basic Java ty%es. RFSURF STIJLT+(6PTE5HTII2U
,() +reate a class with protecte' data. +reate a second class in the
sa#e "ile with a #ethod that #ani%ulates the protecte' data in the "irst class. RFSURFSTIJLT+(6PTE5HTI2KU
,*) In the section titled !+lass access$ you ll "ind code "rag#ents
describing mylib and 0i'get. +reate this library, then create a 0i'get in a class that is not %art o" the mylib %ackage. RFSURF STIJLT+(6PTE5HTI2?U
,+) +reate a new directory and edit your +D6SSP6T( to include that
new directory. +o%y the #!class "ile *%roduced by co#%iling com!br*ceeckel!tools!#!8ava, to your new directory and then change the na#es o" the "ile, the # class inside and the #ethod
28;
na#es. */ou #ight also want to add additional out%ut to watch how it works., +reate another %rogra# in a di""erent directory that uses your new class. RFSURFSTIJLT+(6PTE5HTI2HU
,,) Eollowing the "or# o" the e&a#%le +*nch!8ava, create a class
called -onnection1anager that #anages a "i&ed array o" -onnection ob0ects. The client %rogra##er #ust not be able to e&%licitly create -onnection ob0ects, but can only get the# via a static #ethod in -onnection1anager. :hen the -onnection1anager runs out o" ob0ects, it returns a n*ll re"erence. Test the classes in mainA B. RFSURF STIJLT+(6PTE5HTI23U
///3 c',3local3Package!Class.Hava "ackage c',.local< class Package!Class @ "ublic Package!Class-. @ %yste#.out."rintln8Creating a "ackage! class8.< A A ///3>
Then create the "ollowing "ile in a directory other than c@H=
///3 c',3foreign3Loreign.Hava "ackage c',.foreign< i#"ort c',.local.B< "ublic class Loreign @ "ublic static voi! #ain -%tringNO args. @ Package!Class "c ? ne: Package!Class-.< A A ///3>
E&%lain why the co#%iler generates an error. :ould #aking the Foreign class %art o" the cD@!local %ackage change anythingO RF SU
2:=
-: $eusing Classes
RFSTIJLT+(6PTE53TI@U)ne o" the #ost co#%elling "eatures about Java is code reuse. But to be revolutionary, you ve got to be able to do a lot #ore than co%y code and change it.
That s the a%%roach used in %rocedural languages like +, and it hasn t worked very well. Dike everything in Java, the solution revolves around the class. /ou reuse code by creating new classes, but instead o" creating the# "ro# scratch, you use e&isting classes that so#eone has already built and debugged. RFSURFSTIJLT+(6PTE53TIMU The trick is to use the classes without soiling the e&isting code. In this cha%ter you ll see two ways to acco#%lish this. The "irst is Auite straight"orward= /ou si#%ly create ob0ects o" your e&isting class inside the new class. This is called com ositionD because the new class is co#%osed o" ob0ects o" e&isting classes. /ou re si#%ly reusing the "unctionality o" the code, not its "or#. RFSURFSTIJLT+(6PTE53TIKU The second a%%roach is #ore subtle. It creates a new class as a t) e o$ an e&isting class. /ou literally take the "or# o" the e&isting class and add code to it without #odi"ying the e&isting class. This #agical act is called inheritance, and the co#%iler does #ost o" the work. Inheritance is one o" the cornerstones o" ob0ect'oriented %rogra##ing, and has additional i#%lications that will be e&%lored in +ha%ter G. RFSURF STIJLT+(6PTE53TILU It turns out that #uch o" the synta& and behavior are si#ilar "or both co#%osition and inheritance *which #akes sense because they are both ways o" #aking new ty%es "ro# e&isting ty%es,. In this cha%ter, you ll learn about these code reuse #echanis#s. RFSURF STIJLT+(6PTE53TI?U
2:1
Com.osition s:nta0
4ntil now, co#%osition has been used Auite "reAuently. /ou si#%ly %lace ob0ect re"erences inside new classes. Eor e&a#%le, su%%ose you d like an ob0ect that holds several )tring ob0ects, a cou%le o" %ri#itives, and an ob0ect o" another class. Eor the non%ri#itive ob0ects, you %ut re"erences inside your new class, but you de"ine the %ri#itives directly=
//3 c'+3%"rinkler%yste#.Hava // Co#"osition for co!e reuse. class \ater%ource @ "rivate %tring s< \ater%ource-. @ %yste#.out."rintln-8\ater%ource-.8.< s ? ne: %tring-8Constructe!8.< A "ublic %tring to%tring-. @ return s< A A "ublic class %"rinkler%yste# @ "rivate %tring valve(, valve , valve), valveI< \ater%ource source< int i< float f< voi! "rint-. @ %yste#.out."rintln-8valve( ? 8 K valve(.< %yste#.out."rintln-8valve ? 8 K valve .< %yste#.out."rintln-8valve) ? 8 K valve).< %yste#.out."rintln-8valveI ? 8 K valveI.< %yste#.out."rintln-8i ? 8 K i.< %yste#.out."rintln-8f ? 8 K f.< %yste#.out."rintln-8source ? 8 K source.< A "ublic static voi! #ain-%tringNO args. @ %"rinkler%yste# 6 ? ne: %"rinkler%yste#-.< 6."rint-.< A A ///3>
2:2
Thinking in Java
,,,'0ruceEckel'com
)ne o" the #ethods de"ined in 0ater)o*rce is s%ecial= to)tringA B. /ou will learn later that every non%ri#itive ob0ect has a to)tringA B #ethod, and it s called in s%ecial situations when the co#%iler wants a )tring but it s got one o" these ob0ects. So in the e&%ression=
%yste#.out."rintln-8source ? 8 K source.<
the co#%iler sees you trying to add a )tring ob0ect *c so*rce P c, to a 0ater)o*rce. This doesn t #ake sense to it, because you can only !add$ a )tring to another )tring, so it says !I ll turn so*rce into a )tring by calling to)tringA B.$ 6"ter doing this it can co#bine the two )trings and %ass the resulting )tring to )ystem!o*t!printlnA B. 6ny ti#e you want to allow this behavior with a class you create you need only write a to)tringA B #ethod. RFSURFSTIJLT+(6PTE53TIHU 6t "irst glance, you #ight assu#e9Java being as sa"e and care"ul as it is9 that the co#%iler would auto#atically construct ob0ects "or each o" the re"erences in the above code; "or e&a#%le, calling the de"ault constructor "or 0ater)o*rce to initiali1e so*rce. The out%ut o" the %rint state#ent is in "act=
Pri#itives that are "ields in a class are auto#atically initiali1ed to 1ero, as noted in +ha%ter K. But the ob0ect re"erences are initiali1ed to n*ll, and i" you try to call #ethods "or any o" the# you ll get an e&ce%tion. It s actually %retty good *and use"ul, that you can still %rint the# out without throwing an e&ce%tion. RFSURFSTIJLT+(6PTE53TI3U It #akes sense that the co#%iler doesn t 0ust create a de"ault ob0ect "or every re"erence because that would incur unnecessary overhead in #any cases. I" you want the re"erences initiali1ed, you can do it= RFSURF STIJLT+(6PTE53TIGU
2:3
+,)
6t the %oint the ob0ects are de"ined. This #eans that they ll always be initiali1ed be"ore the constructor is called. RFSURF STIJLT+(6PTE53TIIU In the constructor "or that class. RFSURFSTIJLT+(6PTE53TI2U 5ight be"ore you actually need to use the ob0ect. This is o"ten called la?) initiali?ation. It can reduce overhead in situations where the ob0ect doesn t need to be created every ti#e. RFSURF STIJLT+(6PTE53TIM@U
+-) +4)
//3 c'+3Bath.Hava // Constructor initialiUation :ith co#"osition. class %oa" @ "rivate %tring s< %oa"-. @ %yste#.out."rintln-8%oa"-.8.< s ? ne: %tring-8Constructe!8.< A "ublic %tring to%tring-. @ return s< A A "ublic class Bath @ "rivate %tring // $nitialiUing at "oint of !efinition3 s( ? ne: %tring-8Ma""y8., s ? 8Ma""y8, s), sI< %oa" castille< int i< float toy< Bath-. @ %yste#.out."rintln-8$nsi!e Bath-.8.< s) ? ne: %tring-8Joy8.< i ? I*< toy ? ).(If< castille ? ne: %oa"-.< A
2:4
Thinking in Java
,,,'0ruceEckel'com
voi! "rint-. @ // Delaye! initialiUation3 if-sI ?? null. sI ? ne: %tring-8Joy8.< %yste#.out."rintln-8s( ? 8 K s(.< %yste#.out."rintln-8s ? 8 K s .< %yste#.out."rintln-8s) ? 8 K s).< %yste#.out."rintln-8sI ? 8 K sI.< %yste#.out."rintln-8i ? 8 K i.< %yste#.out."rintln-8toy ? 8 K toy.< %yste#.out."rintln-8castille ? 8 K castille.< A "ublic static voi! #ain-%tringNO args. @ Bath b ? ne: Bath-.< b."rint-.< A A ///3>
Cote that in the 2ath constructor a state#ent is e&ecuted be"ore any o" the initiali1ations take %lace. :hen you don t initiali1e at the %oint o" de"inition, there s still no guarantee that you ll %er"or# any initiali1ation be"ore you send a #essage to an ob0ect re"erence9e&ce%t "or the inevitable run'ti#e e&ce%tion. RFSURFSTIJLT+(6PTE53TIMKU (ere s the out%ut "or the %rogra#=
$nsi!e Bath-. %oa"-. s( ? Ma""y s ? Ma""y s) ? Joy sI ? Joy i ? I* toy ? ).(I castille ? Constructe!
:hen printA B is called it "ills in sQ so that all the "ields are %ro%erly initiali1ed by the ti#e they are used. RFSURFSTIJLT+(6PTE53TIMLU
2:5
Inheritance s:nta0
Inheritance is an integral %art o" Java *and ))P languages in general,. It turns out that you re always doing inheritance when you create a class, because unless you e&%licitly inherit "ro# so#e other class, you i#%licitly inherit "ro# Java s standard root class .b8ect. RFSURF STIJLT+(6PTE53TIM?U The synta& "or co#%osition is obvious, but to %er"or# inheritance there s a distinctly di""erent "or#. :hen you inherit, you say !This new class is like that old class.$ /ou state this in code by giving the na#e o" the class as usual, but be"ore the o%ening brace o" the class body, %ut the keyword e4ten's "ollowed by the na#e o" the base class. :hen you do this, you auto#atically get all the data #e#bers and #ethods in the base class. (ere s an e&a#%le= RFSURFSTIJLT+(6PTE53TIMHU
//3 c'+3Detergent.Hava // $nheritance synta6 D "ro"erties. class Cleanser @ "rivate %tring s ? ne: %tring-8Cleanser8.< "ublic voi! a""en!-%tring a. @ s K? a< A "ublic voi! !ilute-. @ a""en!-8 !ilute-.8.< A "ublic voi! a""ly-. @ a""en!-8 a""ly-.8.< A "ublic voi! scrub-. @ a""en!-8 scrub-.8.< A "ublic voi! "rint-. @ %yste#.out."rintln-s.< A "ublic static voi! #ain-%tringNO args. @ Cleanser 6 ? ne: Cleanser-.< 6.!ilute-.< 6.a""ly-.< 6.scrub-.< 6."rint-.< A A "ublic class Detergent e6ten!s Cleanser @ // Change a #etho!3 "ublic voi! scrub-. @ a""en!-8 Detergent.scrub-.8.< su"er.scrub-.< // Call base-class version A // 0!! #etho!s to the interface3
2:7
Thinking in Java
,,,'0ruceEckel'com
"ublic voi! foa#-. @ a""en!-8 foa#-.8.< A // Test the ne: class3 "ublic static voi! #ain-%tringNO args. @ Detergent 6 ? ne: Detergent-.< 6.!ilute-.< 6.a""ly-.< 6.scrub-.< 6.foa#-.< 6."rint-.< %yste#.out."rintln-8Testing base class38.< Cleanser.#ain-args.< A A ///3>
This de#onstrates a nu#ber o" "eatures. Eirst, in the -leanser appen' A B #ethod, )trings are concatenated to s using the LP o%erator, which is one o" the o%erators *along with [L , that the Java designers !overloaded$ to work with )trings. RFSURFSTIJLT+(6PTE53TIM3U Second, both -leanser and etergent contain a mainA B #ethod. /ou can create a mainA B "or each one o" your classes, and it s o"ten reco##ended to code this way so that your test code is wra%%ed in with the class. Even i" you have a lot o" classes in a %rogra#, only the mainA B "or the class invoked on the co##and line will be called. *6s long as mainA B is p*blic, it doesn t #atter whether the class that it s %art o" is p*blic., So in this case, when you say 8ava etergent, etergent! mainA B will be called. But you can also say 8ava -leanser to invoke -leanser!mainA B, even though -leanser is not a p*blic class. This techniAue o" %utting a mainA B in each class allows easy unit testing "or each class. 6nd you don t need to re#ove the mainA B when you re "inished testing; you can leave it in "or later testing. RFSURF STIJLT+(6PTE53TIMGU (ere, you can see that etergent!mainA B calls -leanser!mainA B e&%licitly, %assing it the sa#e argu#ents "ro# the co##and line *however, you could %ass it any )tring array,. RFSURF STIJLT+(6PTE53TIMIU It s i#%ortant that all o" the #ethods in -leanser are p*blic. 5e#e#ber that i" you leave o"" any access s%eci"ier the #e#ber de"aults
2:8
to !"riendly,$ which allows access only to %ackage #e#bers. Thus, ,ithin this ackage, anyone could use those #ethods i" there were no access s%eci"ier. etergent would have no trouble, "or e&a#%le. (owever, i" a class "ro# so#e other %ackage were to inherit "ro# -leanser it could access only p*blic #e#bers. So to %lan "or inheritance, as a general rule #ake all "ields private and all #ethods p*blic. * protecte' #e#bers also allow access by derived classes; you ll learn about this later., )" course, in %articular cases you #ust #ake ad0ust#ents, but this is a use"ul guideline. RFSURFSTIJLT+(6PTE53TIM2U Cote that -leanser has a set o" #ethods in its inter"ace= appen'A B, 'il*teA B, applyA B, scr*bA B, and printA B. Because etergent is derived $rom -leanser *via the e4ten's keyword, it auto#atically gets all these #ethods in its inter"ace, even though you don t see the# all e&%licitly de"ined in etergent. /ou can think o" inheritance, then, as reusing the inter$ace' *The i#%le#entation also co#es with it, but that %art isn t the %ri#ary %oint., RFSURFSTIJLT+(6PTE53TIK@U 6s seen in scr*bA B, it s %ossible to take a #ethod that s been de"ined in the base class and #odi"y it. In this case, you #ight want to call the #ethod "ro# the base class inside the new version. But inside scr*bA B you cannot si#%ly call scr*bA B, since that would %roduce a recursive call, which isn t what you want. To solve this %roble# Java has the keyword s*per that re"ers to the !su%erclass$ that the current class has been inherited "ro#. Thus the e&%ression s*per!scr*bA B calls the base' class version o" the #ethod scr*bA B. RFSURFSTIJLT+(6PTE53TIKMU :hen inheriting you re not restricted to using the #ethods o" the base class. /ou can also add new #ethods to the derived class e&actly the way you %ut any #ethod in a class= 0ust de"ine it. The #ethod foamA B is an e&a#%le o" this. RFSURFSTIJLT+(6PTE53TIKKU In etergent!mainA B you can see that "or a etergent ob0ect you can call all the #ethods that are available in -leanser as well as in etergent *i.e., foamA B,. RFSURFSTIJLT+(6PTE53TIKLU
2::
Thinking in Java
,,,'0ruceEckel'com
//3 c'+3Cartoon.Hava // Constructor calls !uring inheritance. class 0rt @ 0rt-. @ %yste#.out."rintln-80rt constructor8.< A A class Dra:ing e6ten!s 0rt @ Dra:ing-. @ %yste#.out."rintln-8Dra:ing constructor8.< A A "ublic class Cartoon e6ten!s Dra:ing @ Cartoon-. @ %yste#.out."rintln-8Cartoon constructor8.< A
2:;
//3 c'+3Chess.Hava // $nheritance, constructors an! argu#ents. class aa#e @ aa#e-int i. @ %yste#.out."rintln-8aa#e constructor8.< A A class Boar!aa#e e6ten!s aa#e @ Boar!aa#e-int i. @ su"er-i.< %yste#.out."rintln-8Boar!aa#e constructor8.< A
2;=
Thinking in Java
,,,'0ruceEckel'com
A "ublic class Chess e6ten!s Boar!aa#e @ Chess-. @ su"er-((.< %yste#.out."rintln-8Chess constructor8.< A "ublic static voi! #ain-%tringNO args. @ Chess 6 ? ne: Chess-.< A A ///3>
I" you don t call the base'class constructor in 2oar'"ameA B, the co#%iler will co#%lain that it can t "ind a constructor o" the "or# "ame A B. In addition, the call to the base'class constructor must be the "irst thing you do in the derived'class constructor. *The co#%iler will re#ind you i" you get it wrong., RFSURFSTIJLT+(6PTE53TIKGU
2;1
class Plate @ Plate-int i. @ %yste#.out."rintln-8Plate constructor8.< A A class DinnerPlate e6ten!s Plate @ DinnerPlate-int i. @ su"er-i.< %yste#.out."rintln8DinnerPlate constructor8.< A A class Ytensil @ Ytensil-int i. @ %yste#.out."rintln-8Ytensil constructor8.< A A class %"oon e6ten!s Ytensil @ %"oon-int i. @ su"er-i.< %yste#.out."rintln-8%"oon constructor8.< A A class Lork e6ten!s Ytensil @ Lork-int i. @ su"er-i.< %yste#.out."rintln-8Lork constructor8.< A A class `nife e6ten!s Ytensil @ `nife-int i. @ su"er-i.< %yste#.out."rintln-8`nife constructor8.< A A
2;2
Thinking in Java
,,,'0ruceEckel'com
// 0 cultural :ay of !oing so#ething3 class Custo# @ Custo#-int i. @ %yste#.out."rintln-8Custo# constructor8.< A A "ublic class Place%etting e6ten!s Custo# @ %"oon s"< Lork frk< `nife kn< DinnerPlate "l< Place%etting-int i. @ su"er-i K (.< s" ? ne: %"oon-i K .< frk ? ne: Lork-i K ).< kn ? ne: `nife-i K I.< "l ? ne: DinnerPlate-i K ,.< %yste#.out."rintln8Place%etting constructor8.< A "ublic static voi! #ain-%tringNO args. @ Place%etting 6 ? ne: Place%etting-C.< A A ///3>
:hile the co#%iler "orces you to initiali1e the base classes, and reAuires that you do it right at the beginning o" the constructor, it doesn t watch over you to #ake sure that you initiali1e the #e#ber ob0ects, so you #ust re#e#ber to %ay attention to that. RFSURFSTIJLT+(6PTE53TIK2U
2;3
+ha%ter ?, you can t know when the garbage collector will be called, or i" it will be called. So i" you want so#ething cleaned u% "or a class, you #ust e&%licitly write a s%ecial #ethod to do it, and #ake sure that the client %rogra##er knows that they #ust call this #ethod. )n to% o" this9as described in +ha%ter M@ *!Error (andling with E&ce%tions$,9you #ust guard against an e&ce%tion by %utting such cleanu% in a finally clause. RF SURFSTIJLT+(6PTE53TILMU +onsider an e&a#%le o" a co#%uter'aided design syste# that draws %ictures on the screen=
//3 c'+3C0D%yste#.Hava // Ensuring "ro"er cleanu". i#"ort Hava.util.B< class %ha"e @ %ha"e-int i. @ %yste#.out."rintln-8%ha"e constructor8.< A voi! cleanu"-. @ %yste#.out."rintln-8%ha"e cleanu"8.< A A class Circle e6ten!s %ha"e @ Circle-int i. @ su"er-i.< %yste#.out."rintln-8Dra:ing a Circle8.< A voi! cleanu"-. @ %yste#.out."rintln-8Erasing a Circle8.< su"er.cleanu"-.< A A class Triangle e6ten!s %ha"e @ Triangle-int i. @ su"er-i.< %yste#.out."rintln-8Dra:ing a Triangle8.< A voi! cleanu"-. @
2;4
Thinking in Java
,,,'0ruceEckel'com
%yste#.out."rintln-8Erasing a Triangle8.< su"er.cleanu"-.< A A class Line e6ten!s %ha"e @ "rivate int start, en!< Line-int start, int en!. @ su"er-start.< this.start ? start< this.en! ? en!< %yste#.out."rintln-8Dra:ing a Line3 8 K start K 8, 8 K en!.< A voi! cleanu"-. @ %yste#.out."rintln-8Erasing a Line3 8 K start K 8, 8 K en!.< su"er.cleanu"-.< A A "ublic class C0D%yste# e6ten!s %ha"e @ "rivate Circle c< "rivate Triangle t< "rivate LineNO lines ? ne: LineN('O< C0D%yste#-int i. @ su"er-i K (.< for-int H ? '< H P ('< HKK. linesNHO ? ne: Line-H, HBH.< c ? ne: Circle-(.< t ? ne: Triangle-(.< %yste#.out."rintln-8Co#bine! constructor8.< A voi! cleanu"-. @ %yste#.out."rintln-8C0D%yste#.cleanu"-.8.< // The or!er of cleanu" is the reverse // of the or!er of initialiUation t.cleanu"-.< c.cleanu"-.< for-int i ? lines.length - (< i Q? '< i--. linesNiO.cleanu"-.<
2;5
su"er.cleanu"-.< A "ublic static voi! #ain-%tringNO args. @ C0D%yste# 6 ? ne: C0D%yste#-I*.< try @ // Co!e an! e6ce"tion han!ling... A finally @ 6.cleanu"-.< A A A ///3>
Everything in this syste# is so#e kind o" )hape *which is itsel" a kind o" .b8ect since it s i#%licitly inherited "ro# the root class,. Each class rede"ines )hape s clean*pA B #ethod in addition to calling the base' class version o" that #ethod using s*per. The s%eci"ic )hape classes9 -ircle, Triangle and +ine9all have constructors that !draw,$ although any #ethod called during the li"eti#e o" the ob0ect could be res%onsible "or doing so#ething that needs cleanu%. Each class has its own clean*p A B #ethod to restore non#e#ory things back to the way they were be"ore the ob0ect e&isted. RFSURFSTIJLT+(6PTE53TILKU In mainA B, you can see two keywords that are new, and won t o""icially be introduced until +ha%ter M@= try and finally. The try keyword indicates that the block that "ollows *deli#ited by curly braces, is a guarded region, which #eans that it is given s%ecial treat#ent. )ne o" these s%ecial treat#ents is that the code in the finally clause "ollowing this guarded region is al,a)s e&ecuted, no #atter how the try block e&its. *:ith e&ce%tion handling, it s %ossible to leave a try block in a nu#ber o" nonordinary ways., (ere, the finally clause is saying !always call clean*pA B "or 4, no #atter what ha%%ens.$ These keywords will be e&%lained thoroughly in +ha%ter M@. RFSURFSTIJLT+(6PTE53TILLU Cote that in your cleanu% #ethod you #ust also %ay attention to the calling order "or the base'class and #e#ber'ob0ect cleanu% #ethods in case one subob0ect de%ends on another. In general, you should "ollow the sa#e "or# that is i#%osed by a +<< co#%iler on its destructors= Eirst %er"or# all o" the cleanu% work s%eci"ic to your class, in the reverse order o" creation. *In general, this reAuires that base'class ele#ents still be
2;7
Thinking in Java
,,,'0ruceEckel'com
viable., Then call the base'class cleanu% #ethod, as de#onstrated here. RFSURFSTIJLT+(6PTE53TIL?U There can be #any cases in which the cleanu% issue is not a %roble#; you 0ust let the garbage collector do the work. But when you #ust do it e&%licitly, diligence and attention is reAuired. RFSURF STIJLT+(6PTE53TILHU
2ame hiding
)nly +<< %rogra##ers #ight be sur%rised by na#e hiding, since it works di""erently in that language. I" a Java base class has a #ethod na#e that s overloaded several ti#es, rede"ining that #ethod na#e in the derived class will not hide any o" the base'class versions. Thus overloading works regardless o" whether the #ethod was de"ined at this level or in a base class=
//3 c'+3Mi!e.Hava // Gverloa!ing a base-class #etho! na#e // in a !erive! class !oes not hi!e the // base-class versions. class Mo#er @ char !oh-char c. @ %yste#.out."rintln-8!oh-char.8.< return 2!2< A float !oh-float f. @ %yste#.out."rintln-8!oh-float.8.< return (.'f<
2;8
A A class Jilhouse @A class Bart e6ten!s Mo#er @ voi! !oh-Jilhouse #. @A A "ublic class Mi!e @ "ublic static voi! #ain-%tringNO args. @ Bart b ? ne: Bart-.< b.!oh-(.< // !oh-float. use! b.!oh-262.< b.!oh-(.'f.< b.!oh-ne: Jilhouse-..< A A ///3>
6s you ll see in the ne&t cha%ter, it s "ar #ore co##on to override #ethods o" the sa#e na#e using e&actly the sa#e signature and return ty%e as in the base class. It can be con"using otherwise *which is why +<< disallows it, to %revent you "ro# #aking what is %robably a #istake,. RF SURFSTIJLT+(6PTE53TILGU
2;:
Thinking in Java
,,,'0ruceEckel'com
e""ect, you e#bed private ob0ects o" e&isting classes inside your new class. RFSURFSTIJLT+(6PTE53TIL2U So#eti#es it #akes sense to allow the class user to directly access the co#%osition o" your new class; that is, to #ake the #e#ber ob0ects p*blic. The #e#ber ob0ects use i#%le#entation hiding the#selves, so this is a sa"e thing to do. :hen the user knows you re asse#bling a bunch o" %arts, it #akes the inter"ace easier to understand. 6 car ob0ect is a good e&a#%le=
//3 c'+3Car.Hava // Co#"osition :ith "ublic obHects. class Engine @ "ublic voi! start-. @A "ublic voi! rev-. @A "ublic voi! sto"-. @A A class \heel @ "ublic voi! inflate-int "si. @A A class \in!o: @ "ublic voi! rollu"-. @A "ublic voi! roll!o:n-. @A A class Door @ "ublic \in!o: :in!o: ? ne: \in!o:-.< "ublic voi! o"en-. @A "ublic voi! close-. @A A "ublic class Car @ "ublic Engine engine ? ne: Engine-.< "ublic \heelNO :heel ? ne: \heelNIO< "ublic Door left ? ne: Door-., right ? ne: Door-.< // -!oor "ublic Car-. @ for-int i ? '< i P I< iKK.
2;;
:heelNiO ? ne: \heel-.< A "ublic static voi! #ain-%tringNO args. @ Car car ? ne: Car-.< car.left.:in!o:.rollu"-.< car.:heelN'O.inflate-* .< A A ///3>
Because the co#%osition o" a car is %art o" the analysis o" the %roble# *and not si#%ly %art o" the underlying design,, #aking the #e#bers p*blic assists the client %rogra##er s understanding o" how to use the class and reAuires less code co#%le&ity "or the creator o" the class. (owever, kee% in #ind that this is a s%ecial case and that in general you should #ake "ields private. RFSURFSTIJLT+(6PTE53TI?@U :hen you inherit, you take an e&isting class and #ake a s%ecial version o" it. In general, this #eans that you re taking a general'%ur%ose class and s%eciali1ing it "or a %articular need. :ith a little thought, you ll see that it would #ake no sense to co#%ose a car using a vehicle ob0ect9a car doesn t contain a vehicle, it is a vehicle. The is/a relationshi% is e&%ressed with inheritance, and the has/a relationshi% is e&%ressed with co#%osition. RFSURFSTIJLT+(6PTE53TI?MU
.rotected
Cow that you ve been introduced to inheritance, the keyword protecte' "inally has #eaning. In an ideal world, private #e#bers would always be hard'and'"ast private, but in real %ro0ects there are ti#es when you want to #ake so#ething hidden "ro# the world at large and yet allow access "or #e#bers o" derived classes. The protecte' keyword is a nod to %rag#atis#. It says !This is private as "ar as the class user is concerned, but available to anyone who inherits "ro# this class or anyone else in the sa#e package.$ That is, protecte' in Java is auto#atically !"riendly.$ RFSURFSTIJLT+(6PTE53TI?KU The best tack to take is to leave the data #e#bers private9you should always %reserve your right to change the underlying i#%le#entation. /ou
3==
Thinking in Java
,,,'0ruceEckel'com
can then allow controlled access to inheritors o" your class through protecte' #ethods=
//3 c'+3Grc.Hava // The "rotecte! key:or!. i#"ort Hava.util.B< class Willain @ "rivate int i< "rotecte! int rea!-. @ return i< "rotecte! voi! set-int ii. @ i ? "ublic Willain-int ii. @ i ? ii< "ublic int value-int #. @ return A
A ii< A A #Bi< A
"ublic class Grc e6ten!s Willain @ "rivate int H< "ublic Grc-int HH. @ su"er-HH.< H ? HH< A "ublic voi! change-int 6. @ set-6.< A A ///3>
/ou can see that changeA B has access to setA B because it s protecte'. RFSURFSTIJLT+(6PTE53TI?LU
Incremental develo.ment
)ne o" the advantages o" inheritance is that it su%%orts incremental develo ment by allowing you to introduce new code without causing bugs in e&isting code. This also isolates new bugs inside the new code. By inheriting "ro# an e&isting, "unctional class and adding data #e#bers and #ethods *and rede"ining e&isting #ethods,, you leave the e&isting code9that so#eone else #ight still be using9untouched and unbugged. I" a bug ha%%ens, you know that it s in your new code, which is #uch shorter and easier to read than i" you had #odi"ied the body o" e&isting code. RFSURFSTIJLT+(6PTE53TI??U
3=1
It s rather a#a1ing how cleanly the classes are se%arated. /ou don t even need the source code "or the #ethods in order to reuse the code. 6t #ost, you 0ust i#%ort a %ackage. *This is true "or both inheritance and co#%osition., RFSURFSTIJLT+(6PTE53TI?HU It s i#%ortant to reali1e that %rogra# develo%#ent is an incre#ental %rocess, 0ust like hu#an learning. /ou can do as #uch analysis as you want, but you still won t know all the answers when you set out on a %ro0ect. /ou ll have #uch #ore success9and #ore i##ediate "eedback9 i" you start out to !grow$ your %ro0ect as an organic, evolutionary creature, rather than constructing it all at once like a glass'bo& skyscra%er. RFSURFSTIJLT+(6PTE53TI?3U 6lthough inheritance "or e&%eri#entation can be a use"ul techniAue, at so#e %oint a"ter things stabili1e you need to take a new look at your class hierarchy with an eye to colla%sing it into a sensible structure. 5e#e#ber that underneath it all, inheritance is #eant to e&%ress a relationshi% that says !This new class is a t) e o$ that old class.$ /our %rogra# should not be concerned with %ushing bits around, but instead with creating and #ani%ulating ob0ects o" various ty%es to e&%ress a #odel in the ter#s that co#e "ro# the %roble# s%ace. RFSURFSTIJLT+(6PTE53TI?GU
C.casting
The #ost i#%ortant as%ect o" inheritance is not that it %rovides #ethods "or the new class. It s the relationshi% e&%ressed between the new class and the base class. This relationshi% can be su##ari1ed by saying !The new class is a t) e o$ the e&isting class.$ RFSURF STIJLT+(6PTE53TI?IU This descri%tion is not 0ust a "anci"ul way o" e&%laining inheritance9it s su%%orted directly by the language. 6s an e&a#%le, consider a base class called Instr*ment that re%resents #usical instru#ents, and a derived class called 0in'. Because inheritance #eans that all o" the #ethods in the base class are also available in the derived class, any #essage you can send to the base class can also be sent to the derived class. I" the Instr*ment class has a playA B #ethod, so will 0in' instru#ents. This #eans we can accurately say that a 0in' ob0ect is also a ty%e o"
3=2
Thinking in Java
,,,'0ruceEckel'com
//3 c'+3\in!.Hava // $nheritance D u"casting. i#"ort Hava.util.B< class $nstru#ent @ "ublic voi! "lay-. @A static voi! tune-$nstru#ent i. @ // ... i."lay-.< A A // \in! obHects are instru#ents // because they have the sa#e interface3 "ublic class \in! e6ten!s $nstru#ent @ "ublic static voi! #ain-%tringNO args. @ \in! flute ? ne: \in!-.< $nstru#ent.tune-flute.< // Y"casting A A ///3>
:hat s interesting in this e&a#%le is the t*neA B #ethod, which acce%ts an Instr*ment re"erence. (owever, in 0in'.mainA B the t*neA B #ethod is called by giving it a 0in' re"erence. 8iven that Java is %articular about ty%e checking, it see#s strange that a #ethod that acce%ts one ty%e will readily acce%t another ty%e, until you reali1e that a 0in' ob0ect is also an Instr*ment ob0ect, and there s no #ethod that t*neA B could call "or an Instr*ment that isn t also in 0in'. Inside t*neA B, the code works "or Instr*ment and anything derived "ro# Instr*ment, and the act o" converting a 0in' re"erence into an Instr*ment re"erence is called u casting. RFSURF STIJLT+(6PTE53TI?2U
Wh: Ju.castingKA
The reason "or the ter# is historical, and based on the way class inheritance diagra#s have traditionally been drawn= with the root at the
3=3
to% o" the %age, growing downward. *)" course, you can draw your diagra#s any way you "ind hel%"ul., The inheritance diagra# "or 0in'! 8ava is then=
Instrument
Wind
+asting "ro# derived to base #oves u on the inheritance diagra#, so it s co##only re"erred to as u casting. 4%casting is always sa"e because you re going "ro# a #ore s%eci"ic ty%e to a #ore general ty%e. That is, the derived class is a su%erset o" the base class. It #ight contain #ore #ethods than the base class, but it #ust contain at least the #ethods in the base class. The only thing that can occur to the class inter"ace during the u%cast is that it can lose #ethods, not gain the#. This is why the co#%iler allows u%casting without any e&%licit casts or other s%ecial notation. RFSURFSTIJLT+(6PTE53TIH@U /ou can also %er"or# the reverse o" u%casting, called do,ncasting, but this involves a dile##a that is the sub0ect o" +ha%ter MK. RFSURF STIJLT+(6PTE53TIHMU
3=4
Thinking in Java
,,,'0ruceEckel'com
u%casting, but i" you re#e#ber to ask !7o I need to u%castO$ you ll have a good tool "or deciding between co#%osition and inheritance. RFSURF STIJLT+(6PTE53TIHKU
<inal data
Many %rogra##ing languages have a way to tell the co#%iler that a %iece o" data is !constant.$ 6 constant is use"ul "or two reasons=
+5) +6)
It can be a com ile/time constant that won t ever change. RFSURF STIJLT+(6PTE53TIHHU It can be a value initiali1ed at run'ti#e that you don t want changed. RFSURFSTIJLT+(6PTE53TIH3U
In the case o" a co#%ile'ti#e constant, the co#%iler is allowed to !"old$ the constant value into any calculations in which it s used; that is, the calculation can be %er"or#ed at co#%ile'ti#e, eli#inating so#e run'ti#e overhead. In Java, these sorts o" constants #ust be %ri#itives and are e&%ressed using the final keyword. 6 value #ust be given at the ti#e o" de"inition o" such a constant. RFSURFSTIJLT+(6PTE53TIHGU 6 "ield that is both static and final has only one %iece o" storage that cannot be changed. RFSURFSTIJLT+(6PTE53TIHIU :hen using final with ob0ect re"erences rather than %ri#itives the #eaning gets a bit con"using. :ith a %ri#itive, final #akes the value a constant, but with an ob0ect re"erence, final #akes the re$erence a
3=5
constant. )nce the re"erence is initiali1ed to an ob0ect, it can never be changed to %oint to another ob0ect. (owever, the ob0ect itsel" can be #odi"ied; Java does not %rovide a way to #ake any arbitrary ob0ect a constant. */ou can, however, write your class so that ob0ects have the e""ect o" being constant., This restriction includes arrays, which are also ob0ects. RFSURFSTIJLT+(6PTE53TIH2U (ere s an e&a#%le that de#onstrates final "ields=
//3 c'+3LinalData.Hava // The effect of final on fiel!s. class Walue @ int i ? (< "ublic Walue-int ii. @ i ? ii< A A "ublic class LinalData @ // Can be co#"ile-ti#e constants final int i( ? C< static final int W0LbT\G ? CC< // Ty"ical "ublic constant3 "ublic static final int W0LbTM5EE ? )C< // Cannot be co#"ile-ti#e constants3 final int iI ? -int.-Jath.ran!o#-.B '.< static final int i, ? -int.-Jath.ran!o#-.B '.< Walue v( ? ne: Walue-((.< final Walue v ? ne: Walue- .< static final Walue v) ? ne: Walue-)).< // 0rrays3 final intNO a ? @ (, , ), I, ,, + A< "ublic voi! "rint-%tring i!. @ %yste#.out."rintlni! K 83 8 K 8iI ? 8 K iI K 8, i, ? 8 K i,.< A "ublic static voi! #ain-%tringNO args. @ LinalData f!( ? ne: LinalData-.< //4 f!(.i(KK< // Error3 can2t change value
3=7
Thinking in Java
,,,'0ruceEckel'com
f!(.v .iKK< // GbHect isn2t constant4 f!(.v( ? ne: Walue-C.< // G` -- not final for-int i ? '< i P f!(.a.length< iKK. f!(.aNiOKK< // GbHect isn2t constant4 //4 f!(.v ? ne: Walue-'.< // Error3 Can2t //4 f!(.v) ? ne: Walue-(.< // change reference //4 f!(.a ? ne: intN)O< f!(."rint-8f!(8.< %yste#.out."rintln-8Creating ne: LinalData8.< LinalData f! ? ne: LinalData-.< f!(."rint-8f!(8.< f! ."rint-8f! 8.< A A ///3>
Since i> and VA+XT0. are final %ri#itives with co#%ile'ti#e values, they can both be used as co#%ile'ti#e constants and are not di""erent in any i#%ortant way. VA+XTH$&& is the #ore ty%ical way you ll see such constants de"ined= p*blic so they re usable outside the %ackage, static to e#%hasi1e that there s only one, and final to say that it s a constant. Cote that final static %ri#itives with constant initial values *that is, co#%ile' ti#e constants, are na#ed with all ca%itals by convention, with words se%arated by underscores *This is 0ust like + constants, which is where the convention originated., 6lso note that i@ cannot be known at co#%ile' ti#e, so it is not ca%itali1ed. RFSURFSTIJLT+(6PTE53TI3@U Just because so#ething is final doesn t #ean that its value is known at co#%ile'ti#e. This is de#onstrated by initiali1ing iQ and i@ at run'ti#e using rando#ly generated nu#bers. This %ortion o" the e&a#%le also shows the di""erence between #aking a final value static or non' static. This di""erence shows u% only when the values are initiali1ed at run'ti#e, since the co#%ile'ti#e values are treated the sa#e by the co#%iler. *6nd %resu#ably o%ti#i1ed out o" e&istence., The di""erence is shown in the out%ut "ro# one run=
3=8
Cote that the values o" iQ "or f'> and f'I are uniAue, but the value "or i@ is not changed by creating the second Final ata ob0ect. That s because it s static and is initiali1ed once u%on loading and not each ti#e a new ob0ect is created. RFSURFSTIJLT+(6PTE53TI3MU The variables v> through vQ vJ de#onstrate the #eaning o" a final re"erence. 6s you can see in mainA B, 0ust because vI is final doesn t #ean that you can t change its value. (owever, you cannot rebind vI to a new ob0ect, %recisely because it s final. That s what final #eans "or a re"erence. /ou can also see the sa#e #eaning holds true "or an array, which is 0ust another kind o" re"erence. *There is no way that I know o" to #ake the array re"erences the#selves final., Making re"erences final see#s less use"ul than #aking %ri#itives final. RFSURF STIJLT+(6PTE53TI3KU
;lank finals
Java allows the creation o" blank $inals, which are "ields that are declared as final but are not given an initiali1ation value. In all cases, the blank "inal must be initiali1ed be"ore it is used, and the co#%iler ensures this. (owever, blank "inals %rovide #uch #ore "le&ibility in the use o" the final keyword since, "or e&a#%le, a final "ield inside a class can now be di""erent "or each ob0ect and yet it retains its i##utable Auality. (ere s an e&a#%le=
//3 c'+3BlankLinal.Hava // 8Blank8 final !ata #e#bers. class Po""et @ int i< "ublic Po""et-int ii. @ i ? ii< A A "ublic class BlankLinal @ final int i ? '< // $nitialiUe! final final int H< // Blank final final Po""et "< // Blank final reference // Blank finals JY%T be initialiUe! // in the constructor3 BlankLinal-. @
3=:
Thinking in Java
,,,'0ruceEckel'com
H ? (< // $nitialiUe blank final " ? ne: Po""et-(.< A BlankLinal-int 6. @ H ? 6< // $nitialiUe blank final " ? ne: Po""et-6.< A "ublic static voi! #ain-%tringNO args. @ BlankLinal bf ? ne: BlankLinal-.< ne: BlankLinal-I*.< A A ///3>
/ou re "orced to %er"or# assign#ents to finals either with an e&%ression at the %oint o" de"inition o" the "ield or in every constructor. This way it s guaranteed that the final "ield is always initiali1ed be"ore use. RFSURF STIJLT+(6PTE53TI3LU
<inal arguments
Java allows you to #ake argu#ents final by declaring the# as such in the argu#ent list. This #eans that inside the #ethod you cannot change what the argu#ent re"erence %oints to=
//3 c'+3Linal0rgu#ents.Hava // Ysing 8final8 :ith #etho! argu#ents. class aiU#o @ "ublic voi! s"in-. @A A "ublic class Linal0rgu#ents @ voi! :ith-final aiU#o g. @ //4 g ? ne: aiU#o-.< // $llegal -- g is final A voi! :ithout-aiU#o g. @ g ? ne: aiU#o-.< // G` -- g not final g.s"in-.< A // voi! f-final int i. @ iKK< A // Can2t change // ;ou can only rea! fro# a final "ri#itive3 int g-final int i. @ return i K (< A
3=;
"ublic static voi! #ain-%tringNO args. @ Linal0rgu#ents bf ? ne: Linal0rgu#ents-.< bf.:ithout-null.< bf.:ith-null.< A A ///3>
Cote that you can still assign a n*ll re"erence to an argu#ent that s "inal without the co#%iler catching it, 0ust like you can with a non' final argu#ent. RFSURFSTIJLT+(6PTE53TI3?U The #ethods fA B and gA B show what ha%%ens when %ri#itive argu#ents are final= you can read the argu#ent, but you canVt change it. RFSURF STIJLT+(6PTE53TI3HU
<inal methods
There are two reasons "or final #ethods. The "irst is to %ut a !lock$ on the #ethod to %revent any inheriting class "ro# changing its #eaning. This is done "or design reasons when you want to #ake sure that a #ethod s behavior is retained during inheritance and cannot be overridden. RFSURFSTIJLT+(6PTE53TI33U The second reason "or final #ethods is e""iciency. I" you #ake a #ethod final, you are allowing the co#%iler to turn any calls to that #ethod into inline calls. :hen the co#%iler sees a final #ethod call it can *at its discretion, ski% the nor#al a%%roach o" inserting code to %er"or# the #ethod call #echanis# *%ush argu#ents on the stack, ho% over to the #ethod code and e&ecute it, ho% back and clean o"" the stack argu#ents, and deal with the return value, and instead re%lace the #ethod call with a co%y o" the actual code in the #ethod body. This eli#inates the overhead o" the #ethod call. )" course, i" a #ethod is big, then your code begins to bloat and you %robably won t see any %er"or#ance gains "ro# inlining, since any i#%rove#ents will be dwar"ed by the a#ount o" ti#e s%ent inside the #ethod. It is i#%lied that the Java co#%iler is able to detect these situations and choose wisely whether to inline a final #ethod. (owever, it s better to not trust that the co#%iler is able to do this and #ake a #ethod final only i" it s Auite s#all or i" you want to e&%licitly %revent overriding. RFSURFSTIJLT+(6PTE53TI3GU
31=
Thinking in Java
,,,'0ruceEckel'com
//3 c'+3LinalGverri!ing$llusion.Hava // $t only looks like you can overri!e // a "rivate or "rivate final #etho!. class \ithLinals @ // $!entical to 8"rivate8 alone3 "rivate final voi! f-. @ %yste#.out."rintln-8\ithLinals.f-.8.< A // 0lso auto#atically 8final83 "rivate voi! g-. @ %yste#.out."rintln-8\ithLinals.g-.8.< A A class Gverri!ingPrivate e6ten!s \ithLinals @ "rivate final voi! f-. @ %yste#.out."rintln-8Gverri!ingPrivate.f-.8.< A "rivate voi! g-. @ %yste#.out."rintln-8Gverri!ingPrivate.g-.8.< A A class Gverri!ingPrivate e6ten!s Gverri!ingPrivate @ "ublic final voi! f-. @ %yste#.out."rintln-8Gverri!ingPrivate .f-.8.< A
311
"ublic voi! g-. @ %yste#.out."rintln-8Gverri!ingPrivate .g-.8.< A A "ublic class LinalGverri!ing$llusion @ "ublic static voi! #ain-%tringNO args. @ Gverri!ingPrivate o" ? ne: Gverri!ingPrivate -.< o" .f-.< o" .g-.< // ;ou can u"cast3 Gverri!ingPrivate o" ? o" < // But you can2t call the #etho!s3 //4 o".f-.< //4 o".g-.< // %a#e here3 \ithLinals :f ? o" < //4 :f.f-.< //4 :f.g-.< A A ///3>
!)verriding$ can only occur i" so#ething is %art o" the base'class inter"ace. That is, you #ust be able to u%cast an ob0ect to its base ty%e and call the sa#e #ethod *the %oint o" this will beco#e clear in the ne&t cha%ter,. I" a #ethod is private, it isn t %art o" the base'class inter"ace. It is 0ust so#e code that s hidden away inside the class, and it 0ust ha%%ens to have that na#e, but i" you create a p*blic, protecte' or !"riendly$ #ethod in the derived class, there s no connection to the #ethod that #ight ha%%en to have that na#e in the base class. Since a private #ethod is unreachable and e""ectively invisible, it doesn t "actor into anything e&ce%t "or the code organi1ation o" the class "or which it was de"ined. RFSURFSTIJLT+(6PTE53TI32U
<inal classes
:hen you say that an entire class is final *by %receding its de"inition with the final keyword,, you state that you don t want to inherit "ro# this class or allow anyone else to do so. In other words, "or so#e reason the
312
Thinking in Java
,,,'0ruceEckel'com
design o" your class is such that there is never a need to #ake any changes, or "or sa"ety or security reasons you don t want subclassing. 6lternatively, you #ight be dealing with an e""iciency issue, and you want to #ake sure that any activity involved with ob0ects o" this class are as e""icient as %ossible. RFSURFSTIJLT+(6PTE53TIG@U
//3 c'+3Jurassic.Hava // Jaking an entire class final. class %#allBrain @A final class Dinosaur @ int i ? *< int H ? (< %#allBrain 6 ? ne: %#allBrain-.< voi! f-. @A A //4 class Lurther e6ten!s Dinosaur @A // error3 Cannot e6ten! final class 2Dinosaur2 "ublic class Jurassic @ "ublic static voi! #ain-%tringNO args. @ Dinosaur n ? ne: Dinosaur-.< n.f-.< n.i ? I'< n.HKK< A A ///3>
Cote that the data #e#bers can be final or not, as you choose. The sa#e rules a%%ly to final "or data #e#bers regardless o" whether the class is de"ined as final. 7e"ining the class as final si#%ly %revents inheritance9 nothing #ore. (owever, because it %revents inheritance all #ethods in a final class are i#%licitly final, since there s no way to override the#. So the co#%iler has the sa#e e""iciency o%tions as it does i" you e&%licitly declare a #ethod final. RFSURFSTIJLT+(6PTE53TIGMU /ou can add the final s%eci"ier to a #ethod in a final class, but it doesn t add any #eaning. RFSURFSTIJLT+(6PTE53TIGKU
313
<inal caution
It can see# to be sensible to #ake a #ethod final while you re designing a class. /ou #ight "eel that e""iciency is very i#%ortant when using your class and that no one could %ossibly want to override your #ethods anyway. So#eti#es this is true. RFSURFSTIJLT+(6PTE53TIGLU But be care"ul with your assu#%tions. In general, it s di""icult to antici%ate how a class can be reused, es%ecially a general'%ur%ose class. I" you de"ine a #ethod as final you #ight %revent the %ossibility o" reusing your class through inheritance in so#e other %rogra##er s %ro0ect si#%ly because you couldn t i#agine it being used that way. RFSURF STIJLT+(6PTE53TIG?U The standard Java library is a good e&a#%le o" this. In %articular, the Java [email protected] Vector class was co##only used and #ight have been even #ore use"ul i", in the na#e o" e""iciency, all the #ethods hadn t been #ade final. It s easily conceivable that you #ight want to inherit and override with such a "unda#entally use"ul class, but the designers so#ehow decided this wasn t a%%ro%riate. This is ironic "or two reasons. Eirst, )tack is inherited "ro# Vector, which says that a )tack is a Vector, which isn t really true "ro# a logical stand%oint. Second, #any o" the #ost i#%ortant #ethods o" Vector, such as a''&lementA B and elementAtA B are synchroni7e'. 6s you will see in +ha%ter M?, this incurs a signi"icant %er"or#ance overhead that %robably wi%es out any gains %rovided by final. This lends credence to the theory that %rogra##ers are consistently bad at guessing where o%ti#i1ations should occur. It s 0ust too bad that such a clu#sy design #ade it into the standard library where we #ust all co%e with it. *Eortunately, the Java K container library re%laces Vector with Array+ist, which behaves #uch #ore civilly. 4n"ortunately, there s still %lenty o" new code being written that uses the old container library., RFSURFSTIJLT+(6PTE53TIGHU It s also interesting to note that Hashtable, another i#%ortant standard library class, does not have any final #ethods. 6s #entioned elsewhere in this book, it s Auite obvious that so#e classes were designed by co#%letely di""erent %eo%le than others. */ou ll see that the #ethod na#es in Hashtable are #uch brie"er co#%ared to those in Vector, another %iece o" evidence., This is %recisely the sort o" thing that should
314
Thinking in Java
,,,'0ruceEckel'com
315
//3 c'+3Beetle.Hava // The full "rocess of initialiUation. class $nsect @ int i ? C< int H< $nsect-. @ "rt-8i ? 8 K i K 8, H ? 8 K H.< H ? )C< A static int 6( ? "rt-8static $nsect.6( initialiUe!8.< static int "rt-%tring s. @ %yste#.out."rintln-s.< return I*< A A "ublic class Beetle e6ten!s $nsect @ int k ? "rt-8Beetle.k initialiUe!8.< Beetle-. @ "rt-8k ? 8 K k.< "rt-8H ? 8 K H.< A static int 6 ? "rt-8static Beetle.6 initialiUe!8.< "ublic static voi! #ain-%tringNO args. @ "rt-8Beetle constructor8.< Beetle b ? ne: Beetle-.< A A ///3>
The out%ut "or this %rogra# is=
317
Thinking in Java
,,,'0ruceEckel'com
1ummar:
Both inheritance and co#%osition allow you to create a new ty%e "ro# e&isting ty%es. Ty%ically, however, you use co#%osition to reuse e&isting ty%es as %art o" the underlying i#%le#entation o" the new ty%e, and
318
inheritance when you want to reuse the inter"ace. Since the derived class has the base'class inter"ace, it can be u cast to the base, which is critical "or %oly#or%his#, as you ll see in the ne&t cha%ter. RFSURF STIJLT+(6PTE53TIILU 7es%ite the strong e#%hasis on inheritance in ob0ect'oriented %rogra##ing, when you start a design you should generally %re"er co#%osition during the "irst cut and use inheritance only when it is clearly necessary. +o#%osition tends to be #ore "le&ible. In addition, by using the added arti"ice o" inheritance with your #e#ber ty%e, you can change the e&act ty%e, and thus the behavior, o" those #e#ber ob0ects at run'ti#e. There"ore, you can change the behavior o" the co#%osed ob0ect at run'ti#e. RFSURFSTIJLT+(6PTE53TII?U 6lthough code reuse through co#%osition and inheritance is hel%"ul "or ra%id %ro0ect develo%#ent, you ll generally want to redesign your class hierarchy be"ore allowing other %rogra##ers to beco#e de%endent on it. /our goal is a hierarchy in which each class has a s%eci"ic use and is neither too big *enco#%assing so #uch "unctionality that it s unwieldy to reuse, nor annoyingly s#all *you can t use it by itsel" or without adding "unctionality,. RFSURFSTIJLT+(6PTE53TIIHU
/0ercises
Solutions to selected e&ercises can be "ound in the electronic docu#entThe Thinking in Java "nnotated Solution @uide, available "or a s#all "ee "ro# ,,,'0ruceEckel'com.
31:
Thinking in Java
,,,'0ruceEckel'com
,6) +reate a si#%le class. Inside a second class, de"ine a "ield "or an
ob0ect o" the "irst class. 4se la1y initiali1ation to instantiate this ob0ect. RFSURFSTIJLT+(6PTE53TIIIU
etergent. )verride scr*bA B and add a new #ethod called sterili7eA B. RFSURF STIJLT+(6PTE53TII2U
the -artoon class. E&%lain what ha%%ens. RFSURF STIJLT+(6PTE53TI2@U
-() Take the "ile -artoon!8ava and co##ent out the constructor "or
-!) Take the "ile -hess!8ava and co##ent out the constructor "or
the -hess class. E&%lain what ha%%ens. RFSURF STIJLT+(6PTE53TI2MU
-*) Prove that de"ault constructors are created "or you by the
co#%iler. RFSURFSTIJLT+(6PTE53TI2KU
-+) Prove that the base'class constructors are *a, always called, and
*b, called be"ore derived'class constructors. RFSURF STIJLT+(6PTE53TI2LU
--) +reate a class called $oot that contains an instance o" each o"
classes *that you also create, na#ed -omponent>, -omponentI, and -omponentJ. 7erive a class )tem "ro# $oot that also contains an instance o" each !co#%onent.$ 6ll classes should have de"ault constructors that %rint a #essage about that class. RFSURFSTIJLT+(6PTE53TI2HU
-5) 6dd a %ro%er hierarchy o" clean*pA B #ethods to all the classes
in E&ercise MM. RFSURFSTIJLT+(6PTE53TI2GU
31;
4+) +reate a class with a static final "ield and a final "ield and
de#onstrate the di""erence between the two. RFSURF STIJLT+(6PTE53TIM@LU
4-) +reate a class with a final #ethod. Inherit "ro# that class and
atte#%t to override that #ethod. RFSURF STIJLT+(6PTE53TIM@HU
32=
Thinking in Java
,,,'0ruceEckel'com
44) +reate a final class and atte#%t to inherit "ro# it. RFSURF
STIJLT+(6PTE53TIM@3U
45) Prove that class loading takes %lace only once. Prove that loading
#ay be caused by either the creation o" the "irst instance o" that class, or the access o" a static #e#ber. RFSURF STIJLT+(6PTE53TIM@GU
321
4: ol:mor.hism
RFSTIJLT+(6PTE5GTI@UPoly#or%his# is the third essential "eature o" an ob0ect'oriented %rogra##ing language, a"ter data abstraction and inheritance.
It %rovides another di#ension o" se%aration o" inter"ace "ro# i#%le#entation, to decou%le ,hat "ro# ho,. Poly#or%his# allows i#%roved code organi1ation and readability as well as the creation o" e*tensible %rogra#s that can be !grown$ not only during the original creation o" the %ro0ect but also when new "eatures are desired. RFSURF STIJLT+(6PTE5GTIMU Enca%sulation creates new data ty%es by co#bining characteristics and behaviors. I#%le#entation hiding se%arates the inter"ace "ro# the i#%le#entation by #aking the details private. This sort o" #echanical organi1ation #akes ready sense to so#eone with a %rocedural %rogra##ing background. But %oly#or%his# deals with decou%ling in ter#s o" t) es. In the last cha%ter, you saw how inheritance allows the treat#ent o" an ob0ect as its own ty%e or its base ty%e. This ability is critical because it allows #any ty%es *derived "ro# the sa#e base ty%e, to be treated as i" they were one ty%e, and a single %iece o" code to work on all those di""erent ty%es eAually. The %oly#or%hic #ethod call allows one ty%e to e&%ress its distinction "ro# another, si#ilar ty%e, as long as they re both derived "ro# the sa#e base ty%e. This distinction is e&%ressed through di""erences in behavior o" the #ethods that you can call through the base class. RFSURFSTIJLT+(6PTE5GTIKU In this cha%ter, you ll learn about %oly#or%his# *also called d)namic binding or late binding or run/time binding, starting "ro# the basics, with si#%le e&a#%les that stri% away everything but the %oly#or%hic behavior o" the %rogra#. RFSURFSTIJLT+(6PTE5GTILU
322
C.casting revisited
In +ha%ter 3 you saw how an ob0ect can be used as its own ty%e or as an ob0ect o" its base ty%e. Taking an ob0ect re"erence and treating it as a re"erence to its base ty%e is called u castingD because o" the way inheritance trees are drawn with the base class at the to%. RFSURF STIJLT+(6PTE5GTI?U /ou also saw a %roble# arise, which is e#bodied in the "ollowing=
//3 c'*3#usic3Jusic.Hava // $nheritance D u"casting. class &ote @ "rivate int value< "rivate &ote-int val. @ value ? val< A "ublic static final &ote J$DDLEbC ? ne: &ote-'., Cb%M05P ? ne: &ote-(., BbLL0T ? ne: &ote- .< A // Etc. class $nstru#ent @ "ublic voi! "lay-&ote n. @ %yste#.out."rintln-8$nstru#ent."lay-.8.< A A // \in! obHects are instru#ents // because they have the sa#e interface3 class \in! e6ten!s $nstru#ent @ // 5e!efine interface #etho!3 "ublic voi! "lay-&ote n. @ %yste#.out."rintln-8\in!."lay-.8.< A A "ublic class Jusic @ "ublic static voi! tune-$nstru#ent i. @ // ...
323
i."lay-&ote.J$DDLEbC.< A "ublic static voi! #ain-%tringNO args. @ \in! flute ? ne: \in!-.< tune-flute.< // Y"casting A A ///3>
The #ethod 1*sic!t*neA B acce%ts an Instr*ment re"erence, but also anything derived "ro# Instr*ment. In mainA B, you can see this ha%%ening as a 0in' re"erence is %assed to t*neA B, with no cast necessary. This is acce%table; the inter"ace in Instr*ment #ust e&ist in 0in', because 0in' is inherited "ro# Instr*ment. 4%casting "ro# 0in' to Instr*ment #ay !narrow$ that inter"ace, but it cannot #ake it anything less than the "ull inter"ace to Instr*ment. RFSURF STIJLT+(6PTE5GTIHU
//3 c'*3#usic 3Jusic .Hava // Gverloa!ing instea! of u"casting. class &ote @ "rivate int value< "rivate &ote-int val. @ value ? val< A "ublic static final &ote J$DDLEbC ? ne: &ote-'., Cb%M05P ? ne: &ote-(., BbLL0T ? ne: &ote- .< A // Etc. class $nstru#ent @
324
"ublic voi! "lay-&ote n. @ %yste#.out."rintln-8$nstru#ent."lay-.8.< A A class \in! e6ten!s $nstru#ent @ "ublic voi! "lay-&ote n. @ %yste#.out."rintln-8\in!."lay-.8.< A A class %tringe! e6ten!s $nstru#ent @ "ublic voi! "lay-&ote n. @ %yste#.out."rintln-8%tringe!."lay-.8.< A A class Brass e6ten!s $nstru#ent @ "ublic voi! "lay-&ote n. @ %yste#.out."rintln-8Brass."lay-.8.< A A "ublic class Jusic @ "ublic static voi! tune-\in! i. @ i."lay-&ote.J$DDLEbC.< A "ublic static voi! tune-%tringe! i. @ i."lay-&ote.J$DDLEbC.< A "ublic static voi! tune-Brass i. @ i."lay-&ote.J$DDLEbC.< A "ublic static voi! #ain-%tringNO args. @ \in! flute ? ne: \in!-.< %tringe! violin ? ne: %tringe!-.< Brass frenchMorn ? ne: Brass-.< tune-flute.< // &o u"casting tune-violin.< tune-frenchMorn.< A
325
A ///3>
This works, but there s a #a0or drawback= /ou #ust write ty%e's%eci"ic #ethods "or each new Instr*ment class you add. This #eans #ore %rogra##ing in the "irst %lace, but it also #eans that i" you want to add a new #ethod like t*neA B or a new ty%e o" Instr*ment, you ve got a lot o" work to do. 6dd the "act that the co#%iler won t give you any error #essages i" you "orget to overload one o" your #ethods and the whole %rocess o" working with ty%es beco#es un#anageable. RFSURF STIJLT+(6PTE5GTI3U :ouldn t it be #uch nicer i" you could 0ust write a single #ethod that takes the base class as its argu#ent, and not any o" the s%eci"ic derived classesO That is, wouldn t it be nice i" you could "orget that there are derived classes, and write your code to talk only to the base classO RFSURF STIJLT+(6PTE5GTIGU That s e&actly what %oly#or%his# allows you to do. (owever, #ost %rogra##ers who co#e "ro# a %rocedural %rogra##ing background have a bit o" trouble with the way %oly#or%his# works. RFSURF STIJLT+(6PTE5GTIIU
#he twist
The di""iculty with 1*sic.8ava can be seen by running the %rogra#. The out%ut is 0in'!playA B. This is clearly the desired out%ut, but it doesn t see# to #ake sense that it would work that way. Dook at the t*neA B #ethod=
327
Method@call binding
+onnecting a #ethod call to a #ethod body is called binding. :hen binding is %er"or#ed be"ore the %rogra# is run *by the co#%iler and linker, i" there is one,, it s called earl) binding. /ou #ight not have heard the ter# be"ore because it has never been an o%tion with %rocedural languages. + co#%ilers have only one kind o" #ethod call, and that s early binding. RFSURFSTIJLT+(6PTE5GTIM@U The con"using %art o" the above %rogra# revolves around early binding because the co#%iler cannot know the correct #ethod to call when it has only an Instr*ment re"erence. RFSURFSTIJLT+(6PTE5GTIMMU The solution is called late binding, which #eans that the binding occurs at run'ti#e based on the ty%e o" ob0ect. Date binding is also called d)namic binding or run/time binding. :hen a language i#%le#ents late binding, there #ust be so#e #echanis# to deter#ine the ty%e o" the ob0ect at run'ti#e and to call the a%%ro%riate #ethod. That is, the co#%iler still doesn t know the ob0ect ty%e, but the #ethod'call #echanis# "inds out and calls the correct #ethod body. The late'binding #echanis# varies "ro# language to language, but you can i#agine that so#e sort o" ty%e in"or#ation #ust be installed in the ob0ects. RFSURF STIJLT+(6PTE5GTIMKU 6ll #ethod binding in Java uses late binding unless a #ethod has been declared final. This #eans that ordinarily you don t need to #ake any decisions about whether late binding will occur9it ha%%ens auto#atically. RFSURFSTIJLT+(6PTE5GTIMLU :hy would you declare a #ethod finalO 6s noted in the last cha%ter, it %revents anyone "ro# overriding that #ethod. Perha%s #ore i#%ortant, it e""ectively !turns o""$ dyna#ic binding, or rather it tells the co#%iler that dyna#ic binding isn t necessary. This allows the co#%iler to generate slightly #ore e""icient code "or final #ethod calls. (owever, in #ost cases it won t #ake any overall %er"or#ance di""erence in your %rogra#, so it s best to only use final as a design decision, and not as an atte#%t to i#%rove %er"or#ance. RFSURFSTIJLT+(6PTE5GTIM?U
328
32:
*assigning one ty%e to another,; and yet it s "ine because a -ircle is a )hape by inheritance. So the co#%iler agrees with the state#ent and doesn t issue an error #essage. RFSURFSTIJLT+(6PTE5GTIMGU Su%%ose you call one o" the base'class #ethods *that have been overridden in the derived classes,=
s.!ra:-.<
6gain, you #ight e&%ect that )hape s 'ra(A B is called because this is, a"ter all, a )hape re"erence9so how could the co#%iler know to do anything elseO 6nd yet the %ro%er -ircle!'ra(A B is called because o" late binding *%oly#or%his#,. RFSURFSTIJLT+(6PTE5GTIMIU The "ollowing e&a#%le %uts it a slightly di""erent way=
//3 c'*3%ha"es.Hava // Poly#or"his# in Java. class %ha"e @ voi! !ra:-. @A voi! erase-. @A A class Circle e6ten!s %ha"e @ voi! !ra:-. @ %yste#.out."rintln-8Circle.!ra:-.8.< A voi! erase-. @ %yste#.out."rintln-8Circle.erase-.8.< A A class %=uare e6ten!s %ha"e @ voi! !ra:-. @ %yste#.out."rintln-8%=uare.!ra:-.8.< A voi! erase-. @ %yste#.out."rintln-8%=uare.erase-.8.< A A
32;
class Triangle e6ten!s %ha"e @ voi! !ra:-. @ %yste#.out."rintln-8Triangle.!ra:-.8.< A voi! erase-. @ %yste#.out."rintln-8Triangle.erase-.8.< A A "ublic class %ha"es @ "ublic static %ha"e ran!%ha"e-. @ s:itch--int.-Jath.ran!o#-. B ).. @ !efault3 case '3 return ne: Circle-.< case (3 return ne: %=uare-.< case 3 return ne: Triangle-.< A A "ublic static voi! #ain-%tringNO args. @ %ha"eNO s ? ne: %ha"eNCO< // Lill u" the array :ith sha"es3 for-int i ? '< i P s.length< iKK. sNiO ? ran!%ha"e-.< // Jake "oly#or"hic #etho! calls3 for-int i ? '< i P s.length< iKK. sNiO.!ra:-.< A A ///3>
The base class )hape establishes the co##on inter"ace to anything inherited "ro# )hape9that is, all sha%es can be drawn and erased. The derived classes override these de"initions to %rovide uniAue behavior "or each s%eci"ic ty%e o" sha%e. RFSURFSTIJLT+(6PTE5GTIM2U The #ain class )hapes contains a static #ethod ran')hapeA B that %roduces a re"erence to a rando#ly'selected )hape ob0ect each ti#e you call it. Cote that the u%casting ha%%ens in each o" the ret*rn state#ents, each o" which take s a re"erence to a -ircle, )C*are, or Triangle and sends it out o" the #ethod as the return ty%e, )hape. So whenever you call this #ethod you never get a chance to see what s%eci"ic ty%e it is,
33=
since you always get back a %lain )hape re"erence. RFSURF STIJLT+(6PTE5GTIK@U
mainA B contains an array o" )hape re"erences "illed through calls to ran')hapeA B. 6t this %oint you know you have )hapes, but you don t
know anything #ore s%eci"ic than that *and neither does the co#%iler,. (owever, when you ste% through this array and call 'ra(A B "or each one, the correct ty%e's%eci"ic behavior #agically occurs, as you can see "ro# one out%ut e&a#%le=
/0tensibilit:
Cow let s return to the #usical instru#ent e&a#%le. Because o" %oly#or%his#, you can add as #any new ty%es as you want to the syste# without changing the t*neA B #ethod. In a well'designed ))P %rogra#, #ost or all o" your #ethods will "ollow the #odel o" t*neA B and co##unicate only with the base'class inter"ace. Such a %rogra# is e*tensible because you can add new "unctionality by inheriting new data ty%es "ro# the co##on base class. The #ethods that #ani%ulate the base'class inter"ace will not need to be changed at all to acco##odate the new classes. RFSURFSTIJLT+(6PTE5GTIKKU
331
+onsider what ha%%ens i" you take the instru#ent e&a#%le and add #ore #ethods in the base class and a nu#ber o" new classes. (ere s the diagra#=
Instrument void .la:89 1tring what89 void ad3ust89
6ll these new classes work correctly with the old, unchanged t*neA B #ethod. Even i" t*neA B is in a se%arate "ile and new #ethods are added to the inter"ace o" Instr*ment, t*neA B works correctly without reco#%ilation. (ere is the i#%le#entation o" the above diagra#=
//3 c'*3#usic)3Jusic).Hava // 0n e6tensible "rogra#. i#"ort Hava.util.B< class $nstru#ent @ "ublic voi! "lay-. @ %yste#.out."rintln-8$nstru#ent."lay-.8.< A
332
"ublic %tring :hat-. @ return 8$nstru#ent8< A "ublic voi! a!Hust-. @A A class \in! e6ten!s $nstru#ent @ "ublic voi! "lay-. @ %yste#.out."rintln-8\in!."lay-.8.< A "ublic %tring :hat-. @ return 8\in!8< A "ublic voi! a!Hust-. @A A class Percussion e6ten!s $nstru#ent @ "ublic voi! "lay-. @ %yste#.out."rintln-8Percussion."lay-.8.< A "ublic %tring :hat-. @ return 8Percussion8< A "ublic voi! a!Hust-. @A A class %tringe! e6ten!s $nstru#ent @ "ublic voi! "lay-. @ %yste#.out."rintln-8%tringe!."lay-.8.< A "ublic %tring :hat-. @ return 8%tringe!8< A "ublic voi! a!Hust-. @A A class Brass e6ten!s \in! @ "ublic voi! "lay-. @ %yste#.out."rintln-8Brass."lay-.8.< A "ublic voi! a!Hust-. @ %yste#.out."rintln-8Brass.a!Hust-.8.< A A class \oo!:in! e6ten!s \in! @ "ublic voi! "lay-. @
333
%yste#.out."rintln-8\oo!:in!."lay-.8.< A "ublic %tring :hat-. @ return 8\oo!:in!8< A A "ublic class Jusic) @ // Doesn2t care about ty"e, so ne: ty"es // a!!e! to the syste# still :ork right3 static voi! tune-$nstru#ent i. @ // ... i."lay-.< A static voi! tune0ll-$nstru#entNO e. @ for-int i ? '< i P e.length< iKK. tune-eNiO.< A "ublic static voi! #ain-%tringNO args. @ $nstru#entNO orchestra ? ne: $nstru#entN,O< int i ? '< // Y"casting !uring a!!ition to the array3 orchestraNiKKO ? ne: \in!-.< orchestraNiKKO ? ne: Percussion-.< orchestraNiKKO ? ne: %tringe!-.< orchestraNiKKO ? ne: Brass-.< orchestraNiKKO ? ne: \oo!:in!-.< tune0ll-orchestra.< A A ///3>
The new #ethods are (hatA B, which returns a )tring re"erence with a descri%tion o" the class, and a'8*stA B, which %rovides so#e way to ad0ust each instru#ent. RFSURFSTIJLT+(6PTE5GTIKLU In mainA B, when you %lace so#ething inside the Instr*ment array you auto#atically u%cast to Instr*ment. RFSURFSTIJLT+(6PTE5GTIK?U /ou can see that the t*neA B #ethod is bliss"ully ignorant o" all the code changes that have ha%%ened around it, and yet it works correctly. This is e&actly what %oly#or%his# is su%%osed to %rovide. /our code changes don t cause da#age to %arts o" the %rogra# that should not be a""ected. Put another way, %oly#or%his# is one o" the #ost i#%ortant techniAues
334
that allow the %rogra##er to !se%arate the things that change "ro# the things that stay the sa#e.$ RFSURFSTIJLT+(6PTE5GTIKHU
//3 c'*3\in!Error.Hava // 0cci!entally changing the interface. class &ote9 @ "ublic static final int J$DDLEbC ? ', Cb%M05P ? (, CbLL0T ? A
<
class $nstru#ent9 @ "ublic voi! "lay-int &ote9. @ %yste#.out."rintln-8$nstru#ent9."lay-.8.< A A class \in!9 e6ten!s $nstru#ent9 @ // GGP%4 Changes the #etho! interface3 "ublic voi! "lay-&ote9 n. @ %yste#.out."rintln-8\in!9."lay-&ote9 n.8.< A A "ublic class \in!Error @ "ublic static voi! tune-$nstru#ent9 i. @ // ... i."lay-&ote9.J$DDLEbC.<
335
A "ublic static voi! #ain-%tringNO args. @ \in!9 flute ? ne: \in!9-.< tune-flute.< // &ot the !esire! behavior4 A A ///3>
There s another con"using as%ect thrown in here. In Instr*mentX, the playA B #ethod takes an int that has the identi"ier /oteX. That is, even though /oteX is a class na#e, it can also be used as an identi"ier without co#%laint. But in 0in'X, playA B takes a /oteX re"erence that has an identi"ier n! *6lthough you could even say playA/oteX /oteXB without an error., Thus it a%%ears that the %rogra##er intended to override play A B but #isty%ed the #ethod a bit. The co#%iler, however, assu#ed that an overload and not an override was intended. Cote that i" you "ollow the standard Java na#ing convention, the argu#ent identi"ier would be noteX *lowercase [n ,, which would distinguish it "ro# the class na#e. RF SURFSTIJLT+(6PTE5GTIK3U In t*ne, the Instr*mentX i is sent the playA B #essage, with one o" /oteX s #e#bers * 1I +&X-, as an argu#ent. Since /oteX contains int de"initions, this #eans that the int version o" the now' overloaded playA B #ethod is called, and since that has not been overridden the base'class version is used. RFSURF STIJLT+(6PTE5GTIKGU The out%ut is=
$nstru#ent9."lay-.
This certainly doesn t a%%ear to be a %oly#or%hic #ethod call. )nce you understand what s ha%%ening, you can "i& the %roble# "airly easily, but i#agine how di""icult it #ight be to "ind the bug i" it s buried in a %rogra# o" signi"icant si1e. RFSURFSTIJLT+(6PTE5GTIKIU
337
338
33:
6 class containing abstract #ethods is called an abstract class. I" a class contains one or #ore abstract #ethods, the class #ust be Auali"ied as abstract. *)therwise, the co#%iler gives you an error #essage., RFSURF STIJLT+(6PTE5GTILKU I" an abstract class is inco#%lete, what is the co#%iler su%%osed to do when so#eone tries to #ake an ob0ect o" that classO It cannot sa"ely create an ob0ect o" an abstract class, so you get an error #essage "ro# the co#%iler. This way the co#%iler ensures the %urity o" the abstract class, and you don t need to worry about #isusing it. RFSURF STIJLT+(6PTE5GTILLU I" you inherit "ro# an abstract class and you want to #ake ob0ects o" the new ty%e, you #ust %rovide #ethod de"initions "or all the abstract #ethods in the base class. I" you don t *and you #ay choose not to,, then the derived class is also abstract and the co#%iler will "orce you to Auali"y that class with the abstract keyword. RFSURFSTIJLT+(6PTE5GTIL?U It s %ossible to create a class as abstract without including any abstract #ethods. This is use"ul when you ve got a class in which it doesn t #ake sense to have any abstract #ethods, and yet you want to %revent any instances o" that class. RFSURFSTIJLT+(6PTE5GTILHU The Instr*ment class can easily be turned into an abstract class. )nly so#e o" the #ethods will be abstract, since #aking a class abstract doesn t "orce you to #ake all the #ethods abstract. (ere s what it looks like=
33;
abstract Instrument abstract void .la:89M 1tring what89 N DO ))) OD P abstract void ad3ust89M
(ere s the orchestra e&a#%le #odi"ied to use abstract classes and #ethods=
//3 c'*3#usicI3JusicI.Hava // 0bstract classes an! #etho!s. i#"ort Hava.util.B< abstract class $nstru#ent @ int i< // storage allocate! for each "ublic abstract voi! "lay-.< "ublic %tring :hat-. @ return 8$nstru#ent8< A "ublic abstract voi! a!Hust-.< A class \in! e6ten!s $nstru#ent @
34=
"ublic voi! "lay-. @ %yste#.out."rintln-8\in!."lay-.8.< A "ublic %tring :hat-. @ return 8\in!8< A "ublic voi! a!Hust-. @A A class Percussion e6ten!s $nstru#ent @ "ublic voi! "lay-. @ %yste#.out."rintln-8Percussion."lay-.8.< A "ublic %tring :hat-. @ return 8Percussion8< A "ublic voi! a!Hust-. @A A class %tringe! e6ten!s $nstru#ent @ "ublic voi! "lay-. @ %yste#.out."rintln-8%tringe!."lay-.8.< A "ublic %tring :hat-. @ return 8%tringe!8< A "ublic voi! a!Hust-. @A A class Brass e6ten!s \in! @ "ublic voi! "lay-. @ %yste#.out."rintln-8Brass."lay-.8.< A "ublic voi! a!Hust-. @ %yste#.out."rintln-8Brass.a!Hust-.8.< A A class \oo!:in! e6ten!s \in! @ "ublic voi! "lay-. @ %yste#.out."rintln-8\oo!:in!."lay-.8.< A "ublic %tring :hat-. @ return 8\oo!:in!8< A A "ublic class JusicI @ // Doesn2t care about ty"e, so ne: ty"es
341
// a!!e! to the syste# still :ork right3 static voi! tune-$nstru#ent i. @ // ... i."lay-.< A static voi! tune0ll-$nstru#entNO e. @ for-int i ? '< i P e.length< iKK. tune-eNiO.< A "ublic static voi! #ain-%tringNO args. @ $nstru#entNO orchestra ? ne: $nstru#entN,O< int i ? '< // Y"casting !uring a!!ition to the array3 orchestraNiKKO ? ne: \in!-.< orchestraNiKKO ? ne: Percussion-.< orchestraNiKKO ? ne: %tringe!-.< orchestraNiKKO ? ne: Brass-.< orchestraNiKKO ? ne: \oo!:in!-.< tune0ll-orchestra.< A A ///3>
/ou can see that there s really no change e&ce%t in the base class. RFSURF STIJLT+(6PTE5GTIL3U It s hel%"ul to create abstract classes and #ethods because they #ake the abstractness o" a class e&%licit, and tell both the user and the co#%iler how it was intended to be used. RFSURFSTIJLT+(6PTE5GTILGU
342
//3 c'*3%an!:ich.Hava // Gr!er of constructor calls. class Jeal @ Jeal-. @ %yste#.out."rintln-8Jeal-.8.< A A class Brea! @ Brea!-. @ %yste#.out."rintln-8Brea!-.8.< A A class Cheese @
343
Cheese-. @ %yste#.out."rintln-8Cheese-.8.< A A class Lettuce @ Lettuce-. @ %yste#.out."rintln-8Lettuce-.8.< A A class Lunch e6ten!s Jeal @ Lunch-. @ %yste#.out."rintln-8Lunch-.8.<A A class PortableLunch e6ten!s Lunch @ PortableLunch-. @ %yste#.out."rintln-8PortableLunch-.8.< A A "ublic class %an!:ich e6ten!s PortableLunch @ Brea! b ? ne: Brea!-.< Cheese c ? ne: Cheese-.< Lettuce l ? ne: Lettuce-.< %an!:ich-. @ %yste#.out."rintln-8%an!:ich-.8.< A "ublic static voi! #ain-%tringNO args. @ ne: %an!:ich-.< A A ///3>
This e&a#%le creates a co#%le& class out o" other classes, and each class has a constructor that announces itsel". The i#%ortant class is )an'(ich, which re"lects three levels o" inheritance *"our, i" you count the i#%licit inheritance "ro# .b8ect, and three #e#ber ob0ects. :hen a )an'(ich ob0ect is created in mainA B, the out%ut is=
344
%an!:ich-.
This #eans that the order o" constructor calls "or a co#%le& ob0ect is as "ollows= RFSURFSTIJLT+(6PTE5GTI?MU
,7)
The base'class constructor is called. This ste% is re%eated recursively such that the root o" the hierarchy is constructed "irst, "ollowed by the ne&t'derived class, etc., until the #ost'derived class is reached. RFSURFSTIJLT+(6PTE5GTI?KU Me#ber initiali1ers are called in the order o" declaration. RFSURF STIJLT+(6PTE5GTI?LU The body o" the derived'class constructor is called. RFSURF STIJLT+(6PTE5GTI??U
,() ,!)
The order o" the constructor calls is i#%ortant. :hen you inherit, you know all about the base class and can access any p*blic and protecte' #e#bers o" the base class. This #eans that you #ust be able to assu#e that all the #e#bers o" the base class are valid when you re in the derived class. In a nor#al #ethod, construction has already taken %lace, so all the #e#bers o" all %arts o" the ob0ect have been built. Inside the constructor, however, you #ust be able to assu#e that all #e#bers that you use have been built. The only way to guarantee this is "or the base'class constructor to be called "irst. Then when you re in the derived'class constructor, all the #e#bers you can access in the base class have been initiali1ed. !>nowing that all #e#bers are valid$ inside the constructor is also the reason that, whenever %ossible, you should initiali1e all #e#ber ob0ects *that is, ob0ects %laced in the class using co#%osition, at their %oint o" de"inition in the class *e.g., b, c, and l in the e&a#%le above,. I" you "ollow this %ractice, you will hel% ensure that all base class #e#bers and #e#ber ob0ects o" the current ob0ect have been initiali1ed. 4n"ortunately, this doesn t handle every case, as you will see in the ne&t section. RFSURF STIJLT+(6PTE5GTI?HU
345
o" whether it ha%%ens to be a #e#ber o" your class. :ith inheritance, however, you #ust override finali7eA B in the derived class i" you have any s%ecial cleanu% that #ust ha%%en as %art o" garbage collection. :hen you override finali7eA B in an inherited class, it s i#%ortant to re#e#ber to call the base'class version o" finali7eA B, since otherwise the base'class "inali1ation will not ha%%en. The "ollowing e&a#%le %roves this=
//3 c'*3Lrog.Hava // Testing finaliUe :ith inheritance. class DoBaseLinaliUation @ "ublic static boolean flag ? false< A class Characteristic @ %tring s< Characteristic-%tring c. @ s ? c< %yste#.out."rintln8Creating Characteristic 8 K s.< A "rotecte! voi! finaliUe-. @ %yste#.out."rintln8finaliUing Characteristic 8 K s.< A A class LivingCreature @ Characteristic " ? ne: Characteristic-8is alive8.< LivingCreature-. @ %yste#.out."rintln-8LivingCreature-.8.< A "rotecte! voi! finaliUe-. thro:s Thro:able @ %yste#.out."rintln8LivingCreature finaliUe8.< // Call base-class version L0%T4 if-DoBaseLinaliUation.flag. su"er.finaliUe-.< A A
347
class 0ni#al e6ten!s LivingCreature @ Characteristic " ? ne: Characteristic-8has heart8.< 0ni#al-. @ %yste#.out."rintln-80ni#al-.8.< A "rotecte! voi! finaliUe-. thro:s Thro:able @ %yste#.out."rintln-80ni#al finaliUe8.< if-DoBaseLinaliUation.flag. su"er.finaliUe-.< A A class 0#"hibian e6ten!s 0ni#al @ Characteristic " ? ne: Characteristic-8can live in :ater8.< 0#"hibian-. @ %yste#.out."rintln-80#"hibian-.8.< A "rotecte! voi! finaliUe-. thro:s Thro:able @ %yste#.out."rintln-80#"hibian finaliUe8.< if-DoBaseLinaliUation.flag. su"er.finaliUe-.< A A "ublic class Lrog e6ten!s 0#"hibian @ Lrog-. @ %yste#.out."rintln-8Lrog-.8.< A "rotecte! voi! finaliUe-. thro:s Thro:able @ %yste#.out."rintln-8Lrog finaliUe8.< if-DoBaseLinaliUation.flag. su"er.finaliUe-.< A "ublic static voi! #ain-%tringNO args. @ if-args.length 4? ' DD argsN'O.e=uals-8finaliUe8.. DoBaseLinaliUation.flag ? true< else
348
%yste#.out."rintln-8&ot finaliUing bases8.< ne: Lrog-.< // $nstantly beco#es garbage %yste#.out."rintln-8Bye48.< // Lorce finaliUers to be calle!3 %yste#.gc-.< A A ///3>
The class o2aseFinali7ation si#%ly holds a "lag that indicates to each class in the hierarchy whether to call s*per!finali7eA B. This "lag is set based on a co##and'line argu#ent, so you can view the behavior with and without base'class "inali1ation. RFSURFSTIJLT+(6PTE5GTI?3U Each class in the hierarchy also contains a #e#ber ob0ect o" class -haracteristic. /ou will see that regardless o" whether the base class "inali1ers are called, the -haracteristic #e#ber ob0ects are always "inali1ed. RFSURFSTIJLT+(6PTE5GTI?GU Each overridden finali7eA B #ust have access to at least protecte' #e#bers since the finali7eA B #ethod in class .b8ect is protecte' and the co#%iler will not allow you to reduce the access during inheritance. *! Eriendly$ is less accessible than protecte'., N5WON5
WTIJJX-HA#T&$ZXIQYO
In Frog!mainA B, the o2aseFinali7ation "lag is con"igured and a single Frog ob0ect is created. 5e#e#ber that garbage collection9and in %articular "inali1ation9#ight not ha%%en "or any %articular ob0ect, so to en"orce this, the call to )ystem!gcA B triggers garbage collection, and thus "inali1ation. :ithout base'class "inali1ation, the out%ut is=
&ot finaliUing bases Creating Characteristic is alive LivingCreature-. Creating Characteristic has heart 0ni#al-. Creating Characteristic can live in :ater 0#"hibian-. Lrog-. Bye4 Lrog finaliUe finaliUing Characteristic is alive
34:
Frog *the #e#ber ob0ects are "inali1ed, as you would e&%ect,. But i" you
add the !"inali1e$ argu#ent on the co##and line, you get=
Creating Characteristic is alive LivingCreature-. Creating Characteristic has heart 0ni#al-. Creating Characteristic can live in :ater 0#"hibian-. Lrog-. bye4 Lrog finaliUe 0#"hibian finaliUe 0ni#al finaliUe LivingCreature finaliUe finaliUing Characteristic is alive finaliUing Characteristic has heart finaliUing Characteristic can live in :ater
6lthough the order the #e#ber ob0ects are "inali1ed is the sa#e order that they are created, technically the order o" "inali1ation o" ob0ects is uns%eci"ied. :ith base classes, however, you have control over the order o" "inali1ation. The best order to use is the one that s shown here, which is the reverse o" the order o" initiali1ation. Eollowing the "or# that s used in +<< "or destructors, you should %er"or# the derived'class "inali1ation "irst, then the base'class "inali1ation. That s because the derived'class "inali1ation could call so#e #ethods in the base class that reAuire that the base'class co#%onents are still alive, so you #ust not destroy the# %re#aturely. RFSURFSTIJLT+(6PTE5GTI?2U
34;
#ethod you can i#agine what will ha%%en9the dyna#ically bound call is resolved at run'ti#e because the ob0ect cannot know whether it belongs to the class that the #ethod is in or so#e class derived "ro# it. Eor consistency, you #ight think this is what should ha%%en inside constructors. RFSURFSTIJLT+(6PTE5GTIH@U This is not e&actly the case. I" you call a dyna#ically bound #ethod inside a constructor, the overridden de"inition "or that #ethod is used. (owever, the e$$ect can be rather une&%ected, and can conceal so#e di""icult'to'"ind bugs. RFSURFSTIJLT+(6PTE5GTIHMU +once%tually, the constructor s 0ob is to bring the ob0ect into e&istence *which is hardly an ordinary "eat,. Inside any constructor, the entire ob0ect #ight be only %artially "or#ed9you can know only that the base' class ob0ects have been initiali1ed, but you cannot know which classes are inherited "ro# you. 6 dyna#ically bound #ethod call, however, reaches !outward$ into the inheritance hierarchy. It calls a #ethod in a derived class. I" you do this inside a constructor, you call a #ethod that #ight #ani%ulate #e#bers that haven t been initiali1ed yet9a sure reci%e "or disaster. RFSURFSTIJLT+(6PTE5GTIHKU /ou can see the %roble# in the "ollowing e&a#%le=
//3 c'*3PolyConstructors.Hava // Constructors an! "oly#or"his# // !on2t "ro!uce :hat you #ight e6"ect. abstract class aly"h @ abstract voi! !ra:-.< aly"h-. @ %yste#.out."rintln-8aly"h-. before !ra:-.8.< !ra:-.< %yste#.out."rintln-8aly"h-. after !ra:-.8.< A A class 5oun!aly"h e6ten!s aly"h @ int ra!ius ? (< 5oun!aly"h-int r. @ ra!ius ? r< %yste#.out."rintln-
35=
85oun!aly"h.5oun!aly"h-., ra!ius ? 8 K ra!ius.< A voi! !ra:-. @ %yste#.out."rintln85oun!aly"h.!ra:-., ra!ius ? 8 K ra!ius.< A A "ublic class PolyConstructors @ "ublic static voi! #ain-%tringNO args. @ ne: 5oun!aly"h-,.< A A ///3>
In "lyph, the 'ra(A B #ethod is abstract, so it is designed to be overridden. Indeed, you are "orced to override it in $o*n'"lyph. But the "lyph constructor calls this #ethod, and the call ends u% in $o*n'"lyph!'ra(A B, which would see# to be the intent. But look at the out%ut=
aly"h-. before !ra:-. 5oun!aly"h.!ra:-., ra!ius ? ' aly"h-. after !ra:-. 5oun!aly"h.5oun!aly"h-., ra!ius ? ,
:hen "lyph s constructor calls 'ra(A B, the value o" ra'i*s isn t even the de"ault initial value M. It s @. This would %robably result in either a dot or nothing at all being drawn on the screen, and you d be le"t staring, trying to "igure out why the %rogra# won t work. RFSURF STIJLT+(6PTE5GTIHLU The order o" initiali1ation described in the %revious section isn t Auite co#%lete, and that s the key to solving the #ystery. The actual %rocess o" initiali1ation is=
,*) ,+)
The storage allocated "or the ob0ect is initiali1ed to binary 1ero be"ore anything else ha%%ens. RFSURFSTIJLT+(6PTE5GTIH?U The base'class constructors are called as described %reviously. 6t this %oint, the overridden 'ra(A B #ethod is called *yes, be$ore
351
the $o*n'"lyph constructor is called,, which discovers a ra'i*s value o" 1ero, due to ste% M. RFSURFSTIJLT+(6PTE5GTIHHU
,,) ,-)
Me#ber initiali1ers are called in the order o" declaration. RFSURF STIJLT+(6PTE5GTIH3U The body o" the derived'class constructor is called. RFSURF STIJLT+(6PTE5GTIHGU
There s an u%side to this, which is that everything is at least initiali1ed to 1ero *or whatever 1ero #eans "or that %articular data ty%e, and not 0ust le"t as garbage. This includes ob0ect re"erences that are e#bedded inside a class via co#%osition, which beco#e n*ll. So i" you "orget to initiali1e that re"erence you ll get an e&ce%tion at run'ti#e. Everything else gets 1ero, which is usually a telltale value when looking at out%ut. RFSURF STIJLT+(6PTE5GTIHIU )n the other hand, you should be %retty horri"ied at the outco#e o" this %rogra#. /ou ve done a %er"ectly logical thing, and yet the behavior is #ysteriously wrong, with no co#%laints "ro# the co#%iler. *+<< %roduces #ore rational behavior in this situation., Bugs like this could easily be buried and take a long ti#e to discover. RFSURF STIJLT+(6PTE5GTIH2U 6s a result, a good guideline "or constructors is, !7o as little as %ossible to set the ob0ect into a good state, and i" you can %ossibly avoid it, don t call any #ethods.$ The only sa"e #ethods to call inside a constructor are those that are final in the base class. *This also a%%lies to private #ethods, which are auto#atically final., These cannot be overridden and thus cannot %roduce this kind o" sur%rise. RFSURF STIJLT+(6PTE5GTI3@U
352
e&isting class to #ake a new class, things can beco#e needlessly co#%licated. RFSURFSTIJLT+(6PTE5GTI3MU 6 better a%%roach is to choose co#%osition "irst, when it s not obvious which one you should use. +o#%osition does not "orce a design into an inheritance hierarchy. But co#%osition is also #ore "le&ible since it s %ossible to dyna#ically choose a ty%e *and thus behavior, when using co#%osition, whereas inheritance reAuires an e&act ty%e to be known at co#%ile'ti#e. The "ollowing e&a#%le illustrates this=
//3 c'*3Trans#ogrify.Hava // Dyna#ically changing the behavior of // an obHect via co#"osition. abstract class 0ctor @ abstract voi! act-.< A class Ma""y0ctor e6ten!s 0ctor @ "ublic voi! act-. @ %yste#.out."rintln-8Ma""y0ctor8.< A A class %a!0ctor e6ten!s 0ctor @ "ublic voi! act-. @ %yste#.out."rintln-8%a!0ctor8.< A A class %tage @ 0ctor a ? ne: Ma""y0ctor-.< voi! change-. @ a ? ne: %a!0ctor-.< A voi! go-. @ a.act-.< A A "ublic class Trans#ogrify @ "ublic static voi! #ain-%tringNO args. @ %tage s ? ne: %tage-.< s.go-.< // Prints 8Ma""y0ctor8 s.change-.<
353
354
This can be ter#ed a %ure !is'a$ relationshi% because the inter"ace o" a class establishes what it is. Inheritance guarantees that any derived class will have the inter"ace o" the base class and nothing less. I" you "ollow the above diagra#, derived classes will also have no more than the base class inter"ace. RFSURFSTIJLT+(6PTE5GTI3?U This can be thought o" as ure substitution, because derived class ob0ects can be %er"ectly substituted "or the base class, and you never need to know any e&tra in"or#ation about the subclasses when you re using the#=
#alks to 1ha.e BIs@aB relationshi. CircleH 1%uareH &ineH or new t:.e of 1ha.e
Message
That is, the base class can receive any #essage you can send to the derived class because the two have e&actly the sa#e inter"ace. 6ll you need to do is u%cast "ro# the derived class and never look back to see what e&act ty%e o" ob0ect you re dealing with. Everything is handled through %oly#or%his#. RFSURFSTIJLT+(6PTE5GTI3HU :hen you see it this way, it see#s like a %ure !is'a$ relationshi% is the only sensible way to do things, and any other design indicates #uddled thinking and is by de"inition broken. This too is a tra%. 6s soon as you start thinking this way, you ll turn around and discover that e&tending the inter"ace *which, un"ortunately, the keyword e4ten's see#s to encourage, is the %er"ect solution to a %articular %roble#. This could be ter#ed an !is'like'a$ relationshi% because the derived class is like the base class9it has the sa#e "unda#ental inter"ace9but it has other "eatures that reAuire additional #ethods to i#%le#ent=
355
MoreCseful void void void void void f89 g89 u89 v89 w89
BIs@like@aB
:hile this is also a use"ul and sensible a%%roach *de%ending on the situation, it has a drawback. The e&tended %art o" the inter"ace in the derived class is not available "ro# the base class, so once you u%cast you can t call the new #ethods=
#alks to Cseful ob3ect Cseful .art MoreCseful .art
Message
I" you re not u%casting in this case, it won t bother you, but o"ten you ll get into a situation in which you need to rediscover the e&act ty%e o" the ob0ect so you can access the e&tended #ethods o" that ty%e. The "ollowing section shows how this is done. RFSURFSTIJLT+(6PTE5GTI33U
357
class cannot have a bigger inter"ace than the derived class, there"ore every #essage you send through the base class inter"ace is guaranteed to be acce%ted. But with a downcast, you don t really know that a sha%e *"or e&a#%le, is actually a circle. It could instead be a triangle or sAuare or so#e other ty%e. RFSURFSTIJLT+(6PTE5GTI3GU
Cseful void f89 void g89
MoreCseful void f89 void g89 void u89 void v89 void w89
BIs@like@aB
To solve this %roble# there #ust be so#e way to guarantee that a downcast is correct, so you won t accidentally cast to the wrong ty%e and then send a #essage that the ob0ect can t acce%t. This would be Auite unsa"e. RFSURFSTIJLT+(6PTE5GTI3IU In so#e languages *like +<<, you #ust %er"or# a s%ecial o%eration in order to get a ty%e'sa"e downcast, but in Java ever) cast is checked. So even though it looks like you re 0ust %er"or#ing an ordinary %arenthesi1ed cast, at run'ti#e this cast is checked to ensure that it is in "act the ty%e you think it is. I" it isn t, you get a -lass-ast&4ception. This act o" checking ty%es at run'ti#e is called run/time t) e identi$ication *5TTI,. The "ollowing e&a#%le de#onstrates the behavior o" 5TTI=
//3 c'*35TT$.Hava // Do:ncasting D 5un-ti#e Ty"e // $!entification -5TT$.. i#"ort Hava.util.B< class Yseful @
358
"ublic voi! f-. @A "ublic voi! g-. @A A class JoreYseful e6ten!s Yseful @ "ublic voi! f-. @A "ublic voi! g-. @A "ublic voi! u-. @A "ublic voi! v-. @A "ublic voi! :-. @A A "ublic class 5TT$ @ "ublic static voi! #ain-%tringNO args. @ YsefulNO 6 ? @ ne: Yseful-., ne: JoreYseful-. A< 6N'O.f-.< 6N(O.g-.< // Co#"ile-ti#e3 #etho! not foun! in Yseful3 //4 6N(O.u-.< --JoreYseful.6N(O..u-.< // Do:ncast/5TT$ --JoreYseful.6N'O..u-.< // E6ce"tion thro:n A A ///3>
6s in the diagra#, 1oreUsef*l e&tends the inter"ace o" Usef*l. But since it s inherited, it can also be u%cast to a Usef*l. /ou can see this ha%%ening in the initiali1ation o" the array 4 in mainA B. Since both ob0ects in the array are o" class Usef*l, you can send the fA B and gA B #ethods to both, and i" you try to call *A B *which e&ists only in 1oreUsef*l, you ll get a co#%ile'ti#e error #essage. RFSURF STIJLT+(6PTE5GTI32U I" you want to access the e&tended inter"ace o" a 1oreUsef*l ob0ect, you can try to downcast. I" it s the correct ty%e, it will be success"ul. )therwise, you ll get a -lass-ast&4ception. /ou don t need to write any s%ecial code "or this e&ce%tion, since it indicates a %rogra##er error that could ha%%en anywhere in a %rogra#. RFSURF STIJLT+(6PTE5GTIG@U
35:
There s #ore to 5TTI than a si#%le cast. Eor e&a#%le, there s a way to see what ty%e you re dealing with be$ore you try to downcast it. 6ll o" +ha%ter MK is devoted to the study o" di""erent as%ects o" Java run'ti#e ty%e identi"ication. RFSURFSTIJLT+(6PTE5GTIGMU
1ummar:
Poly#or%his# #eans !di""erent "or#s.$ In ob0ect'oriented %rogra##ing, you have the sa#e "ace *the co##on inter"ace in the base class, and di""erent "or#s using that "ace= the di""erent versions o" the dyna#ically bound #ethods. RFSURFSTIJLT+(6PTE5GTIGKU /ou ve seen in this cha%ter that it s i#%ossible to understand, or even create, an e&a#%le o" %oly#or%his# without using data abstraction and inheritance. Poly#or%his# is a "eature that cannot be viewed in isolation *like a s(itch state#ent can, "or e&a#%le,, but instead works only in concert, as %art o" a !big %icture$ o" class relationshi%s. Peo%le are o"ten con"used by other, non'ob0ect'oriented "eatures o" Java, like #ethod overloading, which are so#eti#es %resented as ob0ect'oriented. 7on t be "ooled= I" it isn t late binding, it isn t %oly#or%his#. RFSURF STIJLT+(6PTE5GTIGLU To use %oly#or%his#9and thus ob0ect'oriented techniAues9e""ectively in your %rogra#s you #ust e&%and your view o" %rogra##ing to include not 0ust #e#bers and #essages o" an individual class, but also the co##onality a#ong classes and their relationshi%s with each other. 6lthough this reAuires signi"icant e""ort, it s a worthy struggle, because the results are "aster %rogra# develo%#ent, better code organi1ation, e&tensible %rogra#s, and easier code #aintenance. RFSURF STIJLT+(6PTE5GTIG?U
/0ercises
Solutions to selected e&ercises can be "ound in the electronic docu#entThe Thinking in Java "nnotated Solution @uide, available "or a s#all "ee "ro# ,,,'0ruceEckel'com.
57) 6dd a new #ethod in the base class o" )hapes!8ava that %rints a
#essage, but don t override it in the derived classes. E&%lain what
35;
ha%%ens. Cow override it in one o" the derived classes but not the others, and see what ha%%ens. Einally, override it in all the derived classes. RFSURFSTIJLT+(6PTE5GTIGHU
5() 6dd a new ty%e o" )hape to )hapes!8ava and veri"y in mainA B
that %oly#or%his# works "or your new ty%e as it does in the old ty%es. RFSURFSTIJLT+(6PTE5GTIG3U
5*) 6dd a new ty%e o" Instr*ment to 1*sicJ!8ava and veri"y that
%oly#or%his# works "or your new ty%e. RFSURF STIJLT+(6PTE5GTIGIU
37=
6() +reate a base class with two #ethods. In the "irst #ethod, call
the second #ethod. Inherit a class and override the second #ethod. +reate an ob0ect o" the derived class, u%cast it to the base ty%e, and call the "irst #ethod. E&%lain what ha%%ens. RFSURF STIJLT+(6PTE5GTII3U
371
372
Interfaces
The interface keyword takes the abstract conce%t one ste% "urther. /ou could think o" it as a !%ure$ abstract class. It allows the creator to establish the "or# "or a class= #ethod na#es, argu#ent lists, and return ty%es, but no #ethod bodies. 6n interface can also contain "ields, but these are i#%licitly static and final. 6n interface %rovides only a "or#, but no i#%le#entation. RFSURFSTIJLT+(6PTE5ITI?U 6n interface says= !This is what all classes that im lement this %articular inter"ace will look like.$ Thus, any code that uses a %articular interface knows what #ethods #ight be called "or that interface, and that s all. So the interface is used to establish a !%rotocol$ between classes. *So#e ob0ect'oriented %rogra##ing languages have a keyword called rotocol to do the sa#e thing., RFSURFSTIJLT+(6PTE5ITIHU To create an interface, use the interface keyword instead o" the class keyword. Dike a class, you can add the p*blic keyword be"ore the interface keyword *but only i" that interface is de"ined in a "ile o" the sa#e na#e, or leave it o"" to give !"riendly$ status so that it is only usable within the sa#e %ackage. RFSURFSTIJLT+(6PTE5ITI3U To #ake a class that con"or#s to a %articular interface *or grou% o" interfaces, use the implements keyword. /ou re saying !The interface is what it looks like but now I # going to say how it ,orks.$ )ther than that, it looks like inheritance. The diagra# "or the instru#ent e&a#%le shows this=
373
)nce you ve i#%le#ented an interface, that i#%le#entation beco#es an ordinary class that can be e&tended in the regular way. RFSURF STIJLT+(6PTE5ITIGU /ou can choose to e&%licitly declare the #ethod declarations in an
interface as p*blic. But they are p*blic even i" you don t say it. So when you implement an interface, the #ethods "ro# the interface #ust be de"ined as p*blic. )therwise they would de"ault to !"riendly,$
and you d be reducing the accessibility o" a #ethod during inheritance, which is not allowed by the Java co#%iler. RFSURF STIJLT+(6PTE5ITIIU /ou can see this in the #odi"ied version o" the Instr*ment e&a#%le. Cote that every #ethod in the interface is strictly a declaration, which is the only thing the co#%iler allows. In addition, none o" the #ethods in
374
//3 c'13#usic,3Jusic,.Hava // $nterfaces. i#"ort Hava.util.B< interface $nstru#ent @ // Co#"ile-ti#e constant3 int i ? ,< // static D final // Cannot have #etho! !efinitions3 voi! "lay-.< // 0uto#atically "ublic %tring :hat-.< voi! a!Hust-.< A class \in! i#"le#ents $nstru#ent @ "ublic voi! "lay-. @ %yste#.out."rintln-8\in!."lay-.8.< A "ublic %tring :hat-. @ return 8\in!8< A "ublic voi! a!Hust-. @A A class Percussion i#"le#ents $nstru#ent @ "ublic voi! "lay-. @ %yste#.out."rintln-8Percussion."lay-.8.< A "ublic %tring :hat-. @ return 8Percussion8< A "ublic voi! a!Hust-. @A A class %tringe! i#"le#ents $nstru#ent @ "ublic voi! "lay-. @ %yste#.out."rintln-8%tringe!."lay-.8.< A "ublic %tring :hat-. @ return 8%tringe!8< A "ublic voi! a!Hust-. @A A class Brass e6ten!s \in! @
375
"ublic voi! "lay-. @ %yste#.out."rintln-8Brass."lay-.8.< A "ublic voi! a!Hust-. @ %yste#.out."rintln-8Brass.a!Hust-.8.< A A class \oo!:in! e6ten!s \in! @ "ublic voi! "lay-. @ %yste#.out."rintln-8\oo!:in!."lay-.8.< A "ublic %tring :hat-. @ return 8\oo!:in!8< A A "ublic class Jusic, @ // Doesn2t care about ty"e, so ne: ty"es // a!!e! to the syste# still :ork right3 static voi! tune-$nstru#ent i. @ // ... i."lay-.< A static voi! tune0ll-$nstru#entNO e. @ for-int i ? '< i P e.length< iKK. tune-eNiO.< A "ublic static voi! #ain-%tringNO args. @ $nstru#entNO orchestra ? ne: $nstru#entN,O< int i ? '< // Y"casting !uring a!!ition to the array3 orchestraNiKKO ? ne: \in!-.< orchestraNiKKO ? ne: Percussion-.< orchestraNiKKO ? ne: %tringe!-.< orchestraNiKKO ? ne: Brass-.< orchestraNiKKO ? ne: \oo!:in!-.< tune0ll-orchestra.< A A ///3>
The rest o" the code works the sa#e. It doesn t #atter i" you are u%casting to a !regular$ class called Instr*ment, an abstract class called
377
Instr*ment, or to an interface called Instr*ment. The behavior is the sa#e. In "act, you can see in the t*neA B #ethod that there isn t any evidence about whether Instr*ment is a !regular$ class, an abstract class, or an interface. This is the intent= Each a%%roach gives the
%rogra##er di""erent control over the way ob0ects are created and used. RFSURFSTIJLT+(6PTE5ITI2U
)))
)))
interface n
interface ( interface !
...
interface n
In a derived class, you aren t "orced to have a base class that is either an abstract or !concrete$ *one with no abstract #ethods,. I" you do inherit "ro# a non' interface, you can inherit "ro# only one. 6ll the rest o" the base ele#ents #ust be interfaces. /ou %lace all the inter"ace na#es a"ter the implements keyword and se%arate the# with co##as. /ou can have as #any interfaces as you want9each one beco#es an inde%endent ty%e that you can u%cast to. The "ollowing e&a#%le shows a
378
concrete class co#bined with several interfaces to %roduce a new class= RFSURFSTIJLT+(6PTE5ITIM@U
//3 c'130!venture.Hava // Julti"le interfaces. i#"ort Hava.util.B< interface CanLight @ voi! fight-.< A interface Can%:i# @ voi! s:i#-.< A interface CanLly @ voi! fly-.< A class 0ctionCharacter @ "ublic voi! fight-. @A A class Mero e6ten!s 0ctionCharacter i#"le#ents CanLight, Can%:i#, CanLly @ "ublic voi! s:i#-. @A "ublic voi! fly-. @A A "ublic class 0!venture @ static voi! t-CanLight 6. @ 6.fight-.< A static voi! u-Can%:i# 6. @ 6.s:i#-.< A static voi! v-CanLly 6. @ 6.fly-.< A static voi! :-0ctionCharacter 6. @ 6.fight-.< A "ublic static voi! #ain-%tringNO args. @ Mero h ? ne: Mero-.< t-h.< // Treat it as a CanLight u-h.< // Treat it as a Can%:i# v-h.< // Treat it as a CanLly :-h.< // Treat it as an 0ctionCharacter A
37:
A ///3>
/ou can see that Hero co#bines the concrete class Action-haracter with the inter"aces -anFight, -an)(im, and -anFly. :hen you co#bine a concrete class with inter"aces this way, the concrete class #ust co#e "irst, then the inter"aces. *The co#%iler gives an error otherwise., RFSURFSTIJLT+(6PTE5ITIMMU Cote that the signature "or fightA B is the sa#e in the interface -anFight and the class Action-haracter, and that fightA B is not %rovided with a de"inition in Hero. The rule "or an interface is that you can inherit "ro# it *as you will see shortly,, but then you ve got another interface. I" you want to create an ob0ect o" the new ty%e, it #ust be a class with all de"initions %rovided. Even though Hero does not e&%licitly %rovide a de"inition "or fightA B, the de"inition co#es along with Action-haracter so it is auto#atically %rovided and it s %ossible to create ob0ects o" Hero. RFSURFSTIJLT+(6PTE5ITIMKU In class A'vent*re, you can see that there are "our #ethods that take as argu#ents the various inter"aces and the concrete class. :hen a Hero ob0ect is created, it can be %assed to any o" these #ethods, which #eans it is being u%cast to each interface in turn. Because o" the way inter"aces are designed in Java, this works without a hitch and without any %articular e""ort on the %art o" the %rogra##er. RFSURF STIJLT+(6PTE5ITIMLU >ee% in #ind that the core reason "or inter"aces is shown in the above e&a#%le= to be able to u%cast to #ore than one base ty%e. (owever, a second reason "or using inter"aces is the sa#e as using an abstract base class= to %revent the client %rogra##er "ro# #aking an ob0ect o" this class and to establish that it is only an inter"ace. This brings u% a Auestion= Should you use an interface or an abstract classO 6n interface gives you the bene"its o" an abstract class and the bene"its o" an interface, so i" it s %ossible to create your base class without any #ethod de"initions or #e#ber variables you should always %re"er interfaces to abstract classes. In "act, i" you know so#ething is going to be a base class, your "irst choice should be to #ake it an interface, and only i" you re "orced to have #ethod de"initions or #e#ber variables should you change to an abstract class, or i" necessary a concrete class. RFSURFSTIJLT+(6PTE5ITIM?U
37;
//3 c'13$nterfaceCollision.Hava interface interface interface class C @ $( @ voi! f-.< A $ @ int f-int i.< A $) @ int f-.< A "ublic int f-. @ return (< A A
class C i#"le#ents $(, $ @ "ublic voi! f-. @A "ublic int f-int i. @ return (< A // overloa!e! A class C) e6ten!s C i#"le#ents $ @ "ublic int f-int i. @ return (< A // overloa!e! A class CI e6ten!s C i#"le#ents $) @ // $!entical, no "roble#3 "ublic int f-. @ return (< A A // Jetho!s !iffer only by return ty"e3 //4 class C, e6ten!s C i#"le#ents $( @A //4 interface $I e6ten!s $(, $) @A ///3>
The di""iculty occurs because overriding, i#%le#entation, and overloading get un%leasantly #i&ed together, and overloaded "unctions cannot di""er only by return ty%e. :hen the last two lines are unco##ented, the error #essages say it all=
Inter$aceCollision'>ava!23! $KA in C cannot im lement $KA in I1E attem ting to use incom atible return t) e $ound ! int re#uired! void
38=
Inter$aceCollision'>ava!24! inter$aces I3 and I1 are incom atibleE both de$ine $KAD but ,ith di$$erent return t) e
4sing the sa#e #ethod na#es in di""erent inter"aces that are intended to be co#bined generally causes con"usion in the readability o" the code, as well. Strive to avoid it. RFSURFSTIJLT+(6PTE5ITIMHU
//3 c'13Morror%ho:.Hava // E6ten!ing an interface :ith inheritance. interface Jonster @ voi! #enace-.< A interface DangerousJonster e6ten!s Jonster @ voi! !estroy-.< A interface Lethal @ voi! kill-.< A class DragonTilla i#"le#ents DangerousJonster @ "ublic voi! #enace-. @A "ublic voi! !estroy-. @A A interface Wa#"ire e6ten!s DangerousJonster, Lethal @ voi! !rinkBloo!-.< A
381
"ublic class Morror%ho: @ static voi! u-Jonster b. @ b.#enace-.< A static voi! v-DangerousJonster !. @ !.#enace-.< !.!estroy-.< A "ublic static voi! #ain-%tringNO args. @ DragonTilla if ? ne: DragonTilla-.< u-if .< v-if .< A A ///3> angero*s1onster is a si#%le e&tension to 1onster that %roduces a new interface. This is i#%le#ented in ragonZilla. RFSURF STIJLT+(6PTE5ITIM3U
The synta& used in Vampire works onl) when inheriting inter"aces. Cor#ally, you can use e4ten's with only a single class, but since an interface can be #ade "ro# #ulti%le other inter"aces, e4ten's can re"er to #ulti%le base inter"aces when building a new interface. 6s you can see, the interface na#es are si#%ly se%arated with co##as. RFSURF STIJLT+(6PTE5ITIMGU
'rou.ing constants
Because any "ields you %ut into an interface are auto#atically static and final, the interface is a convenient tool "or creating grou%s o" constant values, #uch as you would with an en*m in + or +<<. Eor e&a#%le=
//3 c'13Jonths.Hava // Ysing interfaces to create grou"s of constants. "ackage c'1< "ublic interface Jonths @ int J0&Y05; ? (, LEB5Y05; ? , J05CM ? ), 0P5$L ? I, J0; ? ,, JY&E ? +, JYL; ? *, 0YaY%T ? 1, %EPTEJBE5 ? C, GCTGBE5 ? (',
382
cDY!K or cDY!1onths 0ust as you would with any other %ackage, and re"erencing the values with e&%ressions like 1onths!JA/UA$:. )" course, what you get is 0ust an int, so there isn t the e&tra ty%e sa"ety that +<< s en*m has, but this *co##only used, techniAue is certainly an
i#%rove#ent over hard'coding nu#bers into your %rogra#s. *That a%%roach is o"ten re"erred to as using !#agic nu#bers$ and it %roduces very di""icult'to'#aintain code., RFSURFSTIJLT+(6PTE5ITIK@U I" you do want e&tra ty%e sa"ety, you can build a class like this @=
//3 c'13Jonth .Hava // 0 #ore robust enu#eration syste#. "ackage c'1< "ublic final class Jonth @ "rivate %tring na#e< "rivate int or!er< "rivate Jonth -int or!, %tring n#. @ or!er ? or!< na#e ? n#< A "ublic %tring to%tring-. @ return na#e< A "ublic final static Jonth J0& ? ne: Jonth -(, 8January8., LEB ? ne: Jonth - , 8Lebruary8., J05 ? ne: Jonth -), 8Jarch8., 0P5 ? ne: Jonth -I, 80"ril8., J0; ? ne: Jonth -,, 8Jay8., JY& ? ne: Jonth -+, 8June8.,
@ This a%%roach was ins%ired by an e'#ail "ro# 5ich (o""arth.
383
JYL ? ne: Jonth -*, 8July8., 0Ya ? ne: Jonth -1, 80ugust8., %EP ? ne: Jonth -C, 8%e"te#ber8., GCT ? ne: Jonth -(', 8Gctober8., &GW ? ne: Jonth -((, 8&ove#ber8., DEC ? ne: Jonth -( , 8Dece#ber8.< "ublic final static Jonth NO #onth ? @ J0&, LEB, J05, 0P5, J0;, JY&, JYL, 0Ya, %EP, GCT, &GW, DEC A< "ublic final static Jonth nu#ber-int or!. @ return #onthNor! - (O< A "ublic static voi! #ain-%tringNO args. @ Jonth # ? Jonth .J0&< %yste#.out."rintln-#.< # ? Jonth .nu#ber-( .< %yste#.out."rintln-#.< %yste#.out."rintln-# ?? Jonth .DEC.< %yste#.out."rintln-#.e=uals-Jonth .DEC..< A A ///3>//3 c'13Jonth .Hava // 0 #ore robust enu#eration syste#. "ackage c'1< "ublic final class Jonth @ "rivate %tring na#e< "rivate Jonth -%tring n#. @ na#e ? n#< A "ublic %tring to%tring-. @ return na#e< A "ublic final static Jonth J0& ? ne: Jonth -8January8., LEB ? ne: Jonth -8Lebruary8., J05 ? ne: Jonth -8Jarch8., 0P5 ? ne: Jonth -80"ril8., J0; ? ne: Jonth -8Jay8., JY& ? ne: Jonth -8June8., JYL ? ne: Jonth -8July8., 0Ya ? ne: Jonth -80ugust8., %EP ? ne: Jonth -8%e"te#ber8., GCT ? ne: Jonth -8Gctober8., &GW ? ne: Jonth -8&ove#ber8.,
384
DEC ? ne: Jonth -8Dece#ber8.< "ublic final static Jonth NO #onth ? @ J0&, J0&, LEB, J05, 0P5, J0;, JY&, JYL, 0Ya, %EP, GCT, &GW, DEC A< "ublic static voi! #ain-%tringNO args. @ Jonth # ? Jonth .J0&< %yste#.out."rintln-#.< # ? Jonth .#onthN( O< %yste#.out."rintln-#.< %yste#.out."rintln-# ?? Jonth .DEC.< %yste#.out."rintln-#.e=uals-Jonth .DEC..< A A ///3>
The class is called 1onthI, since there s already a 1onth in the standard Java library. It s a final class with a private constructor so no one can inherit "ro# it or #ake any instances o" it. The only instances are the final static ones created in the class itsel"= JA/, F&2, 1A$, etc. These ob0ects are also used in the array month, which lets you choose
#onths by nu#ber instead o" by na#e. *Cotice the e&tra JA/ in the array to %rovide an o""set by one, so that 7ece#ber is #onth MK.,iterate through an array o" 1onthI ob0ects. The n*mberA B #ethod allows you to select a 1onthI by giving its corres%onding #onth nu#ber. In main A B you can see the ty%e sa"ety= m is a 1onthI ob0ect so it can be assigned only to a 1onthI. The %revious e&a#%le 1onths!8ava %rovided only int values, so an int variable intended to re%resent a
#onth could actually be given any integer value, which wasn t very sa"e. RFSURFSTIJLT+(6PTE5ITIKMU This a%%roach also allows you to use PP or eC*alsA B interchangeably, as shown at the end o" mainA B. This works because there can be only one instance o" each value o" 1onthI. RFSURFSTIJLT+(6PTE5ITIKKU
385
//3 c'135an!Wals.Hava // $nitialiUing interface fiel!s :ith // non-constant initialiUers. i#"ort Hava.util.B< "ublic interface 5an!Wals @ int rint ? -int.-Jath.ran!o#-. B ('.< long rlong ? -long.-Jath.ran!o#-. B ('.< float rfloat ? -float.-Jath.ran!o#-. B ('.< !ouble r!ouble ? Jath.ran!o#-. B ('< A ///3>
Since the "ields are static, they are initiali1ed when the class is "irst loaded, which ha%%ens when any o" the "ields are accessed "or the "irst ti#e. (ere s a si#%le test= RFSURFSTIJLT+(6PTE5ITIKLU
//3 c'13Test5an!Wals.Hava "ublic class Test5an!Wals @ "ublic static voi! #ain-%tringNO args. @ %yste#.out."rintln-5an!Wals.rint.< %yste#.out."rintln-5an!Wals.rlong.< %yste#.out."rintln-5an!Wals.rfloat.< %yste#.out."rintln-5an!Wals.r!ouble.< A A ///3>
The "ields, o" course, are not %art o" the inter"ace but instead are stored in the static storage area "or that inter"ace. RFSURF STIJLT+(6PTE5ITIK?U
2esting interfaces
Inter"aces #ay be nested within classes and within other inter"aces. This reveals a nu#ber o" very interesting "eatures=
@
387
voi! f-.< A "ublic class B$#" i#"le#ents B @ "ublic voi! f-. @A A "rivate class B$#" i#"le#ents B @ "ublic voi! f-. @A A "ublic interface C @ voi! f-.< A class C$#" i#"le#ents C @ "ublic voi! f-. @A A "rivate class C$#" i#"le#ents C @ "ublic voi! f-. @A A "rivate interface D @ voi! f-.< A "rivate class D$#" i#"le#ents D @ "ublic voi! f-. @A A "ublic class D$#" i#"le#ents D @ "ublic voi! f-. @A A "ublic D getD-. @ return ne: D$#" -.< A "rivate D !5ef< "ublic voi! receiveD-D !. @ !5ef ? !< !5ef.f-.< A A interface E @ interface a @ voi! f-.< A // 5e!un!ant 8"ublic83 "ublic interface M @ voi! f-.<
388
A voi! g-.< // Cannot be "rivate :ithin an interface3 //4 "rivate interface $ @A A "ublic class &esting$nterfaces @ "ublic class B$#" i#"le#ents 0.B @ "ublic voi! f-. @A A class C$#" i#"le#ents 0.C @ "ublic voi! f-. @A A // Cannot i#"le#ent a "rivate interface e6ce"t // :ithin that interface2s !efining class3 //4 class D$#" i#"le#ents 0.D @ //4 "ublic voi! f-. @A //4 A class E$#" i#"le#ents E @ "ublic voi! g-. @A A class Ea$#" i#"le#ents E.a @ "ublic voi! f-. @A A class E$#" i#"le#ents E @ "ublic voi! g-. @A class Ea i#"le#ents E.a @ "ublic voi! f-. @A A A "ublic static voi! #ain-%tringNO args. @ 0 a ? ne: 0-.< // Can2t access 0.D3 //4 0.D a! ? a.getD-.< // Doesn2t return anything but 0.D3 //4 0.D$#" !i ? a.getD-.< // Cannot access a #e#ber of the interface3 //4 a.getD-..f-.< // Gnly another 0 can !o anything :ith getD-.3 0 a ? ne: 0-.< a .receiveD-a.getD-..<
38:
A A ///3>
The synta& "or nesting an inter"ace within a class is reasonably obvious, and 0ust like non'nested inter"aces these can have p*blic or !"riendly$ visibility. /ou can also see that both p*blic and !"riendly$ nested inter"aces can be i#%le#ented as a p*blic, !"riendly,$ and private nested classes. RFSURFSTIJLT+(6PTE5ITIKHU 6s a new twist, inter"aces can also be private as seen in A! *the sa#e Auali"ication synta& is used "or nested inter"aces as "or nested classes,. :hat good is a private nested inter"aceO /ou #ight guess that it can only be i#%le#ented as a private nested class as in Imp, but A! ImpI shows that it can also be i#%le#ented as a p*blic class. (owever, A! ImpI can only be used as itsel". /ou are not allowed to #ention the "act that it i#%le#ents the private inter"ace, so i#%le#enting a private inter"ace is a way to "orce the de"inition o" the #ethods in that inter"ace without adding any ty%e in"or#ation *that is, without allowing any u%casting,. RFSURFSTIJLT+(6PTE5ITIK3U The #ethod get A B %roduces a "urther Auandary concerning the private inter"ace= it s a p*blic #ethod that returns a re"erence to a private inter"ace. :hat can you do with the return value o" this #ethodO In mainA B, you can see several atte#%ts to use the return value, all o" which "ail. The only thing that works is i" the return value is handed to an ob0ect that has %er#ission to use it9in this case, another A, via the receive'receive A B #ethod. RFSURFSTIJLT+(6PTE5ITIKGU Inter"ace & shows that inter"aces can be nested within each other. (owever, the rules about inter"aces9in %articular, that all inter"ace ele#ents #ust be p*blic9are strictly en"orced here, so an inter"ace nested within another inter"ace is auto#atically p*blic and cannot be #ade private. RFSURFSTIJLT+(6PTE5ITIKIU
38;
Initially, these "eatures #ay see# like they are added strictly "or syntactic consistency, but I generally "ind that once you know about a "eature, you o"ten discover %laces where it is use"ul. RFSURFSTIJLT+(6PTE5ITIL@U
Inner classes
It s %ossible to %lace a class de"inition within another class de"inition. This is called an inner class. The inner class is a valuable "eature because it allows you to grou% classes that logically belong together and to control the visibility o" one within the other. (owever, it s i#%ortant to understand that inner classes are distinctly di""erent "ro# co#%osition. RFSURFSTIJLT+(6PTE5ITILMU )"ten, while you re learning about the#, the need "or inner classes isn t i##ediately obvious. 6t the end o" this section, a"ter all o" the synta& and se#antics o" inner classes have been described, you ll "ind e&a#%les that should #ake clear the bene"its o" inner classes. RFSURF STIJLT+(6PTE5ITILKU /ou create an inner class 0ust as you d e&%ect9by %lacing the class de"inition inside a surrounding class= RFSURFSTIJLT+(6PTE5ITILLU
//3 c'13Parcel(.Hava // Creating inner classes. "ublic class Parcel( @ class Contents @ "rivate int i ? ((< "ublic int value-. @ return i< A A class Destination @ "rivate %tring label< Destination-%tring :hereTo. @ label ? :hereTo< A %tring rea!Label-. @ return label< A A // Ysing inner classes looks Hust like // using any other class, :ithin Parcel(3 "ublic voi! shi"-%tring !est. @
3:=
Contents c ? ne: Contents-.< Destination ! ? ne: Destination-!est.< %yste#.out."rintln-!.rea!Label-..< A "ublic static voi! #ain-%tringNO args. @ Parcel( " ? ne: Parcel(-.< ".shi"-8TanUania8.< A A ///3>
The inner classes, when used inside shipA B, look 0ust like the use o" any other classes. (ere, the only %ractical di""erence is that the na#es are nested within #arcel>. /ou ll see in a while that this isn t the only di""erence. RFSURFSTIJLT+(6PTE5ITIL?U More ty%ically, an outer class will have a #ethod that returns a re"erence to an inner class, like this=
//3 c'13Parcel .Hava // 5eturning a reference to an inner class. "ublic class Parcel @ class Contents @ "rivate int i ? ((< "ublic int value-. @ return i< A A class Destination @ "rivate %tring label< Destination-%tring :hereTo. @ label ? :hereTo< A %tring rea!Label-. @ return label< A A "ublic Destination to-%tring s. @ return ne: Destination-s.< A "ublic Contents cont-. @ return ne: Contents-.< A "ublic voi! shi"-%tring !est. @ Contents c ? cont-.< Destination ! ? to-!est.<
3:1
%yste#.out."rintln-!.rea!Label-..< A "ublic static voi! #ain-%tringNO args. @ Parcel " ? ne: Parcel -.< ".shi"-8TanUania8.< Parcel = ? ne: Parcel -.< // Defining references to inner classes3 Parcel .Contents c ? =.cont-.< Parcel .Destination ! ? =.to-8Borneo8.< A A ///3>
I" you want to #ake an ob0ect o" the inner class anywhere e&ce%t "ro# within a non' static #ethod o" the outer class, you #ust s%eci"y the ty%e o" that ob0ect as OuterClass+ame'InnerClass+ame, as seen in mainA B. RFSURFSTIJLT+(6PTE5ITILHU
3:2
//3 c'13Parcel).Hava // 5eturning a reference to an inner class. "ublic class Parcel) @ "rivate class PContents i#"le#ents Contents @ "rivate int i ? ((< "ublic int value-. @ return i< A A "rotecte! class PDestination i#"le#ents Destination @ "rivate %tring label< "rivate PDestination-%tring :hereTo. @ label ? :hereTo< A "ublic %tring rea!Label-. @ return label< A A "ublic Destination !est-%tring s. @ return ne: PDestination-s.< A "ublic Contents cont-. @ return ne: PContents-.< A A class Test @ "ublic static voi! #ain-%tringNO args. @ Parcel) " ? ne: Parcel)-.< Contents c ? ".cont-.< Destination ! ? ".!est-8TanUania8.< // $llegal -- can2t access "rivate class3
3:3
Hava Test
In the e&a#%le, mainA B #ust be in a se%arate class in order to de#onstrate the %rivateness o" the inner class #-ontents. RFSURF STIJLT+(6PTE5ITIL2U In #arcelJ, so#ething new has been added= the inner class #-ontents is private so no one but #arcelJ can access it. # estination is protecte', so no one but #arcelJ, classes in the #arcelJ %ackage *since protecte' also gives %ackage access9that is, protecte' is also !"riendly$,, and the inheritors o" #arcelJ can access # estination. This #eans that the client %rogra##er has restricted knowledge and access to these #e#bers. In "act, you can t even downcast to a private inner class *or a protecte' inner class unless you re an inheritor,, because you can t access the na#e, as you can see in class Test. Thus, the private inner class %rovides a way "or the class designer to co#%letely %revent any ty%e' coding de%endencies and to co#%letely hide details about i#%le#entation. In addition, e&tension o" an interface is useless "ro# the client %rogra##er s %ers%ective since the client %rogra##er cannot access any additional #ethods that aren t %art o" the p*blic interface class. This also %rovides an o%%ortunity "or the Java co#%iler to generate #ore e""icient code. RFSURFSTIJLT+(6PTE5ITI?@U Cor#al *non'inner, classes cannot be #ade private or protecte'_only p*blic or !"riendly.$ RFSURFSTIJLT+(6PTE5ITI?MU
3:4
other, #ore obscure, ways that you can use the# i" you choose= inner classes can be created within a #ethod or even an arbitrary sco%e. There are two reasons "or doing this= RFSURFSTIJLT+(6PTE5ITI?KU
,4)
6s shown %reviously, you re i#%le#enting an inter"ace o" so#e kind so that you can create and return a re"erence. RFSURF STIJLT+(6PTE5ITI?LU /ou re solving a co#%licated %roble# and you want to create a class to aid in your solution, but you don t want it %ublicly available. RFSURFSTIJLT+(6PTE5ITI??U
,5)
In the "ollowing e&a#%les, the %revious code will be #odi"ied to use= RF SURFSTIJLT+(6PTE5ITI?HU
6 class de"ined within a #ethod 6 class de"ined within a sco%e inside a #ethod 6n anony#ous class i#%le#enting an inter"ace 6n anony#ous class e&tending a class that has a nonde"ault constructor 6n anony#ous class that %er"or#s "ield initiali1ation 6n anony#ous class that %er"or#s construction using instance initiali1ation *anony#ous inner classes cannot have constructors,
6lthough it s an ordinary class with an i#%le#entation, 0rapping is also being used as a co##on !inter"ace$ to its derived classes=
//3 c'13\ra""ing.Hava "ublic class \ra""ing @ "rivate int i< "ublic \ra""ing-int 6. @ i ? 6< A "ublic int value-. @ return i< A A ///3>
/ou ll notice above that 0rapping has a constructor that reAuires an argu#ent, to #ake things a bit #ore interesting. RFSURF STIJLT+(6PTE5ITI?3U
3:5
The "irst e&a#%le shows the creation o" an entire class within the sco%e o" a #ethod *instead o" the sco%e o" another class,=
//3 c'13ParcelI.Hava // &esting a class :ithin a #etho!. "ublic class ParcelI @ "ublic Destination !est-%tring s. @ class PDestination i#"le#ents Destination @ "rivate %tring label< "rivate PDestination-%tring :hereTo. @ label ? :hereTo< A "ublic %tring rea!Label-. @ return label< A A return ne: PDestination-s.< A "ublic static voi! #ain-%tringNO args. @ ParcelI " ? ne: ParcelI-.< Destination ! ? ".!est-8TanUania8.< A A ///3>
The class # estination is %art o" 'estA B rather than being %art o" #arcelQ. *6lso notice that you could use the class identi"ier # estination "or an inner class inside each class in the sa#e subdirectory without a na#e clash., There"ore, # estination cannot be accessed outside o" 'estA B. Cotice the u%casting that occurs in the return state#ent9nothing co#es out o" 'estA B e&ce%t a re"erence to estination, the base class. )" course, the "act that the na#e o" the class # estination is %laced inside 'estA B doesn t #ean that # estination is not a valid ob0ect once 'estA B returns. RFSURF STIJLT+(6PTE5ITI?GU The ne&t e&a#%le shows how you can nest an inner class within any arbitrary sco%e=
3:7
"ublic class Parcel, @ "rivate voi! internalTracking-boolean b. @ if-b. @ class Tracking%li" @ "rivate %tring i!< Tracking%li"-%tring s. @ i! ? s< A %tring get%li"-. @ return i!< A A Tracking%li" ts ? ne: Tracking%li"-8sli"8.< %tring s ? ts.get%li"-.< A // Can2t use it here4 Gut of sco"e3 //4 Tracking%li" ts ? ne: Tracking%li"-868.< A "ublic voi! track-. @ internalTracking-true.< A "ublic static voi! #ain-%tringNO args. @ Parcel, " ? ne: Parcel,-.< ".track-.< A A ///3>
The class Tracking)lip is nested inside the sco%e o" an if state#ent. This does not #ean that the class is conditionally created9it gets co#%iled along with everything else. (owever, it s not available outside the sco%e in which it is de"ined. )ther than that, it looks 0ust like an ordinary class. RFSURFSTIJLT+(6PTE5ITI?IU
//3 c'13Parcel+.Hava // 0 #etho! that returns an anony#ous inner class. "ublic class Parcel+ @ "ublic Contents cont-. @ return ne: Contents-. @ "rivate int i ? ((< "ublic int value-. @ return i< A
3:8
A< // %e#icolon re=uire! in this case A "ublic static voi! #ain-%tringNO args. @ Parcel+ " ? ne: Parcel+-.< Contents c ? ".cont-.< A A ///3>
The contA B #ethod co#bines the creation o" the return value with the de"inition o" the class that re%resents that return value. In addition, the class is anony#ous9it has no na#e. To #ake #atters a bit worse, it looks like you re starting out to create a -ontents ob0ect= RFSURF STIJLT+(6PTE5ITI?2U
return ne: Contents-. @ "rivate int i ? ((< "ublic int value-. @ return i< A A<
:hat this strange synta& #eans is= !+reate an ob0ect o" an anony#ous class that s inherited "ro# -ontents.$ The re"erence returned by the ne( e&%ression is auto#atically u%cast to a -ontents re"erence. The anony#ous inner'class synta& is a shorthand "or= RFSURF STIJLT+(6PTE5ITIHMU
class JyContents i#"le#ents Contents @ "rivate int i ? ((< "ublic int value-. @ return i< A A return ne: JyContents-.<
In the anony#ous inner class, -ontents is created using a de"ault constructor. The "ollowing code shows what to do i" your base class needs a constructor with an argu#ent= RFSURFSTIJLT+(6PTE5ITIHKU
//3 c'13Parcel*.Hava // 0n anony#ous inner class that calls // the base-class constructor.
3::
"ublic class Parcel* @ "ublic \ra""ing :ra"-int 6. @ // Base constructor call3 return ne: \ra""ing-6. @ "ublic int value-. @ return su"er.value-. B I*< A A< // %e#icolon re=uire! A "ublic static voi! #ain-%tringNO args. @ Parcel* " ? ne: Parcel*-.< \ra""ing : ? ".:ra"-('.< A A ///3>
That is, you si#%ly %ass the a%%ro%riate argu#ent to the base'class constructor, seen here as the 4 %assed in ne( 0rappingA4B. 6n anony#ous class cannot have a constructor where you would nor#ally call s*perA B. RFSURFSTIJLT+(6PTE5ITIHLU In both o" the %revious e&a#%les, the se#icolon doesn t #ark the end o" the class body *as it does in +<<,. Instead, it #arks the end o" the e&%ression that ha%%ens to contain the anony#ous class. Thus, it s identical to the use o" the se#icolon everywhere else. RFSURF STIJLT+(6PTE5ITIH?U :hat ha%%ens i" you need to %er"or# so#e kind o" initiali1ation "or an ob0ect o" an anony#ous inner classO Since it s anony#ous, there s no na#e to give the constructor9so you can t have a constructor. /ou can, however, %er"or# initiali1ation at the %oint o" de"inition o" your "ields=
//3 c'13Parcel1.Hava // 0n anony#ous inner class that "erfor#s // initialiUation. 0 briefer version // of Parcel,.Hava. "ublic class Parcel1 @ // 0rgu#ent #ust be final to use insi!e // anony#ous inner class3 "ublic Destination !est-final %tring !est. @
3:;
return ne: Destination-. @ "rivate %tring label ? !est< "ublic %tring rea!Label-. @ return label< A A< A "ublic static voi! #ain-%tringNO args. @ Parcel1 " ? ne: Parcel1-.< Destination ! ? ".!est-8TanUania8.< A A ///3>
I" you re de"ining an anony#ous inner class and want to use an ob0ect that s de"ined outside the anony#ous inner class, the co#%iler reAuires that the outside ob0ect be final. This is why the argu#ent to 'estA B is final. I" you "orget, you ll get a co#%ile'ti#e error #essage. RFSURF STIJLT+(6PTE5ITIHHU 6s long as you re si#%ly assigning a "ield, the above a%%roach is "ine. But what i" you need to %er"or# so#e constructor'like activityO :ith instance initiali?ation, you can, in e""ect, create a constructor "or an anony#ous inner class=
//3 c'13ParcelC.Hava // Ysing 8instance initialiUation8 to "erfor# // construction on an anony#ous inner class. "ublic class ParcelC @ "ublic Destination !est-final %tring !est, final float "rice. @ return ne: Destination-. @ "rivate int cost< // $nstance initialiUation for each obHect3 @ cost ? Jath.roun!-"rice.< if-cost Q (''. %yste#.out."rintln-8Gver bu!get48.< A "rivate %tring label ? !est< "ublic %tring rea!Label-. @ return label< A A< A
3;=
"ublic static voi! #ain-%tringNO args. @ ParcelC " ? ne: ParcelC-.< Destination ! ? ".!est-8TanUania8, ('(.)C,L.< A A ///3>
Inside the instance initiali1er you can see code that couldn t be e&ecuted as %art o" a "ield initiali1er *that is, the if state#ent,. So in e""ect, an instance initiali1er is the constructor "or an anony#ous inner class. )" course, it s li#ited; you can t overload instance initiali1ers so you can have only one o" these constructors. RFSURFSTIJLT+(6PTE5ITIH3U
//3 c'13%e=uence.Hava // Mol!s a se=uence of GbHects. interface %elector @ boolean en!-.< GbHect current-.< voi! ne6t-.< A "ublic class %e=uence @ "rivate GbHectNO obs< "rivate int ne6t ? '< "ublic %e=uence-int siUe. @ obs ? ne: GbHectNsiUeO<
@ This is very di""erent "ro# the design o" nested classes in +<<, which is si#%ly a na#e' hiding #echanis#. There is no link to an enclosing ob0ect and no i#%lied %er#issions in +<<.
3;1
A "ublic voi! a!!-GbHect 6. @ if-ne6t P obs.length. @ obsNne6tO ? 6< ne6tKK< A A "rivate class %%elector i#"le#ents %elector @ int i ? '< "ublic boolean en!-. @ return i ?? obs.length< A "ublic GbHect current-. @ return obsNiO< A "ublic voi! ne6t-. @ if-i P obs.length. iKK< A A "ublic %elector get%elector-. @ return ne: %%elector-.< A "ublic static voi! #ain-%tringNO args. @ %e=uence s ? ne: %e=uence-('.< for-int i ? '< i P ('< iKK. s.a!!-$nteger.to%tring-i..< %elector sl ? s.get%elector-.< :hile-4sl.en!-.. @ %yste#.out."rintln-sl.current-..< sl.ne6t-.< A A A ///3>
The )eC*ence is si#%ly a "i&ed'si1ed array o" .b8ect with a class wra%%ed around it. /ou call a''A B to add a new .b8ect to the end o" the seAuence *i" there s roo# le"t,. To "etch each o" the ob0ects in a )eC*ence, there s an inter"ace called )elector, which allows you to see i" you re at the en'A B, to look at the c*rrentA B .b8ect, and to #ove to the ne4tA B .b8ect in the )eC*ence. Because )elector is an interface, #any other classes can i#%le#ent the interface in their own ways, and
3;2
#any #ethods can take the interface as an argu#ent, in order to create generic code. RFSURFSTIJLT+(6PTE5ITIHGU (ere, the ))elector is a private class that %rovides )elector "unctionality. In mainA B, you can see the creation o" a )eC*ence, "ollowed by the addition o" a nu#ber o" )tring ob0ects. Then, a )elector is %roduced with a call to get)electorA B and this is used to #ove through the )eC*ence and select each ite#. RFSURF STIJLT+(6PTE5ITIHIU 6t "irst, the creation o" ))elector looks like 0ust another inner class. But e&a#ine it closely. Cote that each o" the #ethods en'A B, c*rrentA B, and ne4tA B re"er to obs, which is a re"erence that isn t %art o" ))elector, but is instead a private "ield in the enclosing class. (owever, the inner class can access #ethods and "ields "ro# the enclosing class as i" they owned the#. This turns out to be very convenient, as you can see in the above e&a#%le. RFSURFSTIJLT+(6PTE5ITIH2U So an inner class has auto#atic access to the #e#bers o" the enclosing class. (ow can this ha%%enO The inner class #ust kee% a re"erence to the %articular ob0ect o" the enclosing class that was res%onsible "or creating it. Then when you re"er to a #e#ber o" the enclosing class, that *hidden, re"erence is used to select that #e#ber. Eortunately, the co#%iler takes care o" all these details "or you, but you can also understand now that an ob0ect o" an inner class can be created only in association with an ob0ect o" the enclosing class. +onstruction o" the inner class ob0ect reAuires the re"erence to the ob0ect o" the enclosing class, and the co#%iler will co#%lain i" it cannot access that re"erence. Most o" the ti#e this occurs without any intervention on the %art o" the %rogra##er. RFSURF STIJLT+(6PTE5ITI3@U
3;3
true, however, when you say an inner class is static. 6 static inner class #eans= RFSURFSTIJLT+(6PTE5ITI3MU
-,) --)
/ou don t need an outer'class ob0ect in order to create an ob0ect o" a static inner class. RFSURFSTIJLT+(6PTE5ITI3KU /ou can t access an outer'class ob0ect "ro# an ob0ect o" a static inner class. RFSURFSTIJLT+(6PTE5ITI3LU
static inner classes are di""erent than non' static inner classes in another way, as well. Eields and #ethods in non' static inner classes can only be at the outer level o" a class, so non' static inner classes cannot have static data, static "ields, or static inner classes. (owever, static inner
classes can have all o" these= RFSURFSTIJLT+(6PTE5ITI3?U
//3 c'13Parcel('.Hava // %tatic inner classes. "ublic class Parcel(' @ "rivate static class PContents i#"le#ents Contents @ "rivate int i ? ((< "ublic int value-. @ return i< A A "rotecte! static class PDestination i#"le#ents Destination @ "rivate %tring label< "rivate PDestination-%tring :hereTo. @ label ? :hereTo< A "ublic %tring rea!Label-. @ return label< A // %tatic inner classes can contain // other static ele#ents3 "ublic static voi! f-. @A static int 6 ? ('< static class 0notherLevel @ "ublic static voi! f-. @A static int 6 ? ('< A A "ublic static Destination !est-%tring s. @
3;4
return ne: PDestination-s.< A "ublic static Contents cont-. @ return ne: PContents-.< A "ublic static voi! #ain-%tringNO args. @ Contents c ? cont-.< Destination ! ? !est-8TanUania8.< A A ///3>
In mainA B, no ob0ect o" #arcel>D is necessary; instead you use the nor#al synta& "or selecting a static #e#ber to call the #ethods that return re"erences to -ontents and estination. RFSURF STIJLT+(6PTE5ITI3HU 6s you will see shortly, in an ordinary *non' static, inner class, the link to the outer class ob0ect is achieved with a s%ecial this re"erence. 6 static inner class does not have this s%ecial this re"erence, which #akes it analogous to a static #ethod. RFSURFSTIJLT+(6PTE5ITI33U Cor#ally you can t %ut any code inside an interface, but a static inner class can be %art o" an interface. Since the class is static it doesn t violate the rules "or inter"aces9the static inner class is only %laced inside the na#es%ace o" the inter"ace=
//3 c'13$$nterface.Hava // %tatic inner classes insi!e interfaces. "ublic interface $$nterface @ static class $nner @ int i, H, k< "ublic $nner-. @A voi! f-. @A A A ///3>
Earlier in this book I suggested %utting a mainA B in every class to act as a test bed "or that class. )ne drawback to this is the a#ount o" e&tra co#%iled code you #ust carry around. I" this is a %roble#, you can use a
3;5
//3 c'13TestBe!.Hava // Putting test co!e in a static inner class. "ublic class TestBe! @ TestBe!-. @A voi! f-. @ %yste#.out."rintln-8f-.8.< A "ublic static class Tester @ "ublic static voi! #ain-%tringNO args. @ TestBe! t ? ne: TestBe!-.< t.f-.< A A A ///3>
This generates a se%arate class called Test2e'`Tester *to run the %rogra#, you say 8ava Test2e'`Tester,. /ou can use this class "or testing, but you don t need to include it in your shi%%ing %roduct. RFSURF STIJLT+(6PTE5ITI3IU
//3 c'13Parcel((.Hava // Creating instances of inner classes. "ublic class Parcel(( @ class Contents @
3;7
"rivate int i ? ((< "ublic int value-. @ return i< A A class Destination @ "rivate %tring label< Destination-%tring :hereTo. @ label ? :hereTo< A %tring rea!Label-. @ return label< A A "ublic static voi! #ain-%tringNO args. @ Parcel(( " ? ne: Parcel((-.< // Just use instance of outer class // to create an instances of the inner class3 Parcel((.Contents c ? ".ne: Contents-.< Parcel((.Destination ! ? ".ne: Destination-8TanUania8.< A A ///3>
To create an ob0ect o" the inner class directly, you don t "ollow the sa#e "or# and re"er to the outer class na#e #arcel>> as you #ight e&%ect, but instead you #ust use an ob>ect o" the outer class to #ake an ob0ect o" the inner class=
3;8
//3 c'13Julti&esting0ccess.Hava // &este! classes can access all #e#bers of all // levels of the classes they are neste! :ithin. class J&0 @ "rivate voi! f-. @A class 0 @ "rivate voi! g-. @A "ublic class B @ voi! h-. @ g-.< f-.< A A A A "ublic class Julti&esting0ccess @ "ublic static voi! #ain-%tringNO args. @ J&0 #na ? ne: J&0-.< J&0.0 #naa ? #na.ne: 0-.< J&0.0.B #naab ? #naa.ne: B-.< #naab.h-.< A A ///3>
/ou can see that in 1/A!A!2, the #ethods gA B and fA B are callable without any Auali"ication *des%ite the "act that they are private,. This e&a#%le also de#onstrates the synta& necessary to create ob0ects o" #ulti%ly'nested inner classes when you create the ob0ects in a di""erent class. The ! !ne($ synta& %roduces the correct sco%e so you do not have to
@ Thanks again to Martin 7anner.
3;:
//3 c'13$nherit$nner.Hava // $nheriting an inner class. class \ith$nner @ class $nner @A A "ublic class $nherit$nner e6ten!s \ith$nner.$nner @ //4 $nherit$nner-. @A // \on2t co#"ile $nherit$nner-\ith$nner :i. @ :i.su"er-.< A "ublic static voi! #ain-%tringNO args. @ \ith$nner :i ? ne: \ith$nner-.< $nherit$nner ii ? ne: $nherit$nner-:i.< A A ///3>
/ou can see that InheritInner is e&tending only the inner class, not the outer one. But when it co#es ti#e to create a constructor, the de"ault one is no good and you can t 0ust %ass a re"erence to an enclosing ob0ect. In addition, you #ust use the synta& RFSURFSTIJLT+(6PTE5ITIGKU
enclosingClass5eference.su"er-.<
inside the constructor. This %rovides the necessary re"erence and the %rogra# will then co#%ile. RFSURFSTIJLT+(6PTE5ITIGLU
3;;
//3 c'13BigEgg.Hava // 0n inner class cannot be overri!en // like a #etho!. class Egg @ "rotecte! class ;olk @ "ublic ;olk-. @ %yste#.out."rintln-8Egg.;olk-.8.< A A "rivate ;olk y< "ublic Egg-. @ %yste#.out."rintln-8&e: Egg-.8.< y ? ne: ;olk-.< A A "ublic class BigEgg e6ten!s Egg @ "ublic class ;olk @ "ublic ;olk-. @ %yste#.out."rintln-8BigEgg.;olk-.8.< A A "ublic static voi! #ain-%tringNO args. @ ne: BigEgg-.< A A ///3>
The de"ault constructor is synthesi1ed auto#atically by the co#%iler, and this calls the base'class de"ault constructor. /ou #ight think that since a 2ig&gg is being created, the !overridden$ version o" :olk would be used, but this is not the case. The out%ut is= RFSURFSTIJLT+(6PTE5ITIG?U
4==
//3 c'13BigEgg .Hava // Pro"er inheritance of an inner class. class Egg @ "rotecte! class ;olk @ "ublic ;olk-. @ %yste#.out."rintln-8Egg .;olk-.8.< A "ublic voi! f-. @ %yste#.out."rintln-8Egg .;olk.f-.8.< A A "rivate ;olk y ? ne: ;olk-.< "ublic Egg -. @ %yste#.out."rintln-8&e: Egg -.8.< A "ublic voi! insert;olk-;olk yy. @ y ? yy< A "ublic voi! g-. @ y.f-.< A A "ublic class BigEgg e6ten!s Egg @ "ublic class ;olk e6ten!s Egg .;olk @ "ublic ;olk-. @ %yste#.out."rintln-8BigEgg .;olk-.8.< A "ublic voi! f-. @ %yste#.out."rintln-8BigEgg .;olk.f-.8.< A A "ublic BigEgg -. @ insert;olk-ne: ;olk-..< A "ublic static voi! #ain-%tringNO args. @ Egg e ? ne: BigEgg -.<
4=1
e .g-.< A A ///3>
Cow 2ig&ggI!:olk e&%licitly e4ten's &ggI!:olk and overrides its #ethods. The #ethod insert:olkA B allows 2ig&ggI to u%cast one o" its own :olk ob0ects into the y re"erence in &ggI, so when gA B calls y!fA B the overridden version o" fA B is used. The out%ut is=
Egg .;olk-. &e: Egg -. Egg .;olk-. BigEgg .;olk-. BigEgg .;olk.f-.
The second call to &ggI!:olkA B is the base'class constructor call o" the 2ig&ggI!:olk constructor. /ou can see that the overridden version o" f A B is used when gA B is called. RFSURFSTIJLT+(6PTE5ITIG3U
4=2
6lthough this sche#e o" generating internal na#es is si#%le and straight"orward, it s also robust and handles #ost situations @. Since it is the standard na#ing sche#e "or Java, the generated "iles are auto#atically %lat"or#'inde%endent. *Cote that the Java co#%iler is changing your inner classes in all sorts o" other ways in order to #ake the# work., RFSURFSTIJLT+(6PTE5ITIGIU
Each inner class can inde endentl) inherit $rom an im lementation' ThusD the inner class is not limited b) ,hether the outer class is alread) inheriting $rom an im lementation'
:ithout the ability that inner classes %rovide to inherit9in e""ect9"ro# #ore than one concrete or abstract class, so#e design and %rogra##ing %roble#s would be intractable. So one way to look at the
@ )n the other hand, [d is a #eta'character to the 4ni& shell and so you ll so#eti#es have
trouble when listing the !class "iles. This is a bit strange co#ing "ro# Sun, a 4ni&'based co#%any. My guess is that they weren t considering this issue, but instead thought you d naturally "ocus on the source'code "iles.
4=3
inner class is as the co#%letion o" the solution o" the #ulti%le'inheritance %roble#. Inter"aces solve %art o" the %roble#, but inner classes e""ectively allow !#ulti%le i#%le#entation inheritance.$ That is, inner classes e""ectively allow you to inherit "ro# #ore than one non' interface. RF SURFSTIJLT+(6PTE5ITIIMU To see this in #ore detail, consider a situation where you have two inter"aces that #ust so#ehow be i#%le#ented within a class. Because o" the "le&ibility o" inter"aces, you have two choices= a single class or an inner class=
//3 c'13Julti$nterfaces.Hava // T:o :ays that a class can // i#"le#ent #ulti"le interfaces. interface 0 @A interface B @A class 9 i#"le#ents 0, B @A class ; i#"le#ents 0 @ B #akeB-. @ // 0nony#ous inner class3 return ne: B-. @A< A A "ublic class Julti$nterfaces @ static voi! takes0-0 a. @A static voi! takesB-B b. @A "ublic static voi! #ain-%tringNO args. @ 9 6 ? ne: 9-.< ; y ? ne: ;-.< takes0-6.< takes0-y.< takesB-6.< takesB-y.#akeB-..< A A ///3>
4=4
)" course, this assu#es that the structure o" your code #akes logical sense either way. (owever, you ll ordinarily have so#e kind o" guidance "ro# the nature o" the %roble# about whether to use a single class or an inner class. But without any other constraints, in the above e&a#%le the a%%roach you take doesn t really #ake #uch di""erence "ro# an i#%le#entation stand%oint. Both o" the# work. RFSURF STIJLT+(6PTE5ITIIKU (owever, i" you have abstract or concrete classes instead o" interfaces, you are suddenly li#ited to using inner classes i" your class #ust so#ehow i#%le#ent both o" the others=
//3 c'13Julti$#"le#entation.Hava // \ith concrete or abstract classes, inner // classes are the only :ay to "ro!uce the effect // of 8#ulti"le i#"le#entation inheritance.8 class C @A abstract class D @A class T e6ten!s C @ D #akeD-. @ return ne: D-. @A< A A "ublic class Julti$#"le#entation @ static voi! takesC-C c. @A static voi! takesD-D !. @A "ublic static voi! #ain-%tringNO args. @ T U ? ne: T-.< takesC-U.< takesD-U.#akeD-..< A A ///3>
I" you didn t need to solve the !#ulti%le i#%le#entation inheritance$ %roble#, you could conceivably code around everything else without the need "or inner classes. But with inner classes you have these additional "eatures= RFSURFSTIJLT+(6PTE5ITIILU
4=5
-4)
The inner class can have #ulti%le instances, each with its own state in"or#ation that is inde%endent o" the in"or#ation in the outer class ob0ect. RFSURFSTIJLT+(6PTE5ITII?U In a single outer class you can have several inner classes, each o" which i#%le#ent the sa#e interface or inherit "ro# the sa#e class in a di""erent way. 6n e&a#%le o" this will be shown shortly. RFSURFSTIJLT+(6PTE5ITIIHU The %oint o" creation o" the inner class ob0ect is not tied to the creation o" the outer class ob0ect. RFSURF STIJLT+(6PTE5ITII3U There is no %otentially con"using !is'a$ relationshi% with the inner class; it s a se%arate entity. RFSURFSTIJLT+(6PTE5ITIIGU
-5)
-6)
47)
6s an e&a#%le, i" )eC*ence!8ava did not use inner classes, you d have to say !a )eC*ence is a )elector,$ and you d only be able to have one )elector in e&istence "or a %articular )eC*ence. 6lso, you can have a second #ethod, get$)electorA B, that %roduces a )elector that #oves backward through the seAuence. This kind o" "le&ibility is only available with inner classes. RFSURFSTIJLT+(6PTE5ITIIIU
Closures L Callbacks
6 closure is a callable ob0ect that retains in"or#ation "ro# the sco%e in which it was created. Ero# this de"inition, you can see that an inner class is an ob0ect'oriented closure, because it doesn t 0ust contain each %iece o" in"or#ation "ro# the outer class ob0ect *!the sco%e in which it was created$,, but it auto#atically holds a re"erence back to the whole outer class ob0ect, where it has %er#ission to #ani%ulate all the #e#bers, even private ones. RFSURFSTIJLT+(6PTE5ITII2U )ne o" the #ost co#%elling argu#ents #ade to include so#e kind o" %ointer #echanis# in Java was to allow callbacks. :ith a callback, so#e other ob0ect is given a %iece o" in"or#ation that allows it to call back into the originating ob0ect at so#e later %oint. This is a very %ower"ul conce%t, as you will see in +ha%ters ML and M3. I" a callback is i#%le#ented using a %ointer, however, you #ust rely on the %rogra##er to behave and not #isuse the %ointer. 6s you ve seen by now, Java tends to be #ore care"ul
4=7
than that, so %ointers were not included in the language. RFSURF STIJLT+(6PTE5ITI2@U The closure %rovided by the inner class is a %er"ect solution; #ore "le&ible and "ar sa"er than a %ointer. (ere s a si#%le e&a#%le=
//3 c'13Callbacks.Hava // Ysing inner classes for callbacks interface $ncre#entable @ voi! incre#ent-.< A // Wery si#"le to Hust i#"le#ent the interface3 class Callee( i#"le#ents $ncre#entable @ "rivate int i ? '< "ublic voi! incre#ent-. @ iKK< %yste#.out."rintln-i.< A A class Jy$ncre#ent @ "ublic voi! incre#ent-. @ %yste#.out."rintln-8Gther o"eration8.< A "ublic static voi! f-Jy$ncre#ent #i. @ #i.incre#ent-.< A A // $f your class #ust i#"le#ent incre#ent-. in // so#e other :ay, you #ust use an inner class3 class Callee e6ten!s Jy$ncre#ent @ "rivate int i ? '< "rivate voi! incr-. @ iKK< %yste#.out."rintln-i.< A "rivate class Closure i#"le#ents $ncre#entable @ "ublic voi! incre#ent-. @ incr-.< A
4=8
A $ncre#entable getCallback5eference-. @ return ne: Closure-.< A A class Caller @ "rivate $ncre#entable callback5eference< Caller-$ncre#entable cbh. @ callback5eference ? cbh< A voi! go-. @ callback5eference.incre#ent-.< A A "ublic class Callbacks @ "ublic static voi! #ain-%tringNO args. @ Callee( c( ? ne: Callee(-.< Callee c ? ne: Callee -.< Jy$ncre#ent.f-c .< Caller caller( ? ne: Caller-c(.< Caller caller ? ne: Caller-c .getCallback5eference-..< caller(.go-.< caller(.go-.< caller .go-.< caller .go-.< A A ///3>
This e&a#%le also %rovides a "urther distinction between i#%le#enting an inter"ace in an outer class vs. doing so in an inner class. -allee> is clearly the si#%ler solution in ter#s o" the code. -alleeI inherits "ro# 1yIncrement which already has a di""erent incrementA B #ethod which does so#ething unrelated to that which is e&%ected by the Incrementable inter"ace. :hen 1yIncrement is inherited into -alleeI, incrementA B can t be overridden "or use by Incrementable, so you re "orced to %rovide a se%arate i#%le#entation using an inner class. 6lso note that when you create an inner class you do not add to or #odi"y the inter"ace o" the outer class. RFSURFSTIJLT+(6PTE5ITI2MU
4=:
Cotice that everything e&ce%t get-allback$eferenceA B in -alleeI is private. To allow an) connection to the outside world, the interface Incrementable is essential. (ere you can see how interfaces allow "or a co#%lete se%aration o" inter"ace "ro# i#%le#entation. RFSURF STIJLT+(6PTE5ITI2KU The inner class -los*re si#%ly i#%le#ents Incrementable to %rovide a hook back into -alleeI9but a sa"e hook. :hoever gets the Incrementable re"erence can, o" course, only call incrementA B and has no other abilities *unlike a %ointer, which would allow you to run wild,. RFSURFSTIJLT+(6PTE5ITI2LU
4=;
driven. 6s you will see in +ha%ter ML, the Java Swing library is a control "ra#ework that elegantly solves the 84I %roble# and that heavily uses inner classes. RFSURFSTIJLT+(6PTE5ITI2GU To see how inner classes allow the si#%le creation and use o" control "ra#eworks, consider a control "ra#ework whose 0ob is to e&ecute events whenever those events are !ready.$ 6lthough !ready$ could #ean anything, in this case the de"ault will be based on clock ti#e. :hat "ollows is a control "ra#ework that contains no s%eci"ic in"or#ation about what it s controlling. Eirst, here is the inter"ace that describes any control event. It s an abstract class instead o" an actual interface because the de"ault behavior is to %er"or# the control based on ti#e, so so#e o" the i#%le#entation can be included here=
//3 c'13controller3Event.Hava // The co##on #etho!s for any control event. "ackage c'1.controller< abstract "ublic class Event @ "rivate long evtTi#e< "ublic Event-long eventTi#e. @ evtTi#e ? eventTi#e< A "ublic boolean rea!y-. @ return %yste#.currentTi#eJillis-. Q? evtTi#e< A abstract "ublic voi! action-.< abstract "ublic %tring !escri"tion-.< A ///3>
The constructor si#%ly ca%tures the ti#e when you want the &vent to run, while rea'yA B tells you when it s ti#e to run it. )" course, rea'yA B could be overridden in a derived class to base the &vent on so#ething other than ti#e. RFSURFSTIJLT+(6PTE5ITI2IU
actionA B is the #ethod that s called when the &vent is rea'yA B, and 'escriptionA B gives te&tual in"or#ation about the &vent. RFSURF
STIJLT+(6PTE5ITI22U The "ollowing "ile contains the actual control "ra#ework that #anages and "ires events. The "irst class is really 0ust a !hel%er$ class whose 0ob is
41=
to hold &vent ob0ects. /ou can re%lace it with any a%%ro%riate container, and in +ha%ter 2 you ll discover other containers that will do the trick without reAuiring you to write this e&tra code=
//3 c'13controller3Controller.Hava // 0long :ith Event, the generic // fra#e:ork for all control syste#s3 "ackage c'1.controller< // This is Hust a :ay to hol! Event obHects. class Event%et @ "rivate EventNO events ? ne: EventN(''O< "rivate int in!e6 ? '< "rivate int ne6t ? '< "ublic voi! a!!-Event e. @ if-in!e6 Q? events.length. return< // -$n real life, thro: e6ce"tion. eventsNin!e6KKO ? e< A "ublic Event get&e6t-. @ boolean loo"e! ? false< int start ? ne6t< !o @ ne6t ? -ne6t K (. V events.length< // %ee if it has loo"e! to the beginning3 if-start ?? ne6t. loo"e! ? true< // $f it loo"s "ast start, the list // is e#"ty3 if--ne6t ?? -start K (. V events.length. DD loo"e!. return null< A :hile-eventsNne6tO ?? null.< return eventsNne6tO< A "ublic voi! re#oveCurrent-. @ eventsNne6tO ? null< A A "ublic class Controller @ "rivate Event%et es ? ne: Event%et-.<
411
"ublic voi! a!!Event-Event c. @ es.a!!-c.< A "ublic voi! run-. @ Event e< :hile--e ? es.get&e6t-.. 4? null. @ if-e.rea!y-.. @ e.action-.< %yste#.out."rintln-e.!escri"tion-..< es.re#oveCurrent-.< A A A A ///3> &vent)et arbitrarily holds M@@ &vents. *I" a !real$ container "ro#
+ha%ter 2 is used here you don t need to worry about its #a&i#u# si1e, since it will resi1e itsel",. The in'e4 is used to kee% track o" the ne&t available s%ace, and ne4t is used when you re looking "or the ne&t &vent in the list, to see whether you ve loo%ed around. This is i#%ortant during a call to get/e4tA B, because &vent ob0ects are re#oved "ro# the list *using remove-*rrentA B, once they re run, so get/e4tA B will encounter holes in the list as it #oves through it. RFSURF STIJLT+(6PTE5ITIM@@U Cote that remove-*rrentA B doesn t 0ust set so#e "lag indicating that the ob0ect is no longer in use. Instead, it sets the re"erence to n*ll. This is i#%ortant because i" the garbage collector sees a re"erence that s still in use then it can t clean u% the ob0ect. I" you think your re"erences #ight hang around *as they would here,, then it s a good idea to set the# to n*ll to give the garbage collector %er#ission to clean the# u%. RFSURF STIJLT+(6PTE5ITIM@MU
-ontroller is where the actual work goes on. It uses an &vent)et to hold its &vent ob0ects, and a''&ventA B allows you to add new events to this list. But the i#%ortant #ethod is r*nA B. This #ethod loo%s through the &vent)et, hunting "or an &vent ob0ect that s rea'yA B to run. Eor each one it "inds rea'yA B, it calls the actionA B #ethod, %rints out the 'escriptionA B, and then re#oves the &vent "ro# the list. RFSURF STIJLT+(6PTE5ITIM@KU
412
Cote that so "ar in this design you know nothing about e&actly ,hat an &vent does. 6nd this is the cru& o" the design; how it !se%arates the things that change "ro# the things that stay the sa#e.$ )r, to use #y ter#, the !vector o" change$ is the di""erent actions o" the various kinds o" &vent ob0ects, and you e&%ress di""erent actions by creating di""erent &vent subclasses *in %esign Patterns %arlance, the &vent subclasses re%resent the Command Pattern,. RFSURFSTIJLT+(6PTE5ITIM@LU This is where inner classes co#e into %lay. They allow two things=
4()
To create the entire i#%le#entation o" a control'"ra#ework a%%lication in a single class, thereby enca%sulating everything that s uniAue about that i#%le#entation. Inner classes are used to e&%ress the #any di""erent kinds o" actionA B necessary to solve the %roble#. In addition, the "ollowing e&a#%le uses private inner classes so the i#%le#entation is co#%letely hidden and can be changed with i#%unity. RFSURFSTIJLT+(6PTE5ITIM@?U Inner classes kee% this i#%le#entation "ro# beco#ing awkward, since you re able to easily access any o" the #e#bers in the outer class. :ithout this ability the code #ight beco#e un%leasant enough that you d end u% seeking an alternative. RFSURF STIJLT+(6PTE5ITIM@HU
4!)
+onsider a %articular i#%le#entation o" the control "ra#ework designed to control greenhouse "unctions @. Each action is entirely di""erent= turning lights, water, and ther#ostats on and o"", ringing bells, and restarting the syste#. But the control "ra#ework is designed to easily isolate this di""erent code. Inner classes allow you to have #ulti%le derived versions o" the sa#e base class, &vent, within a single class. Eor each ty%e o" action you inherit a new &vent inner class, and write the control code inside o" actionA B. RFSURFSTIJLT+(6PTE5ITIM@3U 6s is ty%ical with an a%%lication "ra#ework, the class
"reenho*se-ontrols is inherited "ro# -ontroller= //3 c'13areenhouseControls.Hava // This "ro!uces a s"ecific a""lication of the
@ Eor so#e reason this has always been a %leasing %roble# "or #e to solve; it ca#e "ro# #y earlier book C++ Inside & Out, but Java allows a #uch #ore elegant solution.
413
// control syste#, all in a single class. $nner // classes allo: you to enca"sulate !ifferent // functionality for each ty"e of event. i#"ort c'1.controller.B< "ublic class areenhouseControls e6ten!s Controller @ "rivate boolean light ? false< "rivate boolean :ater ? false< "rivate %tring ther#ostat ? 8Day8< "rivate class LightGn e6ten!s Event @ "ublic LightGn-long eventTi#e. @ su"er-eventTi#e.< A "ublic voi! action-. @ // Put har!:are control co!e here to // "hysically turn on the light. light ? true< A "ublic %tring !escri"tion-. @ return 8Light is on8< A A "rivate class LightGff e6ten!s Event @ "ublic LightGff-long eventTi#e. @ su"er-eventTi#e.< A "ublic voi! action-. @ // Put har!:are control co!e here to // "hysically turn off the light. light ? false< A "ublic %tring !escri"tion-. @ return 8Light is off8< A A "rivate class \aterGn e6ten!s Event @ "ublic \aterGn-long eventTi#e. @ su"er-eventTi#e.< A "ublic voi! action-. @
414
// Put har!:are control co!e here :ater ? true< A "ublic %tring !escri"tion-. @ return 8areenhouse :ater is on8< A A "rivate class \aterGff e6ten!s Event @ "ublic \aterGff-long eventTi#e. @ su"er-eventTi#e.< A "ublic voi! action-. @ // Put har!:are control co!e here :ater ? false< A "ublic %tring !escri"tion-. @ return 8areenhouse :ater is off8< A A "rivate class Ther#ostat&ight e6ten!s Event @ "ublic Ther#ostat&ight-long eventTi#e. @ su"er-eventTi#e.< A "ublic voi! action-. @ // Put har!:are control co!e here ther#ostat ? 8&ight8< A "ublic %tring !escri"tion-. @ return 8Ther#ostat on night setting8< A A "rivate class Ther#ostatDay e6ten!s Event @ "ublic Ther#ostatDay-long eventTi#e. @ su"er-eventTi#e.< A "ublic voi! action-. @ // Put har!:are control co!e here ther#ostat ? 8Day8< A "ublic %tring !escri"tion-. @ return 8Ther#ostat on !ay setting8<
415
A A // 0n e6a#"le of an action-. that inserts a // ne: one of itself into the event list3 "rivate int rings< "rivate class Bell e6ten!s Event @ "ublic Bell-long eventTi#e. @ su"er-eventTi#e.< A "ublic voi! action-. @ // 5ing every secon!s, 2rings2 ti#es3 %yste#.out."rintln-8Bing48.< if---rings Q '. a!!Event-ne: Bell%yste#.currentTi#eJillis-. K '''..< A "ublic %tring !escri"tion-. @ return 85ing bell8< A A "rivate class 5estart e6ten!s Event @ "ublic 5estart-long eventTi#e. @ su"er-eventTi#e.< A "ublic voi! action-. @ long t# ? %yste#.currentTi#eJillis-.< // $nstea! of har!-:iring, you coul! "arse // configuration infor#ation fro# a te6t // file here3 rings ? ,< a!!Event-ne: Ther#ostat&ight-t#..< a!!Event-ne: LightGn-t# K ('''..< a!!Event-ne: LightGff-t# K '''..< a!!Event-ne: \aterGn-t# K )'''..< a!!Event-ne: \aterGff-t# K 1'''..< a!!Event-ne: Bell-t# K C'''..< a!!Event-ne: Ther#ostatDay-t# K (''''..< // Can even a!! a 5estart obHect4 a!!Event-ne: 5estart-t# K ''''..< A "ublic %tring !escri"tion-. @
417
return 85estarting syste#8< A A "ublic static voi! #ain-%tringNO args. @ areenhouseControls gc ? ne: areenhouseControls-.< long t# ? %yste#.currentTi#eJillis-.< gc.a!!Event-gc.ne: 5estart-t#..< gc.run-.< A A ///3>
Cote that light, (ater, thermostat, and rings all belong to the outer class "reenho*se-ontrols, and yet the inner classes can access those "ields without Auali"ication or s%ecial %er#ission. 6lso, #ost o" the actionA B #ethods involve so#e sort o" hardware control, which would #ost likely involve calls to non'Java code. RFSURF STIJLT+(6PTE5ITIM@GU Most o" the &vent classes look si#ilar, but 2ell and $estart are s%ecial. 2ell rings, and i" it hasn t yet rung enough ti#es it adds a new 2ell ob0ect to the event list, so it will ring again later. Cotice how inner classes almost look like #ulti%le inheritance= 2ell has all the #ethods o" &vent and it also a%%ears to have all the #ethods o" the outer class "reenho*se-ontrols. RFSURFSTIJLT+(6PTE5ITIM@IU
$estart is res%onsible "or initiali1ing the syste#, so it adds all the a%%ro%riate events. )" course, a #ore "le&ible way to acco#%lish this is to avoid hard'coding the events and instead read the# "ro# a "ile. *6n e&ercise in +ha%ter MM asks you to #odi"y this e&a#%le to do 0ust that., Since $estartA B is 0ust another &vent ob0ect, you can also add a $estart ob0ect within $estart!actionA B so that the syste# regularly restarts itsel". 6nd all you need to do in mainA B is create a "reenho*se-ontrols ob0ect and add a $estart ob0ect to get it going. RFSURFSTIJLT+(6PTE5ITIM@2U This e&a#%le should #ove you a long way toward a%%reciating the value o" inner classes, es%ecially when used within a control "ra#ework. (owever, in +ha%ter ML you ll see how elegantly inner classes are used to describe the actions o" a gra%hical user inter"ace. By the ti#e you "inish that cha%ter you should be "ully convinced.
418
1ummar:
Inter"aces and inner classes are #ore so%histicated conce%ts than what you ll "ind in #any ))P languages. Eor e&a#%le, there s nothing like the# in +<<. Together, they solve the sa#e %roble# that +<< atte#%ts to solve with its #ulti%le inheritance *MI, "eature. (owever, MI in +<< turns out to be rather di""icult to use, while Java inter"aces and inner classes are, by co#%arison, #uch #ore accessible. RFSURF STIJLT+(6PTE5ITIMM@U 6lthough the "eatures the#selves are reasonably straight"orward, the use o" these "eatures is a design issue, #uch the sa#e as %oly#or%his#. )ver ti#e, you ll beco#e better at recogni1ing situations where you should use an inter"ace, or an inner class, or both. But at this %oint in this book you should at least be co#"ortable with the synta& and se#antics. 6s you see these language "eatures in use you ll eventually internali1e the#. RFSURF STIJLT+(6PTE5ITIMMMU
/0ercises
Solutions to selected e&ercises can be "ound in the electronic docu#entThe Thinking in Java "nnotated Solution @uide, available "or a s#all "ee "ro# ,,,'0ruceEckel'com.
6,) Prove that the "ields in an interface are i#%licitly static and
final. RFSURFSTIJLT+(6PTE5ITIMMKU
66) +reate three interfaces, each with two #ethods. Inherit a new
interface "ro# the three, adding a new #ethod. +reate a class by
41:
i#%le#enting the new interface and also inheriting "ro# a concrete class. Cow write "our #ethods, each o" which takes one o" the "our interfaces as an argu#ent. In mainA B, create an ob0ect o" your class and %ass it to each o" the #ethods. RFSURF STIJLT+(6PTE5ITIMM3U
41;
(75) 5e%eat E&ercise ML but de"ine the inner class within a sco%e
within a #ethod. RFSURFSTIJLT+(6PTE5ITIMKHU
42=
(!*) Show that an inner class has access to the private ele#ents o"
its outer class. 7eter#ine whether the reverse is true. RFSU
421
JyGbHect #y5eference<
since you ll never know how #any o" these you ll actually need. RFSURF STIJLT+(6PTE52TIMU To solve this rather essential %roble#, Java has several ways to hold ob0ects *or rather, re"erences to ob0ects,. The built'in ty%e is the array, which has been discussed be"ore. 6lso, the Java utilities library has a reasonably co#%lete set o" container classes *also known as collection classes, but because the Java K libraries use the na#e -ollection to re"er to a %articular subset o" the library, I shall use the #ore inclusive ter# !container$,. +ontainers %rovide so%histicated ways to hold and even #ani%ulate your ob0ects. RFSURFSTIJLT+(6PTE52TIKU
Arra:s
Most o" the necessary introduction to arrays is in the last section o" +ha%ter ?, which showed how you de"ine and initiali1e an array. (olding ob0ects is the "ocus o" this cha%ter, and an array is 0ust one way to hold
422
ob0ects. But there are a nu#ber o" other ways to hold ob0ects, so what #akes an array s%ecialO RFSURFSTIJLT+(6PTE52TILU There are two issues that distinguish arrays "ro# other ty%es o" containers= e""iciency and ty%e. The array is the #ost e""icient way that Java %rovides to store and rando#ly access a seAuence o" ob0ects *actually, ob0ect re"erences,. The array is a si#%le linear seAuence, which #akes ele#ent access "ast, but you %ay "or this s%eed= when you create an array ob0ect, its si1e is "i&ed and cannot be changed "or the li"eti#e o" that array ob0ect. /ou #ight suggest creating an array o" a %articular si1e and then, i" you run out o" s%ace, creating a new one and #oving all the re"erences "ro# the old one to the new one. This is the behavior o" the Array+ist class, which will be studied later in this cha%ter. (owever, because o" the overhead o" this si1e "le&ibility, an Array+ist is #easurably less e""icient than an array. RFSURFSTIJLT+(6PTE52TI?U The vector container class in +<< does know the ty%e o" ob0ects it holds, but it has a di""erent drawback when co#%ared with arrays in Java= the +<< vector s operator]^ doesn t do bounds checking, so you can run %ast the end @. In Java, you get bounds checking regardless o" whether you re using an array or a container9you ll get a $*ntime&4ception i" you e&ceed the bounds. 6s you ll learn in +ha%ter M@, this ty%e o" e&ce%tion indicates a %rogra##er error, and thus you don t need to check "or it in your code. 6s an aside, the reason the +<< vector doesn t check bounds with every access is s%eed9in Java you have the constant %er"or#ance overhead o" bounds checking all the ti#e "or both arrays and containers. RFSURFSTIJLT+(6PTE52TIHU The other generic container classes that will be studied in this cha%ter,
+ist, )et, and 1ap, all deal with ob0ects as i" they had no s%eci"ic ty%e. That is, they treat the# as ty%e .b8ect, the root class o" all classes in
Java. This works "ine "ro# one stand%oint= you need to build only one container, and any Java ob0ect will go into that container. *E&ce%t "or %ri#itives9these can be %laced in containers as constants using the Java %ri#itive wra%%er classes, or as changeable values by wra%%ing in your own class., This is the second %lace where an array is su%erior to the generic containers= when you create an array, you create it to hold a
@ It s %ossible, however, to ask how big the vector is, and the atA B #ethod does %er"or# bounds checking.
423
s%eci"ic ty%e. This #eans that you get co#%ile'ti#e ty%e checking to %revent you "ro# %utting the wrong ty%e in, or #istaking the ty%e that you re e&tracting. )" course, Java will %revent you "ro# sending an ina%%ro%riate #essage to an ob0ect, either at co#%ile'ti#e or at run'ti#e. So it s not #uch riskier one way or the other, it s 0ust nicer i" the co#%iler %oints it out to you, "aster at run'ti#e, and there s less likelihood that the end user will get sur%rised by an e&ce%tion. RFSURF STIJLT+(6PTE52TI3U Eor e""iciency and ty%e checking it s always worth trying to use an array i" you can. (owever, when you re trying to solve a #ore general %roble# arrays can be too restrictive. 6"ter looking at arrays, the rest o" this cha%ter will be devoted to the container classes %rovided by Java. RFSURF STIJLT+(6PTE52TIGU
//3 c'C30rray%iUe.Hava // $nitialiUation D re-assign#ent of arrays. class \eeble @A // 0 s#all #ythical creature "ublic class 0rray%iUe @
424
"ublic static voi! #ain-%tringNO args. @ // 0rrays of obHects3 \eebleNO a< // &ull reference \eebleNO b ? ne: \eebleN,O< // &ull references \eebleNO c ? ne: \eebleNIO< for-int i ? '< i P c.length< iKK. cNiO ? ne: \eeble-.< // 0ggregate initialiUation3 \eebleNO ! ? @ ne: \eeble-., ne: \eeble-., ne: \eeble-. A< // Dyna#ic aggregate initialiUation3 a ? ne: \eebleNO @ ne: \eeble-., ne: \eeble-. A< %yste#.out."rintln-8a.length?8 K a.length.< %yste#.out."rintln-8b.length ? 8 K b.length.< // The references insi!e the array are // auto#atically initialiUe! to null3 for-int i ? '< i P b.length< iKK. %yste#.out."rintln-8bN8 K i K 8O?8 K bNiO.< %yste#.out."rintln-8c.length ? 8 K c.length.< %yste#.out."rintln-8!.length ? 8 K !.length.< a ? !< %yste#.out."rintln-8a.length ? 8 K a.length.< // 0rrays of "ri#itives3 intNO e< // &ull reference intNO f ? ne: intN,O< intNO g ? ne: intNIO< for-int i ? '< i P g.length< iKK. gNiO ? iBi< intNO h ? @ ((, I*, C) A< // Co#"ile error3 variable e not initialiUe!3 //4%yste#.out."rintln-8e.length?8 K e.length.< %yste#.out."rintln-8f.length ? 8 K f.length.< // The "ri#itives insi!e the array are // auto#atically initialiUe! to Uero3 for-int i ? '< i P f.length< iKK. %yste#.out."rintln-8fN8 K i K 8O?8 K fNiO.< %yste#.out."rintln-8g.length ? 8 K g.length.<
425
%yste#.out."rintln-8h.length ? 8 K h.length.< e ? h< %yste#.out."rintln-8e.length ? 8 K e.length.< e ? ne: intNO @ (, A< %yste#.out."rintln-8e.length ? 8 K e.length.< A A ///3>
(ere s the out%ut "ro# the %rogra#=
a.length? b.length ? bN'O?null bN(O?null bN O?null bN)O?null bNIO?null c.length ? !.length ? a.length ? a.length ? f.length ? fN'O?' fN(O?' fN O?' fN)O?' fNIO?' g.length ? h.length ? e.length ? e.length ?
I ) ) ,
I ) )
The array a is initially 0ust a n*ll re"erence, and the co#%iler %revents you "ro# doing anything with this re"erence until you ve %ro%erly initiali1ed it. The array b is initiali1ed to %oint to an array o" 0eeble re"erences, but no actual 0eeble ob0ects are ever %laced in that array. (owever, you can still ask what the si1e o" the array is, since b is %ointing to a legiti#ate ob0ect. This brings u% a slight drawback= you can t "ind out how #any ele#ents are actually in the array, since length tells you only how #any ele#ents can be %laced in the array; that is, the si1e o" the array ob0ect, not the nu#ber o" ele#ents it actually holds. (owever, when
427
an array ob0ect is created its re"erences are auto#atically initiali1ed to n*ll, so you can see whether a %articular array slot has an ob0ect in it by checking to see whether it s n*ll. Si#ilarly, an array o" %ri#itives is auto#atically initiali1ed to 1ero "or nu#eric ty%es, AcharBD "or char, and false "or boolean. RFSURFSTIJLT+(6PTE52TIM@U 6rray c shows the creation o" the array ob0ect "ollowed by the assign#ent o" 0eeble ob0ects to all the slots in the array. 6rray ' shows the !aggregate initiali1ation$ synta& that causes the array ob0ect to be created *i#%licitly with ne( on the hea%, 0ust like "or array c, and initiali1ed with 0eeble ob0ects, all in one state#ent. RFSURFSTIJLT+(6PTE52TIMMU The ne&t array initiali1ation could be thought o" as a !dyna#ic aggregate initiali1ation.$ The aggregate initiali1ation used by ' #ust be used at the %oint o" ' s de"inition, but with the second synta& you can create and initiali1e an array ob0ect anywhere. Eor e&a#%le, su%%ose hi'eA B is a #ethod that takes an array o" 0eeble ob0ects. /ou could call it by saying=
hi!e-!.<
but you can also dyna#ically create the array you want to %ass as the argu#ent=
a ? !<
shows how you can take a re"erence that s attached to one array ob0ect and assign it to another array ob0ect, 0ust as you can do with any other ty%e o" ob0ect re"erence. Cow both a and ' are %ointing to the sa#e array ob0ect on the hea%. RFSURFSTIJLT+(6PTE52TIMLU The second %art o" Array)i7e!8ava shows that %ri#itive arrays work 0ust like ob0ect arrays e*ce t that %ri#itive arrays hold the %ri#itive values directly. RFSURFSTIJLT+(6PTE52TIM?U
428
Containers of .rimitives
+ontainer classes can hold only re"erences to ob0ects. 6n array, however, can be created to hold %ri#itives directly, as well as re"erences to ob0ects. It is %ossible to use the !wra%%er$ classes such as Integer, o*ble, etc. to %lace %ri#itive values inside a container, but the wra%%er classes "or %ri#itives can be awkward to use. In addition, it s #uch #ore e""icient to create and access an array o" %ri#itives than a container o" wra%%ed %ri#itives. RFSURFSTIJLT+(6PTE52TIMHU )" course, i" you re using a %ri#itive ty%e and you need the "le&ibility o" a container that auto#atically e&%ands when #ore s%ace is needed, the array won t work and you re "orced to use a container o" wra%%ed %ri#itives. /ou #ight think that there should be a s%eciali1ed ty%e o" Array+ist "or each o" the %ri#itive data ty%es, but Java doesn t %rovide this "or you. So#e sort o" te#%lati1ing #echanis# #ight so#eday %rovide a better way "or Java to handle this %roble#. @ RFSURF STIJLT+(6PTE52TIM3U
$eturning an arra:
Su%%ose you re writing a #ethod and you don t 0ust want to return 0ust one thing, but a whole bunch o" things. Danguages like + and +<< #ake this di""icult because you can t 0ust return an array, only a %ointer to an array. This introduces %roble#s because it beco#es #essy to control the li"eti#e o" the array, which easily leads to #e#ory leaks. RFSURF STIJLT+(6PTE52TIMGU Java takes a si#ilar a%%roach, but you 0ust !return an array.$ 6ctually, o" course, you re returning a re"erence to an array, but with Java you never worry about res%onsibility "or that array9it will be around as long as you need it, and the garbage collector will clean it u% when you re done. RF SURFSTIJLT+(6PTE52TIMIU 6s an e&a#%le, consider returning an array o" )tring=
42:
"ublic class $ceCrea# @ static %tringNO flav ? @ 8Chocolate8, 8%tra:berry8, 8Wanilla Lu!ge %:irl8, 8Jint Chi"8, 8Jocha 0l#on! Lu!ge8, 85u# 5aisin8, 8Praline Crea#8, 8Ju! Pie8 A< static %tringNO flavor%et-int n. @ // Lorce it to be "ositive D :ithin boun!s3 n ? Jath.abs-n. V -flav.length K (.< %tringNO results ? ne: %tringNnO< booleanNO "icke! ? ne: booleanNflav.lengthO< for -int i ? '< i P n< iKK. @ int t< !o t ? -int.-Jath.ran!o#-. B flav.length.< :hile -"icke!NtO.< resultsNiO ? flavNtO< "icke!NtO ? true< A return results< A "ublic static voi! #ain-%tringNO args. @ for-int i ? '< i P '< iKK. @ %yste#.out."rintln8flavor%et-8 K i K 8. ? 8.< %tringNO fl ? flavor%et-flav.length.< for-int H ? '< H P fl.length< HKK. %yste#.out."rintln-8_t8 K flNHO.< A A A ///3>
The #ethod flavor)etA B creates an array o" )tring called res*lts. The si1e o" this array is n, deter#ined by the argu#ent you %ass into the #ethod. Then it %roceeds to choose "lavors rando#ly "ro# the array flav and %lace the# into res*lts, which it "inally returns. 5eturning an array is 0ust like returning any other ob0ect9it s a re"erence. It s not i#%ortant that the array was created within flavor)etA B, or that the array was
42;
created any%lace else, "or that #atter. The garbage collector takes care o" cleaning u% the array when you re done with it, and the array will %ersist "or as long as you need it. RFSURFSTIJLT+(6PTE52TIM2U 6s an aside, notice that when flavor)etA B chooses "lavors rando#ly, it ensures that a rando# choice hasn t been %icked be"ore. This is %er"or#ed in a 'o loo% that kee%s #aking rando# choices until it "inds one that s not already in the picke' array. *)" course, a )tring co#%arison could also have been %er"or#ed to see i" the rando# choice was already in the res*lts array, but )tring co#%arisons are ine""icient., I" it s success"ul, it adds the entry and "inds the ne&t one * i gets incre#ented,. RFSURFSTIJLT+(6PTE52TIK@U
mainA B %rints out K@ "ull sets o" "lavors, so you can see that flavor)et A B chooses the "lavors in a rando# order each ti#e. It s easiest to see this
i" you redirect the out%ut into a "ile. 6nd while you re looking at the "ile, re#e#ber, you 0ust ,ant the ice crea#, you don t need it. RFSURF STIJLT+(6PTE52TIKMU
43=
br*ceeckel!*til "or convenience. These will %rint an array o" any ty%e,
and "ill an array with values or ob0ects that are created by an ob0ect called a generator that you can de"ine. RFSURFSTIJLT+(6PTE52TIK?U Because code needs to be created "or each %ri#itive ty%e as well as .b8ect, there s a lot o" nearly du%licated code @. Eor e&a#%le, a !generator$ inter"ace is reAuired "or each ty%e because the return ty%e o" ne4tA B #ust be di""erent in each case=
//3 co#3bruceeckel3util3aenerator.Hava "ackage co#.bruceeckel.util< "ublic interface aenerator @ GbHect ne6t-.< A ///3> //3 co#3bruceeckel3util3Booleanaenerator.Hava "ackage co#.bruceeckel.util< "ublic interface Booleanaenerator @ boolean ne6t-.< A ///3> //3 co#3bruceeckel3util3Byteaenerator.Hava "ackage co#.bruceeckel.util< "ublic interface Byteaenerator @ byte ne6t-.< A ///3> //3 co#3bruceeckel3util3Charaenerator.Hava "ackage co#.bruceeckel.util< "ublic interface Charaenerator @ char ne6t-.< A ///3> //3 co#3bruceeckel3util3%hortaenerator.Hava "ackage co#.bruceeckel.util< "ublic interface %hortaenerator @ short ne6t-.< A ///3>
@ The +<< %rogra##er will note how #uch the code could be colla%sed with the use o" de"ault argu#ents and te#%lates. The Python %rogra##er will note that this entire library would be largely unnecessary in that language.
431
//3 co#3bruceeckel3util3$ntaenerator.Hava "ackage co#.bruceeckel.util< "ublic interface $ntaenerator @ int ne6t-.< A ///3> //3 co#3bruceeckel3util3Longaenerator.Hava "ackage co#.bruceeckel.util< "ublic interface Longaenerator @ long ne6t-.< A ///3> //3 co#3bruceeckel3util3Lloataenerator.Hava "ackage co#.bruceeckel.util< "ublic interface Lloataenerator @ float ne6t-.< A ///3> //3 co#3bruceeckel3util3Doubleaenerator.Hava "ackage co#.bruceeckel.util< "ublic interface Doubleaenerator @ !ouble ne6t-.< A ///3> ArraysI contains a variety o" printA B "unctions, overloaded "or each
ty%e. /ou can si#%ly %rint an array, you can add a #essage be"ore the array is %rinted, or you can %rint a range o" ele#ents within an array. The printA B code is sel"'e&%lanatory=
//3 co#3bruceeckel3util30rrays .Hava // 0 su""le#ent to Hava.util.0rrays, to "rovi!e // a!!itional useful functionality :hen :orking // :ith arrays. 0llo:s any array to be "rinte!, // an! to be fille! via a user-!efine! // 8generator8 obHect. "ackage co#.bruceeckel.util< i#"ort Hava.util.B< "ublic class 0rrays @ "rivate static voi!
432
start-int fro#, int to, int length. @ if-fro# 4? ' XX to 4? length. %yste#.out."rint-8N8K fro# K838K to K8O 8.< %yste#.out."rint-8-8.< A "rivate static voi! en!-. @ %yste#.out."rintln-8.8.< A "ublic static voi! "rint-GbHectNO a. @ "rint-a, ', a.length.< A "ublic static voi! "rint-%tring #sg, GbHectNO a. @ %yste#.out."rint-#sg K 8 8.< "rint-a, ', a.length.< A "ublic static voi! "rint-GbHectNO a, int fro#, int to.@ start-fro#, to, a.length.< for-int i ? fro#< i P to< iKK. @ %yste#.out."rint-aNiO.< if-i P to -(. %yste#.out."rint-8, 8.< A en!-.< A "ublic static voi! "rint-booleanNO a. @ "rint-a, ', a.length.< A "ublic static voi! "rint-%tring #sg, booleanNO a. @ %yste#.out."rint-#sg K 8 8.< "rint-a, ', a.length.< A "ublic static voi! "rint-booleanNO a, int fro#, int to. @ start-fro#, to, a.length.< for-int i ? fro#< i P to< iKK. @ %yste#.out."rint-aNiO.< if-i P to -(. %yste#.out."rint-8, 8.<
433
A en!-.< A "ublic static voi! "rint-byteNO a. @ "rint-a, ', a.length.< A "ublic static voi! "rint-%tring #sg, byteNO a. @ %yste#.out."rint-#sg K 8 8.< "rint-a, ', a.length.< A "ublic static voi! "rint-byteNO a, int fro#, int to. @ start-fro#, to, a.length.< for-int i ? fro#< i P to< iKK. @ %yste#.out."rint-aNiO.< if-i P to -(. %yste#.out."rint-8, 8.< A en!-.< A "ublic static voi! "rint-charNO a. @ "rint-a, ', a.length.< A "ublic static voi! "rint-%tring #sg, charNO a. @ %yste#.out."rint-#sg K 8 8.< "rint-a, ', a.length.< A "ublic static voi! "rint-charNO a, int fro#, int to. @ start-fro#, to, a.length.< for-int i ? fro#< i P to< iKK. @ %yste#.out."rint-aNiO.< if-i P to -(. %yste#.out."rint-8, 8.< A en!-.< A "ublic static voi! "rint-shortNO a. @ "rint-a, ', a.length.<
434
A "ublic static voi! "rint-%tring #sg, shortNO a. @ %yste#.out."rint-#sg K 8 8.< "rint-a, ', a.length.< A "ublic static voi! "rint-shortNO a, int fro#, int to. @ start-fro#, to, a.length.< for-int i ? fro#< i P to< iKK. @ %yste#.out."rint-aNiO.< if-i P to - (. %yste#.out."rint-8, 8.< A en!-.< A "ublic static voi! "rint-intNO a. @ "rint-a, ', a.length.< A "ublic static voi! "rint-%tring #sg, intNO a. @ %yste#.out."rint-#sg K 8 8.< "rint-a, ', a.length.< A "ublic static voi! "rint-intNO a, int fro#, int to. @ start-fro#, to, a.length.< for-int i ? fro#< i P to< iKK. @ %yste#.out."rint-aNiO.< if-i P to - (. %yste#.out."rint-8, 8.< A en!-.< A "ublic static voi! "rint-longNO a. @ "rint-a, ', a.length.< A "ublic static voi! "rint-%tring #sg, longNO a. @ %yste#.out."rint-#sg K 8 8.< "rint-a, ', a.length.<
435
A "ublic static voi! "rint-longNO a, int fro#, int to. @ start-fro#, to, a.length.< for-int i ? fro#< i P to< iKK. @ %yste#.out."rint-aNiO.< if-i P to - (. %yste#.out."rint-8, 8.< A en!-.< A "ublic static voi! "rint-floatNO a. @ "rint-a, ', a.length.< A "ublic static voi! "rint-%tring #sg, floatNO a. @ %yste#.out."rint-#sg K 8 8.< "rint-a, ', a.length.< A "ublic static voi! "rint-floatNO a, int fro#, int to. @ start-fro#, to, a.length.< for-int i ? fro#< i P to< iKK. @ %yste#.out."rint-aNiO.< if-i P to - (. %yste#.out."rint-8, 8.< A en!-.< A "ublic static voi! "rint-!oubleNO a. @ "rint-a, ', a.length.< A "ublic static voi! "rint-%tring #sg, !oubleNO a. @ %yste#.out."rint-#sg K 8 8.< "rint-a, ', a.length.< A "ublic static voi! "rint-!oubleNO a, int fro#, int to.@ start-fro#, to, a.length.< for-int i ? fro#< i P to< iKK. @
437
%yste#.out."rint-aNiO.< if-i P to - (. %yste#.out."rint-8, 8.< A en!-.< A // Lill an array using a generator3 "ublic static voi! fill-GbHectNO a, aenerator gen. @ fill-a, ', a.length, gen.< A "ublic static voi! fill-GbHectNO a, int fro#, int to, aenerator gen.@ for-int i ? fro#< i P to< iKK. aNiO ? gen.ne6t-.< A "ublic static voi! fill-booleanNO a, Booleanaenerator gen. @ fill-a, ', a.length, gen.< A "ublic static voi! fill-booleanNO a, int fro#, int to, Booleanaenerator gen. @ for-int i ? fro#< i P to< iKK. aNiO ? gen.ne6t-.< A "ublic static voi! fill-byteNO a, Byteaenerator gen. @ fill-a, ', a.length, gen.< A "ublic static voi! fill-byteNO a, int fro#, int to, Byteaenerator gen. @ for-int i ? fro#< i P to< iKK. aNiO ? gen.ne6t-.< A "ublic static voi! fill-charNO a, Charaenerator gen. @ fill-a, ', a.length, gen.< A
438
"ublic static voi! fill-charNO a, int fro#, int to, Charaenerator gen. @ for-int i ? fro#< i P to< iKK. aNiO ? gen.ne6t-.< A "ublic static voi! fill-shortNO a, %hortaenerator gen. @ fill-a, ', a.length, gen.< A "ublic static voi! fill-shortNO a, int fro#, int to, %hortaenerator gen. @ for-int i ? fro#< i P to< iKK. aNiO ? gen.ne6t-.< A "ublic static voi! fill-intNO a, $ntaenerator gen. @ fill-a, ', a.length, gen.< A "ublic static voi! fill-intNO a, int fro#, int to, $ntaenerator gen. @ for-int i ? fro#< i P to< iKK. aNiO ? gen.ne6t-.< A "ublic static voi! fill-longNO a, Longaenerator gen. @ fill-a, ', a.length, gen.< A "ublic static voi! fill-longNO a, int fro#, int to, Longaenerator gen. @ for-int i ? fro#< i P to< iKK. aNiO ? gen.ne6t-.< A "ublic static voi! fill-floatNO a, Lloataenerator gen. @ fill-a, ', a.length, gen.< A "ublic static voi!
43:
fill-floatNO a, int fro#, int to, Lloataenerator gen. @ for-int i ? fro#< i P to< iKK. aNiO ? gen.ne6t-.< A "ublic static voi! fill-!oubleNO a, Doubleaenerator gen. @ fill-a, ', a.length, gen.< A "ublic static voi! fill-!oubleNO a, int fro#, int to, Doubleaenerator gen.@ for-int i ? fro#< i P to< iKK. aNiO ? gen.ne6t-.< A "rivate static 5an!o# r ? ne: 5an!o#-.< "ublic static class 5an!Booleanaenerator i#"le#ents Booleanaenerator @ "ublic boolean ne6t-. @ return r.ne6tBoolean-.< A A "ublic static class 5an!Byteaenerator i#"le#ents Byteaenerator @ "ublic byte ne6t-. @ return -byte.r.ne6t$nt-.< A A static %tring ssource ? 80BCDELaM$J`LJ&GP/5%TYW\9;T8 K 8abc!efghiHkl#no"=rstuv:6yU8< static charNO src ? ssource.toChar0rray-.< "ublic static class 5an!Charaenerator i#"le#ents Charaenerator @ "ublic char ne6t-. @ int "os ? Jath.abs-r.ne6t$nt-..< return srcN"os V src.lengthO< A A "ublic static class 5an!%tringaenerator i#"le#ents aenerator @
43;
"rivate int len< "rivate 5an!Charaenerator cg ? ne: 5an!Charaenerator-.< "ublic 5an!%tringaenerator-int length. @ len ? length< A "ublic GbHect ne6t-. @ charNO buf ? ne: charNlenO< for-int i ? '< i P len< iKK. bufNiO ? cg.ne6t-.< return ne: %tring-buf.< A A "ublic static class 5an!%hortaenerator i#"le#ents %hortaenerator @ "ublic short ne6t-. @ return -short.r.ne6t$nt-.< A A "ublic static class 5an!$ntaenerator i#"le#ents $ntaenerator @ "rivate int #o! ? (''''< "ublic 5an!$ntaenerator-. @A "ublic 5an!$ntaenerator-int #o!ulo. @ #o! ? #o!ulo< A "ublic int ne6t-. @ return r.ne6t$nt-. V #o!< A A "ublic static class 5an!Longaenerator i#"le#ents Longaenerator @ "ublic long ne6t-. @ return r.ne6tLong-.< A A "ublic static class 5an!Lloataenerator i#"le#ents Lloataenerator @ "ublic float ne6t-. @ return r.ne6tLloat-.< A A "ublic static class 5an!Doubleaenerator i#"le#ents Doubleaenerator @ "ublic !ouble ne6t-. @return r.ne6tDouble-.<A
44=
A A ///3>
To "ill an array o" ele#ents using a generator, the fillA B #ethod takes a re"erence to an a%%ro%riate generator interface, which has a ne4tA B #ethod that will so#ehow %roduce an ob0ect o" the right ty%e *de%ending on how the inter"ace is i#%le#ented,. The fillA B #ethod si#%ly calls ne4tA B until the desired range has been "illed. Cow you can create any generator by i#%le#enting the a%%ro%riate interface, and use your generator with fillA B. RFSURFSTIJLT+(6PTE52TIKHU 5ando# data generators are use"ul "or testing, so a set o" inner classes is created to i#%le#ent all the %ri#itive generator inter"aces, as well as a )tring generator to re%resent .b8ect. /ou can see that $an')tring"enerator uses $an'-har"enerator to "ill an array o" characters, which is then turned into a )tring. The si1e o" the array is deter#ined by the constructor argu#ent. RFSURF STIJLT+(6PTE52TIK3U To generate nu#bers that aren t too large, $an'Int"enerator de"aults to a #odulus o" M@,@@@, but the overloaded constructor allows you to choose a s#aller value. RFSURFSTIJLT+(6PTE52TIKGU (ere s a %rogra# to test the library, and to de#onstrate how it is used=
utilities
"ublic class Test0rrays @ "ublic static voi! #ain-%tringNO args. @ int siUe ? +< // Gr get the siUe fro# the co##an! line3 if-args.length 4? '. siUe ? $nteger."arse$nt-argsN'O.< booleanNO a( ? ne: booleanNsiUeO< byteNO a ? ne: byteNsiUeO< charNO a) ? ne: charNsiUeO< shortNO aI ? ne: shortNsiUeO< intNO a, ? ne: intNsiUeO< longNO a+ ? ne: longNsiUeO<
441
floatNO a* ? ne: floatNsiUeO< !oubleNO a1 ? ne: !oubleNsiUeO< %tringNO aC ? ne: %tringNsiUeO< 0rrays .fill-a(, ne: 0rrays .5an!Booleanaenerator-..< 0rrays ."rint-a(.< 0rrays ."rint-8a( ? 8, a(.< 0rrays ."rint-a(, siUe/), siUe/) K siUe/).< 0rrays .fill-a , ne: 0rrays .5an!Byteaenerator-..< 0rrays ."rint-a .< 0rrays ."rint-8a ? 8, a .< 0rrays ."rint-a , siUe/), siUe/) K siUe/).< 0rrays .fill-a), ne: 0rrays .5an!Charaenerator-..< 0rrays ."rint-a).< 0rrays ."rint-8a) ? 8, a).< 0rrays ."rint-a), siUe/), siUe/) K siUe/).< 0rrays .fill-aI, ne: 0rrays .5an!%hortaenerator-..< 0rrays ."rint-aI.< 0rrays ."rint-8aI ? 8, aI.< 0rrays ."rint-aI, siUe/), siUe/) K siUe/).< 0rrays .fill-a,, ne: 0rrays .5an!$ntaenerator-..< 0rrays ."rint-a,.< 0rrays ."rint-8a, ? 8, a,.< 0rrays ."rint-a,, siUe/), siUe/) K siUe/).< 0rrays .fill-a+, ne: 0rrays .5an!Longaenerator-..< 0rrays ."rint-a+.< 0rrays ."rint-8a+ ? 8, a+.< 0rrays ."rint-a+, siUe/), siUe/) K siUe/).< 0rrays .fill-a*, ne: 0rrays .5an!Lloataenerator-..< 0rrays ."rint-a*.< 0rrays ."rint-8a* ? 8, a*.< 0rrays ."rint-a*, siUe/), siUe/) K siUe/).< 0rrays .fill-a1, ne: 0rrays .5an!Doubleaenerator-..< 0rrays ."rint-a1.<
442
0rrays ."rint-8a1 ? 8, a1.< 0rrays ."rint-a1, siUe/), siUe/) K siUe/).< 0rrays .fill-aC, ne: 0rrays .5an!%tringaenerator-*..< 0rrays ."rint-aC.< 0rrays ."rint-8aC ? 8, aC.< 0rrays ."rint-aC, siUe/), siUe/) K siUe/).< A A ///3>
The si7e %ara#eter has a de"ault value, but you can also set it "ro# the co##and line. RFSURFSTIJLT+(6PTE52TIKIU
<illing an arra:
The Java standard library Arrays also has a fillA B #ethod, but that is rather trivial9it only du%licates a single value into each location, or in the case o" ob0ects, co%ies the sa#e re"erence into each location. 4sing ArraysI!printA B, the Arrays!fillA B #ethods can be easily de#onstrated=
//3 c'C3Lilling0rrays.Hava // Ysing 0rrays.fill-. i#"ort co#.bruceeckel.util.B< i#"ort Hava.util.B< "ublic class Lilling0rrays @ "ublic static voi! #ain-%tringNO args. @ int siUe ? +< // Gr get the siUe fro# the co##an! line3 if-args.length 4? '. siUe ? $nteger."arse$nt-argsN'O.< booleanNO a( ? ne: booleanNsiUeO< byteNO a ? ne: byteNsiUeO< charNO a) ? ne: charNsiUeO< shortNO aI ? ne: shortNsiUeO< intNO a, ? ne: intNsiUeO< longNO a+ ? ne: longNsiUeO< floatNO a* ? ne: floatNsiUeO< !oubleNO a1 ? ne: !oubleNsiUeO< %tringNO aC ? ne: %tringNsiUeO<
443
0rrays.fill-a(, true.< 0rrays ."rint-8a( ? 8, a(.< 0rrays.fill-a , -byte.((.< 0rrays ."rint-8a ? 8, a .< 0rrays.fill-a), 262.< 0rrays ."rint-8a) ? 8, a).< 0rrays.fill-aI, -short.(*.< 0rrays ."rint-8aI ? 8, aI.< 0rrays.fill-a,, (C.< 0rrays ."rint-8a, ? 8, a,.< 0rrays.fill-a+, ).< 0rrays ."rint-8a+ ? 8, a+.< 0rrays.fill-a*, C.< 0rrays ."rint-8a* ? 8, a*.< 0rrays.fill-a1, I*.< 0rrays ."rint-8a1 ? 8, a1.< 0rrays.fill-aC, 8Mello8.< 0rrays ."rint-8aC ? 8, aC.< // Jani"ulating ranges3 0rrays.fill-aC, ), ,, 8\orl!8.< 0rrays ."rint-8aC ? 8, aC.< A A ///3>
/ou can either "ill the entire array, or9as the last two state#ents show9a range o" ele#ents. But since you can only %rovide a single value to use "or "illing using Arrays!fillA B, the ArraysI!fillA B #ethods %roduce #uch #ore interesting results. RFSURFSTIJLT+(6PTE52TIK2U
Co.:ing an arra:
The Java standard library %rovides a static #ethod, )ystem!arraycopy A B, which can #ake #uch "aster co%ies o" an array than i" you use a for loo% to %er"or# the co%y by hand. )ystem!arraycopyA B is overloaded to handle all ty%es. (ere s an e&a#%le that #ani%ulates arrays o" int=
444
"ublic class Co"ying0rrays @ "ublic static voi! #ain-%tringNO args. @ intNO i ? ne: intN ,O< intNO H ? ne: intN ,O< 0rrays.fill-i, I*.< 0rrays.fill-H, CC.< 0rrays ."rint-8i ? 8, i.< 0rrays ."rint-8H ? 8, H.< %yste#.arrayco"y-i, ', H, ', i.length.< 0rrays ."rint-8H ? 8, H.< intNO k ? ne: intN('O< 0rrays.fill-k, (').< %yste#.arrayco"y-i, ', k, ', k.length.< 0rrays ."rint-8k ? 8, k.< 0rrays.fill-k, (').< %yste#.arrayco"y-k, ', i, ', k.length.< 0rrays ."rint-8i ? 8, i.< // GbHects3 $ntegerNO u ? ne: $ntegerN('O< $ntegerNO v ? ne: $ntegerN,O< 0rrays.fill-u, ne: $nteger-I*..< 0rrays.fill-v, ne: $nteger-CC..< 0rrays ."rint-8u ? 8, u.< 0rrays ."rint-8v ? 8, v.< %yste#.arrayco"y-v, ', u, u.length/ , v.length.< 0rrays ."rint-8u ? 8, u.< A A ///3>
The argu#ents to arraycopyA B are the source array, the o""set into the source array "ro# whence to start co%ying, the destination array, the o""set into the destination array where the co%ying begins, and the nu#ber o" ele#ents to co%y. Caturally, any violation o" the array boundaries will cause an e&ce%tion. RFSURFSTIJLT+(6PTE52TIL@U The e&a#%le shows that both %ri#itive arrays and ob0ect arrays can be co%ied. (owever, i" you co%y arrays o" ob0ects then only the re"erences get co%ied9there s no du%lication o" the ob0ects the#selves. This is called a shallo, co ) *see 6%%endi& 6,. RFSURFSTIJLT+(6PTE52TILMU
445
Com.aring arra:s
Arrays %rovides the overloaded #ethod eC*alsA B to co#%are entire
arrays "or eAuality. 6gain, these are overloaded "or all the %ri#itives, and "or .b8ect. To be eAual, the arrays #ust have the sa#e nu#ber o" ele#ents and each ele#ent #ust be eAuivalent to each corres%onding ele#ent in the other array, using the eC*alsA B "or each ele#ent. *Eor %ri#itives, that %ri#itive s wra%%er class eC*alsA B is used; "or e&a#%le, Integer!eC*alsA B "or int., (ere s an e&a#%le=
//3 c'C3Co#"aring0rrays.Hava // Ysing 0rrays.e=uals-. i#"ort Hava.util.B< "ublic class Co#"aring0rrays @ "ublic static voi! #ain-%tringNO args. @ intNO a( ? ne: intN('O< intNO a ? ne: intN('O< 0rrays.fill-a(, I*.< 0rrays.fill-a , I*.< %yste#.out."rintln-0rrays.e=uals-a(, a a N)O ? ((< %yste#.out."rintln-0rrays.e=uals-a(, a %tringNO s( ? ne: %tringN,O< 0rrays.fill-s(, 8Mi8.< %tringNO s ? @8Mi8, 8Mi8, 8Mi8, 8Mi8, %yste#.out."rintln-0rrays.e=uals-s(, s A A ///3>
)riginally, a> and aI are e&actly eAual, so the out%ut is !true,$ but then one o" the ele#ents is changed so the second line o" out%ut is !"alse.$ In the last case, all the ele#ents o" s> %oint to the sa#e ob0ect, but sI has "ive uniAue ob0ects. (owever, array eAuality is based on contents *via .b8ect!eC*alsA B, and so the result is !true.$ RFSURF STIJLT+(6PTE52TILKU
447
//3 c'C3Co#"Ty"e.Hava
448
// $#"le#enting Co#"arable in a class. i#"ort co#.bruceeckel.util.B< i#"ort Hava.util.B< "ublic class Co#"Ty"e i#"le#ents Co#"arable @ int i< int H< "ublic Co#"Ty"e-int n(, int n . @ i ? n(< H ? n < A "ublic %tring to%tring-. @ return 8Ni ? 8 K i K 8, H ? 8 K H K 8O8< A "ublic int co#"areTo-GbHect rv. @ int rvi ? --Co#"Ty"e.rv..i< return -i P rvi [ -( 3 -i ?? rvi [ ' 3 (..< A "rivate static 5an!o# r ? ne: 5an!o#-.< "rivate static int ran!$nt-. @ return Jath.abs-r.ne6t$nt-.. V (''< A "ublic static aenerator generator-. @ return ne: aenerator-. @ "ublic GbHect ne6t-. @ return ne: Co#"Ty"e-ran!$nt-.,ran!$nt-..< A A< A "ublic static voi! #ain-%tringNO args. @ Co#"Ty"eNO a ? ne: Co#"Ty"eN('O< 0rrays .fill-a, generator-..< 0rrays ."rint-8before sorting, a ? 8, a.< 0rrays.sort-a.< 0rrays ."rint-8after sorting, a ? 8, a.< A A ///3>
:hen you de"ine the co#%arison "unction, you are res%onsible "or deciding what it #eans to co#%are one o" your ob0ects to another. (ere,
44:
only the i values are used in the co#%arison, and the 8 values are ignored. RFSURFSTIJLT+(6PTE52TILGU The static ran'IntA B #ethod %roduces %ositive values between 1ero and M@@, and the generatorA B #ethod %roduces an ob0ect that i#%le#ents the "enerator inter"ace, by creating an anony#ous inner class *see +ha%ter I,. This builds -ompType ob0ects by initiali1ing the# with rando# values. In mainA B, the generator is used to "ill an array o" -ompType, which is then sorted. I" -omparable hadn t been i#%le#ented, then you d get a co#%ile'ti#e error #essage when you tried to call sortA B. RFSURFSTIJLT+(6PTE52TILIU Cow su%%ose so#eone hands you a class that doesn t i#%le#ent -omparable, or they hand you this class that does i#%le#ent -omparable, but you decide you don t like the way it works and would rather have a di""erent co#%arison "unction "or the ty%e. To do this, you use the second a%%roach "or co#%aring ob0ects, by creating a se%arate class that i#%le#ents an inter"ace called -omparator. This has two #ethods, compareA B and eC*alsA B. (owever, you don t have to i#%le#ent eC*alsA B e&ce%t "or s%ecial %er"or#ance needs, because anyti#e you create a class it is i#%licitly inherited "ro# .b8ect, which has an eC*alsA B. So you can 0ust use the de"ault .b8ect eC*alsA B and satis"y the contract i#%osed by the inter"ace. RFSURF STIJLT+(6PTE52TIL2U The -ollections class *which we ll look at #ore later, contains a single -omparator that reverses the natural sorting order. This can easily be a%%lied to the -ompType= RFSURFSTIJLT+(6PTE52TI?@U
//3 c'C35everse.Hava // The Collecions.reverseGr!er-. Co#"arator. i#"ort co#.bruceeckel.util.B< i#"ort Hava.util.B< "ublic class 5everse @ "ublic static voi! #ain-%tringNO args. @ Co#"Ty"eNO a ? ne: Co#"Ty"eN('O< 0rrays .fill-a, Co#"Ty"e.generator-..< 0rrays ."rint-8before sorting, a ? 8, a.< 0rrays.sort-a, Collections.reverseGr!er-..<
44;
//3 c'C3Co#"aratorTest.Hava // $#"le#enting a Co#"arator for a class. i#"ort co#.bruceeckel.util.B< i#"ort Hava.util.B< class Co#"Ty"eCo#"arator i#"le#ents Co#"arator @ "ublic int co#"are-GbHect o(, GbHect o . @ int H( ? --Co#"Ty"e.o(..H< int H ? --Co#"Ty"e.o ..H< return -H( P H [ -( 3 -H( ?? H [ ' 3 (..< A A "ublic class Co#"aratorTest @ "ublic static voi! #ain-%tringNO args. @ Co#"Ty"eNO a ? ne: Co#"Ty"eN('O< 0rrays .fill-a, Co#"Ty"e.generator-..< 0rrays ."rint-8before sorting, a ? 8, a.< 0rrays.sort-a, ne: Co#"Ty"eCo#"arator-..< 0rrays ."rint-8after sorting, a ? 8, a.< A A ///3>
The compareA B #ethod #ust return a negative integer, 1ero, or a %ositive integer i" the "irst argu#ent is less than, eAual to, or greater than the second, res%ectively. RFSURFSTIJLT+(6PTE52TI?KU
1orting an arra:
:ith the built'in sorting #ethods, you can sort any array o" %ri#itives, and any array o" ob0ects that either i#%le#ents -omparable or has an
45=
associated -omparator. This "ills a big hole in the Java libraries9 believe it or not, there was no su%%ort in Java M.@ or M.M "or sorting )trings. (ere s an e&a#%le that generates rando# )tring ob0ects and sorts the#=
//3 c'C3%tring%orting.Hava // %orting an array of %trings. i#"ort co#.bruceeckel.util.B< i#"ort Hava.util.B< "ublic class %tring%orting @ "ublic static voi! #ain-%tringNO args. @ %tringNO sa ? ne: %tringN)'O< 0rrays .fill-sa, ne: 0rrays .5an!%tringaenerator-,..< 0rrays ."rint-8Before sorting3 8, sa.< 0rrays.sort-sa.< 0rrays ."rint-80fter sorting3 8, sa.< A A ///3>
)ne thing you ll notice about the out%ut in the )tring sorting algorith# is that it s le*icogra hic, so it %uts all the words starting with u%%ercase letters "irst, "ollowed by all the words starting with lowercase letters. *Tele%hone books are ty%ically sorted this way., /ou #ay also want to grou% the words together regardless o" case, and you can do this by de"ining a -omparator class, thereby overriding the de"ault )tring -omparable behavior. Eor reuse, this will be added to the !util$ %ackage= RFSURFSTIJLT+(6PTE52TI?LU
//3 co#3bruceeckel3util30l"habeticCo#"arator.Hava // `ee"ing u""er an! lo:ercase letters together. "ackage co#.bruceeckel.util< i#"ort Hava.util.B< "ublic class 0l"habeticCo#"arator i#"le#ents Co#"arator @ "ublic int co#"are-GbHect o(, GbHect o . @ %tring s( ? -%tring.o(< %tring s ? -%tring.o < return s(.toLo:erCase-..co#"areTo-
451
s .toLo:erCase-..< A A ///3>
Each )tring is converted to lowercase be"ore the co#%arison. )tring s built'in compareToA B #ethod %rovides the desired "unctionality. RF SURFSTIJLT+(6PTE52TI??U (ere s a test using Alphabetic-omparator=
//3 c'C30l"habetic%orting.Hava // `ee"ing u""er an! lo:ercase letters together. i#"ort co#.bruceeckel.util.B< i#"ort Hava.util.B< "ublic class 0l"habetic%orting @ "ublic static voi! #ain-%tringNO args. @ %tringNO sa ? ne: %tringN)'O< 0rrays .fill-sa, ne: 0rrays .5an!%tringaenerator-,..< 0rrays ."rint-8Before sorting3 8, sa.< 0rrays.sort-sa, ne: 0l"habeticCo#"arator-..< 0rrays ."rint-80fter sorting3 8, sa.< A A ///3>
The sorting algorith# that s used in the Java standard library is designed to be o%ti#al "or the %articular ty%e you re sorting9a euicksort "or %ri#itives, and a stable #erge sort "or ob0ects. So you shouldn t need to s%end any ti#e worrying about %er"or#ance unless your %ro"iling tool %oints you to the sorting %rocess as a bottleneck. RFSURF STIJLT+(6PTE52TI?HU
452
//3 c'C30rray%earching.Hava // Ysing 0rrays.binary%earch-.. i#"ort co#.bruceeckel.util.B< i#"ort Hava.util.B< "ublic class 0rray%earching @ "ublic static voi! #ain-%tringNO args. @ intNO a ? ne: intN(''O< 0rrays .5an!$ntaenerator gen ? ne: 0rrays .5an!$ntaenerator-('''.< 0rrays .fill-a, gen.< 0rrays.sort-a.< 0rrays ."rint-8%orte! array3 8, a.< :hile-true. @ int r ? gen.ne6t-.< int location ? 0rrays.binary%earch-a, r.< if-location Q? '. @ %yste#.out."rintln-8Location of 8 K r K 8 is 8 K location K 8, aN8 K location K 8O ? 8 K aNlocationO.< break< // Gut of :hile loo" A A A A ///3>
In the (hile loo%, rando# values are generated as search ite#s, until one o" the# is "ound. RFSURFSTIJLT+(6PTE52TI?GU
Arrays!binary)earchA B %roduces a value greater than or eAual to 1ero i" the search ite# is "ound. )therwise, it %roduces a negative value re%resenting the %lace that the ele#ent should be inserted i" you are #aintaining the sorted array by hand. The value %roduced is --insertion "oint. - (
The insertion %oint is the inde& o" the "irst ele#ent greater than the key, or a!si7eA B, i" all ele#ents in the array are less than the s%eci"ied key. RF SURFSTIJLT+(6PTE52TI?IU I" the array contains du%licate ele#ents, there is no guarantee which one will be "ound. The algorith# is thus not really designed to su%%ort
453
du%licate ele#ents, as #uch as tolerate the#. I" you need a sorted list o" nondu%licated ele#ents, however, use a Tree)et, which will be introduced later in this cha%ter. This takes care o" all the details "or you auto#atically. )nly in cases o" %er"or#ance bottlenecks should you re%lace the Tree)et with a hand'#aintained array. RFSURF STIJLT+(6PTE52TI?2U I" you have sorted an ob0ect array using a -omparator *%ri#itive arrays do not allow sorting with a -omparator,, you #ust include that sa#e -omparator when you %er"or# a binary)earchA B *using the overloaded version o" the "unction that s %rovided,. Eor e&a#%le, the Alphabetic)orting!8ava %rogra# can be #odi"ied to %er"or# a search=
//3 c'C30l"habetic%earch.Hava // %earching :ith a Co#"arator. i#"ort co#.bruceeckel.util.B< i#"ort Hava.util.B< "ublic class 0l"habetic%earch @ "ublic static voi! #ain-%tringNO args. @ %tringNO sa ? ne: %tringN)'O< 0rrays .fill-sa, ne: 0rrays .5an!%tringaenerator-,..< 0l"habeticCo#"arator co#" ? ne: 0l"habeticCo#"arator-.< 0rrays.sort-sa, co#".< int in!e6 ? 0rrays.binary%earch-sa, saN('O, co#".< %yste#.out."rintln-8$n!e6 ? 8 K in!e6.< A A ///3>
The -omparator #ust be %assed to the overloaded binary)earchA B as the third argu#ent. In the above e&a#%le, success is guaranteed because the search ite# is %lucked out o" the array itsel". RFSURF STIJLT+(6PTE52TIH@U
454
Arra: summar:
To su##ari1e what you ve seen so "ar, your "irst and #ost e""icient choice to hold a grou% o" ob0ects should be an array, and you re "orced into this choice i" you want to hold a grou% o" %ri#itives. In the re#ainder o" this cha%ter we ll look at the #ore general case, when you don t know at the ti#e you re writing the %rogra# how #any ob0ects you re going to need, or i" you need a #ore so%histicated way to store your ob0ects. Java %rovides a library o" container classes to solve this %roble#, the basic ty%es o" which are +ist, )et, and 1ap. /ou can solve a sur%rising nu#ber o" %roble#s using these tools. RFSURFSTIJLT+(6PTE52TIHMU 6#ong their other characteristics9 )et, "or e&a#%le, holds only one ob0ect o" each value, and 1ap is an associative arra) that lets you associate any ob0ect with any other ob0ect9the Java container classes will auto#atically resi1e the#selves. So, unlike arrays, you can %ut in any nu#ber o" ob0ects and you don t need to worry about how big to #ake the container while you re writing the %rogra#. RFSURF STIJLT+(6PTE52TIHKU
Introduction to containers
To #e, container classes are one o" the #ost %ower"ul tools "or raw develo%#ent because they signi"icantly increase your %rogra##ing #uscle. The Java K containers re%resent a thorough redesign @ o" the rather %oor showings in Java M.@ and M.M. So#e o" the redesign #akes things tighter and #ore sensible. It also "ills out the "unctionality o" the containers library, %roviding the behavior o" linked lists, Aueues, and deAues *double'ended Aueues, %ronounced !decks$,. RFSURF STIJLT+(6PTE52TIHLU The design o" a containers library is di""icult *true o" #ost library design %roble#s,. In +<<, the container classes covered the bases with #any di""erent classes. This was better than what was available %rior to the +<<
@ By Joshua Bloch at Sun.
455
container classes *nothing,, but it didn t translate well into Java. )n the other e&tre#e, I ve seen a containers library that consists o" a single class, !container,$ which acts like both a linear seAuence and an associative array at the sa#e ti#e. The Java K container library strikes a balance= the "ull "unctionality that you e&%ect "ro# a #ature container library, but easier to learn and use than the +<< container classes and other si#ilar container libraries. The result can see# a bit odd in %laces. 4nlike so#e o" the decisions #ade in the early Java libraries, these oddities were not accidents, but care"ully considered decisions based on trade'o""s in co#%le&ity. It #ight take you a little while to get co#"ortable with so#e as%ects o" the library, but I think you ll "ind yoursel" ra%idly acAuiring and using these new tools. RFSURFSTIJLT+(6PTE52TIH?U The Java K container library takes the issue o" !holding your ob0ects$ and divides it into two distinct conce%ts=
4*)
-ollection= a grou% o" individual ele#ents, o"ten with so#e rule a%%lied to the#. 6 +ist #ust hold the ele#ents in a %articular seAuence, and a )et cannot have any du%licate ele#ents. *6 bag,
which is not i#%le#ented in the Java container library9since +ists %rovide you with enough o" that "unctionality9has no such rules., N5WON5WTIJJX-HA#T&$?XI@@O
4+)
1ap= a grou% o" key'value ob0ect %airs. 6t "irst glance, this #ight see# like it ought to be a -ollection o" %airs, but when you try to
i#%le#ent it that way the design gets awkward, so it s clearer to #ake it a se%arate conce%t. )n the other hand, it s convenient to look at %ortions o" a 1ap by creating a -ollection to re%resent that %ortion. Thus, a 1ap can return a )et o" its keys, a -ollection o" its values, or a )et o" its %airs. 1aps, like arrays, can easily be e&%anded to #ulti%le di#ensions without adding new conce%ts= you si#%ly #ake a 1ap whose values are 1aps *and the values o" those 1aps can be 1aps, etc.,. N5WON5
WTIJJX-HA#T&$?XI@\O
:e will "irst look at the general "eatures o" containers, then go into details, and "inally learn why there are di""erent versions o" so#e containers, and how to choose between the#. RFSURF STIJLT+(6PTE52TIHGU
457
rinting containers
4nlike arrays, the containers %rint nicely without any hel%. (ere s an e&a#%le that also introduces you to the basic ty%es o" containers=
//3 c'C3PrintingContainers.Hava // Containers "rint the#selves auto#atically. i#"ort Hava.util.B< "ublic class PrintingContainers @ static Collection fill-Collection c. @ c.a!!-8!og8.< c.a!!-8!og8.< c.a!!-8cat8.< return c< A static Ja" fill-Ja" #. @ #."ut-8!og8, 8Bosco8.< #."ut-8!og8, 8%"ot8.< #."ut-8cat8, 85ags8.< return #< A "ublic static voi! #ain-%tringNO args. @ %yste#.out."rintln-fill-ne: 0rrayList-...< %yste#.out."rintln-fill-ne: Mash%et-...< %yste#.out."rintln-fill-ne: MashJa"-...< A A ///3>
6s #entioned be"ore, there are two basic categories in the Java container library. The distinction is based on the nu#ber o" ite#s that are held in each location o" the container. The -ollection category only holds one ite# in each location *the na#e is a bit #isleading since entire container libraries are o"ten called !collections$,. It includes the +ist, which holds a grou% o" ite#s in a s%eci"ied seAuence, and the )et, which only allows the addition o" one ite# o" each ty%e. The Array+ist is a ty%e o" +ist, and Hash)et is a ty%e o" )et. To add ite#s to any -ollection, there s an a''A B #ethod. RFSURFSTIJLT+(6PTE52TIHIU The 1ap holds key'value %airs, rather like a #ini database. The above %rogra# uses one "lavor o" 1ap, the Hash1ap. I" you have a 1ap that
458
associates states with their ca%itals and you want to know the ca%ital o" )hio, you look it u%9al#ost as i" you were inde&ing into an array. *Ma%s are also called associative arra)s., To add ele#ents to a 1ap there s a p*tA B #ethod that takes a key and a value as argu#ents. The above e&a#%le only shows adding ele#ents and does not look the ele#ents u% a"ter they re added. That will be shown later. RFSURF STIJLT+(6PTE52TIH2U The overloaded fillA B #ethods "ill -ollections and 1aps, res%ectively. I" you look at the out%ut, you can see that the de"ault %rinting behavior *%rovided via the container s various to)tringA B #ethods, %roduces Auite readable results, so no additional %rinting su%%ort is necessary as it was with arrays=
<illing containers
6lthough the %roble# o" %rinting the containers is taken care o", "illing containers su""ers "ro# the sa#e de"iciency as 8ava!*til!Arrays. Just like Arrays, there is a co#%anion class called -ollections containing static utility #ethods including one called fillA B. This fillA B also 0ust
45:
du%licates a single ob0ect re"erence throughout the container, and also only works "or +ist ob0ects and not )ets or 1aps=
//3 c'C3LillingLists.Hava // The Collections.fill-. #etho!. i#"ort Hava.util.B< "ublic class LillingLists @ "ublic static voi! #ain-%tringNO args. @ List list ? ne: 0rrayList-.< for-int i ? '< i P ('< iKK. list.a!!-88.< Collections.fill-list, 8Mello8.< %yste#.out."rintln-list.< A A ///3>
This #ethod is #ade even less use"ul by the "act that it can only re%lace ele#ents that are already in the +ist, and will not add new ele#ents. RF SURFSTIJLT+(6PTE52TI3KU To be able to create interesting e&a#%les, here is a co#%le#entary
-ollectionsI library *%art o" com!br*ceeckel!*til "or convenience, with a fillA B #ethod that uses a generator to add ele#ents, and allows you to s%eci"y the nu#ber o" ele#ents you want to a''A B. The "enerator interface de"ined %reviously will work "or -ollections, but the 1ap reAuires its own generator interface since a %air o" ob0ects *one key and one value, #ust be %roduced by each call to ne4tA B. (ere is the #air class= //3 co#3bruceeckel3util3Pair.Hava "ackage co#.bruceeckel.util< "ublic class Pair @ "ublic GbHect key, value< Pair-GbHect k, GbHect v. @ key ? k< value ? v< A A ///3>
Ce&t, the generator interface that %roduces the #air=
45;
//3 co#3bruceeckel3util3Ja"aenerator.Hava "ackage co#.bruceeckel.util< "ublic interface Ja"aenerator @ Pair ne6t-.< A ///3>
:ith these, a set o" utilities "or working with the container classes can be develo%ed=
//3 co#3bruceeckel3util3Collections .Hava // To fill any ty"e of container // using a generator obHect. "ackage co#.bruceeckel.util< i#"ort Hava.util.B< "ublic class Collections @ // Lill an array using a generator3 "ublic static voi! fill-Collection c, aenerator gen, int count. @ for-int i ? '< i P count< iKK. c.a!!-gen.ne6t-..< A "ublic static voi! fill-Ja" #, Ja"aenerator gen, int count. @ for-int i ? '< i P count< iKK. @ Pair " ? gen.ne6t-.< #."ut-".key, ".value.< A A "ublic static class 5an!%tringPairaenerator i#"le#ents Ja"aenerator @ "rivate 0rrays .5an!%tringaenerator gen< "ublic 5an!%tringPairaenerator-int len. @ gen ? ne: 0rrays .5an!%tringaenerator-len.< A "ublic Pair ne6t-. @ return ne: Pair-gen.ne6t-., gen.ne6t-..< A A // Default obHect so you !on2t have // to create your o:n3 "ublic static 5an!%tringPairaenerator rs" ?
47=
ne: 5an!%tringPairaenerator-('.< "ublic static class %tringPairaenerator i#"le#ents Ja"aenerator @ "rivate int in!e6 ? -(< "rivate %tringNONO !< "ublic %tringPairaenerator-%tringNONO !ata. @ ! ? !ata< A "ublic Pair ne6t-. @ // Lorce the in!e6 to :ra"3 in!e6 ? -in!e6 K (. V !.length< return ne: Pair-!Nin!e6ON'O, !Nin!e6ON(O.< A "ublic %tringPairaenerator reset-. @ in!e6 ? -(< return this< A A // Yse a "re!efine! !ataset3 "ublic static %tringPairaenerator geogra"hy ? ne: %tringPairaeneratorCountryCa"itals."airs.< // Pro!uce a se=uence fro# a D array3 "ublic static class %tringaenerator i#"le#ents aenerator @ "rivate %tringNONO !< "rivate int "osition< "rivate int in!e6 ? -(< "ublic %tringaenerator-%tringNONO !ata, int "os. @ ! ? !ata< "osition ? "os< A "ublic GbHect ne6t-. @ // Lorce the in!e6 to :ra"3 in!e6 ? -in!e6 K (. V !.length< return !Nin!e6ON"ositionO< A "ublic %tringaenerator reset-. @ in!e6 ? -(< return this<
471
A A // Yse a "re!efine! !ataset3 "ublic static %tringaenerator countries ? ne: %tringaenerator-CountryCa"itals."airs,'.< "ublic static %tringaenerator ca"itals ? ne: %tringaenerator-CountryCa"itals."airs,(.< A ///3>
Both versions o" fillA B take an argu#ent that deter#ines the nu#ber o" ite#s to add to the container. In addition, there are two generators "or the #a%= $an')tring#air"enerator, which creates any nu#ber o" %airs o" gibberish )trings with length deter#ined by the constructor argu#ent; and )tring#air"enerator, which %roduces %airs o" )trings given a two'di#ensional array o" )tring. The )tring"enerator also takes a two'di#ensional array o" )tring but generates single ite#s rather than #airs. The static rsp, geography, co*ntries, and capitals ob0ects %rovide %rebuilt generators, the last three using all the countries o" the world and their ca%itals. Cote that i" you try to create #ore %airs than are available, the generators will loo% around to the beginning, and i" you are %utting the %airs into a 1ap, the du%licates will 0ust be ignored. RFSURFSTIJLT+(6PTE52TI3LU (ere is the %rede"ined dataset, which consists o" country na#es and their ca%itals. It is set in a s#all "ont to %revent taking u% unnecessary s%ace=
"ublic class CountryCa"itals @ "ublic static final %tringNONO "airs ? @ // 0frica @80LaE5$08,80lgiers8A, @80&aGL08,8Luan!a8A, @8BE&$&8,8Porto-&ovo8A, @8BGT%\0&08,8aaberone8A, @8BY5`$&0 L0%G8,8Guaga!ougou8A, @8BY5Y&D$8,8BuHu#bura8A, @8C0JE5GG&8,8;aoun!e8A, @8C0PE WE5DE8,8Praia8A, @8CE&T50L 0L5$C0& 5EPYBL$C8,8Bangui8A, @8CM0D8,8&2!Ha#ena8A, @8CGJG5G%8,8Joroni8A, @8CG&aG8,8BraUUaville8A, @8DJ$BGYT$8,8DiHibouti8A, @8Ea;PT8,8Cairo8A, @8E/Y0TG5$0L aY$&E08,8Jalabo8A, @8E5$T5E08,80s#ara8A, @8ETM$GP$08,80!!is 0baba8A, @8a0BG&8,8Libreville8A, @8TME a0JB$08,8BanHul8A, @8aM0&08,80ccra8A, @8aY$&E08,8Conakry8A, @8aY$&E08,8-8A, @8B$%%0Y8,8Bissau8A, @8CETE D2$WG$5 -$WG5; CG0%T.8,8;a#oussoukro8A, @8`E&;08,8&airobi8A, @8LE%GTMG8,8Jaseru8A, @8L$BE5$08,8Jonrovia8A, @8L$B;08,8Tri"oli8A,
472
@8J0D0a0%C058,80ntananarivo8A, @8J0L0\$8,8Lilong:e8A, @8J0L$8,8Ba#ako8A, @8J0Y5$T0&$08,8&ouakchott8A, @8J0Y5$T$Y%8,8Port Louis8A, @8JG5GCCG8,85abat8A, @8JGT0JB$/YE8,8Ja"uto8A, @8&0J$B$08,8\in!hoek8A, @8&$aE58,8&ia#ey8A, @8&$aE5$08,80buHa8A, @85\0&D08,8`igali8A, @8%0G TGJE E P5$&C$PE8,8%ao To#e8A, @8%E&Ea0L8,8Dakar8A, @8%E;CMELLE%8,8Wictoria8A, @8%$E550 LEG&E8,8Lreeto:n8A, @8%GJ0L$08,8Joga!ishu8A, @8%GYTM 0L5$C08,8Pretoria/Ca"e To:n8A, @8%YD0&8,8`hartou#8A, @8%\0T$L0&D8,8Jbabane8A, @8T0&T0&$08,8Do!o#a8A, @8TGaG8,8Lo#e8A, @8TY&$%$08,8Tunis8A, @8Ya0&D08,8`a#"ala8A, @8DEJGC50T$C 5EPYBL$C GL TME CG&aG -T0$5E.8,8`inshasa8A, @8T0JB$08,8Lusaka8A, @8T$JB0B\E8,8Marare8A, // 0sia @80LaM0&$%T0&8,8`abul8A, @8B0M50$&8,8Jana#a8A, @8B0&aL0DE%M8,8Dhaka8A, @8BMYT0&8,8Thi#"hu8A, @8B5Y&E$8,8Ban!ar %eri Bega:an8A, @8C0JBGD$08,8Phno# Penh8A, @8CM$&08,8BeiHing8A, @8C;P5Y%8,8&icosia8A, @8$&D$08,8&e: Delhi8A, @8$&DG&E%$08,8Jakarta8A, @8$50&8,8Tehran8A, @8$50/8,8Bagh!a!8A, @8$%50EL8,8Jerusale#8A, @8J0P0&8,8Tokyo8A, @8JG5D0&8,80##an8A, @8`Y\0$T8,8`u:ait City8A, @8L0G%8,8Wientiane8A, @8LEB0&G&8,8Beirut8A, @8J0L0;%$08,8`uala Lu#"ur8A, @8TME J0LD$WE%8,8Jale8A, @8JG&aGL$08,8Ylan Bator8A, @8J;0&J05 -BY5J0.8,85angoon8A, @8&EP0L8,8`at#an!u8A, @8&G5TM `G5E08,8P2yongyang8A, @8GJ0&8,8Juscat8A, @8P0`$%T0&8,8$sla#aba!8A, @8PM$L$PP$&E%8,8Janila8A, @8/0T058,8Doha8A, @8%0YD$ 050B$08,85iya!h8A, @8%$&a0PG5E8,8%inga"ore8A, @8%GYTM `G5E08,8%eoul8A, @8%5$ L0&`08,8Colo#bo8A, @8%;5$08,8Da#ascus8A, @8T0$\0& -5EPYBL$C GL CM$&0.8,8Tai"ei8A, @8TM0$L0&D8,8Bangkok8A, @8TY5`E;8,80nkara8A, @8Y&$TED 050B EJ$50TE%8,80bu Dhabi8A, @8W$ET&0J8,8Manoi8A, @8;EJE&8,8%ana2a8A, // 0ustralia an! Gceania @80Y%T50L$08,8Canberra8A, @8L$J$8,8%uva8A, @8`$5$B0T$8,8Bairiki8A, @8J05%M0LL $%L0&D%8,8Dala"-Yliga-Darrit8A, @8J$C5G&E%$08,8Palikir8A, @8&0Y5Y8,8;aren8A, @8&E\ TE0L0&D8,8\ellington8A, @8P0L0Y8,8`oror8A, @8P0PY0 &E\ aY$&E08,8Port Joresby8A, @8%GLGJG& $%L0&D%8,8Monaira8A, @8TG&a08,8&uku2alofa8A, @8TYW0LY8,8Longafale8A, @8W0&Y0TY8,8P Port-Wila8A, @8\E%TE5& %0JG08,80"ia8A, // Eastern Euro"e an! for#er Y%%5 @805JE&$08,8;erevan8A, @80TE5B0$J0&8,8Baku8A, @8BEL05Y% -B;ELG5Y%%$0.8,8Jinsk8A, @8aEG5a$08,8Tbilisi8A, @8`0T0`%T0&8,80l#aty8A, @8`;5a;T%T0&8,80l#a-0ta8A, @8JGLDGW08,8Chisinau8A, @85Y%%$08,8Josco:8A, @8T0J$`$%T0&8,8Dushanbe8A, @8TY5`JE&$%T0&8,80shkaba!8A, @8Y`50$&E8,8`yiv8A, @8YTBE`$%T0&8,8Tashkent8A, // Euro"e @80LB0&$08,8Tirana8A, @80&DG5508,80n!orra la Wella8A, @80Y%T5$08,8Wienna8A, @8BELa$YJ8,8Brussels8A,
473
@8BG%&$08,8-8A, @8ME5TEaGW$&08,8%araHevo8A, @8C5G0T$08,8Tagreb8A, @8CTECM 5EPYBL$C8,8Prague8A, @8DE&J05`8,8Co"enhagen8A, @8E%TG&$08,8Tallinn8A, @8L$&L0&D8,8Melsinki8A, @8L50&CE8,8Paris8A, @8aE5J0&;8,8Berlin8A, @8a5EECE8,80thens8A, @8MY&a05;8,8Bu!a"est8A, @8$CEL0&D8,85eykHavik8A, @8$5EL0&D8,8Dublin8A, @8$T0L;8,85o#e8A, @8L0TW$08,85iga8A, @8L$ECMTE&%TE$&8,8Wa!uU8A, @8L$TMY0&$08,8Wilnius8A, @8LY9EJBGY5a8,8Lu6e#bourg8A, @8J0CEDG&$08,8%ko"He8A, @8J0LT08,8Walletta8A, @8JG&0CG8,8Jonaco8A, @8JG&TE&Ea5G8,8Po!gorica8A, @8TME &ETME5L0&D%8,80#ster!a#8A, @8&G5\0;8,8Gslo8A, @8PGL0&D8,8\arsa:8A, @8PG5TYa0L8,8Lisbon8A, @85GJ0&$08,8Bucharest8A, @8%0& J05$&G8,8%an Jarino8A, @8%E5B$08,8Belgra!e8A, @8%LGW0`$08,8Bratislava8A, @8%LGWE&$08,8LHuHiana8A, @8%P0$&8,8Ja!ri!8A, @8%\EDE&8,8%tockhol#8A, @8%\$TTE5L0&D8,8Berne8A, @8Y&$TED `$&aDGJ8,8Lon!on8A, @8W0T$C0& C$T;8,8---8A, // &orth an! Central 0#erica @80&T$aY0 0&D B05BYD08,8%aint John2s8A, @8B0M0J0%8,8&assau8A, @8B05B0DG%8,8Bri!geto:n8A, @8BEL$TE8,8Bel#o"an8A, @8C0&0D08,8Gtta:a8A, @8CG%T0 5$C08,8%an Jose8A, @8CYB08,8Mavana8A, @8DGJ$&$C08,85oseau8A, @8DGJ$&$C0& 5EPYBL$C8,8%anto Do#ingo8A, @8EL %0LW0DG58,8%an %alva!or8A, @8a5E&0D08,8%aint aeorge2s8A, @8aY0TEJ0L08,8auate#ala City8A, @8M0$T$8,8Port-au-Prince8A, @8MG&DY50%8,8Tegucigal"a8A, @8J0J0$C08,8`ingston8A, @8JE9$CG8,8Je6ico City8A, @8&$C050aY08,8Janagua8A, @8P0&0J08,8Pana#a City8A, @8%T. `$TT%8,8-8A, @8&EW$%8,8Basseterre8A, @8%T. LYC$08,8Castries8A, @8%T. W$&CE&T 0&D TME a5E&0D$&E%8,8`ingsto:n8A, @8Y&$TED %T0TE% GL 0JE5$C08,8\ashington, D.C.8A, // %outh 0#erica @805aE&T$&08,8Buenos 0ires8A, @8BGL$W$08,8%ucre -legal./La PaU-a!#inistrative.8A, @8B50T$L8,8Brasilia8A, @8CM$LE8,8%antiago8A, @8CGLGJB$08,8Bogota8A, @8ECY0DG58,8/uito8A, @8aY;0&08,8aeorgeto:n8A, @8P050aY0;8,80suncion8A, @8PE5Y8,8Li#a8A, @8%Y5$&0JE8,8Para#aribo8A, @8T5$&$D0D 0&D TGB0aG8,8Port of %"ain8A, @8Y5YaY0;8,8Jontevi!eo8A, @8WE&ETYEL08,8Caracas8A, A< A ///3>
This is si#%ly a two'di#ensional array o" )tring data@. (ere s a si#%le test using the fillA B #ethods and generators= //3 c'C3LillTest.Hava i#"ort co#.bruceeckel.util.B<
@ This data was "ound on the Internet, then %rocessed by creating a Python %rogra# *see ,,,'P)thon'org,.
474
i#"ort Hava.util.B< "ublic class LillTest @ static aenerator sg ? ne: 0rrays .5an!%tringaenerator-*.< "ublic static voi! #ain-%tringNO args. @ List list ? ne: 0rrayList-.< Collections .fill-list, sg, ,.< %yste#.out."rintln-list K 8_n8.< List list ? ne: 0rrayList-.< Collections .fill-list , Collections .ca"itals, ,.< %yste#.out."rintln-list K 8_n8.< %et set ? ne: Mash%et-.< Collections .fill-set, sg, ,.< %yste#.out."rintln-set K 8_n8.< Ja" # ? ne: MashJa"-.< Collections .fill-#, Collections .rs", %yste#.out."rintln-# K 8_n8.< Ja" # ? ne: MashJa"-.< Collections .fill-# , Collections .geogra"hy, ,.< %yste#.out."rintln-# .< A A ///3>
,.<
:ith these tools you can easily test the various containers by "illing the# with interesting data. RFSURFSTIJLT+(6PTE52TI3?U
475
only your ty%e would %revent it "ro# being a general'%ur%ose tool. So instead, the container holds re"erences to .b8ect, which is the root o" all the classes so it holds any ty%e. *)" course, this doesn t include %ri#itive ty%es, since they aren t inherited "ro# anything., This is a great solution, e&ce%t= RFSURFSTIJLT+(6PTE52TI3HU
4,)
Since the ty%e in"or#ation is thrown away when you %ut an ob0ect re"erence into a container, there s no restriction on the ty%e o" ob0ect that can be %ut into your container, even i" you #ean it to hold only, say, cats. So#eone could 0ust as easily %ut a dog into the container. RFSURFSTIJLT+(6PTE52TI33U Since the ty%e in"or#ation is lost, the only thing the container knows that it holds is a re"erence to an ob0ect. /ou #ust %er"or# a cast to the correct ty%e be"ore you use it. RFSURF STIJLT+(6PTE52TI3GU
4-)
)n the u% side, Java won t let you misuse the ob0ects that you %ut into a container. I" you throw a dog into a container o" cats and then try to treat everything in the container as a cat, you ll get a run'ti#e e&ce%tion when you %ull the dog re"erence out o" the cat container and try to cast it to a cat. RFSURFSTIJLT+(6PTE52TI3IU (ere s an e&a#%le using the basic workhorse container, Array+ist. Eor starters, you can think o" Array+ist as !an array that auto#atically e&%ands itsel".$ 4sing an Array+ist is straight"orward= create one, %ut ob0ects in using a''A B, and later get the# out with getA B using an inde& 90ust like you would with an array but without the sAuare brackets @. Array+ist also has a #ethod si7eA B to let you know how #any ele#ents have been added so you don t inadvertently run o"" the end and cause an e&ce%tion. RFSURFSTIJLT+(6PTE52TI32U Eirst, -at and
//3 c'C3Cat.Hava "ublic class Cat @ "rivate int cat&u#ber< Cat-int i. @ cat&u#ber ? i< A voi! "rint-. @
@ This is a %lace where o%erator overloading would be nice.
477
%yste#.out."rintln-8Cat S8 K cat&u#ber.< A A ///3> //3 c'C3Dog.Hava "ublic class Dog @ "rivate int !og&u#ber< Dog-int i. @ !og&u#ber ? i< A voi! "rint-. @ %yste#.out."rintln-8Dog S8 K !og&u#ber.< A A ///3> -ats and ogs are %laced into the container, then %ulled out=
//3 c'C3Cats0n!Dogs.Hava // %i#"le container e6a#"le. i#"ort Hava.util.B< "ublic class Cats0n!Dogs @ "ublic static voi! #ain-%tringNO args. @ 0rrayList cats ? ne: 0rrayList-.< for-int i ? '< i P *< iKK. cats.a!!-ne: Cat-i..< // &ot a "roble# to a!! a !og to cats3 cats.a!!-ne: Dog-*..< for-int i ? '< i P cats.siUe-.< iKK. --Cat.cats.get-i..."rint-.< // Dog is !etecte! only at run-ti#e A A ///3>
The classes -at and og are distinct9they have nothing in co##on e&ce%t that they are .b8ects. *I" you don t e&%licitly say what class you re inheriting "ro#, you auto#atically inherit "ro# .b8ect., Since Array+ist holds .b8ects, you can not only %ut -at ob0ects into this container using the Array+ist #ethod a''A B, but you can also add og ob0ects without co#%laint at either co#%ile'ti#e or run'ti#e. :hen you go to "etch out what you think are -at ob0ects using the Array+ist #ethod getA B, you get back a re"erence to an ob0ect that you #ust cast to a -at. Then you need to surround the entire e&%ression with %arentheses
478
to "orce the evaluation o" the cast be"ore calling the printA B #ethod "or -at, otherwise you ll get a synta& error. Then, at run'ti#e, when you try to cast the og ob0ect to a -at, you ll get an e&ce%tion. RFSURF STIJLT+(6PTE52TIG@U This is #ore than 0ust an annoyance. It s so#ething that can create di""icult'to'"ind bugs. I" one %art *or several %arts, o" a %rogra# inserts ob0ects into a container, and you discover only in a se%arate %art o" the %rogra# through an e&ce%tion that a bad ob0ect was %laced in the container, then you #ust "ind out where the bad insert occurred. )n the u%side, it s convenient to start with so#e standardi1ed container classes "or %rogra##ing, des%ite the scarcity and awkwardness. RFSURF STIJLT+(6PTE52TIGMU
//3 c'C3Jouse.Hava // Gverri!ing to%tring-.. "ublic class Jouse @ "rivate int #ouse&u#ber< Jouse-int i. @ #ouse&u#ber ? i< A // Gverri!e GbHect.to%tring-.3 "ublic %tring to%tring-. @ return 8This is Jouse S8 K #ouse&u#ber< A "ublic int get&u#ber-. @ return #ouse&u#ber< A
47:
A ///3> //3 c'C3\orks0ny:ay.Hava // $n s"ecial cases, things Hust // see# to :ork correctly. i#"ort Hava.util.B< class JouseTra" @ static voi! caught;a-GbHect #. @ Jouse #ouse ? -Jouse.#< // Cast fro# GbHect %yste#.out."rintln-8Jouse3 8 K #ouse.get&u#ber-..< A A "ublic class \orks0ny:ay @ "ublic static voi! #ain-%tringNO args. @ 0rrayList #ice ? ne: 0rrayList-.< for-int i ? '< i P )< iKK. #ice.a!!-ne: Jouse-i..< for-int i ? '< i P #ice.siUe-.< iKK. @ // &o cast necessary, auto#atic // call to GbHect.to%tring-.3 %yste#.out."rintln8Lree #ouse3 8 K #ice.get-i..< JouseTra".caught;a-#ice.get-i..< A A A ///3>
/ou can see to)tringA B overridden in 1o*se. In the second for loo% in mainA B you "ind the state#ent=
47;
1o*seTrap. The ca*ght:aA B #ethod acce%ts not a 1o*se, but an .b8ect, which it then casts to a 1o*se. This is Auite %resu#%tuous, o" course, since by acce%ting an .b8ect anything could be %assed to the
#ethod. (owever, i" the cast is incorrect9i" you %assed the wrong ty%e9 you ll get an e&ce%tion at run'ti#e. This is not as good as co#%ile'ti#e checking but it s still robust. Cote that in the use o" this #ethod=
JouseTra".caught;a-#ice.get-i..<
no cast is necessary. RFSURFSTIJLT+(6PTE52TIG?U
//3 c'C3JouseList.Hava // 0 ty"e-conscious 0rrayList. i#"ort Hava.util.B< "ublic class JouseList @ "rivate 0rrayList list ? ne: 0rrayList-.< "ublic voi! a!!-Jouse #. @ list.a!!-#.< A "ublic Jouse get-int in!e6. @ return -Jouse.list.get-in!e6.< A "ublic int siUe-. @ return list.siUe-.< A A ///3>
(ere s a test "or the new container=
//3 c'C3JouseListTest.Hava "ublic class JouseListTest @ "ublic static voi! #ain-%tringNO args. @ JouseList #ice ? ne: JouseList-.< for-int i ? '< i P )< iKK. #ice.a!!-ne: Jouse-i..< for-int i ? '< i P #ice.siUe-.< iKK.
48=
JouseTra".caught;a-#ice.get-i..< A A ///3>
This is si#ilar to the %revious e&a#%le, e&ce%t that the new 1o*se+ist class has a private #e#ber o" ty%e Array+ist, and #ethods 0ust like Array+ist. (owever, it doesn t acce%t and %roduce generic .b8ects, only 1o*se ob0ects. RFSURFSTIJLT+(6PTE52TIGHU Cote that i" 1o*se+ist had instead been inherited "ro# Array+ist, the a''A1o*seB #ethod would si#%ly overload the e&isting a''A.b8ectB and there would still be no restriction on what ty%e o" ob0ects could be added. Thus, the 1o*se+ist beco#es a surrogate to the Array+ist, %er"or#ing so#e activities be"ore %assing on the res%onsibility *see Thinking in Patterns ,ith Java, downloadable at ,,,'0ruceEckel'com,. RFSURFSTIJLT+(6PTE52TIG3U Because a 1o*se+ist will acce%t only a 1o*se, i" you say=
#ice.a!!-ne: Pigeon-..<
you will get an error #essage at com ile/time. This a%%roach, while #ore tedious "ro# a coding stand%oint, will tell you i##ediately i" you re using a ty%e i#%ro%erly. RFSURFSTIJLT+(6PTE52TIGGU Cote that no cast is necessary when using getA B9it s always a 1o*se. RF SURFSTIJLT+(6PTE52TIGIU
arameteri?ed t:.es
This kind o" %roble# isn t isolated9there are nu#erous cases in which you need to create new ty%es based on other ty%es, and in which it is use"ul to have s%eci"ic ty%e in"or#ation at co#%ile'ti#e. This is the conce%t o" a arameteri?ed t) e. In +<<, this is directly su%%orted by the language with tem lates. It is likely that a "uture version o" Java will su%%ort so#e variation o" %ara#eteri1ed ty%es; the current "ront'runner auto#atically creates classes si#ilar to 1o*se+ist. RFSURF STIJLT+(6PTE52TIG2U
481
Iterators
In any container class, you #ust have a way to %ut things in and a way to get things out. 6"ter all, that s the %ri#ary 0ob o" a container9to hold things. In the Array+ist, a''A B is the way that you insert ob0ects, and getA B is one way to get things out. Array+ist is Auite "le&ible9you can select anything at any ti#e, and select #ulti%le ele#ents at once using di""erent inde&es. RFSURFSTIJLT+(6PTE52TII@U I" you want to start thinking at a higher level, there s a drawback= you need to know the e&act ty%e o" the container in order to use it. This #ight not see# bad at "irst, but what i" you start out using an Array+ist, and later on in your %rogra# you discover that because o" the way you are using the container it would be #uch #ore e""icient to use a +inke'+ist insteadO )r su%%ose you d like to write a %iece o" generic code that doesn t know or care what ty%e o" container it s working with, so that it could be used on di""erent ty%es o" containers without rewriting that codeO RFSURFSTIJLT+(6PTE52TIIMU The conce%t o" an iterator can be used to achieve this abstraction. 6n iterator is an ob0ect whose 0ob is to #ove through a seAuence o" ob0ects and select each ob0ect in that seAuence without the client %rogra##er knowing or caring about the underlying structure o" that seAuence. In addition, an iterator is usually what s called a !light'weight$ ob0ect= one that s chea% to create. Eor that reason, you ll o"ten "ind see#ingly strange constraints "or iterators; "or e&a#%le, so#e iterators can #ove in only one direction. RFSURFSTIJLT+(6PTE52TIIKU The Java Iterator is an e&a#%le o" an iterator with these kinds o" constraints. There s not #uch you can do with one e&ce%t= RFSURF STIJLT+(6PTE52TIILU
44)
6sk a container to hand you an Iterator using a #ethod called iteratorA B. This Iterator will be ready to return the "irst ele#ent in the seAuence on your "irst call to its ne4tA B #ethod. 8et the ne&t ob0ect in the seAuence with ne4tA B. See i" there are any #ore ob0ects in the seAuence with has/e4tA B.
45) 46)
482
57)
That s all. It s a si#%le i#%le#entation o" an iterator, but still %ower"ul *and there s a #ore so%histicated +istIterator "or +ists,. To see how it works, let s revisit the -atsAn' ogs!8ava %rogra# "ro# earlier in this cha%ter. In the original version, the #ethod getA B was used to select each ele#ent, but in the "ollowing #odi"ied version an Iterator is used= RF SURFSTIJLT+(6PTE52TII?U
//3 c'C3Cats0n!Dogs .Hava // %i#"le container :ith $terator. i#"ort Hava.util.B< "ublic class Cats0n!Dogs @ "ublic static voi! #ain-%tringNO args. @ 0rrayList cats ? ne: 0rrayList-.< for-int i ? '< i P *< iKK. cats.a!!-ne: Cat-i..< $terator e ? cats.iterator-.< :hile-e.has&e6t-.. --Cat.e.ne6t-..."rint-.< A A ///3>
/ou can see that the last "ew lines now use an Iterator to ste% through the seAuence instead o" a for loo%. :ith the Iterator, you don t need to worry about the nu#ber o" ele#ents in the container. That s taken care o" "or you by has/e4tA B and ne4tA B. RFSURFSTIJLT+(6PTE52TIIHU 6s another e&a#%le, consider the creation o" a general'%ur%ose %rinting #ethod=
//3 c'C3Ma#sterJaUe.Hava // Ysing an $terator. i#"ort Hava.util.B< class Ma#ster @ "rivate int ha#ster&u#ber< Ma#ster-int i. @ ha#ster&u#ber ? i< A "ublic %tring to%tring-. @ return 8This is Ma#ster S8 K ha#ster&u#ber< A
483
A class Printer @ static voi! "rint0ll-$terator e. @ :hile-e.has&e6t-.. %yste#.out."rintln-e.ne6t-..< A A "ublic class Ma#sterJaUe @ "ublic static voi! #ain-%tringNO args. @ 0rrayList v ? ne: 0rrayList-.< for-int i ? '< i P )< iKK. v.a!!-ne: Ma#ster-i..< Printer."rint0ll-v.iterator-..< A A ///3>
Dook closely at printAllA B. Cote that there s no in"or#ation about the ty%e o" seAuence. 6ll you have is an Iterator, and that s all you need to know about the seAuence= that you can get the ne&t ob0ect, and that you can know when you re at the end. This idea o" taking a container o" ob0ects and %assing through it to %er"or# an o%eration on each one is %ower"ul, and will be seen throughout this book. RFSURF STIJLT+(6PTE52TII3U The e&a#%le is even #ore generic, since it i#%licitly uses the .b8ect! to)tringA B #ethod. The printlnA B #ethod is overloaded "or all the %ri#itive ty%es as well as .b8ect; in each case a )tring is auto#atically %roduced by calling the a%%ro%riate to)tringA B #ethod. RFSURF STIJLT+(6PTE52TIIGU 6lthough it s unnecessary, you can be #ore e&%licit using a cast, which has the e""ect o" calling to)tringA B=
%yste#.out."rintln--%tring.e.ne6t-..<
In general, however, you ll want to do so#ething #ore than call .b8ect #ethods, so you ll run u% against the ty%e'casting issue again. /ou #ust assu#e you ve gotten an Iterator to a seAuence o" the %articular ty%e
484
you re interested in, and cast the resulting ob0ects to that ty%e *getting a run'ti#e e&ce%tion i" you re wrong,. RFSURFSTIJLT+(6PTE52TIIIU
Cnintended recursion
Because *like every other class,, the Java standard containers are inherited "ro# .b8ect, they contain a to)tringA B #ethod. This has been overridden so that they can %roduce a )tring re%resentation o" the#selves, including the ob0ects they hold. Inside Array+ist, "or e&a#%le, the to)tringA B ste%s through the ele#ents o" the Array+ist and calls to)tringA B "or each one. Su%%ose you d like to %rint the address o" your class. It see#s to #ake sense to si#%ly re"er to this *in %articular, +<< %rogra##ers are %rone to this a%%roach,=
//3 c'C3$nfinite5ecursion.Hava // 0cci!ental recursion. i#"ort Hava.util.B< "ublic class $nfinite5ecursion @ "ublic %tring to%tring-. @ return 8 $nfinite5ecursion a!!ress3 8 K this K 8_n8< A "ublic static voi! #ain-%tringNO args. @ 0rrayList v ? ne: 0rrayList-.< for-int i ? '< i P ('< iKK. v.a!!-ne: $nfinite5ecursion-..< %yste#.out."rintln-v.< A A ///3>
I" you si#%ly create an Infinite$ec*rsion ob0ect and then %rint it, you ll get an endless seAuence o" e&ce%tions. This is also true i" you %lace the Infinite$ec*rsion ob0ects in an Array+ist and %rint that Array+ist as shown here. :hat s ha%%ening is auto#atic ty%e conversion "or )trings. :hen you say=
485
calling to)tringA B, which %roduces a recursive call. RFSURF STIJLT+(6PTE52TII2U I" you really do want to %rint the address o" the ob0ect in this case, the solution is to call the .b8ect to)tringA B #ethod, which does 0ust that. So instead o" saying this, you d say s*per!to)tringA B. *This only works i" youVre directly inheriting "ro# .b8ect, or i" none o" your %arent classes have overridden the to)tringA B #ethod., RFSURF STIJLT+(6PTE52TI2@U
Container ta0onom:
-ollections and 1aps #ay be i#%le#ented in di""erent ways, according
to your %rogra##ing needs. It s hel%"ul to look at a diagra# o" the Java K containers=
487
Iterator
roduces
Collection
roduces
Ma.
&istIterator
roduces
AbstractCollection
Abstract&ist
>ash1et
#ree1et
Arra:&ist
Abstract1e%uential&ist
Collections Arra:s
This diagra# can be a bit overwhel#ing at "irst, but you ll see that there are really only three container co#%onents= 1ap, +ist, and )et, and only two or three i#%le#entations o" each one *with, ty%ically, a %re"erred version,. :hen you see this, the containers are not so daunting. RFSURF STIJLT+(6PTE52TI2MU The dotted bo&es re%resent interfaces, the dashed bo&es re%resent abstract classes, and the solid bo&es are regular *concrete, classes. The dotted'line arrows indicate that a %articular class is i#%le#enting an interface *or in the case o" an abstract class, %artially i#%le#enting that interface,. The solid arrows show that a class can %roduce ob0ects o" the class the arrow is %ointing to. Eor e&a#%le, any -ollection can %roduce an Iterator, while a +ist can %roduce a +istIterator *as well as an ordinary Iterator, since +ist is inherited "ro# -ollection,. RFSURF STIJLT+(6PTE52TI2KU
488
The inter"aces that are concerned with holding ob0ects are -ollection, +ist, )et, and 1ap. Ideally, you ll write #ost o" your code to talk to these inter"aces, and the only %lace where you ll s%eci"y the %recise ty%e you re using is at the %oint o" creation. So you can create a +ist like this= RFSURF STIJLT+(6PTE52TI2LU
48:
Iterator
roduces
Collection
roduces
Ma.
&istIterator
roduces
&ist
1et
>ashMa.
#reeMa.
Weak>ashMa.
Arra:&ist
&inked&ist
>ash1et
#ree1et
Ctilities Collections
Com.arable
Com.arator
Arra:s
Cow it only includes the inter"aces and classes that you will encounter on a regular basis, and also the ele#ents that we will "ocus on in this cha%ter. RFSURFSTIJLT+(6PTE52TI23U (ere s a si#%le e&a#%le, which "ills a -ollection *re%resented here with an Array+ist, with )tring ob0ects, and then %rints each ele#ent in the -ollection=
Collections.
"ublic class %i#"leCollection @ "ublic static voi! #ain-%tringNO args. @ // Y"cast because :e Hust :ant to // :ork :ith Collection features Collection c ? ne: 0rrayList-.< for-int i ? '< i P ('< iKK. c.a!!-$nteger.to%tring-i..< $terator it ? c.iterator-.< :hile-it.has&e6t-.. %yste#.out."rintln-it.ne6t-..< A A ///3>
48;
The "irst line in mainA B creates an Array+ist ob0ect and then u%casts it to a -ollection. Since this e&a#%le uses only the -ollection #ethods, any ob0ect o" a class inherited "ro# -ollection would work, but Array+ist is the ty%ical workhorse -ollection. RFSURF STIJLT+(6PTE52TI2GU The a''A B #ethod, as its na#e suggests, %uts a new ele#ent in the -ollection. (owever, the docu#entation care"ully states that a''A B !ensures that this +ontainer contains the s%eci"ied ele#ent.$ This is to allow "or the #eaning o" )et, which adds the ele#ent only i" it isn t already there. :ith an Array+ist, or any sort o" +ist, a''A B always #eans !%ut it in,$ because +ists don t care i" there are du%licates. RFSURF STIJLT+(6PTE52TI2IU 6ll -ollections can %roduce an Iterator via their iteratorA B #ethod. (ere, an Iterator is created and used to traverse the -ollection, %rinting each ele#ent. RFSURFSTIJLT+(6PTE52TI22U
$ollection functionalit:
The "ollowing table shows everything you can do with a -ollection *not including the #ethods that auto#atically co#e through with .b8ect,, and thus, everything you can do with a )et or a +ist. * +ist also has additional "unctionality., 1aps are not inherited "ro# -ollection, and will be treated se%arately.
boolean a''A.b8ectB
Ensures that the container holds the argu#ent. 5eturns "alse i" it doesn t add the argu#ent. *This is an !o%tional$ #ethod, described later in this cha%ter., 6dds all the ele#ents in the argu#ent. 5eturns tr*e i" any ele#ents were added. *!)%tional.$, 5e#oves all the ele#ents in the container. *!)%tional.$, tr*e i" the container holds the argu#ent.
4:=
boolean containsAll A-ollectionB boolean is&mptyA B Iterator iteratorA B boolean removeA.b8ectB boolean removeAll A-ollectionB boolean retainAll A-ollectionB
tr*e i" the container holds all the ele#ents in the argu#ent. tr*e i" the container has no ele#ents. 5eturns an Iterator that you can use to #ove through the ele#ents in the container. I" the argu#ent is in the container, one instance o" that ele#ent is re#oved. 5eturns tr*e i" a re#oval occurred. *!)%tional.$, 5e#oves all the ele#ents that are contained in the argu#ent. 5eturns tr*e i" any re#ovals occurred. *!)%tional.$, 5etains only ele#ents that are contained in the argu#ent *an !intersection$ "ro# set theory,. 5eturns tr*e i" any changes occurred. *!)%tional.$, 5eturns the nu#ber o" ele#ents in the container. 5eturns an array containing all the ele#ents in the container. 5eturns an array containing all the ele#ents in the container, whose ty%e is that o" the array a rather than %lain .b8ect *you #ust cast the array to the right ty%e,.
Cotice that there s no getA B "unction "or rando#'access ele#ent selection. That s because -ollection also includes )et, which #aintains its own internal ordering *and thus #akes rando#'access looku% #eaningless,. Thus, i" you want to e&a#ine all the ele#ents o" a -ollection you #ust use an iterator; that s the only way to "etch things back. The "ollowing e&a#%le de#onstrates all o" these #ethods. 6gain, these work with anything that inherits "ro# -ollection, but an Array+ist is used as a kind o" !least'co##on deno#inator$= RFSURF STIJLT+(6PTE52TIM@@U
4:1
//3 c'C3Collection(.Hava // Things you can !o :ith all Collections. i#"ort Hava.util.B< i#"ort co#.bruceeckel.util.B< "ublic class Collection( @ "ublic static voi! #ain-%tringNO args. @ Collection c ? ne: 0rrayList-.< Collections .fill-c, Collections .countries, ('.< c.a!!-8ten8.< c.a!!-8eleven8.< %yste#.out."rintln-c.< // Jake an array fro# the List3 GbHectNO array ? c.to0rray-.< // Jake a %tring array fro# the List3 %tringNO str ? -%tringNO.c.to0rray-ne: %tringN(O.< // Lin! #a6 an! #in ele#ents< this #eans // !ifferent things !e"en!ing on the :ay // the Co#"arable interface is i#"le#ente!3 %yste#.out."rintln-8Collections.#a6-c. ? 8 K Collections.#a6-c..< %yste#.out."rintln-8Collections.#in-c. ? 8 K Collections.#in-c..< // 0!! a Collection to another Collection Collection c ? ne: 0rrayList-.< Collections .fill-c , Collections .countries, ('.< c.a!!0ll-c .< %yste#.out."rintln-c.< c.re#ove-CountryCa"itals."airsN'ON'O.< %yste#.out."rintln-c.< c.re#ove-CountryCa"itals."airsN(ON'O.< %yste#.out."rintln-c.< // 5e#ove all co#"onents that are in the // argu#ent collection3 c.re#ove0ll-c .< %yste#.out."rintln-c.< c.a!!0ll-c .< %yste#.out."rintln-c.<
4:2
// $s an ele#ent in this Collection[ %tring val ? CountryCa"itals."airsN)ON'O< %yste#.out."rintln8c.contains-8 K val K 8. ? 8 K c.contains-val..< // $s a Collection in this Collection[ %yste#.out."rintln8c.contains0ll-c . ? 8K c.contains0ll-c ..< Collection c) ? --List.c..subList-), ,.< // `ee" all the ele#ents that are in both // c an! c) -an intersection of sets.3 c .retain0ll-c).< %yste#.out."rintln-c.< // Thro: a:ay all the ele#ents // in c that also a""ear in c)3 c .re#ove0ll-c).< %yste#.out."rintln-8c.isE#"ty-. ? 8 K c.isE#"ty-..< c ? ne: 0rrayList-.< Collections .fill-c, Collections .countries, ('.< %yste#.out."rintln-c.< c.clear-.< // 5e#ove all ele#ents %yste#.out."rintln-8after c.clear-.38.< %yste#.out."rintln-c.< A A ///3> Array+ists are created containing di""erent sets o" data and u%cast to -ollection ob0ects, so it s clear that nothing other than the -ollection inter"ace is being used. mainA B uses si#%le e&ercises to show all o" the #ethods in -ollection. RFSURFSTIJLT+(6PTE52TIM@MU
The "ollowing sections describe the various i#%le#entations o" +ist, )et, and 1ap and indicate in each case *with an asterisk, which one should be your de"ault choice. /ou ll notice that the legacy classes Vector, )tack, and Hashtable are not included because in all cases there are %re"erred classes within the Java K +ontainers. RFSURFSTIJLT+(6PTE52TIM@KU
4:3
#ist functionalit:
The basic +ist is Auite si#%le to use, as you ve seen so "ar with Array+ist. 6lthough #ost o" the ti#e you ll 0ust use a''A B to insert ob0ects, getA B to get the# out one at a ti#e, and iteratorA B to get an Iterator to "or the seAuence, there s also a set o" other #ethods that can be use"ul. RFSURFSTIJLT+(6PTE52TIM@LU In addition, there are actually two ty%es o" +ist= the basic Array+ist, which e&cels at rando#ly accessing ele#ents, and the #uch #ore %ower"ul +inke'+ist *which is not designed "or "ast rando# access, but has a #uch #ore general set o" #ethods,.
+ist
*inter"ace,
Array+ist
B
+inke'+i st
)rder is the #ost i#%ortant "eature o" a +ist; it %ro#ises to #aintain ele#ents in a %articular seAuence. +ist adds a nu#ber o" #ethods to -ollection that allow insertion and re#oval o" ele#ents in the #iddle o" a +ist. *This is reco##ended only "or a +inke'+ist., 6 +ist will %roduce a +istIterator, and using this you can traverse the +ist in both directions, as well as insert and re#ove ele#ents in the #iddle o" the +ist. 6 +ist i#%le#ented with an array. 6llows ra%id rando# access to ele#ents, but is slow when inserting and re#oving ele#ents "ro# the #iddle o" a list. +istIterator should be used only "or back'and'"orth traversal o" an Array+ist, but not "or inserting and re#oving ele#ents, which is e&%ensive co#%ared to +inke'+ist. Provides o%ti#al seAuential access, with ine&%ensive insertions and deletions "ro# the #iddle o" the +ist. 5elatively slow "or rando# access. *4se Array+ist instead., 6lso has a''FirstA B, a''+astA B, getFirstA B, get+ast A B, removeFirstA B, and remove+astA B *which are not de"ined in any inter"aces or base classes, to allow it to be used as a stack, a Aueue, and a deAue.
4:4
The #ethods in the "ollowing e&a#%le each cover a di""erent grou% o" activities= things that every list can do * basicTestA B,, #oving around with an Iterator * iter1otionA B, versus changing things with an Iterator * iter1anip*lationA B,, seeing the e""ects o" +ist #ani%ulation * testVis*alA B,, and o%erations available only to +inke'+ists.
//3 c'C3List(.Hava // Things you can !o :ith Lists. i#"ort Hava.util.B< i#"ort co#.bruceeckel.util.B< "ublic class List( @ "ublic static List fill-List a. @ Collections .countries.reset-.< Collections .fill-a, Collections .countries, ('.< return a< A static boolean b< static GbHect o< static int i< static $terator it< static List$terator lit< "ublic static voi! basicTest-List a. @ a.a!!-(, 868.< // 0!! at location ( a.a!!-868.< // 0!! at en! // 0!! a collection3 a.a!!0ll-fill-ne: 0rrayList-...< // 0!! a collection starting at location )3 a.a!!0ll-), fill-ne: 0rrayList-...< b ? a.contains-8(8.< // $s it in there[ // $s the entire collection in there[ b ? a.contains0ll-fill-ne: 0rrayList-...< // Lists allo: ran!o# access, :hich is chea" // for 0rrayList, e6"ensive for Linke!List3 o ? a.get-(.< // aet obHect at location ( i ? a.in!e6Gf-8(8.< // Tell in!e6 of obHect b ? a.isE#"ty-.< // 0ny ele#ents insi!e[ it ? a.iterator-.< // Gr!inary $terator lit ? a.list$terator-.< // List$terator
4:5
lit ? a.list$terator-).< // %tart at loc ) i ? a.last$n!e6Gf-8(8.< // Last #atch a.re#ove-(.< // 5e#ove location ( a.re#ove-8)8.< // 5e#ove this obHect a.set-(, 8y8.< // %et location ( to 8y8 // `ee" everything that2s in the argu#ent // -the intersection of the t:o sets.3 a.retain0ll-fill-ne: 0rrayList-...< // 5e#ove everything that2s in the argu#ent3 a.re#ove0ll-fill-ne: 0rrayList-...< i ? a.siUe-.< // Mo: big is it[ a.clear-.< // 5e#ove all ele#ents A "ublic static voi! iterJotion-List a. @ List$terator it ? a.list$terator-.< b ? it.has&e6t-.< b ? it.hasPrevious-.< o ? it.ne6t-.< i ? it.ne6t$n!e6-.< o ? it."revious-.< i ? it."revious$n!e6-.< A "ublic static voi! iterJani"ulation-List a. @ List$terator it ? a.list$terator-.< it.a!!-8I*8.< // Just #ove to an ele#ent after a!!-.3 it.ne6t-.< // 5e#ove the ele#ent that :as Hust "ro!uce!3 it.re#ove-.< // Just #ove to an ele#ent after re#ove-.3 it.ne6t-.< // Change the ele#ent that :as Hust "ro!uce!3 it.set-8I*8.< A "ublic static voi! testWisual-List a. @ %yste#.out."rintln-a.< List b ? ne: 0rrayList-.< fill-b.< %yste#.out."rint-8b ? 8.< %yste#.out."rintln-b.< a.a!!0ll-b.<
4:7
a.a!!0ll-fill-ne: 0rrayList-...< %yste#.out."rintln-a.< // $nsert, re#ove, an! re"lace ele#ents // using a List$terator3 List$terator 6 ? a.list$terator-a.siUe-./ .< 6.a!!-8one8.< %yste#.out."rintln-a.< %yste#.out."rintln-6.ne6t-..< 6.re#ove-.< %yste#.out."rintln-6.ne6t-..< 6.set-8I*8.< %yste#.out."rintln-a.< // Traverse the list back:ar!s3 6 ? a.list$terator-a.siUe-..< :hile-6.hasPrevious-.. %yste#.out."rint-6."revious-. K 8 8.< %yste#.out."rintln-.< %yste#.out."rintln-8testWisual finishe!8.< A // There are so#e things that only // Linke!Lists can !o3 "ublic static voi! testLinke!List-. @ Linke!List ll ? ne: Linke!List-.< fill-ll.< %yste#.out."rintln-ll.< // Treat it like a stack, "ushing3 ll.a!!Lirst-8one8.< ll.a!!Lirst-8t:o8.< %yste#.out."rintln-ll.< // Like 8"eeking8 at the to" of a stack3 %yste#.out."rintln-ll.getLirst-..< // Like "o""ing a stack3 %yste#.out."rintln-ll.re#oveLirst-..< %yste#.out."rintln-ll.re#oveLirst-..< // Treat it like a =ueue, "ulling ele#ents // off the tail en!3 %yste#.out."rintln-ll.re#oveLast-..< // \ith the above o"erations, it2s a !e=ueue4 %yste#.out."rintln-ll.< A "ublic static voi! #ain-%tringNO args. @
4:8
// Jake an! fill a ne: list each ti#e3 basicTest-fill-ne: Linke!List-...< basicTest-fill-ne: 0rrayList-...< iterJotion-fill-ne: Linke!List-...< iterJotion-fill-ne: 0rrayList-...< iterJani"ulation-fill-ne: Linke!List-...< iterJani"ulation-fill-ne: 0rrayList-...< testWisual-fill-ne: Linke!List-...< testLinke!List-.< A A ///3>
In basicTestA B and iter1otionA B the calls are si#%ly #ade to show the %ro%er synta&, and while the return value is ca%tured, it is not used. In so#e cases, the return value isn t ca%tured since it isn t ty%ically used. /ou should look u% the "ull usage o" each o" these #ethods in the online docu#entation "ro# >ava'sun'com be"ore you use the#. RFSURF STIJLT+(6PTE52TIM@?U
//3 c'C3%tackL.Hava // Jaking a stack fro# a Linke!List. i#"ort Hava.util.B< i#"ort co#.bruceeckel.util.B< "ublic class %tackL @ "rivate Linke!List list ? ne: Linke!List-.< "ublic voi! "ush-GbHect v. @ list.a!!Lirst-v.<
4::
A "ublic GbHect to"-. @ return list.getLirst-.< A "ublic GbHect "o"-. @ return list.re#oveLirst-.< A "ublic static voi! #ain-%tringNO args. @ %tackL stack ? ne: %tackL-.< for-int i ? '< i P ('< iKK. stack."ush-Collections .countries.ne6t-..< %yste#.out."rintln-stack.to"-..< %yste#.out."rintln-stack.to"-..< %yste#.out."rintln-stack."o"-..< %yste#.out."rintln-stack."o"-..< %yste#.out."rintln-stack."o"-..< A A ///3>
I" you want only stack behavior, inheritance is ina%%ro%riate here because it would %roduce a class with all the rest o" the +inke'+ist #ethods *you ll see later that this very #istake was #ade by the Java M.@ library designers with )tack,. RFSURFSTIJLT+(6PTE52TIM@GU
//3 c'C3/ueue.Hava // Jaking a =ueue fro# a Linke!List. i#"ort Hava.util.B< "ublic class /ueue @ "rivate Linke!List list ? ne: Linke!List-.< "ublic voi! "ut-GbHect v. @ list.a!!Lirst-v.< A "ublic GbHect get-. @ return list.re#oveLast-.< A "ublic boolean isE#"ty-. @
4:;
return list.isE#"ty-.< A "ublic static voi! #ain-%tringNO args. @ /ueue =ueue ? ne: /ueue-.< for-int i ? '< i P ('< iKK. =ueue."ut-$nteger.to%tring-i..< :hile-4=ueue.isE#"ty-.. %yste#.out."rintln-=ueue.get-..< A A ///3>
/ou can also easily create a de#ue *double'ended Aueue, "ro# a +inke'+ist. This is like a Aueue, but you can add and re#ove ele#ents "ro# either end. RFSURFSTIJLT+(6PTE52TIM@IU
Set functionalit:
)et has e&actly the sa#e inter"ace as -ollection, so there isn t any e&tra "unctionality like there is with the two di""erent +ists. Instead, the )et is e&actly a -ollection, it 0ust has di""erent behavior. *This is the ideal use o" inheritance and %oly#or%his#= to e&%ress di""erent behavior., 6 )et re"uses to hold #ore than one instance o" each ob0ect value *what constitutes the !value$ o" an ob0ect is #ore co#%le&, as you shall see,. )et
*inter"ace, Each ele#ent that you add to the )et #ust be uniAue; otherwise the )et doesn t add the du%licate ele#ent. .b8ects added to a )et #ust de"ine eC*alsA B to establish ob0ect uniAueness. )et has e&actly the sa#e inter"ace as -ollection. The )et inter"ace does not guarantee it will #aintain its ele#ents in any %articular order. Eor )ets where "ast looku% ti#e is i#%ortant. .b8ects #ust also de"ine hash-o'eA B. 6n ordered )et backed by a tree. This way, you can e&tract an ordered seAuence "ro# a )et.
Hash)etB Tree)et
The "ollowing e&a#%le does not show everything you can do with a )et, since the inter"ace is the sa#e as -ollection, and so was e&ercised in the %revious e&a#%le. Instead, this de#onstrates the behavior that #akes a )et uniAue=
4;=
//3 c'C3%et(.Hava // Things you can !o :ith %ets. i#"ort Hava.util.B< i#"ort co#.bruceeckel.util.B< "ublic class %et( @ static Collections .%tringaenerator gen ? Collections .countries< "ublic static voi! testWisual-%et a. @ Collections .fill-a, gen.reset-., ('.< Collections .fill-a, gen.reset-., ('.< Collections .fill-a, gen.reset-., ('.< %yste#.out."rintln-a.< // &o !u"licates4 // 0!! another set to this one3 a.a!!0ll-a.< a.a!!-8one8.< a.a!!-8one8.< a.a!!-8one8.< %yste#.out."rintln-a.< // Look so#ething u"3 %yste#.out."rintln-8a.contains-_8one_8.3 8 K a.contains-8one8..< A "ublic static voi! #ain-%tringNO args. @ %yste#.out."rintln-8Mash%et8.< testWisual-ne: Mash%et-..< %yste#.out."rintln-8Tree%et8.< testWisual-ne: Tree%et-..< A A ///3>
7u%licate values are added to the )et, but when it is %rinted you ll see the )et has acce%ted only one instance o" each value. RFSURF STIJLT+(6PTE52TIM@2U :hen you run this %rogra# you ll notice that the order #aintained by the
Hash)et is di""erent "ro# Tree)et, since each has a di""erent way o" storing ele#ents so they can be located later. * Tree)et kee%s the# sorted, while Hash)et uses a hashing "unction, which is designed
s%eci"ically "or ra%id looku%s., :hen creating your own ty%es, be aware that a )et needs a way to #aintain a storage order, which #eans you
4;1
#ust i#%le#ent the -omparable inter"ace and de"ine the compareTo A B #ethod. (ere s an e&a#%le=
//3 c'C3%et .Hava // Putting your o:n ty"e in a %et. i#"ort Hava.util.B< class JyTy"e i#"le#ents Co#"arable @ "rivate int i< "ublic JyTy"e-int n. @ i ? n< A "ublic boolean e=uals-GbHect o. @ return -o instanceof JyTy"e. DD -i ?? --JyTy"e.o..i.< A "ublic int hashCo!e-. @ return i< A "ublic %tring to%tring-. @ return i K 8 8< A "ublic int co#"areTo-GbHect o. @ int i ? --JyTy"e.o..i< return -i P i [ -( 3 -i ?? i [ ' 3 (..< A A "ublic class %et @ "ublic static %et fill-%et a, int siUe. @ for-int i ? '< i P siUe< iKK. a.a!!-ne: JyTy"e-i..< return a< A "ublic static voi! test-%et a. @ fill-a, ('.< fill-a, ('.< // Try to a!! !u"licates fill-a, ('.< a.a!!0ll-fill-ne: Tree%et-., ('..< %yste#.out."rintln-a.< A "ublic static voi! #ain-%tringNO args. @ test-ne: Mash%et-..< test-ne: Tree%et-..< A A ///3>
4;2
The "or# "or the de"initions "or eC*alsA B and hash-o'eA B will be described later in this cha%ter. /ou #ust de"ine an eC*alsA B in both cases, but the hash-o'eA B is absolutely necessary only i" the class will be %laced in a Hash)et *which is likely, since that should generally be your "irst choice as a )et i#%le#entation,. (owever, as a %rogra##ing style you should always override hash-o'eA B when you override eC*alsA B. This %rocess will be "ully detailed later in this cha%ter. RFSURF STIJLT+(6PTE52TIMM@U In the compareToA B, note that I did not use the !si#%le and obvious$ "or# ret*rn i6iI. 6lthough this is a co##on %rogra##ing error, it would only work %ro%erly i" i and iI were !unsigned$ ints *i" Java had an !unsigned$ keyword, which it does not,. It breaks "or Java s signed int, which is not big enough to re%resent the di""erence o" two signed ints. I" i is a large %ositive integer and 8 is a large negative integer, i68 will over"low and return a negative value, which will not work. RFSURF STIJLT+(6PTE52TIMMMU
SortedSet
I" you have a )orte')et *o" which Tree)et is the only one available,, the ele#ents are guaranteed to be in sorted order which allows additional "unctionality to be %rovided with these #ethods in the )orte')et inter"ace= RFSURFSTIJLT+(6PTE52TIMMKU
-omparator comparatorAB< Produces the -omparator used "or this )et, or n*ll "or natural ordering. .b8ect firstAB< Produces the lowest ele#ent. .b8ect lastAB< Produces the highest ele#ent. )orte')et s*b)etAfrom&lement, to&lementB< Produces a view o" this )et with ele#ents "ro# from&lement, inclusive, to to&lement, e&clusive. )orte')et hea')etAto&lementB< Produces a view o" this )et with
ele#ents less than to&lement.
)orte')et tail)etAfrom&lementB< Produces a view o" this )et with ele#ents greater than or eAual to from&lement.
4;3
3a
functionalit:
6n Array+ist allows you to select "ro# a seAuence o" ob0ects using a nu#ber, so in a sense it associates nu#bers to ob0ects. But what i" you d like to select "ro# a seAuence o" ob0ects using so#e other criterionO 6 stack is an e&a#%le= its selection criterion is !the last thing %ushed on the stack.$ 6 %ower"ul twist on this idea o" !selecting "ro# a seAuence$ is alternately ter#ed a ma , a dictionar)D or an associative arra). +once%tually, it see#s like an Array+ist, but instead o" looking u% ob0ects using a nu#ber, you look the# u% using another ob>ect. This is o"ten a key %rocess in a %rogra#. RFSURFSTIJLT+(6PTE52TIMMLU The conce%t shows u% in Java as the 1ap inter"ace. The p*tA.b8ect key, .b8ect val*eB #ethod adds a value *the thing you want,, and associates it with a key *the thing you look it u% with,. getA.b8ect keyB %roduces the value given the corres%onding key. /ou can also test a 1ap to see i" it contains a key or a value with contains%eyA B and containsVal*eA B. RFSURFSTIJLT+(6PTE52TIMM?U The standard Java library contains two di""erent ty%es o" 1aps= Hash1ap and Tree1ap. Both have the sa#e inter"ace *since they both i#%le#ent 1ap,, but they di""er in one distinct way= e""iciency. I" you look at what #ust be done "or a getA B, it see#s %retty slow to search through *"or e&a#%le, an Array+ist "or the key. This is where Hash1ap s%eeds things u%. Instead o" a slow search "or the key, it uses a s%ecial value called a hash code. The hash code is a way to take so#e in"or#ation in the ob0ect in Auestion and turn it into a !relatively uniAue$ int "or that ob0ect. 6ll Java ob0ects can %roduce a hash code, and hash-o'eA B is a #ethod in the root class .b8ect. 6 Hash1ap takes the hash-o'eA B o" the ob0ect and uses it to Auickly hunt "or the key. This results in a dra#atic %er"or#ance i#%rove#ent@.
@ I" these s%eedu%s still don t #eet your %er"or#ance needs, you can "urther accelerate table looku% by writing your own 1ap and custo#i1ing it to your %articular ty%es to avoid delays due to casting to and "ro# .b8ects. To reach even higher levels o" %er"or#ance, s%eed enthusiasts can use 7onald >nuth s The "rt o$ Com uter ProgrammingD Colume 3! Sorting and SearchingD Second Edition to re%lace over"low bucket lists with arrays that have two additional bene"its= they can be o%ti#i1ed "or disk storage characteristics and they can save #ost o" the ti#e o" creating and garbage collecting individual records.
4;4
1ap
*inter"ace ,
Maintains key'value associations *%airs,, so you can look u% a value using a key. I#%le#entation based on a hash table. *4se this instead o" Hashtable., Provides constant'ti#e %er"or#ance "or inserting and locating %airs. Per"or#ance can be ad0usted via constructors that allow you to set the ca acit) and load $actor o" the hash table. I#%le#entation based on a red'black tree. :hen you view the keys or the %airs, they will be in sorted order *deter#ined by -omparable or -omparator, discussed later,. The %oint o" a Tree1ap is that you get the results in sorted order. Tree1ap is the only 1ap with the s*b1apA B #ethod, which allows you to return a %ortion o" the tree.
Hash1a pB
Tree1a p
So#eti#es you ll also need to know the details o" how hashing works, so we ll look at that a little later. The "ollowing e&a#%le uses the -ollectionsI!fillA B #ethod and the test data sets that were %reviously de"ined= RFSURFSTIJLT+(6PTE52TIMMHU
//3 c'C3Ja"(.Hava // Things you can !o :ith Ja"s. i#"ort Hava.util.B< i#"ort co#.bruceeckel.util.B< "ublic class Ja"( @ static Collections .%tringPairaenerator geo ? Collections .geogra"hy< static Collections .5an!%tringPairaenerator rs" ? Collections .rs"< // Pro!ucing a %et of the keys3 "ublic static voi! "rint`eys-Ja" #. @ %yste#.out."rint-8%iUe ? 8 K #.siUe-. K8, 8.< %yste#.out."rint-8`eys3 8.< %yste#.out."rintln-#.key%et-..< A // Pro!ucing a Collection of the values3 "ublic static voi! "rintWalues-Ja" #. @
4;5
%yste#.out."rint-8Walues3 8.< %yste#.out."rintln-#.values-..< A "ublic static voi! test-Ja" #. @ Collections .fill-#, geo, ,.< // Ja" has 2%et2 behavior for keys3 Collections .fill-#, geo.reset-., ,.< "rint`eys-#.< "rintWalues-#.< %yste#.out."rintln-#.< %tring key ? CountryCa"itals."airsNION'O< %tring value ? CountryCa"itals."airsNION(O< %yste#.out."rintln-8#.contains`ey-_88 K key K 8_8.3 8 K #.contains`ey-key..< %yste#.out."rintln-8#.get-_88 K key K 8_8.3 8 K #.get-key..< %yste#.out."rintln-8#.containsWalue-_88 K value K 8_8.3 8 K #.containsWalue-value..< Ja" # ? ne: TreeJa"-.< Collections .fill-# , rs", ,.< #."ut0ll-# .< "rint`eys-#.< key ? #.key%et-..iterator-..ne6t-..to%tring-.< %yste#.out."rintln-8Lirst key in #a"3 8Kkey.< #.re#ove-key.< "rint`eys-#.< #.clear-.< %yste#.out."rintln-8#.isE#"ty-.3 8 K #.isE#"ty-..< Collections .fill-#, geo.reset-., ,.< // G"erations on the %et change the Ja"3 #.key%et-..re#ove0ll-#.key%et-..< %yste#.out."rintln-8#.isE#"ty-.3 8 K #.isE#"ty-..< A "ublic static voi! #ain-%tringNO args. @ %yste#.out."rintln-8Testing MashJa"8.< test-ne: MashJa"-..< %yste#.out."rintln-8Testing TreeJa"8.< test-ne: TreeJa"-..<
4;7
A A ///3>
The print%eysA B and printVal*esA B #ethods are not only use"ul utilities, they also de#onstrate how to %roduce -ollection views o" a 1ap. The key)etA B #ethod %roduces a )et backed by the keys in the 1ap. Si#ilar treat#ent is given to val*esA B, which %roduces a -ollection containing all the values in the 1ap! *Cote that keys #ust be uniAue, while values #ay contain du%licates., Since these -ollections are backed by the 1ap, any changes in a -ollection will be re"lected in the associated 1ap. RFSURFSTIJLT+(6PTE52TIMM3U The rest o" the %rogra# %rovides si#%le e&a#%les o" each 1ap o%eration, and tests each ty%e o" 1ap. RFSURFSTIJLT+(6PTE52TIMMGU 6s an e&a#%le o" the use o" a Hash1ap, consider a %rogra# to check the rando#ness o" Java s 1ath!ran'omA B #ethod. Ideally, it would %roduce a %er"ect distribution o" rando# nu#bers, but to test this you need to generate a bunch o" rando# nu#bers and count the ones that "all in the various ranges. 6 Hash1ap is %er"ect "or this, since it associates ob0ects with ob0ects *in this case, the value ob0ect contains the nu#ber %roduced by 1ath!ran'omA B along with the nu#ber o" ti#es that nu#ber a%%ears,=
//3 c'C3%tatistics.Hava // %i#"le !e#onstration of MashJa". i#"ort Hava.util.B< class Counter @ int i ? (< "ublic %tring to%tring-. @ return $nteger.to%tring-i.< A A "ublic class %tatistics @ "ublic static voi! #ain-%tringNO args. @ MashJa" h# ? ne: MashJa"-.< for-int i ? '< i P (''''< iKK. @ // Pro!uce a nu#ber bet:een ' an! '3 $nteger r ?
4;8
ne: $nteger--int.-Jath.ran!o#-. B if-h#.contains`ey-r.. --Counter.h#.get-r...iKK< else h#."ut-r, ne: Counter-..< A %yste#.out."rintln-h#.< A A ///3>
'..<
In mainA B, each ti#e a rando# nu#ber is generated it is wra%%ed inside an Integer ob0ect so that re"erence can be used with the Hash1ap. */ou can t use a %ri#itive with a container, only an ob0ect re"erence., The contains%eyA B #ethod checks to see i" this key is already in the container. *That is, has the nu#ber been "ound alreadyO, I" so, the getA B #ethod %roduces the associated value "or the key, which in this case is a -o*nter ob0ect. The value i inside the counter is incre#ented to indicate that one #ore o" this %articular rando# nu#ber has been "ound. RFSURF STIJLT+(6PTE52TIMMIU I" the key has not been "ound yet, the #ethod p*tA B will %lace a new key' value %air into the Hash1ap. Since -o*nter auto#atically initiali1es its variable i to one when it s created, it indicates the "irst occurrence o" this %articular rando# nu#ber. RFSURFSTIJLT+(6PTE52TIMM2U To dis%lay the Hash1ap, it is si#%ly %rinted. The Hash1ap to)tring A B #ethod #oves through all the key'value %airs and calls the to)tring A B "or each one. The Integer!to)tringA B is %rede"ined, and you can see the to)tringA B "or -o*nter. The out%ut "ro# one run *with so#e line breaks added, is=
@(C?, +, (1?,)), (*?I+', (+?,(), (,?, (, (I?IC,, ()?,( , ( ?I1), ((?I11, ('?I1*, C?,(I, 1?, ), *?IC*, +?I1*, ,?I1', I?I1C, )?,'C, ?,'), (?I*,, '?,',A
/ou #ight wonder at the necessity o" the class -o*nter, which see#s like it doesn t even have the "unctionality o" the wra%%er class Integer. :hy not use int or IntegerO :ell, you can t use an int because all o" the containers can hold only .b8ect re"erences. 6"ter seeing containers the wra%%er classes #ight begin to #ake a little #ore sense to you, since you
4;:
can t %ut any o" the %ri#itive ty%es in containers. (owever, the only thing you can do with the Java wra%%ers is to initiali1e the# to a %articular value and read that value. That is, there s no way to change a value once a wra%%er ob0ect has been created. This #akes the Integer wra%%er i##ediately useless to solve our %roble#, so we re "orced to create a new class that does satis"y the need. RFSURFSTIJLT+(6PTE52TIMK@U
Sorted3a
I" you have a )orte'1ap *o" which Tree1ap is the only one available,, the keys are guaranteed to be in sorted order which allows additional "unctionality to be %rovided with these #ethods in the )orte'1ap inter"ace= RFSURFSTIJLT+(6PTE52TIMKMU
-omparator comparatorAB< Produces the co#%arator used "or this 1ap, or n*ll "or natural ordering. .b8ect first%eyAB< Produces the lowest key. .b8ect last%eyAB< Produces the highest key. )orte'1ap s*b1apAfrom%ey, to%eyB< Produces a view o" this 1ap with keys "ro# from%ey, inclusive, to to%ey, e&clusive. )orte'1ap hea'1apAto%eyB< Produces a view o" this 1ap with
keys less than to%ey.
)orte'1ap tail1apAfrom%eyB< Produces a view o" this 1ap with keys greater than or eAual to from%ey.
4;;
i#"ort Hava.util.B< class aroun!hog @ int gh&u#ber< aroun!hog-int n. @ gh&u#ber ? n< A A class Pre!iction @ boolean sha!o: ? Jath.ran!o#-. Q '.,< "ublic %tring to%tring-. @ if-sha!o:. return 8%i6 #ore :eeks of \inter48< else return 8Early %"ring48< A A "ublic class %"ringDetector @ "ublic static voi! #ain-%tringNO args. @ MashJa" h# ? ne: MashJa"-.< for-int i ? '< i P ('< iKK. h#."ut-ne: aroun!hog-i., ne: Pre!iction-..< %yste#.out."rintln-8h# ? 8 K h# K 8_n8.< %yste#.out."rintln8Looking u" "re!iction for aroun!hog S)38.< aroun!hog gh ? ne: aroun!hog-).< if-h#.contains`ey-gh.. %yste#.out."rintln--Pre!iction.h#.get-gh..< else %yste#.out."rintln-8`ey not foun!3 8 K gh.< A A ///3>
Each "ro*n'hog is given an identity nu#ber, so you can look u% a #re'iction in the Hash1ap by saying, !8ive #e the #re'iction associated with "ro*n'hog nu#ber L.$ The #re'iction class contains a boolean that is initiali1ed using 1ath!ran'omA B, and a to)tringA B that inter%rets the result "or you. In mainA B, a Hash1ap is "illed with "ro*n'hogs and their associated #re'ictions. The Hash1ap is %rinted so you can see that it has been "illed. Then a "ro*n'hog with an identity nu#ber o" L is used as a key to look u% the %rediction "or
5==
//3 c'C3%"ringDetector .Hava // 0 class that2s use! as a key in a MashJa" // #ust overri!e hashCo!e-. an! e=uals-.. i#"ort Hava.util.B< class aroun!hog @ int gh&u#ber< aroun!hog -int n. @ gh&u#ber ? n< A "ublic int hashCo!e-. @ return gh&u#ber< A "ublic boolean e=uals-GbHect o. @ return -o instanceof aroun!hog . DD -gh&u#ber ?? --aroun!hog .o..gh&u#ber.< A A "ublic class %"ringDetector @
5=1
"ublic static voi! #ain-%tringNO args. @ MashJa" h# ? ne: MashJa"-.< for-int i ? '< i P ('< iKK. h#."ut-ne: aroun!hog -i.,ne: Pre!iction-..< %yste#.out."rintln-8h# ? 8 K h# K 8_n8.< %yste#.out."rintln8Looking u" "re!iction for groun!hog S)38.< aroun!hog gh ? ne: aroun!hog -).< if-h#.contains`ey-gh.. %yste#.out."rintln--Pre!iction.h#.get-gh..< A A ///3>
Cote that this uses the #re'iction class "ro# the %revious e&a#%le, so )pring etector!8ava #ust be co#%iled "irst or you ll get a co#%ile' ti#e error when you try to co#%ile )pring etectorI!8ava. RFSURF STIJLT+(6PTE52TIMK3U
"ro*n'hogI!hash-o'eA B returns the groundhog nu#ber as an identi"ier. In this e&a#%le, the %rogra##er is res%onsible "or ensuring that no two groundhogs e&ist with the sa#e I7 nu#ber. The hash-o'e A B is not reAuired to return a uniAue identi"ier *so#ething you ll understand better later in this cha%ter,, but the eC*alsA B #ethod #ust be able to strictly deter#ine whether two ob0ects are eAuivalent. RFSURF STIJLT+(6PTE52TIMKGU
Even though it a%%ears that the eC*alsA B #ethod is only checking to see whether the argu#ent is an instance o" "ro*n'hogI *using the instanceof keyword, which is "ully e&%lained in +ha%ter MK,, the instanceof actually Auietly does a second sanity check, to see i" the ob0ect is n*ll, since instanceof %roduces false i" the le"t'hand argu#ent is n*ll. 6ssu#ing it s the correct ty%e and not n*ll, the co#%arison is based on the actual gh/*mbers. This ti#e, when you run the %rogra#, you ll see it %roduces the correct out%ut. RFSURF STIJLT+(6PTE52TIMKIU :hen creating your own class to use in a Hash)et, you #ust %ay attention to the sa#e issues as when it is used as a key in a Hash1ap. RF SURFSTIJLT+(6PTE52TIMK2U
5=2
Cnderstanding hash$ode1 2
The above e&a#%le is only a start toward solving the %roble# correctly. It shows that i" you do not override hash-o'eA B and eC*alsA B "or your key, the hashed data structure * Hash)et or Hash1ap, will not be able to deal with your key %ro%erly. (owever, to get a good solution "or the %roble# you need to understand what s going on inside the hashed data structure. RFSURFSTIJLT+(6PTE52TIML@U Eirst, consider the #otivation behind hashing= you want to look u% an ob0ect using another ob0ect. But you can acco#%lish this with a Tree)et or Tree1ap, too. It s also %ossible to i#%le#ent your own 1ap. To do so, the 1ap!entry)etA B #ethod #ust be su%%lied to %roduce a set o" 1ap!&ntry ob0ects. 1#air will be de"ined as the new ty%e o" 1ap! &ntry. In order "or it to be %laced in a Tree)et it #ust i#%le#ent eC*alsA B and be -omparable=
//3 c'C3JPair.Hava // 0 Ja" i#"le#ente! :ith 0rrayListsne: ty"e of Ja". Entry. i#"ort Hava.util.B< "ublic class JPair i#"le#ents Ja".Entry, Co#"arable @ GbHect key, value< JPair-GbHect k, GbHect v. @ key ? k< value ? v< A "ublic GbHect get`ey-. @ return key< A "ublic GbHect getWalue-. @ return value< A "ublic GbHect setWalue-GbHect v.@ GbHect result ? value< value ? v< return result< A "ublic boolean e=uals-GbHect o. @ return key.e=uals---JPair.o..key.< A "ublic int co#"areTo-GbHect rv. @ return --Co#"arable.key..co#"areTo-
5=3
--JPair.rv..key.< A A ///3> Cotice that the co#%arisons are only interested in the keys, so du%licate values are %er"ectly acce%table.
The "ollowing e&a#%le i#%le#ents a 1ap using a %air o" Array+ists= RF SURFSTIJLT+(6PTE52TIMLMU
//3 c'C3%lo:Ja".Hava // 0 Ja" i#"le#ente! :ith 0rrayLists. i#"ort Hava.util.B< i#"ort co#.bruceeckel.util.B< "ublic class %lo:Ja" e6ten!s 0bstractJa" @ "rivate 0rrayList keys ? ne: 0rrayList-., values ? ne: 0rrayList-.< "ublic GbHect "ut-GbHect key, GbHect value. @ GbHect result ? get-key.< if-4keys.contains-key.. @ keys.a!!-key.< values.a!!-value.< A else values.set-keys.in!e6Gf-key., value.< return result< A "ublic GbHect get-GbHect key. @ if-4keys.contains-key.. return null< return values.get-keys.in!e6Gf-key..< A "ublic %et entry%et-. @ %et entries ? ne: Mash%et-.< $terator ki ? keys.iterator-., vi ? values.iterator-.< :hile-ki.has&e6t-.. entries.a!!-ne: JPair-ki.ne6t-., vi.ne6t-...< return entries< A
5=4
"ublic static voi! #ain-%tringNO args. @ %lo:Ja" # ? ne: %lo:Ja"-.< Collections .fill-#, Collections .geogra"hy, ,.< %yste#.out."rintln-#.< A A ///3>
The p*tA B #ethod si#%ly %laces the keys and values in corres%onding Array+ists. In mainA B, a )lo(1ap is loaded and then %rinted to show that it works. This shows that it s not that hard to %roduce a new ty%e o" 1ap. But as the na#e suggests, a )lo(1ap isn t very "ast, so you %robably wouldn t use it i" you had an alternative available. The %roble# is in the looku% o" the key= there is no order so a si#%le linear search is used, which is the slowest way to look so#ething u%. RFSURFSTIJLT+(6PTE52TIMLKU The whole %oint o" hashing is s%eed= hashing allows the looku% to ha%%en Auickly. Since the bottleneck is in the s%eed o" the key looku%, one o" the solutions to the %roble# could be by kee%ing the keys sorted and then using -ollections!binary)earchA B to %er"or# the looku% *an e&ercise at the end o" this cha%ter will walk you through this %rocess,. RFSURF STIJLT+(6PTE52TIMLLU (ashing goes "urther by saying that all you want to do is to store the key
5=5
#ore than one key #ay %roduce the sa#e inde&. That is, there #ay be collisions. Because o" this, it doesn t #atter how big the array is because each key ob0ect will land so#ewhere in that array. RFSURF STIJLT+(6PTE52TIMLHU So the %rocess o" looking u% a value starts by co#%uting the hash code and using it to inde& into the array. I" you could guarantee that there were no collisions *which could be %ossible i" you have a "i&ed nu#ber o" values, then you d have a er$ect hashing $unction, but that s a s%ecial case. In all other cases, collisions are handled by e*ternal chaining! the array %oints not directly to a value, but instead to a list o" values. These values are searched in a linear "ashion using the eC*alsA B #ethod. )" course, this as%ect o" the search is #uch slower, but i" the hash "unction is good there will only be a "ew values in each slot, at the #ost. So instead o" searching through the entire list, you Auickly 0u#% to a slot where you have to co#%are a "ew entries to "ind the value. This is #uch "aster, which is why the Hash1ap is so Auick. RFSURFSTIJLT+(6PTE52TIML3U >nowing the basics o" hashing, it s %ossible to i#%le#ent a si#%le hashed 1ap=
//3 c'C3%i#"leMashJa".Hava // 0 !e#onstration hashe! Ja". i#"ort Hava.util.B< i#"ort co#.bruceeckel.util.B< "ublic class %i#"leMashJa" e6ten!s 0bstractJa" @ // Choose a "ri#e nu#ber for the hash table // siUe, to achieve a unifor# !istribution3 "rivate final static int %T ? CC*< "rivate Linke!ListNO bucket? ne: Linke!ListN%TO< "ublic GbHect "ut-GbHect key, GbHect value. @ GbHect result ? null< int in!e6 ? key.hashCo!e-. V %T< if-in!e6 P '. in!e6 ? -in!e6< if-bucketNin!e6O ?? null. bucketNin!e6O ? ne: Linke!List-.< Linke!List "airs ? bucketNin!e6O< JPair "air ? ne: JPair-key, value.< List$terator it ? "airs.list$terator-.< boolean foun! ? false<
5=7
:hile-it.has&e6t-.. @ GbHect iPair ? it.ne6t-.< if-iPair.e=uals-"air.. @ result ? --JPair.iPair..getWalue-.< it.set-"air.< // 5e"lace ol! :ith ne: foun! ? true< break< A A if-4foun!. bucketNin!e6O.a!!-"air.< return result< A "ublic GbHect get-GbHect key. @ int in!e6 ? key.hashCo!e-. V %T< if-in!e6 P '. in!e6 ? -in!e6< if-bucketNin!e6O ?? null. return null< Linke!List "airs ? bucketNin!e6O< JPair #atch ? ne: JPair-key, null.< List$terator it ? "airs.list$terator-.< :hile-it.has&e6t-.. @ GbHect iPair ? it.ne6t-.< if-iPair.e=uals-#atch.. return --JPair.iPair..getWalue-.< A return null< A "ublic %et entry%et-. @ %et entries ? ne: Mash%et-.< for-int i ? '< i P bucket.length< iKK. @ if-bucketNiO ?? null. continue< $terator it ? bucketNiO.iterator-.< :hile-it.has&e6t-.. entries.a!!-it.ne6t-..< A return entries< A "ublic static voi! #ain-%tringNO args. @ %i#"leMashJa" # ? ne: %i#"leMashJa"-.< Collections .fill-#, Collections .geogra"hy, ,.<
5=8
%yste#.out."rintln-#.< A A ///3>
Because the !slots$ in a hash table are o"ten re"erred to as bucketsD the array that re%resents the actual table is called b*cket. To %ro#ote even distribution, the nu#ber o" buckets is ty%ically a %ri#e nu#ber. Cotice that it is an array o" +inke'+ist, which auto#atically %rovides "or collisions9each new ite# is si#%ly added to the end o" the list. RFSURF STIJLT+(6PTE52TIMLGU The return value o" p*tA B is n*ll or, i" the key was already in the list, the old value associated with that key. The return value is res*lt, which is initiali1ed to n*ll, but i" a key is discovered in the list then res*lt is assigned to that key. RFSURFSTIJLT+(6PTE52TIMLIU Eor both p*tA B and getA B, the "irst thing that ha%%ens is that the hash-o'eA B is called "or the key, and the result is "orced to a %ositive nu#ber. Then it is "orced to "it into the b*cket array using the #odulus o%erator and the si1e o" the array. I" that location is n*ll, it #eans there are no ele#ents that hash to that location, so a new +inke'+ist is created to hold the ob0ect that 0ust did. (owever, the nor#al %rocess is to look through the list to see i" there are du%licates, and i" there are, the old value is %ut into res*lt and the new value re%laces the old. The fo*n' "lag kee%s track o" whether an old key'value %air was "ound and, i" not, the new %air is a%%ended to the end o" the list. RFSURF STIJLT+(6PTE52TIML2U In getA B, you ll see very si#ilar code as that contained in p*tA B, but si#%ler. The inde& is calculated into the b*cket array, and i" a +inke'+ist e&ists it is searched "or a #atch. RFSURF STIJLT+(6PTE52TIM?@U
entry)etA B #ust "ind and traverse all the lists, adding the# to the result )et. )nce this #ethod has been created, the 1ap can be tested by "illing
it with values and then %rinting the#. RFSURFSTIJLT+(6PTE52TIM?MU
Hash3a
.erformance factors
5=:
Initial ca'acit!! The nu#ber o" buckets when the table is created. Hash1ap and Hash)et= have constructors that allow you to s%eci"y
the initial ca%acity.
*i%e! The nu#ber o" entries currently in the table. 5oad factor! si1eFca%acity. 6 load "actor o" @ is an e#%ty table, @.H
is a hal"'"ull table, etc. 6 lightly'loaded table will have "ew collisions and so is o%ti#al "or insertions and looku%s *but will slow down the %rocess o" traversing with an iterator,. Hash1ap and Hash)et have constructors that allow you to s%eci"y the load "actor, which #eans that when this load "actor is reached the container will auto#atically increase the ca%acity *the nu#ber o" buckets, by roughly doubling it, and will redistribute the e&isting ob0ects into the new set o" buckets *this is called rehashing,. The de"ault load "actor used by Hash1ap is @.GH *it doesn t rehash until the table is f "ull,. This see#s to be a good trade'o"" between ti#e and s%ace costs. 6 higher load "actor decreases the s%ace reAuired by the table but increases the looku% cost, which is i#%ortant because looku% is what you do #ost o" the ti#e *including both getA B and p*tA B,. RFSURF STIJLT+(6PTE52TIM?KU I" you know that you ll be storing #any entries in a Hash1ap, creating it with an a%%ro%riately large initial ca%acity will %revent the overhead o" auto#atic rehashing. RFSURFSTIJLT+(6PTE52TIM?LU
Overriding hash$ode1 2
Cow that you understand what s involved in the "unction o" the Hash1ap, the issues involved in writing a hash-o'eA B will #ake #ore sense. RFSURFSTIJLT+(6PTE52TIM??U Eirst o" all, you don t have control o" the creation o" the actual value that s used to inde& into the array o" buckets. That is de%endent on the ca%acity o" the %articular Hash1ap ob0ect, and that ca%acity changes de%ending on how "ull the container is, and what the load "actor is. The value %roduced by your hash-o'eA B will be "urther %rocessed in order to create the bucket inde& *in )impleHash1ap the calculation is 0ust a #odulo by the si1e o" the bucket array,. RFSURF STIJLT+(6PTE52TIM?HU
5=;
The #ost i#%ortant "actor in creating a hash-o'eA B is that, regardless o" when hash-o'eA B is called, it %roduces the sa#e value "or a %articular ob0ect every ti#e it is called. I" you end u% with an ob0ect that %roduces one hash-o'eA B value when it is p*tA B into a Hash1ap, and another during a getA B, you won t be able to retrieve the ob0ects. So i" your hash-o'eA B de%ends on #utable data in the ob0ect the user #ust be #ade aware that changing the data will e""ectively %roduce a di""erent key by generating a di""erent hash-o'eA B. RFSURF STIJLT+(6PTE52TIM?3U In addition, you will %robably not want to generate a hash-o'eA B that is based on uniAue ob0ect in"or#ation9in %articular, the value o" this #akes a bad hash-o'eA B because then you can t generate a new identical key to the one used to p*tA B the original key'value %air. This was the %roble# that occurred in )pring etector!8ava because the de"ault i#%le#entation o" hash-o'eA B does use the ob0ect address. So you ll want to use in"or#ation in the ob0ect that identi"ies the ob0ect in a #eaning"ul way. RFSURFSTIJLT+(6PTE52TIM?GU )ne e&a#%le is "ound in the )tring class. )trings have the s%ecial characteristic that i" a %rogra# has several )tring ob0ects that contain identical character seAuences, then those )tring ob0ects all #a% to the sa#e #e#ory *the #echanis# "or this is described in 6%%endi& 6,. So it #akes sense that the hash-o'eA B %roduced by two se%arate instances o" ne( )tringAahellobB should be identical. /ou can see it by running this %rogra#=
//3 c'C3%tringMashCo!e.Hava "ublic class %tringMashCo!e @ "ublic static voi! #ain-%tringNO args. @ %yste#.out."rintln-8Mello8.hashCo!e-..< %yste#.out."rintln-8Mello8.hashCo!e-..< A A ///3>
Eor this to work, the hash-o'eA B "or )tring #ust be based on the contents o" the )tring. RFSURFSTIJLT+(6PTE52TIM?IU So "or a hash-o'eA B to be e""ective, it #ust be "ast and it #ust be #eaning"ul= that is, it #ust generate a value based on the contents o" the
51=
ob0ect. 5e#e#ber that this value doesn t have to be uniAue9you should lean toward s%eed rather than uniAueness9but between hash-o'eA B and eC*alsA B the identity o" the ob0ect #ust be co#%letely resolved. RF SURFSTIJLT+(6PTE52TIM?2U Because the hash-o'eA B is "urther %rocessed be"ore the bucket inde& is %roduced, the range o" values is not i#%ortant; it 0ust needs to generate an int. RFSURFSTIJLT+(6PTE52TIMH@U There s one other "actor= a good hash-o'eA B should result in an even distribution o" values. I" the values tend to cluster, then the Hash1ap or Hash)et will be #ore heavily loaded in so#e areas and will not be as "ast as it could be with an evenly distributed hashing "unction. RFSURF STIJLT+(6PTE52TIMHMU (ere s an e&a#%le that "ollows these guidelines=
//3 c'C3Counte!%tring.Hava // Creating a goo! hashCo!e-.. i#"ort Hava.util.B< "ublic class Counte!%tring @ "rivate %tring s< "rivate int i! ? '< "rivate static 0rrayList create! ? ne: 0rrayList-.< "ublic Counte!%tring-%tring str. @ s ? str< create!.a!!-s.< $terator it ? create!.iterator-.< // $! is the total nu#ber of instances // of this string in use by Counte!%tring3 :hile-it.has&e6t-.. if-it.ne6t-..e=uals-s.. i!KK< A "ublic %tring to%tring-. @ return 8%tring3 8 K s K 8 i!3 8 K i! K 8 hashCo!e-.3 8 K hashCo!e-. K 8_n8< A "ublic int hashCo!e-. @
511
return s.hashCo!e-. B i!< A "ublic boolean e=uals-GbHect o. @ return -o instanceof Counte!%tring. DD s.e=uals---Counte!%tring.o..s. DD i! ?? --Counte!%tring.o..i!< A "ublic static voi! #ain-%tringNO args. @ MashJa" # ? ne: MashJa"-.< Counte!%tringNO cs ? ne: Counte!%tringN('O< for-int i ? '< i P cs.length< iKK. @ csNiO ? ne: Counte!%tring-8hi8.< #."ut-csNiO, ne: $nteger-i..< A %yste#.out."rintln-#.< for-int i ? '< i P cs.length< iKK. @ %yste#.out."rint-8Looking u" 8 K csNiO.< %yste#.out."rintln-#.get-csNiO..< A A A ///3> -o*nte')tring includes a )tring and an i' that re%resents the nu#ber o" -o*nte')tring ob0ects that contain an identical )tring. The counting is acco#%lished in the constructor by iterating through the static Array+ist where all the )trings are stored. RFSURF STIJLT+(6PTE52TIMHKU
Both hash-o'eA B and eC*alsA B %roduce results based on both "ields; i" they were 0ust based on the )tring alone or the i' alone there would be du%licate #atches "or distinct values. RFSURFSTIJLT+(6PTE52TIMHLU Cote how si#%le the hash-o'eA B is= )tring s hash-o'eA B is #ulti%lied by the i'. S#aller is generally better *and "aster, "or hash-o'eA B. RFSURFSTIJLT+(6PTE52TIMH?U In mainA B, a bunch o" -o*nte')tring ob0ects are created, using the sa#e )tring to show that the du%licates create uniAue values because o" the count i'. The Hash1ap is dis%layed so that you can see how it is stored internally *no discernible orders, and then each key is looked u%
512
>olding references
The 8ava!lang!ref library contains a set o" classes that allow greater "le&ibility in garbage collection, which are es%ecially use"ul when you have large ob0ects that #ay cause #e#ory e&haustion. There are three classes inherited "ro# the abstract class $eference= )oft$eference, 0eak$eference, and #hantom$eference. Each o" these %rovides a di""erent level o" indirection "or the garbage collector, i" the ob0ect in Auestion is onl) reachable through one o" these $eference ob0ects. RF SURFSTIJLT+(6PTE52TIMH3U I" an ob0ect is reachable it #eans that so#ewhere in your %rogra# the ob0ect can be "ound. This could #ean that you have an ordinary re"erence on the stack that goes right to the ob0ect, but you #ight also have a re"erence to an ob0ect that has a re"erence to the ob0ect in Auestion; there could be #any inter#ediate links. I" an ob0ect is reachable, the garbage collector cannot release it because it s still in use by your %rogra#. I" an ob0ect isn t reachable, there s no way "or your %rogra# to use it so it s sa"e to garbage'collect that ob0ect. RFSURFSTIJLT+(6PTE52TIMHGU /ou use $eference ob0ects when you want to continue to hold onto a re"erence to that ob0ect9you want to be able to reach that ob0ect9but you also want to allow the garbage collector to release that ob0ect. Thus, you have a way to go on using the ob0ect, but i" #e#ory e&haustion is i##inent you allow that ob0ect to be released. RFSURF STIJLT+(6PTE52TIMHIU /ou acco#%lish this by using a $eference ob0ect as an inter#ediary between you and the ordinary re"erence, and there #ust be no ordinary re"erences to the ob0ect *ones that are not wra%%ed inside $eference ob0ects,. I" the garbage collector discovers that an ob0ect is reachable through an ordinary re"erence, it will not release that ob0ect. RFSURF STIJLT+(6PTE52TIMH2U In the order )oft$eference, 0eak$eference, and #hantom$eference, each one is !weaker$ than the last, and
513
corres%onds to a di""erent level o" reachability. So"t re"erences are "or i#%le#enting #e#ory'sensitive caches. :eak re"erences are "or i#%le#enting !canonicali1ing #a%%ings$9where instances o" ob0ects can be si#ultaneously used in #ulti%le %laces in a %rogra#, to save storage9 that do not %revent their keys *or values, "ro# being reclai#ed. Phanto# re"erences are "or scheduling %re'#orte# cleanu% actions in a #ore "le&ible way than is %ossible with the Java "inali1ation #echanis#. RF SURFSTIJLT+(6PTE52TIM3@U :ith )oft$eferences and 0eak$eferences, you have a choice about whether to %lace the# on a $eference3*e*e *the device used "or %re#orte# cleanu% actions,, but a #hantom$eference can only be built on a $eference3*e*e. (ere s a si#%le de#onstration=
//3 c'C35eferences.Hava // De#onstrates 5eference obHects i#"ort Hava.lang.ref.B< class WeryBig @ static final int %T ? (''''< !oubleNO ! ? ne: !oubleN%TO< %tring i!ent< "ublic WeryBig-%tring i!. @ i!ent ? i!< A "ublic %tring to%tring-. @ return i!ent< A "ublic voi! finaliUe-. @ %yste#.out."rintln-8LinaliUing 8 K i!ent.< A A "ublic class 5eferences @ static 5eference/ueue r=? ne: 5eference/ueue-.< "ublic static voi! check/ueue-. @ GbHect in= ? r=."oll-.< if-in= 4? null. %yste#.out."rintln-8$n =ueue3 8 K -WeryBig.--5eference.in=..get-..< A "ublic static voi! #ain-%tringNO args. @ int siUe ? ('< // Gr, choose siUe via the co##an! line3 if-args.length Q '.
514
siUe ? $nteger."arse$nt-argsN'O.< %oft5eferenceNO sa ? ne: %oft5eferenceNsiUeO< for-int i ? '< i P sa.length< iKK. @ saNiO ? ne: %oft5eferencene: WeryBig-8%oft 8 K i., r=.< %yste#.out."rintln-8Just create!3 8 K -WeryBig.saNiO.get-..< check/ueue-.< A \eak5eferenceNO :a ? ne: \eak5eferenceNsiUeO< for-int i ? '< i P :a.length< iKK. @ :aNiO ? ne: \eak5eferencene: WeryBig-8\eak 8 K i., r=.< %yste#.out."rintln-8Just create!3 8 K -WeryBig.:aNiO.get-..< check/ueue-.< A %oft5eference s ? ne: %oft5eferencene: WeryBig-8%oft8..< \eak5eference : ? ne: \eak5eferencene: WeryBig-8\eak8..< %yste#.gc-.< Phanto#5eferenceNO "a ? ne: Phanto#5eferenceNsiUeO< for-int i ? '< i P "a.length< iKK. @ "aNiO ? ne: Phanto#5eferencene: WeryBig-8Phanto# 8 K i., r=.< %yste#.out."rintln-8Just create!3 8 K -WeryBig."aNiO.get-..< check/ueue-.< A A A ///3>
:hen you run this %rogra# *you ll want to %i%e the out%ut through a !#ore$ utility so that you can view the out%ut in %ages,, you ll see that the ob0ects are garbage'collected, even though you still have access to the# through the $eference ob0ect *to get the actual ob0ect re"erence, you use getA B,. /ou ll also see that the $eference3*e*e always %roduces a
515
$eference containing a n*ll ob0ect. To #ake use o" this, you can inherit "ro# the %articular $eference class you re interested in and add #ore use"ul #ethods to the new ty%e o" $eference. RFSURF
STIJLT+(6PTE52TIM3MU
#he 4eakHash3a
The containers library has a s%ecial 1ap to hold weak re"erences= the 0eakHash1ap. This class is designed to #ake the creation o" canonicali1ed #a%%ings easier. In such a #a%%ing, you are saving storage by #aking only one instance o" a %articular value. :hen the %rogra# needs that value, it looks u% the e&isting ob0ect in the #a%%ing and uses that *rather than creating one "ro# scratch,. The #a%%ing #ay #ake the values as %art o" its initiali1ation, but it s #ore likely that the values are #ade on de#and. RFSURFSTIJLT+(6PTE52TIM3KU Since this is a storage'saving techniAue, it s very convenient that the 0eakHash1ap allows the garbage collector to auto#atically clean u% the keys and values. /ou don t have to do anything s%ecial to the keys and values you want to %lace in the 0eakHash1ap; these are auto#atically wra%%ed in 0eak$eferences by the #a%. The trigger to allow cleanu% is i" the key is no longer in use, as de#onstrated here=
//3 c'C3CanonicalJa""ing.Hava // De#onstrates \eakMashJa". i#"ort Hava.util.B< i#"ort Hava.lang.ref.B< class `ey @ %tring i!ent< "ublic `ey-%tring i!. @ i!ent ? i!< A "ublic %tring to%tring-. @ return i!ent< A "ublic int hashCo!e-. @ return i!ent.hashCo!e-.< A "ublic boolean e=uals-GbHect r. @ return -r instanceof `ey. DD i!ent.e=uals---`ey.r..i!ent.< A "ublic voi! finaliUe-. @
517
%yste#.out."rintln-8LinaliUing `ey 8K i!ent.< A A class Walue @ %tring i!ent< "ublic Walue-%tring i!. @ i!ent ? i!< A "ublic %tring to%tring-. @ return i!ent< A "ublic voi! finaliUe-. @ %yste#.out."rintln-8LinaliUing Walue 8Ki!ent.< A A "ublic class CanonicalJa""ing @ "ublic static voi! #ain-%tringNO args. @ int siUe ? ('''< // Gr, choose siUe via the co##an! line3 if-args.length Q '. siUe ? $nteger."arse$nt-argsN'O.< `eyNO keys ? ne: `eyNsiUeO< \eakMashJa" :h# ? ne: \eakMashJa"-.< for-int i ? '< i P siUe< iKK. @ `ey k ? ne: `ey-$nteger.to%tring-i..< Walue v ? ne: Walue-$nteger.to%tring-i..< if-i V ) ?? '. keysNiO ? k< // %ave as 8real8 references :h#."ut-k, v.< A %yste#.gc-.< A A ///3>
The %ey class #ust have a hash-o'eA B and an eC*alsA B since it is being used as a key in a hashed data structure, as described %reviously in this cha%ter. RFSURFSTIJLT+(6PTE52TIM3LU :hen you run the %rogra# you ll see that the garbage collector will ski% every third key, because an ordinary re"erence to that key has also been %laced in the keys array and thus those ob0ects cannot be garbage' collected. RFSURFSTIJLT+(6PTE52TIM3?U
518
Iterators revisited
:e can now de#onstrate the true %ower o" the Iterator= the ability to se%arate the o%eration o" traversing a seAuence "ro# the underlying structure o" that seAuence. In the "ollowing e&a#%le, the class #rint ata uses an Iterator to #ove through a seAuence and call the to)tringA B #ethod "or every ob0ect. Two di""erent ty%es o" containers are created9an Array+ist and a Hash1ap9and they are each "illed with, res%ectively, 1o*se and Hamster ob0ects. *These classes are de"ined earlier in this cha%ter., Because an Iterator hides the structure o" the underlying container, #rint ata doesn t know or care what kind o" container the Iterator co#es "ro#=
//3 c'C3$terators .Hava // 5evisiting $terators. i#"ort Hava.util.B< class PrintData @ static voi! "rint-$terator e. @ :hile-e.has&e6t-.. %yste#.out."rintln-e.ne6t-..< A A "ublic class $terators @ "ublic static voi! #ain-%tringNO args. @ 0rrayList v ? ne: 0rrayList-.< for-int i ? '< i P ,< iKK. v.a!!-ne: Jouse-i..< MashJa" # ? ne: MashJa"-.< for-int i ? '< i P ,< iKK. #."ut-ne: $nteger-i., ne: Ma#ster-i..< %yste#.out."rintln-80rrayList8.< PrintData."rint-v.iterator-..< %yste#.out."rintln-8MashJa"8.< PrintData."rint-#.entry%et-..iterator-..< A A ///3>
51:
Eor the Hash1ap, the entry)etA B #ethod %roduces a )et o" 1ap! entry ob0ects, which contain both the key and the value "or each entry, so you see both o" the# %rinted. RFSURFSTIJLT+(6PTE52TIM3HU Cote that #rint ata!printA B takes advantage o" the "act that the ob0ects in these containers are o" class .b8ect so the call to)tringA B by )ystem!o*t!printlnA B is auto#atic. It s #ore likely that in your %roble#, you #ust #ake the assu#%tion that your Iterator is walking through a container o" so#e s%eci"ic ty%e. Eor e&a#%le, you #ight assu#e that everything in the container is a )hape with a 'ra(A B #ethod. Then you #ust downcast "ro# the .b8ect that Iterator!ne4t A B returns to %roduce a )hape. RFSURFSTIJLT+(6PTE52TIM33U
Choosing an im.lementation
By now you should understand that there are really only three container co#%onents= 1ap, +ist, and )et, and only two or three i#%le#entations o" each inter"ace. I" you need to use the "unctionality o""ered by a %articular interface, how do you decide which %articular i#%le#entation to useO RFSURFSTIJLT+(6PTE52TIM3GU To understand the answer, you #ust be aware that each di""erent i#%le#entation has its own "eatures, strengths, and weaknesses. Eor e&a#%le, you can see in the diagra# that the !"eature$ o" Hashtable, Vector, and )tack is that they are legacy classes, so that old code doesn t break. )n the other hand, it s best i" you don t use those "or new *Java K, code. RFSURFSTIJLT+(6PTE52TIM3IU The distinction between the other containers o"ten co#es down to what they are !backed by$; that is, the data structures that %hysically i#%le#ent your desired interface. This #eans that, "or e&a#%le, Array+ist and +inke'+ist i#%le#ent the +ist inter"ace so your %rogra# will %roduce the sa#e results regardless o" the one you use. (owever, Array+ist is backed by an array, while the +inke'+ist is i#%le#ented in the usual way "or a doubly linked list, as individual ob0ects each containing data along with re"erences to the %revious and
51;
ne&t ele#ents in the list. Because o" this, i" you want to do #any insertions and re#ovals in the #iddle o" a list, a +inke'+ist is the a%%ro%riate choice. * +inke'+ist also has additional "unctionality that is established in Abstract)eC*ential+ist., I" not, an Array+ist is ty%ically "aster. RFSURFSTIJLT+(6PTE52TIM32U 6s another e&a#%le, a )et can be i#%le#ented as either a Tree)et or a Hash)et. 6 Tree)et is backed by a Tree1ap and is designed to %roduce a constantly sorted set. (owever, i" you re going to have larger Auantities in your )et, the %er"or#ance o" Tree)et insertions will get slow. :hen you re writing a %rogra# that needs a )et, you should choose Hash)et by de"ault, and change to Tree)et when itVs #ore i#%ortant to have a constantly sorted set. RFSURFSTIJLT+(6PTE52TIMG@U
//3 c'C3ListPerfor#ance.Hava // De#onstrates "erfor#ance !ifferences in Lists. i#"ort Hava.util.B< i#"ort co#.bruceeckel.util.B< "ublic class ListPerfor#ance @ "rivate abstract static class Tester @ %tring na#e< int siUe< // Test =uantity Tester-%tring na#e, int siUe. @ this.na#e ? na#e< this.siUe ? siUe< A abstract voi! test-List a, int re"s.< A "rivate static TesterNO tests ? @ ne: Tester-8get8, )''. @
52=
voi! test-List a, int re"s. @ for-int i ? '< i P re"s< iKK. @ for-int H ? '< H P a.siUe-.< HKK. a.get-H.< A A A, ne: Tester-8iteration8, )''. @ voi! test-List a, int re"s. @ for-int i ? '< i P re"s< iKK. @ $terator it ? a.iterator-.< :hile-it.has&e6t-.. it.ne6t-.< A A A, ne: Tester-8insert8, ,'''. @ voi! test-List a, int re"s. @ int half ? a.siUe-./ < %tring s ? 8test8< List$terator it ? a.list$terator-half.< for-int i ? '< i P siUe B ('< iKK. it.a!!-s.< A A, ne: Tester-8re#ove8, ,'''. @ voi! test-List a, int re"s. @ List$terator it ? a.list$terator-).< :hile-it.has&e6t-.. @ it.ne6t-.< it.re#ove-.< A A A, A< "ublic static voi! test-List a, int re"s. @ // 0 trick to "rint out the class na#e3 %yste#.out."rintln-8Testing 8 K a.getClass-..get&a#e-..< for-int i ? '< i P tests.length< iKK. @ Collections .fill-a,
521
Collections .countries.reset-., testsNiO.siUe.< %yste#.out."rint-testsNiO.na#e.< long t( ? %yste#.currentTi#eJillis-.< testsNiO.test-a, re"s.< long t ? %yste#.currentTi#eJillis-.< %yste#.out."rintln-83 8 K -t - t(..< A A "ublic static voi! test0rray-int re"s. @ %yste#.out."rintln-8Testing array as List8.< // Can only !o first t:o tests on an array3 for-int i ? '< i P < iKK. @ %tringNO sa ? ne: %tringNtestsNiO.siUeO< 0rrays .fill-sa, Collections .countries.reset-..< List a ? 0rrays.asList-sa.< %yste#.out."rint-testsNiO.na#e.< long t( ? %yste#.currentTi#eJillis-.< testsNiO.test-a, re"s.< long t ? %yste#.currentTi#eJillis-.< %yste#.out."rintln-83 8 K -t - t(..< A A "ublic static voi! #ain-%tringNO args. @ int re"s ? ,''''< // Gr, choose the nu#ber of re"etitions // via the co##an! line3 if-args.length Q '. re"s ? $nteger."arse$nt-argsN'O.< %yste#.out."rintln-re"s K 8 re"etitions8.< test0rray-re"s.< test-ne: 0rrayList-., re"s.< test-ne: Linke!List-., re"s.< test-ne: Wector-., re"s.< A A ///3>
The inner class Tester is abstract, to %rovide a base class "or the s%eci"ic tests. It contains a )tring to be %rinted when the test starts, a si7e %ara#eter to be used by the test "or Auantity o" ele#ents or re%etitions o"
522
tests, a constructor to initiali1e the "ields, and an abstract #ethod test A B that does the work. 6ll the di""erent ty%es o" tests are collected in one %lace, the array tests, which is initiali1ed with di""erent anony#ous inner classes that inherit "ro# Tester. To add or re#ove tests, si#%ly add or re#ove an inner class de"inition "ro# the array, and everything else ha%%ens auto#atically. RFSURFSTIJLT+(6PTE52TIMGMU To co#%are array access to container access *%ri#arily against
Array+ist,, a s%ecial test is created "or arrays by wra%%ing one as a +ist using Arrays!as+istA B. Cote that only the "irst two tests can be
%er"or#ed in this case, because you cannot insert or re#ove ele#ents "ro# an array. RFSURFSTIJLT+(6PTE52TIMGKU The +ist that s handed to testA B is "irst "illed with ele#ents, then each test in the tests array is ti#ed. The results will vary "ro# #achine to #achine; they are intended to give only an order o" #agnitude co#%arison between the %er"or#ance o" the di""erent containers. (ere is a su##ary o" one run=
Type
array
"et
M?L@ L@G@ M3LK @ ?I2@
Iteratio n
LIH@ MKK@@ 2MM@ M3KH@
Inser t
na H@@ MM@ HH@
$emov e
na ?3IH@ 3@ ?3IH@
6s e&%ected, arrays are "aster than any container "or rando#'access looku%s and iteration. /ou can see that rando# accesses * getA B, are chea% "or Array+ists and e&%ensive "or +inke'+ists. *)ddly, iteration is $aster "or a +inke'+ist than an Array+ist, which is a bit counterintuitive., )n the other hand, insertions and re#ovals "ro# the #iddle o" a list are dra#atically chea%er "or a +inke'+ist than "or an Array+ist9 es eciall) re#ovals. Vector is generally not as "ast as Array+ist, and it should be avoided; it s only in the library "or legacy code su%%ort *the only reason it works in this %rogra# is because it was ada%ted to be a +ist in Java K,. The best a%%roach is %robably to choose an Array+ist as your de"ault, and to change to a +inke'+ist i" you discover %er"or#ance %roble#s due to #any insertions and re#ovals
523
"ro# the #iddle o" the list. 6nd o" course, i" you are working with a "i&ed' si1ed grou% o" ele#ents, use an array.
//3 c'C3%etPerfor#ance.Hava i#"ort Hava.util.B< i#"ort co#.bruceeckel.util.B< "ublic class %etPerfor#ance @ "rivate abstract static class Tester @ %tring na#e< Tester-%tring na#e. @ this.na#e ? na#e< A abstract voi! test-%et s, int siUe, int re"s.< A "rivate static TesterNO tests ? @ ne: Tester-8a!!8. @ voi! test-%et s, int siUe, int re"s. @ for-int i ? '< i P re"s< iKK. @ s.clear-.< Collections .fill-s, Collections .countries.reset-.,siUe.< A A A, ne: Tester-8contains8. @ voi! test-%et s, int siUe, int re"s. @ for-int i ? '< i P re"s< iKK. for-int H ? '< H P siUe< HKK. s.contains-$nteger.to%tring-H..< A A, ne: Tester-8iteration8. @ voi! test-%et s, int siUe, int re"s. @ for-int i ? '< i P re"s B ('< iKK. @ $terator it ? s.iterator-.<
524
:hile-it.has&e6t-.. it.ne6t-.< A A A, A< "ublic static voi! test-%et s, int siUe, int re"s. @ %yste#.out."rintln-8Testing 8 K s.getClass-..get&a#e-. K 8 siUe 8 K siUe.< Collections .fill-s, Collections .countries.reset-., siUe.< for-int i ? '< i P tests.length< iKK. @ %yste#.out."rint-testsNiO.na#e.< long t( ? %yste#.currentTi#eJillis-.< testsNiO.test-s, siUe, re"s.< long t ? %yste#.currentTi#eJillis-.< %yste#.out."rintln-83 8 K --!ouble.-t - t(./-!ouble.siUe..< A A "ublic static voi! #ain-%tringNO args. @ int re"s ? ,''''< // Gr, choose the nu#ber of re"etitions // via the co##an! line3 if-args.length Q '. re"s ? $nteger."arse$nt-argsN'O.< // %#all3 test-ne: Tree%et-., (', re"s.< test-ne: Mash%et-., (', re"s.< // Je!iu#3 test-ne: Tree%et-., ('', re"s.< test-ne: Mash%et-., ('', re"s.< // Large3 test-ne: Tree%et-., (''', re"s.< test-ne: Mash%et-., (''', re"s.< A A ///3>
525
The "ollowing table shows the results o" one run. *)" course, this will be di""erent according to the co#%uter and JVM you are using; you should run the test yoursel" as well,=
Type
Test si7e
M@
A' '
ML I.@ MI 2.H MH @.3 HH. @ ?H. 3 L3. M?
-ontai ns
MMH.@ MHM.M MGG.? IK.@ 2@.@ [email protected]
Iterati on
MIG.@ [email protected] ?@.@? M2K.@ [email protected] L2.L2
Tree) et
M@@ M@@@ M@
Hash )et
M@@ M@@@
The %er"or#ance o" Hash)et is generally su%erior to Tree)et "or all o%erations *but in %articular addition and looku%, the two #ost i#%ortant o%erations,. The only reason Tree)et e&ists is because it #aintains its ele#ents in sorted order, so you only use it when you need a sorted )et.
Choosing between 3a s
:hen choosing between i#%le#entations o" 1ap, the si1e o" the 1ap is what #ost strongly a""ects %er"or#ance, and the "ollowing test %rogra# gives an indication o" this trade'o""= RFSURFSTIJLT+(6PTE52TIMG?U
//3 c'C3Ja"Perfor#ance.Hava // De#onstrates "erfor#ance !ifferences in Ja"s. i#"ort Hava.util.B< i#"ort co#.bruceeckel.util.B< "ublic class Ja"Perfor#ance @ "rivate abstract static class Tester @ %tring na#e< Tester-%tring na#e. @ this.na#e ? na#e< A
527
abstract voi! test-Ja" #, int siUe, int re"s.< A "rivate static TesterNO tests ? @ ne: Tester-8"ut8. @ voi! test-Ja" #, int siUe, int re"s. @ for-int i ? '< i P re"s< iKK. @ #.clear-.< Collections .fill-#, Collections .geogra"hy.reset-., siUe.< A A A, ne: Tester-8get8. @ voi! test-Ja" #, int siUe, int re"s. @ for-int i ? '< i P re"s< iKK. for-int H ? '< H P siUe< HKK. #.get-$nteger.to%tring-H..< A A, ne: Tester-8iteration8. @ voi! test-Ja" #, int siUe, int re"s. @ for-int i ? '< i P re"s B ('< iKK. @ $terator it ? #.entry%et-..iterator-.< :hile-it.has&e6t-.. it.ne6t-.< A A A, A< "ublic static voi! test-Ja" #, int siUe, int re"s. @ %yste#.out."rintln-8Testing 8 K #.getClass-..get&a#e-. K 8 siUe 8 K siUe.< Collections .fill-#, Collections .geogra"hy.reset-., siUe.< for-int i ? '< i P tests.length< iKK. @ %yste#.out."rint-testsNiO.na#e.< long t( ? %yste#.currentTi#eJillis-.< testsNiO.test-#, siUe, re"s.< long t ? %yste#.currentTi#eJillis-.< %yste#.out."rintln-83 8 K
528
--!ouble.-t A
- t(./-!ouble.siUe..<
A "ublic static voi! #ain-%tringNO args. @ int re"s ? ,''''< // Gr, choose the nu#ber of re"etitions // via the co##an! line3 if-args.length Q '. re"s ? $nteger."arse$nt-argsN'O.< // %#all3 test-ne: TreeJa"-., (', re"s.< test-ne: MashJa"-., (', re"s.< test-ne: Mashtable-., (', re"s.< // Je!iu#3 test-ne: TreeJa"-., ('', re"s.< test-ne: MashJa"-., ('', re"s.< test-ne: Mashtable-., ('', re"s.< // Large3 test-ne: TreeJa"-., (''', re"s.< test-ne: MashJa"-., (''', re"s.< test-ne: Mashtable-., (''', re"s.< A A ///3>
Because the si1e o" the #a% is the issue, you ll see that the ti#ing tests divide the ti#e by the si1e to nor#ali1e each #easure#ent. (ere is one set o" results. */ours will %robably be di""erent.,
Type
Tes t si7 e
M@
#*t
"et
Iteratio n
Tree1a p
M@@ M@@ @ M@
52:
Type
Tes t si7 e
M@@ M@@ @ M@
#*t
"et
Iteratio n
Hash1a p
Hashtab le
M@@ M@@ @
6s you #ight e&%ect, Hashtable %er"or#ance is roughly eAuivalent to Hash1ap. */ou can also see that Hash1ap is generally a bit "aster. Hash1ap is intended to re%lace Hashtable., The Tree1ap is generally slower than the Hash1ap, so why would you use itO So you could use it not as a 1ap, but as a way to create an ordered list. The behavior o" a tree is such that it s always in order and doesn t have to be s%ecially sorted. )nce you "ill a Tree1ap, you can call key)etA B to get a )et view o" the keys, then toArrayA B to %roduce an array o" those keys. /ou can then use the static #ethod Arrays!binary)earchA B *discussed later, to ra%idly "ind ob0ects in your sorted array. )" course, you would %robably only do this i", "or so#e reason, the behavior o" a Hash1ap was unacce%table, since Hash1ap is designed to ra%idly "ind things. 6lso, you can easily create a Hash1ap "ro# a Tree1ap with a single ob0ect creation In the end, when you re using a 1ap your "irst choice should be Hash1ap, and only i" you need a constantly sorted 1ap will you need Tree1ap.
52;
#ethods o" -ollections instead o" Arrays. (ere s an e&a#%le, #odi"ied "ro# Array)earching!8ava=
//3 c'C3List%ort%earch.Hava // %orting an! searching Lists :ith 2Collections.2 i#"ort co#.bruceeckel.util.B< i#"ort Hava.util.B< "ublic class List%ort%earch @ "ublic static voi! #ain-%tringNO args. @ List list ? ne: 0rrayList-.< Collections .fill-list, Collections .ca"itals, ,.< %yste#.out."rintln-list K 8_n8.< Collections.shuffle-list.< %yste#.out."rintln-80fter shuffling3 8Klist.< Collections.sort-list.< %yste#.out."rintln-list K 8_n8.< GbHect key ? list.get-( .< int in!e6 ? Collections.binary%earch-list, key.< %yste#.out."rintln-8Location of 8 K key K 8 is 8 K in!e6 K 8, list.get-8 K in!e6 K 8. ? 8 K list.get-in!e6..< 0l"habeticCo#"arator co#" ? ne: 0l"habeticCo#"arator-.< Collections.sort-list, co#".< %yste#.out."rintln-list K 8_n8.< key ? list.get-( .< in!e6 ? Collections.binary%earch-list, key, co#".< %yste#.out."rintln-8Location of 8 K key K 8 is 8 K in!e6 K 8, list.get-8 K in!e6 K 8. ? 8 K list.get-in!e6..< A A ///3>
The use o" these #ethods is identical to the ones in Arrays, but you re using a +ist instead o" an array. Just like searching and sorting with arrays, i" you sort using a -omparator you #ust binary)earchA B using the sa#e -omparator. RFSURFSTIJLT+(6PTE52TIMGHU
53=
This %rogra# also de#onstrates the sh*ffleA B #ethod in -ollections, which rando#i1es the order o" a +ist. RFSURFSTIJLT+(6PTE52TIMG3U
Ctilities
There are a nu#ber o" other use"ul utilities in the -ollections class=
ma4A-ollection, -omparatorB minA-ollection, -omparatorB reverseA B copyA+ist 'est, +ist srcB fillA+ist list, .b8ect oB n-opiesAint n, .b8ect oB
Produces an old'style &n*meration "or the argu#ent. Produces the #a&i#u# or #ini#u# ele#ent in the argu#ent using the natural co#%arison #ethod o" the ob0ects in the -ollection. Produces the #a&i#u# or #ini#u# ele#ent in the -ollection using the -omparator. 5everses all the ele#ents in %lace. +o%ies ele#ents "ro# src to dest. 5e%laces all the ele#ents o" list with o. 5eturns an i##utable +ist o" si1e n whose re"erences all %oint to o.
Cote that minA B and ma4A B work with -ollection ob0ects, not with +ists, so you don t need to worry about whether the -ollection should be sorted or not. *6s #entioned earlier, you do need to sortA B a +ist or an array be"ore %er"or#ing a binary)earchA B., RFSURF STIJLT+(6PTE52TIMGGU
531
//3 c'C35ea!Gnly.Hava // Ysing the Collections.un#o!ifiable #etho!s. i#"ort Hava.util.B< i#"ort co#.bruceeckel.util.B< "ublic class 5ea!Gnly @ static Collections .%tringaenerator gen ? Collections .countries< "ublic static voi! #ain-%tringNO args. @ Collection c ? ne: 0rrayList-.< Collections .fill-c, gen, ,.< // $nsert !ata c ? Collections.un#o!ifiableCollection-c.< %yste#.out."rintln-c.< // 5ea!ing is G` c.a!!-8one8.< // Can2t change it List a ? ne: 0rrayList-.< Collections .fill-a, gen.reset-., ,.< a ? Collections.un#o!ifiableList-a.< List$terator lit ? a.list$terator-.< %yste#.out."rintln-lit.ne6t-..< // 5ea!ing G` lit.a!!-8one8.< // Can2t change it %et s ? ne: Mash%et-.< Collections .fill-s, gen.reset-., ,.< s ? Collections.un#o!ifiable%et-s.< %yste#.out."rintln-s.< // 5ea!ing G` //4 s.a!!-8one8.< // Can2t change it Ja" # ? ne: MashJa"-.< Collections .fill-#,
532
Collections .geogra"hy, ,.< # ? Collections.un#o!ifiableJa"-#.< %yste#.out."rintln-#.< // 5ea!ing G` //4 #."ut-85al"h8, 8Mo:!y48.< A A ///3>
In each case, you #ust "ill the container with #eaning"ul data be$ore you #ake it read'only. )nce it is loaded, the best a%%roach is to re%lace the e&isting re"erence with the re"erence that is %roduced by the !un#odi"iable$ call. That way, you don t run the risk o" accidentally changing the contents once you ve #ade it un#odi"iable. )n the other hand, this tool also allows you to kee% a #odi"iable container as private within a class and to return a read'only re"erence to that container "ro# a #ethod call. So you can change it "ro# within the class, but everyone else can only read it. RFSURFSTIJLT+(6PTE52TIMGIU +alling the !un#odi"iable$ #ethod "or a %articular ty%e does not cause co#%ile'ti#e checking, but once the trans"or#ation has occurred, any calls to #ethods that #odi"y the contents o" a %articular container will %roduce an Uns*pporte'.peration&4ception. RFSURF STIJLT+(6PTE52TIMG2U
1:nchroni?ing a $ollection or 3a
The synchroni7e' keyword is an i#%ortant %art o" the sub0ect o" multithreading, a #ore co#%licated to%ic that will not be introduced until +ha%ter M?. (ere, I shall note only that the -ollections class contains a way to auto#atically synchroni1e an entire container. The synta& is si#ilar to the !un#odi"iable$ #ethods=
//3 c'C3%ynchroniUation.Hava // Ysing the Collections.synchroniUe! #etho!s. i#"ort Hava.util.B< "ublic class %ynchroniUation @ "ublic static voi! #ain-%tringNO args. @ Collection c ? Collections.synchroniUe!Collectionne: 0rrayList-..<
533
List list ? Collections.synchroniUe!Listne: 0rrayList-..< %et s ? Collections.synchroniUe!%etne: Mash%et-..< Ja" # ? Collections.synchroniUe!Ja"ne: MashJa"-..< A A ///3>
In this case, you i##ediately %ass the new container through the a%%ro%riate !synchroni1ed$ #ethod; that way there s no chance o" accidentally e&%osing the unsynchroni1ed version. RFSURF STIJLT+(6PTE52TIMI@U
<ail fast
The Java containers also have a #echanis# to %revent #ore than one %rocess "ro# #odi"ying the contents o" a container. The %roble# occurs i" you re iterating through a container and so#e other %rocess ste%s in and inserts, re#oves, or changes an ob0ect in that container. Maybe you ve already %assed that ob0ect, #aybe it s ahead o" you, #aybe the si1e o" the container shrinks a"ter you call si7eA B9there are #any scenarios "or disaster. The Java containers library incor%orates a $ail/$ast #echanis# that looks "or any changes to the container other than the ones your %rocess is %ersonally res%onsible "or. I" it detects that so#eone else is #odi"ying the container, it i##ediately %roduces a -onc*rrent1o'ification&4ception. This is the !"ail'"ast$ as%ect9it doesn t try to detect a %roble# later on using a #ore co#%le& algorith#. RFSURFSTIJLT+(6PTE52TIMIMU It s Auite easy to see the "ail'"ast #echanis# in o%eration9all you have to do is create an iterator and then add so#ething to the collection that the iterator is %ointing to, like this=
//3 c'C3LailLast.Hava // De#onstrates the 8fail fast8 behavior. i#"ort Hava.util.B< "ublic class LailLast @ "ublic static voi! #ain-%tringNO args. @ Collection c ? ne: 0rrayList-.<
534
Cnsu..orted o.erations
It s %ossible to turn an array into a +ist with the Arrays!as+istA B #ethod=
//3 c'C3Ynsu""orte!.Hava // %o#eti#es #etho!s !efine! in the // Collection interfaces !on2t :ork4 i#"ort Hava.util.B< "ublic class Ynsu""orte! @ "rivate static %tringNO s ? @ 8one8, 8t:o8, 8three8, 8four8, 8five8, 8si68, 8seven8, 8eight8, 8nine8, 8ten8, A< static List a ? 0rrays.asList-s.< static List a ? a.subList-), +.< "ublic static voi! #ain-%tringNO args. @ %yste#.out."rintln-a.< %yste#.out."rintln-a .< %yste#.out."rintln8a.contains-8 K sN'O K 8. ? 8 K
535
a.contains-sN'O..< %yste#.out."rintln8a.contains0ll-a . ? 8 K a.contains0ll-a ..< %yste#.out."rintln-8a.isE#"ty-. ? 8 K a.isE#"ty-..< %yste#.out."rintln8a.in!e6Gf-8 K sN,O K 8. ? 8 K a.in!e6Gf-sN,O..< // Traverse back:ar!s3 List$terator lit ? a.list$terator-a.siUe-..< :hile-lit.hasPrevious-.. %yste#.out."rint-lit."revious-. K 8 8.< %yste#.out."rintln-.< // %et the ele#ents to !ifferent values3 for-int i ? '< i P a.siUe-.< iKK. a.set-i, 8I*8.< %yste#.out."rintln-a.< // Co#"iles, but :on2t run3 lit.a!!-898.< // Ynsu""orte! o"eration a.clear-.< // Ynsu""orte! a.a!!-8eleven8.< // Ynsu""orte! a.a!!0ll-a .< // Ynsu""orte! a.retain0ll-a .< // Ynsu""orte! a.re#ove-sN'O.< // Ynsu""orte! a.re#ove0ll-a .< // Ynsu""orte! A A ///3>
/ou ll discover that only a %ortion o" the -ollection and +ist inter"aces are actually i#%le#ented. The rest o" the #ethods cause the unwelco#e a%%earance o" so#ething called an Uns*pporte'.peration&4ception. /ou ll learn all about e&ce%tions in the ne&t cha%ter, but the short story is that the -ollection interface 9as well as so#e o" the other interfaces in the Java containers library9 contain !o%tional$ #ethods, which #ight or #ight not be !su%%orted$ in the concrete class that implements that interface. +alling an unsu%%orted #ethod causes an Uns*pporte'.peration&4ception to indicate a %rogra##ing error. RFSURFSTIJLT+(6PTE52TIMI?U
537
!:hatO.O$ you say, incredulous. !The whole %oint o" interfaces and base classes is that they %ro#ise these #ethods will do so#ething #eaning"ul. This breaks that %ro#ise9it says that not only will calling so#e #ethods not %er"or# a #eaning"ul behavior, they will sto% the %rogra#. Ty%e sa"ety was 0ust thrown out the window.$ RFSURF STIJLT+(6PTE52TIMIHU It s not Auite that bad. :ith a -ollection, +ist, )et, or 1ap, the co#%iler still restricts you to calling only the #ethods in that interface, so it s not like S#alltalk *in which you can call any #ethod "or any ob0ect, and "ind out only when you run the %rogra# whether your call does anything,. In addition, #ost #ethods that take a -ollection as an argu#ent only read "ro# that -ollection9all the !read$ #ethods o" -ollection are not o%tional. RFSURFSTIJLT+(6PTE52TIMI3U This a%%roach %revents an e&%losion o" inter"aces in the design. )ther designs "or container libraries always see# to end u% with a con"using %lethora o" inter"aces to describe each o" the variations on the #ain the#e and are thus di""icult to learn. It s not even %ossible to ca%ture all o" the s%ecial cases in interfaces, because so#eone can always invent a new interface. The !unsu%%orted o%eration$ a%%roach achieves an i#%ortant goal o" the Java containers library= the containers are si#%le to learn and use; unsu%%orted o%erations are a s%ecial case that can be learned later. Eor this a%%roach to work, however= RFSURF STIJLT+(6PTE52TIMIGU
5()
The Uns*pporte'.peration&4ception #ust be a rare event. That is, "or #ost classes all o%erations should work, and only in s%ecial cases should an o%eration be unsu%%orted. This is true in the Java containers library, since the classes you ll use 22 %ercent o" the ti#e9 Array+ist, +inke'+ist, Hash)et, and Hash1ap, as well as the other concrete i#%le#entations9su%%ort all o" the o%erations. The design does %rovide a !back door$ i" you want to create a new -ollection without %roviding #eaning"ul de"initions "or all the #ethods in the -ollection interface, and yet still "it it into the e&isting library. RFSURFSTIJLT+(6PTE52TIMIIU :hen an o%eration is unsu%%orted, there should be reasonable likelihood that an Uns*pporte'.peration&4ception will
5!)
538
a%%ear at i#%le#entation ti#e, rather than a"ter you ve shi%%ed the %roduct to the custo#er. 6"ter all, it indicates a %rogra##ing error= you ve used an i#%le#entation incorrectly. This %oint is less certain, and is where the e&%eri#ental nature o" this design co#es into %lay. )nly over ti#e will we "ind out how well it works. RF SURFSTIJLT+(6PTE52TIMI2U In the e&a#%le above, Arrays!as+istA B %roduces a +ist that is backed by a "i&ed'si1e array. There"ore it #akes sense that the only su%%orted o%erations are the ones that don t change the si1e o" the array. I", on the other hand, a new interface were reAuired to e&%ress this di""erent kind o" behavior *called, %erha%s, ! Fi4e')i7e+ist$,, it would throw o%en the door to co#%le&ity and soon you wouldn t know where to start when trying to use the library. RFSURFSTIJLT+(6PTE52TIM2@U The docu#entation "or a #ethod that takes a -ollection, +ist, )et, or 1ap as an argu#ent should s%eci"y which o" the o%tional #ethods #ust be i#%le#ented. Eor e&a#%le, sorting reAuires the setA B and Iterator! setA B #ethods, but not a''A B and removeA B. RFSURF STIJLT+(6PTE52TIM2MU
=ector L /numeration
The only sel"'e&%anding seAuence in Java [email protected] was the Vector, and so it saw a lot o" use. Its "laws are too nu#erous to describe here *see the "irst edition o" this book, available on this book s +7 5)M and as a "ree download "ro# ,,,'0ruceEckel'com,. Basically, you can think o" it as an Array+ist with long, awkward #ethod na#es. In the Java K container
53:
library, Vector was ada%ted so that it could "it as a -ollection and a +ist, so in the "ollowing e&a#%le the -ollectionsI!fillA B #ethod is success"ully used. This turns out to be a bit %erverse, as it #ay con"use so#e %eo%le into thinking that Vector has gotten better, when it is actually included only to su%%ort %re'Java K code. RFSURF STIJLT+(6PTE52TIM2LU The Java [email protected] version o" the iterator chose to invent a new na#e, !enu#eration,$ instead o" using a ter# that everyone was already "a#iliar with. The &n*meration inter"ace is s#aller than Iterator, with only two #ethods, and it uses longer #ethod na#es= boolean has1ore&lementsA B %roduces tr*e i" this enu#eration contains #ore ele#ents, and .b8ect ne4t&lementA B returns the ne&t ele#ent o" this enu#eration i" there are any #ore *otherwise it throws an e&ce%tion,. RF SURFSTIJLT+(6PTE52TIM2?U
&n*meration is only an inter"ace, not an i#%le#entation, and even new libraries so#eti#es still use the old &n*meration9which is
un"ortunate but generally har#less. Even though you should always use Iterator when you can in your own code, you #ust be %re%ared "or libraries that want to hand you an &n*meration. RFSURF STIJLT+(6PTE52TIM2HU In addition, you can %roduce an &n*meration "or any -ollection by using the -ollections!en*merationA B #ethod, as seen in this e&a#%le=
//3 c'C3Enu#erations.Hava // Java (.'/(.( Wector an! Enu#eration. i#"ort Hava.util.B< i#"ort co#.bruceeckel.util.B< "ublic class Enu#erations @ "ublic static voi! #ain-%tringNO args. @ Wector v ? ne: Wector-.< Collections .fillv, Collections .countries, (''.< Enu#eration e ? v.ele#ents-.< :hile-e.hasJoreEle#ents-.. %yste#.out."rintln-e.ne6tEle#ent-..<
53;
>ashtable
6s you ve seen in the %er"or#ance co#%arison in this cha%ter, the basic Hashtable is very si#ilar to the Hash1ap, even down to the #ethod na#es. There s no reason to use Hashtable instead o" Hash1ap in new code. RFSURFSTIJLT+(6PTE52TIM2IU
1tack
The conce%t o" the stack was introduced earlier, with the +inke'+ist. :hat s rather odd about the Java [email protected] )tack is that instead o" using a Vector as a building block, )tack is inherited "ro# Vector. So it has all o" the characteristics and behaviors o" a Vector %lus so#e e&tra )tack behaviors. It s di""icult to know whether the designers e&%licitly decided that this was an es%ecially use"ul way o" doing things, or whether it was 0ust a naive design. RFSURFSTIJLT+(6PTE52TIM22U (ere s a si#%le de#onstration o" )tack that %ushes each line "ro# a )tring array=
//3 c'C3%tacks.Hava // De#onstration of %tack Class. i#"ort Hava.util.B< "ublic class %tacks @
54=
static %tringNO #onths ? @ 8January8, 8Lebruary8, 8Jarch8, 80"ril8, 8Jay8, 8June8, 8July8, 80ugust8, 8%e"te#ber8, 8Gctober8, 8&ove#ber8, 8Dece#ber8 A< "ublic static voi! #ain-%tringNO args. @ %tack stk ? ne: %tack-.< for-int i ? '< i P #onths.length< iKK. stk."ush-#onthsNiO K 8 8.< %yste#.out."rintln-8stk ? 8 K stk.< // Treating a stack as a Wector3 stk.a!!Ele#ent-8The last line8.< %yste#.out."rintln8ele#ent , ? 8 K stk.ele#ent0t-,..< %yste#.out."rintln-8"o""ing ele#ents38.< :hile-4stk.e#"ty-.. %yste#.out."rintln-stk."o"-..< A A ///3>
Each line in the months array is inserted into the )tack with p*shA B, and later "etched "ro# the to% o" the stack with a popA B. To #ake a %oint, Vector o%erations are also %er"or#ed on the )tack ob0ect. This is %ossible because, by virtue o" inheritance, a )tack is a Vector. Thus, all o%erations that can be %er"or#ed on a Vector can also be %er"or#ed on a )tack, such as elementAtA B. RFSURFSTIJLT+(6PTE52TIK@@U 6s #entioned earlier, you should use a +inke'+ist when you want stack behavior. RFSURFSTIJLT+(6PTE52TIK@MU
;it1et
6 2it)et is used i" you want to e""iciently store a lot o" on'o"" in"or#ation. It s e""icient only "ro# the stand%oint o" si1e; i" you re looking "or e""icient access, it is slightly slower than using an array o" so#e native ty%e. RFSURFSTIJLT+(6PTE52TIK@KU In addition, the #ini#u# si1e o" the 2it)et is that o" a long= 3? bits. This i#%lies that i" you re storing anything s#aller, like I bits, a 2it)et will be waste"ul; you re better o"" creating your own class, or 0ust an array, to hold your "lags i" si1e is an issue. RFSURFSTIJLT+(6PTE52TIK@LU
541
6 nor#al container e&%ands as you add #ore ele#ents, and the 2it)et does this as well. The "ollowing e&a#%le shows how the 2it)et works=
//3 c'C3Bits.Hava // De#onstration of Bit%et. i#"ort Hava.util.B< "ublic class Bits @ static voi! "rintBit%et-Bit%et b. @ %yste#.out."rintln-8bits3 8 K b.< %tring bbits ? ne: %tring-.< for-int H ? '< H P b.siUe-. < HKK. bbits K? -b.get-H. [ 8(8 3 8'8.< %yste#.out."rintln-8bit "attern3 8 K bbits.< A "ublic static voi! #ain-%tringNO args. @ 5an!o# ran! ? ne: 5an!o#-.< // Take the L%B of ne6t$nt-.3 byte bt ? -byte.ran!.ne6t$nt-.< Bit%et bb ? ne: Bit%et-.< for-int i ? *< i Q?'< i--. if---( PP i. D bt. 4? '. bb.set-i.< else bb.clear-i.< %yste#.out."rintln-8byte value3 8 K bt.< "rintBit%et-bb.< short st ? -short.ran!.ne6t$nt-.< Bit%et bs ? ne: Bit%et-.< for-int i ? (,< i Q?'< i--. if---( PP i. D st. 4? '. bs.set-i.< else bs.clear-i.< %yste#.out."rintln-8short value3 8 K st.< "rintBit%et-bs.< int it ? ran!.ne6t$nt-.< Bit%et bi ? ne: Bit%et-.< for-int i ? )(< i Q?'< i--.
542
if---( PP i. D it. 4? '. bi.set-i.< else bi.clear-i.< %yste#.out."rintln-8int value3 8 K it.< "rintBit%et-bi.< // Test bitsets Q? +I bits3 Bit%et b( * ? ne: Bit%et-.< b( *.set-( *.< %yste#.out."rintln-8set bit ( *3 8 K b( *.< Bit%et b ,, ? ne: Bit%et-+,.< b ,,.set- ,,.< %yste#.out."rintln-8set bit ,,3 8 K b ,,.< Bit%et b(' ) ? ne: Bit%et-,( .< b(' ).set-(' ).< b(' ).set-(' I.< %yste#.out."rintln-8set bit (' )3 8 K b(' ).< A A ///3>
The rando# nu#ber generator is used to create a rando# byte, short, and int, and each one is trans"or#ed into a corres%onding bit %attern in a 2it)et. This works "ine because a 2it)et is 3? bits, so none o" these cause it to increase in si1e. Then a 2it)et o" HMK bits is created. The constructor allocates storage "or twice that nu#ber o" bits. (owever, you can still set bit M@K? or greater. RFSURFSTIJLT+(6PTE52TIK@?U
1ummar:
To review the containers %rovided in the standard Java library= RFSURF STIJLT+(6PTE52TIK@HU
5*)
6n array associates nu#erical indices to ob0ects. It holds ob0ects o" a known ty%e so that you don t have to cast the result when you re looking u% an ob0ect. It can be #ultidi#ensional, and it can hold %ri#itives. (owever, its si1e cannot be changed once you create it. RFSURFSTIJLT+(6PTE52TIK@3U
543
5+) 5,)
6 -ollection holds single ele#ents, while a 1ap holds associated %airs. RFSURFSTIJLT+(6PTE52TIK@GU Dike an array, a +ist also associates nu#erical indices to ob0ects9 you can think o" arrays and +ists as ordered containers. The +ist auto#atically resi1es itsel" as you add #ore ele#ents. But a +ist can hold only .b8ect references, so it won t hold %ri#itives and you #ust always cast the result when you %ull an .b8ect re"erence out o" a container. RFSURFSTIJLT+(6PTE52TIK@IU 4se an Array+ist i" you re doing a lot o" rando# accesses, and a +inke'+ist i" you will be doing a lot o" insertions and re#ovals in the #iddle o" the list. RFSURFSTIJLT+(6PTE52TIK@2U The behavior o" Aueues, deAues, and stacks is %rovided via the +inke'+ist. RFSURFSTIJLT+(6PTE52TIKM@U 6 1ap is a way to associate not nu#bers, but ob>ects with other ob0ects. The design o" a Hash1ap is "ocused on ra%id access, while a Tree1ap kee%s its keys in sorted order, and thus is not as "ast as a Hash1ap. RFSURFSTIJLT+(6PTE52TIKMMU 6 )et only acce%ts one o" each ty%e o" ob0ect. Hash)ets %rovide #a&i#ally "ast looku%s, while Tree)ets kee% the ele#ents in sorted order. RFSURFSTIJLT+(6PTE52TIKMKU There s no need to use the legacy classes Vector, Hashtable and )tack in new code. RFSURFSTIJLT+(6PTE52TIKMLU
5-)
54) 55)
56)
67)
The containers are tools that you can use on a day'to'day basis to #ake your %rogra#s si#%ler, #ore %ower"ul, and #ore e""ective. RFSURF STIJLT+(6PTE52TIKM?U
/0ercises
Solutions to selected e&ercises can be "ound in the electronic docu#entThe Thinking in Java "nnotated Solution @uide, available "or a s#all "ee "ro# ,,,'0ruceEckel'com.
544
(!4) Take the "erbil class in E&ercise K and %ut it into a 1ap
instead, associating the na#e o" the "erbil as a )tring *the key, "or each "erbil *the value, you %ut in the table. 8et an Iterator "or the key)etA B and use it to #ove through the 1ap, looking u% the "erbil "or each key and %rinting out the key and telling the gerbil to hopA B. RFSURFSTIJLT+(6PTE52TIKMIU
(!5) +reate a +ist *try both Array+ist and +inke'+ist, and "ill it
using -ollectionsI!co*ntries. Sort the list and %rint it, then a%%ly -ollections!sh*ffleA B to the list re%eatedly, %rinting it each ti#e so that you can see how the sh*ffleA B #ethod rando#i1es the list di""erently each ti#e. RFSURF STIJLT+(6PTE52TIKM2U
545
mainA B, co#%are the %er"or#ance o" your container with an Array+ist holding )trings. RFSURFSTIJLT+(6PTE52TIKKLU
(**) 5e%eat E&ercise 2 "or a container o" int, and co#%are the
%er"or#ance to an Array+ist holding Integer ob0ects. In your %er"or#ance co#%arison, include the %rocess o" incre#enting each ob0ect in the container. RFSURFSTIJLT+(6PTE52TIKK?U
547
insertion starting at the end o" the "irst list and #oving backward. RFSURFSTIJLT+(6PTE52TIKL@U
(+!) +reate a class, then #ake an initiali1ed array o" ob0ects o" your
class. Eill a +ist "ro# your array. +reate a subset o" your +ist using s*b+istA B, and then re#ove this subset "ro# your +ist using removeAllA B. RFSURFSTIJLT+(6PTE52TIKLLU
(+-) Produce a 1ap and a )et containing all the countries that
begin with [6. RFSURFSTIJLT+(6PTE52TIKLGU
548
(,*) I#%le#ent the rest o" the 1ap inter"ace "or )lo(1ap. RF
SURFSTIJLT+(6PTE52TIK??U
54:
54;
&vent)et is 0ust a container. +hange the code to use a +inke'+ist instead o" an &vent)et. This will reAuire #ore than 0ust re%lacing &vent)et with +inke'+ist; you ll also need to use an Iterator to cycle through the set o" events. RFSURF
STIJLT+(6PTE52TIKH3U
(-4) *+hallenging,. Eind the source code "or +ist in the Java source
code library that co#es with all Java distributions. +o%y this code and #ake a s%ecial version called int+ist that holds only ints. +onsider what it would take to #ake a s%ecial version o" +ist "or all the %ri#itive ty%es. Cow consider what ha%%ens i" you want to #ake a linked list class that works with all the %ri#itive ty%es. I" %ara#eteri1ed ty%es are ever i#%le#ented in Java, they will %rovide a way to do this work "or you auto#atically *as well as #any other bene"its,. RFSURFSTIJLT+(6PTE52TIKHIU
55=
@ The + %rogra##er can look u% the return value o" printfA B "or an e&a#%le o" this.
551
The solution is to take the casual nature out o" error handling and to en"orce "or#ality. This actually has a long history, since i#%le#entations o" e*ce tion handling go back to o%erating syste#s in the M23@s, and even to B6SI+ s ! on error goto.$ But +<< e&ce%tion handling was based on 6da, and Java s is based %ri#arily on +<< *although it looks even #ore like )b0ect Pascal,. RFSURFSTIJLT+(6PTE5M@TILU The word !e&ce%tion$ is #eant in the sense o" !I take e&ce%tion to that.$ 6t the %oint where the %roble# occurs you #ight not know what to do with it, but you do know that you can t 0ust continue on #errily; you #ust sto% and so#ebody, so#ewhere, #ust "igure out what to do. But you don t have enough in"or#ation in the current conte&t to "i& the %roble#. So you hand the %roble# out to a higher conte&t where so#eone is Auali"ied to #ake the %ro%er decision *#uch like a chain o" co##and,. RF SURFSTIJLT+(6PTE5M@TI?U The other rather signi"icant bene"it o" e&ce%tions is that they clean u% error handling code. Instead o" checking "or a %articular error and dealing with it at #ulti%le %laces in your %rogra#, you no longer need to check at the %oint o" the #ethod call *since the e&ce%tion will guarantee that so#eone catches it,. 6nd, you need to handle the %roble# in only one %lace, the so'called e*ce tion handler. This saves you code, and it se%arates the code that describes what you want to do "ro# the code that is e&ecuted when things go awry. In general, reading, writing, and debugging code beco#es #uch clearer with e&ce%tions than when using the old way o" error handling. RFSURFSTIJLT+(6PTE5M@TIHU Because e&ce%tion handling is en"orced by the Java co#%iler, there are only so #any e&a#%les that can be written in this book without learning about e&ce%tion handling. This cha%ter introduces you to the code you need to write to %ro%erly handle e&ce%tions, and the way you can generate your own e&ce%tions i" one o" your #ethods gets into trouble. RFSURF STIJLT+(6PTE5M@TI3U
;asic e0ce.tions
6n e*ce tional condition is a %roble# that %revents the continuation o" the #ethod or sco%e that you re in. It s i#%ortant to distinguish an
552
Thinking in Java
,,,'0ruceEckel'com
e&ce%tional condition "ro# a nor#al %roble#, in which you have enough in"or#ation in the current conte&t to so#ehow co%e with the di""iculty. :ith an e&ce%tional condition, you cannot continue %rocessing because you don t have the in"or#ation necessary to deal with the %roble# in the current conte*t. 6ll you can do is 0u#% out o" the current conte&t and relegate that %roble# to a higher conte&t. This is what ha%%ens when you throw an e&ce%tion. RFSURFSTIJLT+(6PTE5M@TIGU 6 si#%le e&a#%le is a divide. I" you re about to divide by 1ero, it s worth checking to #ake sure you don t go ahead and %er"or# the divide. But what does it #ean that the deno#inator is 1eroO Maybe you know, in the conte&t o" the %roble# you re trying to solve in that %articular #ethod, how to deal with a 1ero deno#inator. But i" it s an une&%ected value, you can t deal with it and so #ust throw an e&ce%tion rather than continuing along that %ath. RFSURFSTIJLT+(6PTE5M@TIIU :hen you throw an e&ce%tion, several things ha%%en. Eirst, the e&ce%tion ob0ect is created in the sa#e way that any Java ob0ect is created= on the hea%, with ne(. Then the current %ath o" e&ecution *the one you couldn t continue, is sto%%ed and the re"erence "or the e&ce%tion ob0ect is e0ected "ro# the current conte&t. 6t this %oint the e&ce%tion handling #echanis# takes over and begins to look "or an a%%ro%riate %lace to continue e&ecuting the %rogra#. This a%%ro%riate %lace is the e*ce tion handlerD whose 0ob is to recover "ro# the %roble# so the %rogra# can either try another tack or 0ust continue. RFSURFSTIJLT+(6PTE5M@TI2U 6s a si#%le e&a#%le o" throwing an e&ce%tion, consider an ob0ect re"erence called t. It s %ossible that you #ight be %assed a re"erence that hasn t been initiali1ed, so you #ight want to check be"ore trying to call a #ethod using that ob0ect re"erence. /ou can send in"or#ation about the error into a larger conte&t by creating an ob0ect re%resenting your in"or#ation and !throwing$ it out o" your current conte&t. This is called thro,ing an e*ce tion' (ere s what it looks like=
553
#agically handled so#ewhere else. Precisely ,here will be shown shortly. RFSURFSTIJLT+(6PTE5M@TIM@U
/0ce.tion arguments
Dike any ob0ect in Java, you always create e&ce%tions on the hea% using ne(, which allocates storage and calls a constructor. There are two constructors in all standard e&ce%tions= the "irst is the de"ault constructor, and the second takes a string argu#ent so you can %lace %ertinent in"or#ation in the e&ce%tion=
554
Thinking in Java
,,,'0ruceEckel'com
e&ce%tion. *)"ten, the only in"or#ation is the ty%e o" e&ce%tion ob0ect, and nothing #eaning"ul is stored within the e&ce%tion ob0ect., RFSURF STIJLT+(6PTE5M@TIM?U
Catching an e0ce.tion
I" a #ethod throws an e&ce%tion, it #ust assu#e that e&ce%tion is !caught$ and dealt with. )ne o" the advantages o" Java e&ce%tion handling is that it allows you to concentrate on the %roble# you re trying to solve in one %lace, and then deal with the errors "ro# that code in another %lace. RFSURFSTIJLT+(6PTE5M@TIMHU To see how an e&ce%tion is caught, you #ust "irst understand the conce%t o" a guarded regionD which is a section o" code that #ight %roduce e&ce%tions, and which is "ollowed by the code to handle those e&ce%tions. RFSURFSTIJLT+(6PTE5M@TIM3U
555
/0ce.tion handlers
)" course, the thrown e&ce%tion #ust end u% so#e%lace. This !%lace$ is the e*ce tion handlerD and there s one "or every e&ce%tion ty%e you want to catch. E&ce%tion handlers i##ediately "ollow the try block and are denoted by the keyword catch=
try @ // Co!e that #ight generate e6ce"tions A catch-Ty"e( i!(. @ // Man!le e6ce"tions of Ty"e( A catch-Ty"e i! . @ // Man!le e6ce"tions of Ty"e A catch-Ty"e) i!). @ // Man!le e6ce"tions of Ty"e) A // etc...
Each catch clause *e&ce%tion handler, is like a little #ethod that takes one and only one argu#ent o" a %articular ty%e. The identi"ier * i'>, i'I, and so on, can be used inside the handler, 0ust like a #ethod argu#ent. So#eti#es you never use the identi"ier because the ty%e o" the e&ce%tion gives you enough in"or#ation to deal with the e&ce%tion, but the identi"ier #ust still be there. RFSURFSTIJLT+(6PTE5M@TIMIU The handlers #ust a%%ear directly a"ter the try block. I" an e&ce%tion is thrown, the e&ce%tion handling #echanis# goes hunting "or the "irst handler with an argu#ent that #atches the ty%e o" the e&ce%tion. Then it enters that catch clause, and the e&ce%tion is considered handled. The search "or handlers sto%s once the catch clause is "inished. )nly the #atching catch clause e&ecutes; it s not like a s(itch state#ent in which you need a break a"ter each case to %revent the re#aining ones "ro# e&ecuting. RFSURFSTIJLT+(6PTE5M@TIM2U Cote that, within the try block, a nu#ber o" di""erent #ethod calls #ight generate the sa#e e&ce%tion, but you need only one handler. RFSURF STIJLT+(6PTE5M@TIK@U
557
Thinking in Java
,,,'0ruceEckel'com
558
"oreseen when the Java e&ce%tion hierarchy was created. RFSURF STIJLT+(6PTE5M@TIK?U To create your own e&ce%tion class, you re "orced to inherit "ro# an e&isting ty%e o" e&ce%tion, %re"erably one that is close in #eaning to your new e&ce%tion *this is o"ten not %ossible, however,. The #ost trivial way to create a new ty%e o" e&ce%tion is 0ust to let the co#%iler create the de"ault constructor "or you, so it reAuires al#ost no code at all=
//3 c('3%i#"leE6ce"tionDe#o.Hava // $nheriting your o:n e6ce"tions. class %i#"leE6ce"tion e6ten!s E6ce"tion @A "ublic class %i#"leE6ce"tionDe#o @ "ublic voi! f-. thro:s %i#"leE6ce"tion @ %yste#.out."rintln8Thro:ing %i#"leE6ce"tion fro# f-.8.< thro: ne: %i#"leE6ce"tion -.< A "ublic static voi! #ain-%tringNO args. @ %i#"leE6ce"tionDe#o se! ? ne: %i#"leE6ce"tionDe#o-.< try @ se!.f-.< A catch-%i#"leE6ce"tion e. @ %yste#.err."rintln-8Caught it48.< A A A ///3>
:hen the co#%iler creates the de"ault constructor, it which auto#atically *and invisibly, calls the base'class de"ault constructor. )" course, in this case you don t get a )imple&4ceptionA)tringB constructor, but in %ractice that isn t used #uch. 6s you ll see, the #ost i#%ortant thing about an e&ce%tion is the class na#e, so #ost o" the ti#e an e&ce%tion like the one shown above is satis"actory. RFSURFSTIJLT+(6PTE5M@TIKHU (ere, the result is %rinted to the console standard error strea# by writing to )ystem!err. This is usually a better %lace to send error in"or#ation than )ystem!o*t, which #ay be redirected. I" you send
55:
Thinking in Java
,,,'0ruceEckel'com
out%ut to )ystem!err it will not be redirected along with )ystem!o*t so the user is #ore likely to notice it. RFSURFSTIJLT+(6PTE5M@TIK3U +reating an e&ce%tion class that also has a constructor that takes a )tring is also Auite si#%le=
//3 c('3LullConstructors.Hava // $nheriting your o:n e6ce"tions. class JyE6ce"tion e6ten!s E6ce"tion @ "ublic JyE6ce"tion-. @A "ublic JyE6ce"tion-%tring #sg. @ su"er-#sg.< A A "ublic class LullConstructors @ "ublic static voi! f-. thro:s JyE6ce"tion @ %yste#.out."rintln8Thro:ing JyE6ce"tion fro# f-.8.< thro: ne: JyE6ce"tion-.< A "ublic static voi! g-. thro:s JyE6ce"tion @ %yste#.out."rintln8Thro:ing JyE6ce"tion fro# g-.8.< thro: ne: JyE6ce"tion-8Griginate! in g-.8.< A "ublic static voi! #ain-%tringNO args. @ try @ f-.< A catch-JyE6ce"tion e. @ e."rint%tackTrace-%yste#.err.< A try @ g-.< A catch-JyE6ce"tion e. @ e."rint%tackTrace-%yste#.err.< A A A ///3>
55;
The added code is s#all9the addition o" two constructors that de"ine the way 1y&4ception is created. In the second constructor, the base'class constructor with a )tring argu#ent is e&%licitly invoked by using the s*per keyword. RFSURFSTIJLT+(6PTE5M@TIKGU The stack trace in"or#ation is sent to )ystem!err so that it s #ore likely it will be noticed in the event that )ystem!o*t has been redirected. RF SURFSTIJLT+(6PTE5M@TIKIU The out%ut o" the %rogra# is=
Thro:ing JyE6ce"tion fro# f-. JyE6ce"tion at LullConstructors.f-LullConstructors.Hava3(+. at LullConstructors.#ain-LullConstructors.Hava3 I. Thro:ing JyE6ce"tion fro# g-. JyE6ce"tion3 Griginate! in g-. at LullConstructors.g-LullConstructors.Hava3 '. at LullConstructors.#ain-LullConstructors.Hava3 C.
/ou can see the absence o" the detail #essage in the 1y&4ception thrown "ro# fA B. RFSURFSTIJLT+(6PTE5M@TIK2U The %rocess o" creating your own e&ce%tions can be taken "urther. /ou can add e&tra constructors and #e#bers=
//3 c('3E6traLeatures.Hava // Lurther e#bellish#ent of e6ce"tion classes. class JyE6ce"tion e6ten!s E6ce"tion @ "ublic JyE6ce"tion -. @A "ublic JyE6ce"tion -%tring #sg. @ su"er-#sg.< A "ublic JyE6ce"tion -%tring #sg, int 6. @ su"er-#sg.< i ? 6< A "ublic int val-. @ return i< A "rivate int i< A
57=
Thinking in Java
,,,'0ruceEckel'com
"ublic class E6traLeatures @ "ublic static voi! f-. thro:s JyE6ce"tion @ %yste#.out."rintln8Thro:ing JyE6ce"tion fro# f-.8.< thro: ne: JyE6ce"tion -.< A "ublic static voi! g-. thro:s JyE6ce"tion @ %yste#.out."rintln8Thro:ing JyE6ce"tion fro# g-.8.< thro: ne: JyE6ce"tion -8Griginate! in g-.8.< A "ublic static voi! h-. thro:s JyE6ce"tion @ %yste#.out."rintln8Thro:ing JyE6ce"tion fro# h-.8.< thro: ne: JyE6ce"tion 8Griginate! in h-.8, I*.< A "ublic static voi! #ain-%tringNO args. @ try @ f-.< A catch-JyE6ce"tion e. @ e."rint%tackTrace-%yste#.err.< A try @ g-.< A catch-JyE6ce"tion e. @ e."rint%tackTrace-%yste#.err.< A try @ h-.< A catch-JyE6ce"tion e. @ e."rint%tackTrace-%yste#.err.< %yste#.err."rintln-8e.val-. ? 8 K e.val-..< A A A ///3>
6 data #e#ber i has been added, along with a #ethod that reads that value and an additional constructor that sets it. The out%ut is= RFSURF STIJLT+(6PTE5M@TIL@U
571
Thro:ing JyE6ce"tion fro# f-. JyE6ce"tion at E6traLeatures.f-E6traLeatures.Hava3 . at E6traLeatures.#ain-E6traLeatures.Hava3)I. Thro:ing JyE6ce"tion fro# g-. JyE6ce"tion 3 Griginate! in g-. at E6traLeatures.g-E6traLeatures.Hava3 +. at E6traLeatures.#ain-E6traLeatures.Hava3)C. Thro:ing JyE6ce"tion fro# h-. JyE6ce"tion 3 Griginate! in h-. at E6traLeatures.h-E6traLeatures.Hava3)'. at E6traLeatures.#ain-E6traLeatures.Hava3II. e.val-. ? I*
Since an e&ce%tion is 0ust another kind o" ob0ect, you can continue this %rocess o" e#bellishing the %ower o" your e&ce%tion classes. >ee% in #ind, however, that all this dressing'u% #ight be lost on the client %rogra##ers using your %ackages, since they #ight si#%ly look "or the e&ce%tion to be thrown and nothing #ore. *That s the way #ost o" the Java library e&ce%tions are used., RFSURFSTIJLT+(6PTE5M@TILMU
572
Thinking in Java
,,,'0ruceEckel'com
The e&ce%tion s%eci"ication uses an additional keyword, thro(s, "ollowed by a list o" all the %otential e&ce%tion ty%es. So your #ethod de"inition #ight look like this=
573
)tring to)tringA B
5eturns a short descri%tion o" the Throwable, including the detail #essage i" there is one. RFSURFSTIJLT+(6PTE5M@TILIU
Thro(able fillIn)tackTraceA B
5ecords in"or#ation within this Thro(able ob0ect about the current state o" the stack "ra#es. 4se"ul when an a%%lication is rethrowing an error or e&ce%tion *#ore about this shortly,. RFSURF STIJLT+(6PTE5M@TI?@U In addition, you get so#e other #ethods "ro# Thro(able s base ty%e .b8ect *everybody s base ty%e,. The one that #ight co#e in handy "or e&ce%tions is get-lassA B, which returns an ob0ect re%resenting the class
574
Thinking in Java
,,,'0ruceEckel'com
o" this ob0ect. /ou can in turn Auery this -lass ob0ect "or its na#e with get/ameA B or to)tringA B. /ou can also do #ore so%histicated things with -lass ob0ects that aren t necessary in e&ce%tion handling. -lass ob0ects will be studied later in this book. RFSURF STIJLT+(6PTE5M@TI?MU (ere s an e&a#%le that shows the use o" the basic &4ception #ethods=
//3 c('3E6ce"tionJetho!s.Hava // De#onstrating the E6ce"tion Jetho!s. "ublic class E6ce"tionJetho!s @ "ublic static voi! #ain-%tringNO args. @ try @ thro: ne: E6ce"tion-8Mere2s #y E6ce"tion8.< A catch-E6ce"tion e. @ %yste#.err."rintln-8Caught E6ce"tion8.< %yste#.err."rintln8e.getJessage-.3 8 K e.getJessage-..< %yste#.err."rintln8e.getLocaliUe!Jessage-.3 8 K e.getLocaliUe!Jessage-..< %yste#.err."rintln-8e.to%tring-.3 8 K e.< %yste#.err."rintln-8e."rint%tackTrace-.38.< e."rint%tackTrace-%yste#.err.< A A A ///3>
The out%ut "or this %rogra# is=
Caught E6ce"tion e.getJessage-.3 Mere2s #y E6ce"tion e.getLocaliUe!Jessage-.3 Mere2s #y E6ce"tion e.to%tring-.3 Hava.lang.E6ce"tion3 Mere2s #y E6ce"tion e."rint%tackTrace-.3 Hava.lang.E6ce"tion3 Mere2s #y E6ce"tion at E6ce"tionJetho!s.#ain-E6ce"tionJetho!s.Hava3*. Hava.lang.E6ce"tion3 Mere2s #y E6ce"tion at E6ce"tionJetho!s.#ain-E6ce"tionJetho!s.Hava3*.
575
/ou can see that the #ethods %rovide successively #ore in"or#ation9 each is e""ectively a su%erset o" the %revious one. RFSURF STIJLT+(6PTE5M@TI?KU
$ethrowing an e0ce.tion
So#eti#es you ll want to rethrow the e&ce%tion that you 0ust caught, %articularly when you use &4ception to catch any e&ce%tion. Since you already have the re"erence to the current e&ce%tion, you can si#%ly rethrow that re"erence=
//3 c('35ethro:ing.Hava // De#onstrating fill$n%tackTrace-. "ublic class 5ethro:ing @ "ublic static voi! f-. thro:s E6ce"tion @ %yste#.out."rintln8originating the e6ce"tion in f-.8.< thro: ne: E6ce"tion-8thro:n fro# f-.8.< A
577
Thinking in Java
,,,'0ruceEckel'com
"ublic static voi! g-. thro:s Thro:able @ try @ f-.< A catch-E6ce"tion e. @ %yste#.err."rintln8$nsi!e g-., e."rint%tackTrace-.8.< e."rint%tackTrace-%yste#.err.< thro: e< // (* // thro: e.fill$n%tackTrace-.< // (1 A A "ublic static voi! #ain-%tringNO args. thro:s Thro:able @ try @ g-.< A catch-E6ce"tion e. @ %yste#.err."rintln8Caught in #ain, e."rint%tackTrace-.8.< e."rint%tackTrace-%yste#.err.< A A A ///3>
The i#%ortant line nu#bers are #arked as co##ents. :ith line MG unco##ented *as shown,, the out%ut is=
originating the e6ce"tion in f-. $nsi!e g-., e."rint%tackTrace-. Hava.lang.E6ce"tion3 thro:n fro# f-. at 5ethro:ing.f-5ethro:ing.Hava31. at 5ethro:ing.g-5ethro:ing.Hava3( . at 5ethro:ing.#ain-5ethro:ing.Hava3 I. Caught in #ain, e."rint%tackTrace-. Hava.lang.E6ce"tion3 thro:n fro# f-. at 5ethro:ing.f-5ethro:ing.Hava31. at 5ethro:ing.g-5ethro:ing.Hava3( . at 5ethro:ing.#ain-5ethro:ing.Hava3 I.
So the e&ce%tion stack trace always re#e#bers its true %oint o" origin, no #atter how #any ti#es it gets rethrown. RFSURF STIJLT+(6PTE5M@TI??U
578
:ith line MG co##ented and line MI unco##ented, fillIn)tackTraceA B is used instead, and the result is=
originating the e6ce"tion in f-. $nsi!e g-., e."rint%tackTrace-. Hava.lang.E6ce"tion3 thro:n fro# f-. at 5ethro:ing.f-5ethro:ing.Hava31. at 5ethro:ing.g-5ethro:ing.Hava3( . at 5ethro:ing.#ain-5ethro:ing.Hava3 I. Caught in #ain, e."rint%tackTrace-. Hava.lang.E6ce"tion3 thro:n fro# f-. at 5ethro:ing.g-5ethro:ing.Hava3(1. at 5ethro:ing.#ain-5ethro:ing.Hava3 I.
Because o" fillIn)tackTraceA B, line MI beco#es the new %oint o" origin o" the e&ce%tion. RFSURFSTIJLT+(6PTE5M@TI?HU The class Thro(able #ust a%%ear in the e&ce%tion s%eci"ication "or gA B and mainA B because fillIn)tackTraceA B %roduces a re"erence to a Thro(able ob0ect. Since Thro(able is a base class o" &4ception, it s %ossible to get an ob0ect that s a Thro(able but not an &4ception, so the handler "or &4ception in mainA B #ight #iss it. To #ake sure everything is in order, the co#%iler "orces an e&ce%tion s%eci"ication "or Thro(able. Eor e&a#%le, the e&ce%tion in the "ollowing %rogra# is not caught in mainA B= RFSURFSTIJLT+(6PTE5M@TI?3U
//3 c('3Thro:Gut.Hava "ublic class Thro:Gut @ "ublic static voi! #ain-%tringNO args. thro:s Thro:able @ try @ thro: ne: Thro:able-.< A catch-E6ce"tion e. @ %yste#.err."rintln-8Caught in #ain-.8.< A A A ///3>
It s also %ossible to rethrow a di""erent e&ce%tion "ro# the one you caught. I" you do this, you get a si#ilar e""ect as when you use fillIn)tackTraceA B9the in"or#ation about the original site o" the
57:
Thinking in Java
,,,'0ruceEckel'com
e&ce%tion is lost, and what you re le"t with is the in"or#ation %ertaining to the new thro(= RFSURFSTIJLT+(6PTE5M@TI?GU
//3 c('35ethro:&e:.Hava // 5ethro: a !ifferent obHect // fro# the one that :as caught. class GneE6ce"tion e6ten!s E6ce"tion @ "ublic GneE6ce"tion-%tring s. @ su"er-s.< A A class T:oE6ce"tion e6ten!s E6ce"tion @ "ublic T:oE6ce"tion-%tring s. @ su"er-s.< A A "ublic class 5ethro:&e: @ "ublic static voi! f-. thro:s GneE6ce"tion @ %yste#.out."rintln8originating the e6ce"tion in f-.8.< thro: ne: GneE6ce"tion-8thro:n fro# f-.8.< A "ublic static voi! #ain-%tringNO args. thro:s T:oE6ce"tion @ try @ f-.< A catch-GneE6ce"tion e. @ %yste#.err."rintln8Caught in #ain, e."rint%tackTrace-.8.< e."rint%tackTrace-%yste#.err.< thro: ne: T:oE6ce"tion-8fro# #ain-.8.< A A A ///3>
The out%ut is=
originating the e6ce"tion in f-. Caught in #ain, e."rint%tackTrace-. GneE6ce"tion3 thro:n fro# f-. at 5ethro:&e:.f-5ethro:&e:.Hava3(*. at 5ethro:&e:.#ain-5ethro:&e:.Hava3 . E6ce"tion in threa! 8#ain8 T:oE6ce"tion3 fro# #ain-.
57;
at 5ethro:&e:.#ain-5ethro:&e:.Hava3 *.
The "inal e&ce%tion knows only that it ca#e "ro# mainA B, and not "ro# f
A B. RFSURFSTIJLT+(6PTE5M@TI?IU
/ou never have to worry about cleaning u% the %revious e&ce%tion, or any e&ce%tions "or that #atter. They re all hea%'based ob0ects created with ne(, so the garbage collector auto#atically cleans the# all u%. RFSURF STIJLT+(6PTE5M@TI?2U
58=
Thinking in Java
,,,'0ruceEckel'com
see "ro# their "ull class na#es or what they are inherited "ro#. Eor e&a#%le, all IF) e&ce%tions are inherited "ro# 8ava!io!I.&4ception. RF SURFSTIJLT+(6PTE5M@TIHKU
581
#ethod without being caught. To see what ha%%ens in this case, try the "ollowing e&a#%le=
//3 c('3&everCaught.Hava // $gnoring 5unti#eE6ce"tions. "ublic class &everCaught @ static voi! f-. @ thro: ne: 5unti#eE6ce"tion-8Lro# f-.8.< A static voi! g-. @ f-.< A "ublic static voi! #ain-%tringNO args. @ g-.< A A ///3>
/ou can already see that a $*ntime&4ception *or anything inherited "ro# it, is a s%ecial case, since the co#%iler doesn t reAuire an e&ce%tion s%eci"ication "or these ty%es. RFSURFSTIJLT+(6PTE5M@TIHHU The out%ut is=
6()
6n error you cannot catch *receiving a n*ll re"erence handed to your #ethod by a client %rogra##er, "or e&a#%le, . RFSURF STIJLT+(6PTE5M@TIHGU
582
Thinking in Java
,,,'0ruceEckel'com
6!)
6n error that you, as a %rogra##er, should have checked "or in your code *such as ArrayIn'e4.*t.f2o*n's&4ception where you should have %aid attention to the si1e o" the array,. RFSURF STIJLT+(6PTE5M@TIHIU
/ou can see what a tre#endous bene"it it is to have e&ce%tions in this case, since they hel% in the debugging %rocess. RFSURF STIJLT+(6PTE5M@TIH2U It s interesting to notice that you cannot classi"y Java e&ce%tion handling as a single'%ur%ose tool. /es, it is designed to handle those %esky run' ti#e errors that will occur because o" "orces outside your code s control, but it s also essential "or certain ty%es o" %rogra##ing bugs that the co#%iler cannot detect. RFSURFSTIJLT+(6PTE5M@TI3@U
try @ // The guar!e! region3 Dangerous activities // that #ight thro: 0, B, or C A catch-0 a(. @ // Man!ler for situation 0 A catch-B b(. @ // Man!ler for situation B A catch-C c(. @ // Man!ler for situation C A finally @ // 0ctivities that ha""en every ti#e
@ +<< e&ce%tion handling does not have the finally clause because it relies on destructors to acco#%lish this sort o" cleanu%.
583
A
To de#onstrate that the finally clause always runs, try this %rogra#= RF SURFSTIJLT+(6PTE5M@TI3MU
//3 c('3Linally\orks.Hava // The finally clause is al:ays e6ecute!. class ThreeE6ce"tion e6ten!s E6ce"tion @A "ublic class Linally\orks @ static int count ? '< "ublic static voi! #ain-%tringNO args. @ :hile-true. @ try @ // Post-incre#ent is Uero first ti#e3 if-countKK ?? '. thro: ne: ThreeE6ce"tion-.< %yste#.out."rintln-8&o e6ce"tion8.< A catch-ThreeE6ce"tion e. @ %yste#.err."rintln-8ThreeE6ce"tion8.< A finally @ %yste#.err."rintln-8$n finally clause8.< if-count ?? . break< // out of 8:hile8 A A A A ///3>
This %rogra# also gives a hint "or how you can deal with the "act that e&ce%tions in Java *like e&ce%tions in +<<, do not allow you to resu#e back to where the e&ce%tion was thrown, as discussed earlier. I" you %lace your try block in a loo%, you can establish a condition that #ust be #et be"ore you continue the %rogra#. /ou can also add a static counter or so#e other device to allow the loo% to try several di""erent a%%roaches be"ore giving u%. This way you can build a greater level o" robustness into your %rogra#s. RFSURFSTIJLT+(6PTE5M@TI3KU The out%ut is=
584
Thinking in Java
,,,'0ruceEckel'com
finally is necessary when you need to set so#ething other than #e#ory back to its original state. This is so#e kind o" cleanu% like an o%en "ile or network connection, so#ething you ve drawn on the screen, or even a switch in the outside world, as #odeled in the "ollowing e&a#%le= //3 c('3GnGff%:itch.Hava // \hy use finally[ class %:itch @ boolean state ? false< boolean rea!-. @ return state< A voi! on-. @ state ? true< A voi! off-. @ state ? false< A A class GnGffE6ce"tion( e6ten!s E6ce"tion @A class GnGffE6ce"tion e6ten!s E6ce"tion @A "ublic class GnGff%:itch @ static %:itch s: ? ne: %:itch-.< static voi! f-. thro:s GnGffE6ce"tion(, GnGffE6ce"tion @A "ublic static voi! #ain-%tringNO args. @
@ 6 destructor is a "unction that s always called when an ob0ect beco#es unused. /ou
always know e&actly where and when the destructor gets called. +<< has auto#atic destructor calls, but 7el%hi s )b0ect Pascal versions M and K do not *which changes the #eaning and use o" the conce%t o" a destructor "or that language,.
585
try @ s:.on-.< // Co!e that can thro: e6ce"tions... f-.< s:.off-.< A catch-GnGffE6ce"tion( e. @ %yste#.err."rintln-8GnGffE6ce"tion(8.< s:.off-.< A catch-GnGffE6ce"tion e. @ %yste#.err."rintln-8GnGffE6ce"tion 8.< s:.off-.< A A A ///3>
The goal here is to #ake sure that the switch is o"" when mainA B is co#%leted, so s(!offA B is %laced at the end o" the try block and at the end o" each e&ce%tion handler. But it s %ossible that an e&ce%tion could be thrown that isn t caught here, so s(!offA B would be #issed. (owever, with finally you can %lace the cleanu% code "ro# a try block in 0ust one %lace= RFSURFSTIJLT+(6PTE5M@TI3HU
//3 c('3\ithLinally.Hava // Linally auarantees cleanu". "ublic class \ithLinally @ static %:itch s: ? ne: %:itch-.< "ublic static voi! #ain-%tringNO args. @ try @ s:.on-.< // Co!e that can thro: e6ce"tions... GnGff%:itch.f-.< A catch-GnGffE6ce"tion( e. @ %yste#.err."rintln-8GnGffE6ce"tion(8.< A catch-GnGffE6ce"tion e. @ %yste#.err."rintln-8GnGffE6ce"tion 8.< A finally @ s:.off-.< A A A ///3>
587
Thinking in Java
,,,'0ruceEckel'com
(ere the s(!offA B has been #oved to 0ust one %lace, where it s guaranteed to run no #atter what ha%%ens. RFSURF STIJLT+(6PTE5M@TI33U Even in cases in which the e&ce%tion is not caught in the current set o" catch clauses, finally will be e&ecuted be"ore the e&ce%tion handling #echanis# continues its search "or a handler at the ne&t higher level=
//3 c('30l:aysLinally.Hava // Linally is al:ays e6ecute!. class LourE6ce"tion e6ten!s E6ce"tion @A "ublic class 0l:aysLinally @ "ublic static voi! #ain-%tringNO args. @ %yste#.out."rintln8Entering first try block8.< try @ %yste#.out."rintln8Entering secon! try block8.< try @ thro: ne: LourE6ce"tion-.< A finally @ %yste#.out."rintln8finally in n! try block8.< A A catch-LourE6ce"tion e. @ %yste#.err."rintln8Caught LourE6ce"tion in (st try block8.< A finally @ %yste#.err."rintln8finally in (st try block8.< A A A ///3>
The out%ut "or this %rogra# shows you what ha%%ens= RFSURF STIJLT+(6PTE5M@TI3GU
Entering first try block Entering secon! try block finally in n! try block
588
//3 c('3LostJessage.Hava // Mo: an e6ce"tion can be lost. class Wery$#"ortantE6ce"tion e6ten!s E6ce"tion @ "ublic %tring to%tring-. @ return 80 very i#"ortant e6ce"tion48< A A class MoMu#E6ce"tion e6ten!s E6ce"tion @ "ublic %tring to%tring-. @ return 80 trivial e6ce"tion8< A A "ublic class LostJessage @ voi! f-. thro:s Wery$#"ortantE6ce"tion @ thro: ne: Wery$#"ortantE6ce"tion-.< A voi! !is"ose-. thro:s MoMu#E6ce"tion @ thro: ne: MoMu#E6ce"tion-.< A "ublic static voi! #ain-%tringNO args. thro:s E6ce"tion @ LostJessage l# ? ne: LostJessage-.<
58:
Thinking in Java
,,,'0ruceEckel'com
/0ce.tion restrictions
:hen you override a #ethod, you can throw only the e&ce%tions that have been s%eci"ied in the base'class version o" the #ethod. This is a use"ul restriction, since it #eans that code that works with the base class will auto#atically work with any ob0ect derived "ro# the base class *a "unda#ental ))P conce%t, o" course,, including e&ce%tions. RFSURF STIJLT+(6PTE5M@TIG@U This e&a#%le de#onstrates the kinds o" restrictions i#%osed *at co#%ile' ti#e, "or e&ce%tions=
//3 c('3%tor#y$nning.Hava // Gverri!!en #etho!s #ay thro: only the // e6ce"tions s"ecifie! in their base-class
58;
// versions, or e6ce"tions !erive! fro# the // base-class e6ce"tions. class BaseballE6ce"tion e6ten!s E6ce"tion @A class Loul e6ten!s BaseballE6ce"tion @A class %trike e6ten!s BaseballE6ce"tion @A abstract class $nning @ $nning-. thro:s BaseballE6ce"tion @A voi! event -. thro:s BaseballE6ce"tion @ // Doesn2t actually have to thro: anything A abstract voi! atBat-. thro:s %trike, Loul< voi! :alk-. @A // Thro:s nothing A class %tor#E6ce"tion e6ten!s E6ce"tion @A class 5aine!Gut e6ten!s %tor#E6ce"tion @A class Po"Loul e6ten!s Loul @A interface %tor# @ voi! event-. thro:s 5aine!Gut< voi! rainMar!-. thro:s 5aine!Gut< A "ublic class %tor#y$nning e6ten!s $nning i#"le#ents %tor# @ // G` to a!! ne: e6ce"tions for // constructors, but you #ust !eal // :ith the base constructor e6ce"tions3 %tor#y$nning-. thro:s 5aine!Gut, BaseballE6ce"tion @A %tor#y$nning-%tring s. thro:s Loul, BaseballE6ce"tion @A // 5egular #etho!s #ust confor# to base class3 //4 voi! :alk-. thro:s Po"Loul @A //Co#"ile error // $nterface C0&> a!! e6ce"tions to e6isting // #etho!s fro# the base class3 //4 "ublic voi! event-. thro:s 5aine!Gut @A // $f the #etho! !oesn2t alrea!y e6ist in the // base class, the e6ce"tion is G`3
5:=
Thinking in Java
,,,'0ruceEckel'com
"ublic voi! rainMar!-. thro:s 5aine!Gut @A // ;ou can choose to not thro: any e6ce"tions, // even if base version !oes3 "ublic voi! event-. @A // Gverri!!en #etho!s can thro: // inherite! e6ce"tions3 voi! atBat-. thro:s Po"Loul @A "ublic static voi! #ain-%tringNO args. @ try @ %tor#y$nning si ? ne: %tor#y$nning-.< si.atBat-.< A catch-Po"Loul e. @ %yste#.err."rintln-8Po" foul8.< A catch-5aine!Gut e. @ %yste#.err."rintln-85aine! out8.< A catch-BaseballE6ce"tion e. @ %yste#.err."rintln-8aeneric error8.< A // %trike not thro:n in !erive! version. try @ // \hat ha""ens if you u"cast[ $nning i ? ne: %tor#y$nning-.< i.atBat-.< // ;ou #ust catch the e6ce"tions fro# the // base-class version of the #etho!3 A catch-%trike e. @ %yste#.err."rintln-8%trike8.< A catch-Loul e. @ %yste#.err."rintln-8Loul8.< A catch-5aine!Gut e. @ %yste#.err."rintln-85aine! out8.< A catch-BaseballE6ce"tion e. @ %yste#.err."rintln8aeneric baseball e6ce"tion8.< A A A ///3>
In Inning, you can see that both the constructor and the eventA B #ethod say they will throw an e&ce%tion, but they never do. This is legal because it allows you to "orce the user to catch any e&ce%tions that #ight
5:1
be added in overridden versions o" eventA B. The sa#e idea holds "or abstract #ethods, as seen in at2atA B. RFSURF STIJLT+(6PTE5M@TIGMU The interface )torm is interesting because it contains one #ethod * eventA B, that is de"ined in Inning, and one #ethod that isn t. Both #ethods throw a new ty%e o" e&ce%tion, $aine'.*t. :hen )tormyInning e4ten's Inning and implements )torm, you ll see that the eventA B #ethod in )torm cannot change the e&ce%tion inter"ace o" eventA B in Inning. 6gain, this #akes sense because otherwise you d never know i" you were catching the correct thing when working with the base class. )" course, i" a #ethod described in an interface is not in the base class, such as rainHar'A B, then there s no %roble# i" it throws e&ce%tions. RFSURFSTIJLT+(6PTE5M@TIGKU The restriction on e&ce%tions does not a%%ly to constructors. /ou can see in )tormyInning that a constructor can throw anything it wants, regardless o" what the base'class constructor throws. (owever, since a base'class constructor #ust always be called one way or another *here, the de"ault constructor is called auto#atically,, the derived'class constructor #ust declare any base'class constructor e&ce%tions in its e&ce%tion s%eci"ication. Cote that a derived'class constructor cannot catch e&ce%tions thrown by its base'class constructor. RFSURF STIJLT+(6PTE5M@TIGLU The reason )tormyInning!(alkA B will not co#%ile is that it throws an e&ce%tion, while Inning!(alkA B does not. I" this was allowed, then you could write code that called Inning!(alkA B and that didn t have to handle any e&ce%tions, but then when you substituted an ob0ect o" a class derived "ro# Inning, e&ce%tions would be thrown so your code would break. By "orcing the derived'class #ethods to con"or# to the e&ce%tion s%eci"ications o" the base'class #ethods, substitutability o" ob0ects is #aintained. RFSURFSTIJLT+(6PTE5M@TIG?U The overridden eventA B #ethod shows that a derived'class version o" a #ethod #ay choose not to throw any e&ce%tions, even i" the base'class version does. 6gain, this is "ine since it doesn t break any code that is written9assu#ing the base'class version throws e&ce%tions. Si#ilar logic a%%lies to at2atA B, which throws #opFo*l, an e&ce%tion that is derived
5:2
Thinking in Java
,,,'0ruceEckel'com
"ro# Fo*l thrown by the base'class version o" at2atA B. This way, i" so#eone writes code that works with Inning and calls at2atA B, they #ust catch the Fo*l e&ce%tion. Since #opFo*l is derived "ro# Fo*l, the e&ce%tion handler will also catch #opFo*l. RFSURF STIJLT+(6PTE5M@TIGHU The last %oint o" interest is in mainA B. (ere you can see that i" you re dealing with e&actly a )tormyInning ob0ect, the co#%iler "orces you to catch only the e&ce%tions that are s%eci"ic to that class, but i" you u%cast to the base ty%e then the co#%iler *correctly, "orces you to catch the e&ce%tions "or the base ty%e. 6ll these constraints %roduce #uch #ore robust e&ce%tion'handling code @. RFSURFSTIJLT+(6PTE5M@TIG3U It s use"ul to reali1e that although e&ce%tion s%eci"ications are en"orced by the co#%iler during inheritance, the e&ce%tion s%eci"ications are not %art o" the ty%e o" a #ethod, which is co#%rised o" only the #ethod na#e and argu#ent ty%es. There"ore, you cannot overload #ethods based on e&ce%tion s%eci"ications. In addition, 0ust because an e&ce%tion s%eci"ication e&ists in a base'class version o" a #ethod doesn t #ean that it #ust e&ist in the derived'class version o" the #ethod. This is Auite di""erent "ro# inheritance rules, where a #ethod in the base class #ust also e&ist in the derived class. Put another way, the !e&ce%tion s%eci"ication inter"ace$ "or a %articular #ethod #ay narrow during inheritance and overriding, but it #ay not widen9this is %recisely the o%%osite o" the rule "or the class inter"ace during inheritance. RFSURF STIJLT+(6PTE5M@TIGGU
Constructors
:hen writing code with e&ce%tions, it s %articularly i#%ortant that you always ask, !I" an e&ce%tion occurs, will this be %ro%erly cleaned u%O$ Most o" the ti#e you re "airly sa"e, but in constructors there s a %roble#. The constructor %uts the ob0ect into a sa"e starting state, but it #ight %er"or# so#e o%eration9such as o%ening a "ile9that doesn t get cleaned u% until the user is "inished with the ob0ect and calls a s%ecial cleanu%
@ IS) +<< added si#ilar constraints that reAuire derived'#ethod e&ce%tions to be the sa#e as, or derived "ro#, the e&ce%tions thrown by the base'class #ethod. This is one case in which +<< is actually able to check e&ce%tion s%eci"ications at co#%ile'ti#e.
5:3
#ethod. I" you throw an e&ce%tion "ro# inside a constructor, these cleanu% behaviors #ight not occur %ro%erly. This #eans that you #ust be es%ecially diligent while you write your constructor. RFSURF STIJLT+(6PTE5M@TIGIU Since you ve 0ust learned about finally, you #ight think that it is the correct solution. But it s not Auite that si#%le, because finally %er"or#s the cleanu% code ever) timeD even in the situations in which you don t want the cleanu% code e&ecuted until the cleanu% #ethod runs. Thus, i" you do %er"or# cleanu% in finally, you #ust set so#e kind o" "lag when the constructor "inishes nor#ally so that you don t do anything in the finally block i" the "lag is set. Because this isn t %articularly elegant *you are cou%ling your code "ro# one %lace to another,, it s best i" you try to avoid %er"or#ing this kind o" cleanu% in finally unless you are "orced to. RFSURFSTIJLT+(6PTE5M@TIG2U In the "ollowing e&a#%le, a class called Inp*tFile is created that o%ens a "ile and allows you to read it one line *converted into a )tring, at a ti#e. It uses the classes File$ea'er and 2*ffere'$ea'er "ro# the Java standard IF) library that will be discussed in +ha%ter MM, but which are si#%le enough that you %robably won t have any trouble understanding their basic use=
//3 c('3Cleanu".Hava // Paying attention to e6ce"tions // in constructors. i#"ort Hava.io.B< class $n"utLile @ "rivate Buffere!5ea!er in< $n"utLile-%tring fna#e. thro:s E6ce"tion @ try @ in ? ne: Buffere!5ea!erne: Lile5ea!er-fna#e..< // Gther co!e that #ight thro: e6ce"tions A catch-Lile&otLoun!E6ce"tion e. @ %yste#.err."rintln8Coul! not o"en 8 K fna#e.< // \asn2t o"en, so !on2t close it
5:4
Thinking in Java
,,,'0ruceEckel'com
thro: e< A catch-E6ce"tion e. @ // 0ll other e6ce"tions #ust close it try @ in.close-.< A catch-$GE6ce"tion e . @ %yste#.err."rintln8in.close-. unsuccessful8.< A thro: e< // 5ethro: A finally @ // Don2t close it here444 A A %tring getLine-. @ %tring s< try @ s ? in.rea!Line-.< A catch-$GE6ce"tion e. @ %yste#.err."rintln8rea!Line-. unsuccessful8.< s ? 8faile!8< A return s< A voi! cleanu"-. @ try @ in.close-.< A catch-$GE6ce"tion e . @ %yste#.err."rintln8in.close-. unsuccessful8.< A A A "ublic class Cleanu" @ "ublic static voi! #ain-%tringNO args. @ try @ $n"utLile in ? ne: $n"utLile-8Cleanu".Hava8.< %tring s<
5:5
int i ? (< :hile--s ? in.getLine-.. 4? null. %yste#.out."rintln-88K iKK K 83 8 K s.< in.cleanu"-.< A catch-E6ce"tion e. @ %yste#.err."rintln8Caught in #ain, e."rint%tackTrace-.8.< e."rint%tackTrace-%yste#.err.< A A A ///3>
The constructor "or Inp*tFile takes a )tring argu#ent, which is the na#e o" the "ile you want to o%en. Inside a try block, it creates a File$ea'er using the "ile na#e. 6 File$ea'er isn t %articularly use"ul until you turn around and use it to create a 2*ffere'$ea'er that you can actually talk to9notice that one o" the bene"its o" Inp*tFile is that it co#bines these two actions. RFSURFSTIJLT+(6PTE5M@TII@U I" the File$ea'er constructor is unsuccess"ul, it throws a File/otFo*n'&4ception, which #ust be caught se%arately because that s the one case in which you don t want to close the "ile since it wasn t success"ully o%ened. 6ny other catch clauses #ust close the "ile because it ,as o%ened by the ti#e those catch clauses are entered. *)" course, this is trickier i" #ore than one #ethod can throw a File/otFo*n'&4ception. In that case, you #ight want to break things into several try blocks., The closeA B #ethod #ight throw an e&ce%tion so it is tried and caught even though it s within the block o" another catch clause9it s 0ust another %air o" curly braces to the Java co#%iler. 6"ter %er"or#ing local o%erations, the e&ce%tion is rethrown, which is a%%ro%riate because this constructor "ailed, and you wouldn t want the calling #ethod to assu#e that the ob0ect had been %ro%erly created and was valid. RFSURF STIJLT+(6PTE5M@TIIMU In this e&a#%le, which doesn t use the a"ore#entioned "lagging techniAue, the finally clause is de"initely not the %lace to closeA B the "ile, since that would close it every ti#e the constructor co#%leted. Since we want the "ile to be o%en "or the use"ul li"eti#e o" the Inp*tFile ob0ect this would not be a%%ro%riate. RFSURFSTIJLT+(6PTE5M@TIIKU
5:7
Thinking in Java
,,,'0ruceEckel'com
The get+ineA B #ethod returns a )tring containing the ne&t line in the "ile. It calls rea'+ineA B, which can throw an e&ce%tion, but that e&ce%tion is caught so get+ineA B doesn t throw any e&ce%tions. )ne o" the design issues with e&ce%tions is whether to handle an e&ce%tion co#%letely at this level, to handle it %artially and %ass the sa#e e&ce%tion *or a di""erent one, on, or whether to si#%ly %ass it on. Passing it on, when a%%ro%riate, can certainly si#%li"y coding. The get+ineA B #ethod beco#es=
5:8
/0ce.tion matching
:hen an e&ce%tion is thrown, the e&ce%tion handling syste# looks through the !nearest$ handlers in the order they are written. :hen it "inds a #atch, the e&ce%tion is considered handled, and no "urther searching occurs. RFSURFSTIJLT+(6PTE5M@TIIGU Matching an e&ce%tion doesn t reAuire a %er"ect #atch between the e&ce%tion and its handler. 6 derived'class ob0ect will #atch a handler "or the base class, as shown in this e&a#%le=
//3 c('3Mu#an.Hava // Catching e6ce"tion hierarchies. class 0nnoyance e6ten!s E6ce"tion @A class %neeUe e6ten!s 0nnoyance @A "ublic class Mu#an @ "ublic static voi! #ain-%tringNO args. @ try @ thro: ne: %neeUe-.< A catch-%neeUe s. @ %yste#.err."rintln-8Caught %neeUe8.< A catch-0nnoyance a. @ %yste#.err."rintln-8Caught 0nnoyance8.< A A A ///3>
The )nee7e e&ce%tion will be caught by the "irst catch clause that it #atches9which is the "irst one, o" course. (owever, i" you re#ove the "irst catch clause, leaving only= RFSURFSTIJLT+(6PTE5M@TIIIU
5::
Thinking in Java
,,,'0ruceEckel'com
A
The code will still work because it s catching the base class o" )nee7e. Put another way, catchAAnnoyance eB will catch an Annoyance or an) class derived $rom it. This is use"ul because i" you decide to add #ore derived e&ce%tions to a #ethod, then the client %rogra##er s code will not need changing as long as the client catches the base class e&ce%tions. RFSURFSTIJLT+(6PTE5M@TII2U I" you try to !#ask$ the derived'class e&ce%tions by %utting the base'class catch clause "irst, like this=
try @ thro: ne: %neeUe-.< A catch-0nnoyance a. @ %yste#.err."rintln-8Caught 0nnoyance8.< A catch-%neeUe s. @ %yste#.err."rintln-8Caught %neeUe8.< A
the co#%iler will give you an error #essage, since it sees that the )nee7e catch'clause can never be reached. RFSURFSTIJLT+(6PTE5M@TI2@U
/0ce.tion guidelines
4se e&ce%tions to=
Ei& the %roble# and call the #ethod that caused the e&ce%tion again. Patch things u% and continue without retrying the #ethod. +alculate so#e alternative result instead o" what the #ethod was su%%osed to %roduce. 7o whatever you can in the current conte&t and rethrow the same e&ce%tion to a higher conte&t. 7o whatever you can in the current conte&t and throw a di$$erent e&ce%tion to a higher conte&t. Ter#inate the %rogra#.
5:;
66)
Si#%li"y. *I" your e&ce%tion sche#e #akes things #ore co#%licated, then it is %ain"ul and annoying to use.,
1ummar:
I#%roved error recovery is one o" the #ost %ower"ul ways that you can increase the robustness o" your code. Error recovery is a "unda#ental concern "or every %rogra# you write, but it s es%ecially i#%ortant in Java, where one o" the %ri#ary goals is to create %rogra# co#%onents "or others to use. To create a robust s)stemD each com onent must be robust' RFSURFSTIJLT+(6PTE5M@TI2KU The goals "or e&ce%tion handling in Java are to si#%li"y the creation o" large, reliable %rogra#s using less code than currently %ossible, and with #ore con"idence that your a%%lication doesn t have an unhandled error. RFSURFSTIJLT+(6PTE5M@TI2LU
E&ce%tions are not terribly di""icult to learn, and are one o" those "eatures that %rovide i##ediate and signi"icant bene"its to your %ro0ect. Eortunately, Java en"orces all as%ects o" e&ce%tions so it s guaranteed that they will be used consistently by both library designers and client %rogra##ers. RFSURFSTIJLT+(6PTE5M@TI2?U
/0ercises
Solutions to selected e&ercises can be "ound in the electronic docu#entThe Thinking in Java "nnotated Solution @uide, available "or a s#all "ee "ro# ,,,'0ruceEckel'com.
(47) +reate a class with a mainA B that throws an ob0ect o" class
&4ception inside a try block. 8ive the constructor "or &4ception a )tring argu#ent. +atch the e&ce%tion inside a catch clause and %rint the )tring argu#ent. 6dd a finally clause
and %rint a #essage to %rove you were there. RFSURF STIJLT+(6PTE5M@TI2HU
5;=
Thinking in Java
,,,'0ruceEckel'com
(4() +reate your own e&ce%tion class using the e4ten's keyword.
:rite a constructor "or this class that takes a )tring argu#ent and stores it inside the ob0ect with a )tring re"erence. :rite a #ethod that %rints out the stored )tring. +reate a try6catch clause to e&ercise your new e&ce%tion. RFSURF STIJLT+(6PTE5M@TI23U
(4!) :rite a class with a #ethod that throws an e&ce%tion o" the
ty%e created in E&ercise K. Try co#%iling it without an e&ce%tion s%eci"ication to see what the co#%iler says. 6dd the a%%ro%riate e&ce%tion s%eci"ication. Try out your class and its e&ce%tion inside a try'catch clause. RFSURFSTIJLT+(6PTE5M@TI2GU
(4,) +reate three new ty%es o" e&ce%tions. :rite a class with a
#ethod that throws all three. In mainA B, call the #ethod but only use a single catch clause that will catch all three ty%es o" e&ce%tions. RFSURFSTIJLT+(6PTE5M@TIM@@U
5;1
class - "ro# 2. In mainA B, create a - and u%cast it to A, then call the #ethod. RFSURFSTIJLT+(6PTE5M@TIM@LU
(5,) 5e#ove the "irst catch clause in H*man!8ava and veri"y that
the code still co#%iles and runs %ro%erly. RFSURF STIJLT+(6PTE5M@TIMM@U
5;2
Thinking in Java
,,,'0ruceEckel'com
5;3
5;4
A director: lister
Su%%ose you d like to see a directory listing. The File ob0ect can be listed in two ways. I" you call listA B with no argu#ents, you ll get the "ull list that the File ob0ect contains. (owever, i" you want a restricted list9"or e&a#%le, i" you want all o" the "iles with an e&tension o" !8ava9then you use a !directory "ilter,$ which is a class that tells how to select the File ob0ects "or dis%lay. RFSURFSTIJLT+(6PTE5MMTI3U (ere s the code "or the e&a#%le. Cote that the result has been e""ortlessly sorted *al%habetically, using the 8ava!*tils!Array!sortA B #ethod and the Alphabetic-omparator de"ined in +ha%ter 2=
//3 c((3DirList.Hava // Dis"lays !irectory listing. i#"ort Hava.io.B< i#"ort Hava.util.B< i#"ort co#.bruceeckel.util.B< "ublic class DirList @ "ublic static voi! #ain-%tringNO args. @ Lile "ath ? ne: Lile-8.8.<
5;5
%tringNO list< if-args.length ?? '. list ? "ath.list-.< else list ? "ath.list-ne: DirLilter-argsN'O..< 0rrays.sort-list, ne: 0l"habeticCo#"arator-..< for-int i ? '< i P list.length< iKK. %yste#.out."rintln-listNiO.< A A class DirLilter i#"le#ents Lilena#eLilter @ %tring afn< DirLilter-%tring afn. @ this.afn ? afn< A "ublic boolean acce"t-Lile !ir, %tring na#e. @ // %tri" "ath infor#ation3 %tring f ? ne: Lile-na#e..get&a#e-.< return f.in!e6Gf-afn. 4? -(< A A ///3>
The irFilter class !i#%le#ents$ the interface FilenameFilter. It s use"ul to see how si#%le the FilenameFilter interface is= RFSURF STIJLT+(6PTE5MMTIGU
5;7
irFilter shows that 0ust because an interface contains only a set o" #ethods, you re not restricted to writing only those #ethods. */ou #ust at least %rovide de"initions "or all the #ethods in an inter"ace, however., In this case, the irFilter constructor is also created. RFSURF STIJLT+(6PTE5MMTI2U
The acceptA B #ethod #ust acce%t a File ob0ect re%resenting the directory that a %articular "ile is "ound in, and a )tring containing the na#e o" that "ile. /ou #ight choose to use or ignore either o" these argu#ents, but you will %robably at least use the "ile na#e. 5e#e#ber that the listA B #ethod is calling acceptA B "or each o" the "ile na#es in the directory ob0ect to see which one should be included9this is indicated by the boolean result returned by acceptA B. RFSURF STIJLT+(6PTE5MMTIM@U To #ake sure the ele#ent you re working with is only the "ile na#e and contains no %ath in"or#ation, all you have to do is take the )tring ob0ect and create a File ob0ect out o" it, then call get/ameA B, which stri%s away all the %ath in"or#ation *in a %lat"or#'inde%endent way,. Then acceptA B uses the )tring class in'e4.fA B #ethod to see i" the search string afn a%%ears anywhere in the na#e o" the "ile. I" afn is "ound within the string, the return value is the starting inde& o" afn, but i" it s not "ound the return value is 'M. >ee% in #ind that this is a si#%le string search and does not have !glob$ e&%ression wildcard #atching9such as !"oO.bOrB$9which is #uch #ore di""icult to i#%le#ent. RFSURF STIJLT+(6PTE5MMTIMMU The listA B #ethod returns an array. /ou can Auery this array "or its length and then #ove through it selecting the array ele#ents. This ability to easily %ass an array in and out o" a #ethod is a tre#endous i#%rove#ent over the behavior o" + and +<<. RFSURF STIJLT+(6PTE5MMTIMKU
5;8
//3 c((3DirList .Hava // Yses anony#ous inner classes. i#"ort Hava.io.B< i#"ort Hava.util.B< i#"ort co#.bruceeckel.util.B< "ublic class DirList @ "ublic static Lilena#eLilter filter-final %tring afn. @ // Creation of anony#ous inner class3 return ne: Lilena#eLilter-. @ %tring fn ? afn< "ublic boolean acce"t-Lile !ir, %tring n. @ // %tri" "ath infor#ation3 %tring f ? ne: Lile-n..get&a#e-.< return f.in!e6Gf-fn. 4? -(< A A< // En! of anony#ous inner class A "ublic static voi! #ain-%tringNO args. @ Lile "ath ? ne: Lile-8.8.< %tringNO list< if-args.length ?? '. list ? "ath.list-.< else list ? "ath.list-filter-argsN'O..< 0rrays.sort-list, ne: 0l"habeticCo#"arator-..< for-int i ? '< i P list.length< iKK. %yste#.out."rintln-listNiO.< A A ///3>
5;:
Cote that the argu#ent to filterA B #ust be final. This is reAuired by the anony#ous inner class so that it can use an ob0ect "ro# outside its sco%e. RFSURFSTIJLT+(6PTE5MMTIMLU This design is an i#%rove#ent because the FilenameFilter class is now tightly bound to ir+istI. (owever, you can take this a%%roach one ste% "urther and de"ine the anony#ous inner class as an argu#ent to listA B, in which case it s even s#aller=
//3 c((3DirList).Hava // Buil!ing the anony#ous inner class 8in-"lace.8 i#"ort Hava.io.B< i#"ort Hava.util.B< i#"ort co#.bruceeckel.util.B< "ublic class DirList) @ "ublic static voi! #ain-final %tringNO args. @ Lile "ath ? ne: Lile-8.8.< %tringNO list< if-args.length ?? '. list ? "ath.list-.< else list ? "ath.list-ne: Lilena#eLilter-. @ "ublic boolean acce"t-Lile !ir, %tring n. @ %tring f ? ne: Lile-n..get&a#e-.< return f.in!e6Gf-argsN'O. 4? -(< A A.< 0rrays.sort-list, ne: 0l"habeticCo#"arator-..< for-int i ? '< i P list.length< iKK. %yste#.out."rintln-listNiO.< A A ///3>
The argu#ent to mainA B is now final, since the anony#ous inner class uses args]D^ directly. RFSURFSTIJLT+(6PTE5MMTIM?U This shows you how anony#ous inner classes allow the creation o" Auick' and'dirty classes to solve %roble#s. Since everything in Java revolves
5;;
around classes, this can be a use"ul coding techniAue. )ne bene"it is that it kee%s the code that solves a %articular %roble# isolated together in one s%ot. )n the other hand, it is not always as easy to read, so you #ust use it 0udiciously. RFSURFSTIJLT+(6PTE5MMTIMHU
//3 c((3JakeDirectories.Hava // De#onstrates the use of the Lile class to // create !irectories an! #ani"ulate files. i#"ort Hava.io.B< "ublic class JakeDirectories @ "rivate final static %tring usage ? 8Ysage3JakeDirectories "ath( ..._n8 K 8Creates each "ath_n8 K 8Ysage3JakeDirectories -! "ath( ..._n8 K 8Deletes each "ath_n8 K 8Ysage3JakeDirectories -r "ath( "ath _n8 K 85ena#es fro# "ath( to "ath _n8< "rivate static voi! usage-. @ %yste#.err."rintln-usage.< %yste#.e6it-(.< A "rivate static voi! fileData-Lile f. @ %yste#.out."rintln80bsolute "ath3 8 K f.get0bsolutePath-. K 8_n Can rea!3 8 K f.can5ea!-. K 8_n Can :rite3 8 K f.can\rite-. K 8_n get&a#e3 8 K f.get&a#e-. K
7==
8_n getParent3 8 K f.getParent-. K 8_n getPath3 8 K f.getPath-. K 8_n length3 8 K f.length-. K 8_n lastJo!ifie!3 8 K f.lastJo!ifie!-..< if-f.isLile-.. %yste#.out."rintln-8it2s a file8.< else if-f.isDirectory-.. %yste#.out."rintln-8it2s a !irectory8.< A "ublic static voi! #ain-%tringNO args. @ if-args.length P (. usage-.< if-argsN'O.e=uals-8-r8.. @ if-args.length 4? ). usage-.< Lile ol! ? ne: Lile-argsN(O., rna#e ? ne: Lile-argsN O.< ol!.rena#eTo-rna#e.< fileData-ol!.< fileData-rna#e.< return< // E6it #ain A int count ? '< boolean !el ? false< if-argsN'O.e=uals-8-!8.. @ countKK< !el ? true< A for- < count P args.length< countKK. @ Lile f ? ne: Lile-argsNcountO.< if-f.e6ists-.. @ %yste#.out."rintln-f K 8 e6ists8.< if-!el. @ %yste#.out."rintln-8!eleting...8 K f.< f.!elete-.< A A else @ // Doesn2t e6ist if-4!el. @ f.#k!irs-.< %yste#.out."rintln-8create! 8 K f.< A
7=1
A fileData-f.< A A A ///3>
In file ataA B you can see various "ile investigation #ethods used to dis%lay in"or#ation about the "ile or directory %ath. RFSURF STIJLT+(6PTE5MMTIM3U The "irst #ethod that s e&ercised by mainA B is renameToA B, which allows you to rena#e *or #ove, a "ile to an entirely new %ath re%resented by the argu#ent, which is another File ob0ect. This also works with directories o" any length. RFSURFSTIJLT+(6PTE5MMTIMGU I" you e&%eri#ent with the above %rogra#, you ll "ind that you can #ake a directory %ath o" any co#%le&ity because mk'irsA B will do all the work "or you. RFSURFSTIJLT+(6PTE5MMTIMIU
7=2
It s hel%"ul to categori1e the classes by their "unctionality. In Java M.@, the library designers started by deciding that all classes that had anything to do with in%ut would be inherited "ro# Inp*t)tream and all classes that were associated with out%ut would be inherited "ro# .*tp*t)tream. RFSURFSTIJLT+(6PTE5MMTIKMU
#:.es of 7n utStream
Inp*t)tream s 0ob is to re%resent classes that %roduce in%ut "ro# di""erent sources. These sources can be= (7() 6n array o" bytes. (7!) 6 )tring ob0ect. (7*) 6 "ile. (7+) 6 !%i%e,$ which works like a %hysical %i%e= you %ut things in one
end and they co#e out the other.
(7,) 6 seAuence o" other strea#s, so you can collect the# together into
a single strea#.
7=3
-lass
F*nction
2yteArray6 Inp*t)trea m
Inp*t)tream
+onverts a
FilterInp*t)tream
ob0ect to %rovide a use"ul inter"ace.
#ipe'6 Inp*t)trea m
Produces the data that s being written to the associated #ipe'.*tp*t' )tream. I#%le#ents the !%i%ing$ conce%t.
#ipe'.*tp*t)tream
FilterInp*t)tream
ob0ect to %rovide a use"ul inter"ace.
7=4
-lass
F*nction
)eC*ence6 Inp*t)trea m
Inp*t)tream
ob0ects into a single
&n*meration "or a
container o"
Inp*t)tream ob0ects.
6s a source o" data. +onnect it to a
Inp*t)tream.
6bstract class which is an inter"ace "or decorators that %rovide use"ul "unctionality to the other
Inp*t)tream
classes. See Table MM'L.
7=5
-lass
F*nction
2yteArray6 .*tp*t)trea m
+reates a bu""er in #e#ory. 6ll the data that you send to the strea# is %laced in this bu""er.
Filter.*tp*t)tream
ob0ect to %rovide a use"ul inter"ace.
#ipe'6 .*tp*t)trea m
6ny in"or#ation you write to this auto#atically ends u% as in%ut "or the associated
#ipe'Inp*t)tream
#ipe'Inp*t6 )tream.
I#%le#ents the !%i%ing$ conce%t.
Filter.*tp*t)tream
ob0ect to %rovide a use"ul inter"ace.
7=7
-lass
F*nction
Filter6 .*tp*t)trea m
6bstract class which is an inter"ace "or decorators that %rovide use"ul "unctionality to the other
.*tp*t)tream
classes. See Table MM'?.
7=8
writing a %rogra# *since you can easily #i& and #atch attributes,, but they add co#%le&ity to your code. The reason that the Java IF) library is awkward to use is that you #ust create #any classes9the !core$ IF) ty%e %lus all the decorators9in order to get the single IF) ob0ect that you want. RFSURFSTIJLT+(6PTE5MMTIKGU The classes that %rovide the decorator inter"ace to control a %articular Inp*t)tream or .*tp*t)tream are the FilterInp*t)tream and Filter.*tp*t)tream9which don t have very intuitive na#es. FilterInp*t)tream and Filter.*tp*t)tream are abstract classes that are derived "ro# the base classes o" the IF) library, Inp*t)tream and .*tp*t)tream, which is the key reAuire#ent o" the decorator *so that it %rovides the co##on inter"ace to all the ob0ects that are being decorated,. RFSURFSTIJLT+(6PTE5MMTIKIU
7=:
Table >>6J! Types of FilterInp*t)tream -lass F*nction -onstr*ctor Arg*ments Ho( to *se it Inp*t)tream
ata6 Inp*t)trea m
ata.*tp*t)tream
, so you can read %ri#itives * int, char, long, etc., "ro# a strea# in a %ortable "ashion. 4se this to %revent a %hysical read every ti#e you want #ore data. /ou re saying !4se a bu""er.$ +ontains a "ull inter"ace to allow you to read %ri#itive ty%es. Inp*t)tream, with o%tional bu""er si1e. This doesn t %rovide an inter"ace er se, 0ust a reAuire#ent that a bu""er be used. 6ttach an inter"ace ob0ect.
2*ffere'6 Inp*t)tream
+ine/*mber 6 Inp*t)tream
>ee%s track o" line nu#bers in the in%ut strea#; you can call
Inp*t)tream
get+ine/*mberA B
and
set+ine/*mberA intB.
This 0ust adds line nu#bering, so you ll %robably attach an inter"ace ob0ect.
7=;
#*shback6 Inp*t)tream
(as a one byte %ush' back bu""er so that you can %ush back the last character read.
Inp*t)tream
8enerally used in the scanner "or a co#%iler and %robably included because the Java co#%iler needed it. /ou %robably won t use this.
#rint)tream can be %roble#atic because it tra%s all I.&4ceptions */ou #ust e&%licitly test the error status with check&rrorA B, which returns tr*e i" an error has occurred,. 6lso, #rint)tream doesn t internationali1e %ro%erly and doesn t handle line breaks in a %lat"or# inde%endent way *these %roble#s are solved with #rint0riter,. RFSURF STIJLT+(6PTE5MMTILHU
71=
2*ffere'.*tp*t)tream is a #odi"ier and tells the strea# to use bu""ering so you don t get a %hysical write every ti#e you write to the strea#. /ou ll %robably always want to use this with "iles, and %ossibly console IF). RFSURFSTIJLT+(6PTE5MMTIL3U Table >>6Q! Types of Filter.*tp*t)tream -lass F*nction -onstr*ctor Arg*ments Ho( to *se it .*tp*t)tream
ata6 .*tp*t)trea m
ataInp*t)tream
so you can write %ri#itives *int, char, long, etc., to a strea# in a %ortable "ashion. Eor %roducing "or#atted out%ut. :hile +ontains "ull inter"ace to allow you to write %ri#itive ty%es. .*tp*t)tream, with o%tional
#rint)tream
boolean
indicating that the bu""er is "lushed with every newline. Should be the !"inal$ wra%%ing "or your
ata.*tp*t)trea m handles the storage o" data, #rint)tream handles dis la).
.*tp*t)tream
ob0ect. /ou ll %robably use this a lot. .*tp*t)tream, with o%tional bu""er si1e. This doesn t %rovide an inter"ace er se, 0ust a reAuire#ent that a bu""er is used. 6ttach an inter"ace ob0ect.
2*ffere'6 .*tp*t)trea m
4se this to %revent a %hysical write every ti#e you send a %iece o" data. /ou re saying !4se a bu""er.$ /ou can call fl*shA B to "lush the bu""er.
711
5eaders L 4riters
Java M.M #ade so#e signi"icant #odi"ications to the "unda#ental IF) strea# library *Java K, however, did not #ake "unda#ental #odi"ications,. :hen you see the $ea'er and 0riter classes your "irst thought *like #ine, #ight be that these were #eant to re%lace the Inp*t)tream and .*tp*t)tream classes. But that s not the case. 6lthough so#e as%ects o" the original strea#s library are de%recated *i" you use the# you will receive a warning "ro# the co#%iler,, the Inp*t)tream and .*tp*t)tream classes still %rovide valuable "unctionality in the "or# o" byte'oriented IF), while the $ea'er and 0riter classes %rovide 4nicode'co#%liant, character'based IF). In addition= RFSURFSTIJLT+(6PTE5MMTILGU
(74) Java M.M added new classes into the Inp*t)tream and .*tp*t)tream hierarchy, so it s obvious those classes weren t
being re%laced. RFSURFSTIJLT+(6PTE5MMTILIU
(75) There are ti#es when you #ust use classes "ro# the !byte$ hierarchy in combination with classes in the !character$ hierarchy.
To acco#%lish this there are !bridge$ classes= Inp*t)tream$ea'er converts an Inp*t)tream to a $ea'er and .*tp*t)tream0riter converts an .*tp*t)tream to a 0riter. RFSURFSTIJLT+(6PTE5MMTIL2U The #ost i#%ortant reason "or the $ea'er and 0riter hierarchies is "or internationali1ation. The old IF) strea# hierarchy su%%orts only I'bit byte strea#s and doesn t handle the M3'bit 4nicode characters well. Since 4nicode is used "or internationali1ation *and Java s native char is M3'bit 4nicode,, the $ea'er and 0riter hierarchies were added to su%%ort 4nicode in all IF) o%erations. In addition, the new libraries are designed "or "aster o%erations than the old. RFSURFSTIJLT+(6PTE5MMTI?@U 6s is the %ractice in this book, I will atte#%t to %rovide an overview o" the classes, but assu#e that you will use online docu#entation to deter#ine all the details, such as the e&haustive list o" #ethods. RFSURF STIJLT+(6PTE5MMTI?MU
712
)o*rces , )inks< Java >!D class Inp*t)tream .*tp*t)tream FileInp*t)tream File.*tp*t)tream )tring2*fferInp*t)trea m
*no corres%onding class,
Inp*t)tream$ea'er 0riter
converter=
In general, you ll "ind that the inter"aces "or the two di""erent hierarchies are si#ilar i" not identical.
713
#*sh2ack$ea'er
There s one direction that s Auite clear= :henever you want to use rea'+ineA B, you shouldn t do it with a ataInp*t)tream any #ore
714
*this is #et with a de%recation #essage at co#%ile'ti#e,, but instead use a 2*ffere'$ea'er. )ther than this, ataInp*t)tream is still a !%re"erred$ #e#ber o" the IF) library. To #ake the transition to using a #rint0riter easier, it has constructors that take any .*tp*t)tream ob0ect, as well as 0riter ob0ects. (owever, #rint0riter has no #ore su%%ort "or "or#atting than #rint)tream does; the inter"aces are virtually the sa#e. RFSURF STIJLT+(6PTE5MMTI??U The #rint0riter constructor also has an o%tion to %er"or# auto#atic "lushing, which ha%%ens a"ter every printlnA B i" the constructor "lag is set. RFSURFSTIJLT+(6PTE5MMTI?HU
Cnchanged Classes
So#e classes were le"t unchanged between Java M.@ and Java M.M= Java M.@ classes without corres%onding Java M.M classes
ata.*tp*t)tream File $an'omAccessFile )eC*enceInp*t)tream ata.*tp*t)tream, in %articular, is used without change, so "or
storing and retrieving data in a trans%ortable "or#at you use the Inp*t)tream and .*tp*t)tream hierarchies.
715
have to be able to deter#ine how big they are and where they are %laced in the "ile. RFSURFSTIJLT+(6PTE5MMTI?3U 6t "irst it s a little bit hard to believe that $an'omAccessFile is not %art o" the Inp*t)tream or .*tp*t)tream hierarchy. (owever, it has no association with those hierarchies other than that it ha%%ens to i#%le#ent the ataInp*t and ata.*tp*t inter"aces *which are also i#%le#ented by ataInp*t)tream and ata.*tp*t)tream,. It doesn t even use any o" the "unctionality o" the e&isting Inp*t)tream or .*tp*t)tream classes9it s a co#%letely se%arate class, written "ro# scratch, with all o" its own *#ostly native, #ethods. The reason "or this #ay be that $an'omAccessFile has essentially di""erent behavior than the other IF) ty%es, since you can #ove "orward and backward within a "ile. In any event, it stands alone, as a direct descendant o" .b8ect. RF SURFSTIJLT+(6PTE5MMTI?GU Essentially, a $an'omAccessFile works like a ataInp*t)tream %asted together with a ata.*tp*t)tream, along with the #ethods getFile#ointerA B to "ind out where you are in the "ile, seekA B to #ove to a new %oint in the "ile, and lengthA B to deter#ine the #a&i#u# si1e o" the "ile. In addition, the constructors reAuire a second argu#ent *identical to fopenA B in +, indicating whether you are 0ust rando#ly reading * arb, or reading and writing * ar(b,. There s no su%%ort "or write'only "iles, which could suggest that $an'omAccessFile #ight have worked well i" it were inherited "ro# ataInp*t)tream. RFSURF STIJLT+(6PTE5MMTI?IU The seeking #ethods are available only in $an'omAccessFile, which works "or "iles only. 2*ffere'Inp*t)tream does allow you to markA B a %osition *whose value is held in a single internal variable, and resetA B to that %osition, but this is li#ited and not very use"ul. RFSURF STIJLT+(6PTE5MMTI?2U
717
//3 c((3$G%trea#De#o.Hava // Ty"ical $/G strea# configurations. i#"ort Hava.io.B< "ublic class $G%trea#De#o @ // Thro: e6ce"tions to console3 "ublic static voi! #ain-%tringNO args. thro:s $GE6ce"tion @ // (. 5ea!ing in"ut by lines3 Buffere!5ea!er in ? ne: Buffere!5ea!erne: Lile5ea!er-8$G%trea#De#o.Hava8..< %tring s, s ? ne: %tring-.< :hile--s ? in.rea!Line-..4? null. s K? s K 8_n8< in.close-.< // (b. 5ea!ing stan!ar! in"ut3 Buffere!5ea!er st!in ? ne: Buffere!5ea!erne: $n"ut%trea#5ea!er-%yste#.in..< %yste#.out."rint-8Enter a line38.< %yste#.out."rintln-st!in.rea!Line-..< // . $n"ut fro# #e#ory %tring5ea!er in ? ne: %tring5ea!er-s .< int c< :hile--c ? in .rea!-.. 4? -(.
718
%yste#.out."rint--char.c.< // ). Lor#atte! #e#ory in"ut try @ Data$n"ut%trea# in) ? ne: Data$n"ut%trea#ne: Byte0rray$n"ut%trea#-s .getBytes-...< :hile-true. %yste#.out."rint--char.in).rea!Byte-..< A catch-EGLE6ce"tion e. @ %yste#.err."rintln-8En! of strea#8.< A // I. Lile out"ut try @ Buffere!5ea!er inI ? ne: Buffere!5ea!erne: %tring5ea!er-s ..< Print\riter out( ? ne: Print\riterne: Buffere!\riterne: Lile\riter-8$GDe#o.out8...< int lineCount ? (< :hile--s ? inI.rea!Line-.. 4? null . out(."rintln-lineCountKK K 83 8 K s.< out(.close-.< A catch-EGLE6ce"tion e. @ %yste#.err."rintln-8En! of strea#8.< A // ,. %toring D recovering !ata try @ DataGut"ut%trea# out ? ne: DataGut"ut%trea#ne: Buffere!Gut"ut%trea#ne: LileGut"ut%trea#-8Data.t6t8...< out .:riteDouble-).(I(,C.< out .:riteChars:riteYTL-8That :as "i_n8.< out .:riteBytes-8That :as "i_n8.< out .:riteDouble-(.I(I().<
71:
out .:riteYTL-8%=uare root of 8.< out .close-.< Data$n"ut%trea# in, ? ne: Data$n"ut%trea#ne: Buffere!$n"ut%trea#ne: Lile$n"ut%trea#-8Data.t6t8...< Buffere!5ea!er in,br ? ne: Buffere!5ea!erne: $n"ut%trea#5ea!er-in,..< // Just use Data$n"ut%trea# for !ata3 %yste#.out."rintln-in,.rea!Double-..< // Gnly rea!YTL-. :ill recover the // Java-YTL %tring "ro"erly3 // Can no: use the 8"ro"er8 rea!Line-.3 %yste#.out."rintln-in,br.rea!Linerea!YTL-..< // But the line co#es out funny. // The one create! :ith :riteBytes is G`3 %yste#.out."rintln-in,br.rea!Line-..< // 5ea! the follo:ing !ouble an! %tring3 %yste#.out."rintln-in,.rea!Double-..< %yste#.out."rintln-in,.rea!YTL-..< A catch-EGLE6ce"tion e. @ %yste#.err."rintln-8En! of strea#8.< A // +. 5ea!ing/:riting ran!o# access files 5an!o#0ccessLile rf ? ne: 5an!o#0ccessLile-8rtest.!at8, 8r:8.< for-int i ? '< i P ('< iKK. rf.:riteDouble-iB(.I(I.< rf.close-.< rf ? ne: 5an!o#0ccessLile-8rtest.!at8, 8r:8.< rf.seek-,B1.< rf.:riteDouble-I*.'''(.< rf.close-.< rf ? ne: 5an!o#0ccessLile-8rtest.!at8, 8r8.< for-int i ? '< i P ('< iKK.
71;
In.ut streams
Parts M through ? de#onstrate the creation and use o" in%ut strea#s. Part ? also shows the si#%le use o" an out%ut strea#.
72=
//3 c((3TestEGL.Hava // Testing for the en! of file // :hile rea!ing a byte at a ti#e. i#"ort Hava.io.B< "ublic class TestEGL @ // Thro: e6ce"tions to console3 "ublic static voi! #ain-%tringNO args. thro:s $GE6ce"tion @ Data$n"ut%trea# in ? ne: Data$n"ut%trea#ne: Buffere!$n"ut%trea#ne: Lile$n"ut%trea#-8TestEof.Hava8...< :hile-in.available-. 4? '. %yste#.out."rint--char.in.rea!Byte-..<
721
A A ///3>
Cote that availableA B works di""erently de%ending on what sort o" #ediu# you re reading "ro#; it s literally !the nu#ber o" bytes that can be read ,ithout blocking.$ :ith a "ile this #eans the whole "ile, but with a di""erent kind o" strea# this #ight not be true, so use it thought"ully. RF SURFSTIJLT+(6PTE5MMTIH3U /ou could also detect the end o" in%ut in cases like these by catching an e&ce%tion. (owever, the use o" e&ce%tions "or control "low is considered a #isuse o" that "eature. RFSURFSTIJLT+(6PTE5MMTIHGU
+) <ile out.ut
This e&a#%le also shows how to write data to a "ile. Eirst, a File0riter is created to connect to the "ile. /ou ll virtually always want to bu""er the out%ut by wra%%ing it in a 2*ffere'0riter *try re#oving this wra%%ing to see the i#%act on the %er"or#ance9bu""ering tends to dra#atically increase %er"or#ance o" IF) o%erations,. Then "or the "or#atting it s turned into a #rint0riter. The data "ile created this way is readable as an ordinary te&t "ile. RFSURFSTIJLT+(6PTE5MMTIHIU 6s the lines are written to the "ile, line nu#bers are added. Cote that +ine/*mberInp*t)tream is not used, because it s a silly class and you don t need it. 6s shown here, it s trivial to kee% track o" your own line nu#bers. RFSURFSTIJLT+(6PTE5MMTIH2U :hen the in%ut strea# is e&hausted, rea'+ineA B returns n*ll. /ou ll see an e&%licit closeA B "or o*t>, because i" you don t call closeA B "or all your out%ut "iles, you #ight discover that the bu""ers don t get "lushed so they re inco#%lete. RFSURFSTIJLT+(6PTE5MMTI3@U
Out.ut streams
The two %ri#ary kinds o" out%ut strea#s are se%arated by the way they write data= one writes it "or hu#an consu#%tion, and the other writes it to be reacAuired by a ataInp*t)tream. The $an'omAccessFile stands alone, although its data "or#at is co#%atible with the
722
Cote that the character string is written using both (rite-harsA B and (rite2ytesA B. :hen you run the %rogra#, you ll discover that (rite-harsA B out%uts M3'bit 4nicode characters. :hen you read the line using rea'+ineA B, you ll see that there is a s%ace between each character, because o" the e&tra byte inserted by 4nicode. Since there is no co#%le#entary !read+hars$ #ethod in ataInp*t)tream, you re stuck %ulling these characters o"" one at a ti#e with rea'-harA B. So "or 6S+II, it s easier to write the characters as bytes "ollowed by a newline; then use rea'+ineA B to read back the bytes as a regular 6S+II line.:hen using a ata.*tp*t)tream, the only reliable way to write a )tring so that it can be recovered by a ataInp*t)tream is to use 4TE'I encoding, acco#%lished above using (riteUTFA B and rea'UTFA B. 4TE'I is a variation on 4nicode, which stores all characters in K bytes. I" you re working with 6S+II or #ostly 6S+II characters *which only occu%y G bits,, this is a tre#endous waste o" s%ace andFor bandwidth, so 4TE'I encodes 6S+II characters in a single byte, and non'6S+II characters in
@ ZMD is another way to solve the %roble# o" #oving data across di""erent co#%uting %lat"or#s, and does not de%end on having Java on all %lat"or#s. (owever, Java tools e&ist that su%%ort ZMD.
723
two or three bytes. In addition, the length o" the string is stored in the "irst two bytes. (owever, (riteUTFA B and rea'UTFA B use a s%ecial variation o" 4TE'I "or Java *which is co#%letely described in the JavaSo"t (TMD docu#entation "or those #ethods, and so i" you read a string written with (riteUTFA B using a non'Java %rogra#, you #ust write s%ecial code in order to read the string %ro%erly. RFSURF
STIJLT+(6PTE5MMTI3?U
:ith (riteUTFA B and rea'UTFA B, you can inter#ingle )trings and other ty%es o" data using a ata.*tp*t)tream with the knowledge that the )trings will be %ro%erly stored as 4nicode, and will be easily recoverable with a ataInp*t)tream. RFSURF
STIJLT+(6PTE5MMTI3HU The (rite o*bleA B stores the 'o*ble nu#ber to the strea# and the co#%le#entary rea' o*bleA B recovers it *there are si#ilar #ethods "or reading and writing the other ty%es,. But "or any o" the reading #ethods to work correctly, you #ust know the e&act %lace#ent o" the data ite# in the strea#, since it would be eAually %ossible to read the stored 'o*ble as a si#%le seAuence o" bytes, or as a char, etc. So you #ust either have a "i&ed "or#at "or the data in the "ile or e&tra in"or#ation #ust be stored in the "ile that you %arse to deter#ine where the data is located. Cote that ob0ect seriali1ation *described later in this
cha%ter, #ay be an easier way to store and retrieve co#%le& data structures. RFSURFSTIJLT+(6PTE5MMTI33U
724
4sing a $an'omAccessFile is like using a co#bined ataInp*t)tream and ata.*tp*t)tream *because it i#%le#ents the eAuivalent inter"aces,. In addition, you can see that seekA B is used to #ove about in the "ile and change one o" the values. RFSURF STIJLT+(6PTE5MMTI32U
A bugAA bugA
I" you look at section H, you ll see that the data is written be$ore the te&t. That s because a %roble# was introduced in Java M.M *and %ersists in Java K, that sure see#s like a bug to #e, but I re%orted it and the bug %eo%le at JavaSo"t said that this is the way it is su%%osed to work *however, the %roble# did not occur in Java M.@, which #akes #e sus%icious,. The %roble# is shown in the "ollowing code= //3 c((3$GProble#.Hava // Java (.( an! higher $/G Proble#. i#"ort Hava.io.B< "ublic class $GProble# @ // Thro: e6ce"tions to console3 "ublic static voi! #ain-%tringNO args. thro:s $GE6ce"tion @ DataGut"ut%trea# out ? ne: DataGut"ut%trea#ne: Buffere!Gut"ut%trea#ne: LileGut"ut%trea#-8Data.t6t8...< out.:riteDouble-).(I(,C.< out.:riteBytes-8That :as the value of "i_n8.< out.:riteBytes-8This is "i/ 3_n8.< out.:riteDouble-).(I(,C/ .< out.close-.< Data$n"ut%trea# in ? ne: Data$n"ut%trea#ne: Buffere!$n"ut%trea#ne: Lile$n"ut%trea#-8Data.t6t8...< Buffere!5ea!er inbr ? ne: Buffere!5ea!erne: $n"ut%trea#5ea!er-in..<
725
// The !oubles :ritten BELG5E the line of te6t // rea! back correctly3 %yste#.out."rintln-in.rea!Double-..< // 5ea! the lines of te6t3 %yste#.out."rintln-inbr.rea!Line-..< %yste#.out."rintln-inbr.rea!Line-..< // Trying to rea! the !oubles after the line // "ro!uces an en!-of-file e6ce"tion3 %yste#.out."rintln-in.rea!Double-..< A A ///3>
_5e#oved "ro# te&t` *This was a bug in #y reasoning Y I did not understand the intention o" (riteUTFA B and rea'UTFA B. 6lso, creating two bu""ers "or the sa#e strea# turns out to be a big #istake Y the "irst bu""er that you read sucks u% e&tra bytes so the second bu""er gets indeter#inate out%ut,. RFSURFSTIJLT+(6PTE5MMTIG@U
i.ed streams
The #ipe'Inp*t)tream, #ipe'.*tp*t)tream, #ipe'$ea'er and #ipe'0riter have been #entioned only brie"ly in this cha%ter. This is not to suggest that they aren t use"ul, but their value is not a%%arent until you begin to understand #ultithreading, since the %i%ed strea#s are used to co##unicate between threads. This is covered along with an e&a#%le in +ha%ter M?. RFSURFSTIJLT+(6PTE5MMTIGMU
1tandard IDO
The ter# standard I/O re"ers to the 4ni& conce%t *which is re%roduced in so#e "or# in :indows and #any other o%erating syste#s, o" a single strea# o" in"or#ation that is used by a %rogra#. 6ll the %rogra# s in%ut can co#e "ro# standard in ut, all its out%ut can go to standard out ut, and all o" its error #essages can be sent to standard error. The value o" standard IF) is that %rogra#s can easily be chained together and one %rogra# s standard out%ut can beco#e the standard in%ut "or another %rogra#. This is a %ower"ul tool. RFSURFSTIJLT+(6PTE5MMTIGKU
727
//3 c((3Echo.Hava // Mo: to rea! fro# stan!ar! in"ut. i#"ort Hava.io.B< "ublic class Echo @ "ublic static voi! #ain-%tringNO args. thro:s $GE6ce"tion @ Buffere!5ea!er in ? ne: Buffere!5ea!erne: $n"ut%trea#5ea!er-%yste#.in..< %tring s< :hile--s ? in.rea!Line-...length-. 4? '. %yste#.out."rintln-s.< // 0n e#"ty line ter#inates the "rogra# A A ///3>
The reason "or the e&ce%tion s%eci"ication is that rea'+ineA B can throw an I.&4ception. Cote that )ystem!in should usually be bu""ered, as with #ost strea#s. RFSURFSTIJLT+(6PTE5MMTIG?U
728
72:
%rogra# in which you want to test a %articular user'in%ut seAuence re%eatedly. (ere s a si#%le e&a#%le that shows the use o" these #ethods=
//3 c((35e!irecting.Hava // De#onstrates stan!ar! $/G re!irection. i#"ort Hava.io.B< "ublic class 5e!irecting @ // Thro: e6ce"tions to console3 "ublic static voi! #ain-%tringNO args. thro:s $GE6ce"tion @ Buffere!$n"ut%trea# in ? ne: Buffere!$n"ut%trea#ne: Lile$n"ut%trea#85e!irecting.Hava8..< Print%trea# out ? ne: Print%trea#ne: Buffere!Gut"ut%trea#ne: LileGut"ut%trea#-8test.out8...< %yste#.set$n-in.< %yste#.setGut-out.< %yste#.setErr-out.< Buffere!5ea!er br ? ne: Buffere!5ea!erne: $n"ut%trea#5ea!er-%yste#.in..< %tring s< :hile--s ? br.rea!Line-.. 4? null. %yste#.out."rintln-s.< out.close-.< // 5e#e#ber this4 A A ///3>
This %rogra# attaches standard in%ut to a "ile, and redirects standard out%ut and standard error to another "ile. RFSURF STIJLT+(6PTE5MMTIGGU IF) redirection #ani%ulates strea#s o" bytes, not strea#s o" characters, thus Inp*t)treams and .*tp*t)treams are used rather than $ea'ers and 0riters. RFSURFSTIJLT+(6PTE5MMTIGIU
72;
Com.ression
The Java IF) library contains classes to su%%ort reading and writing strea#s in a co#%ressed "or#at. These are wra%%ed around e&isting IF) classes to %rovide co#%ression "unctionality. RFSURF STIJLT+(6PTE5MMTIG2U These classes are not derived "ro# the $ea'er and 0riter classes, but instead are %art o" the Inp*t)tream and .*tp*t)tream hierarchies. This is because the co#%ression library works with bytes, not characters. (owever, you #ight so#eti#es be "orced to #i& the two ty%es o" strea#s. *5e#e#ber that you can use Inp*t)tream$ea'er and .*tp*t)tream0riter to %rovide easy conversion between one ty%e and another.,
-ompression class -hecke'Inp*t)tream -hecke'.*tp*t)trea m eflater.*tp*t)trea m Zip.*tp*t)tream "ZI#.*tp*t)tream InflaterInp*t)tream ZipInp*t)tream "ZI#Inp*t)tream
73=
6lthough there are #any co#%ression algorith#s, Qi% and 8QIP are %ossibly the #ost co##only used. Thus you can easily #ani%ulate your co#%ressed data with the #any tools available "or reading and writing these "or#ats.
//3 c((3aT$Pco#"ress.Hava // Yses aT$P co#"ression to co#"ress a file // :hose na#e is "asse! on the co##an! line. i#"ort Hava.io.B< i#"ort Hava.util.Ui".B< "ublic class aT$Pco#"ress @ // Thro: e6ce"tions to console3 "ublic static voi! #ain-%tringNO args. thro:s $GE6ce"tion @ Buffere!5ea!er in ? ne: Buffere!5ea!erne: Lile5ea!er-argsN'O..< Buffere!Gut"ut%trea# out ? ne: Buffere!Gut"ut%trea#ne: aT$PGut"ut%trea#ne: LileGut"ut%trea#-8test.gU8...< %yste#.out."rintln-8\riting file8.< int c< :hile--c ? in.rea!-.. 4? -(. out.:rite-c.< in.close-.< out.close-.< %yste#.out."rintln-85ea!ing file8.< Buffere!5ea!er in ? ne: Buffere!5ea!erne: $n"ut%trea#5ea!erne: aT$P$n"ut%trea#-
731
//3 c((3Ti"Co#"ress.Hava // Yses Ti" co#"ression to co#"ress any // nu#ber of files given on the co##an! line. i#"ort Hava.io.B< i#"ort Hava.util.B< i#"ort Hava.util.Ui".B< "ublic class Ti"Co#"ress @ // Thro: e6ce"tions to console3 "ublic static voi! #ain-%tringNO args.
732
thro:s $GE6ce"tion @ LileGut"ut%trea# f ? ne: LileGut"ut%trea#-8test.Ui"8.< Checke!Gut"ut%trea# csu# ? ne: Checke!Gut"ut%trea#f, ne: 0!ler) -..< Ti"Gut"ut%trea# out ? ne: Ti"Gut"ut%trea#ne: Buffere!Gut"ut%trea#-csu#..< out.setCo##ent-80 test of Java Ti""ing8.< // &o corres"on!ing getCo##ent-., though. for-int i ? '< i P args.length< iKK. @ %yste#.out."rintln8\riting file 8 K argsNiO.< Buffere!5ea!er in ? ne: Buffere!5ea!erne: Lile5ea!er-argsNiO..< out."ut&e6tEntry-ne: Ti"Entry-argsNiO..< int c< :hile--c ? in.rea!-.. 4? -(. out.:rite-c.< in.close-.< A out.close-.< // Checksu# vali! only after the file // has been close!4 %yste#.out."rintln-8Checksu#3 8 K csu#.getChecksu#-..getWalue-..< // &o: e6tract the files3 %yste#.out."rintln-85ea!ing file8.< Lile$n"ut%trea# fi ? ne: Lile$n"ut%trea#-8test.Ui"8.< Checke!$n"ut%trea# csu#i ? ne: Checke!$n"ut%trea#fi, ne: 0!ler) -..< Ti"$n"ut%trea# in ? ne: Ti"$n"ut%trea#ne: Buffere!$n"ut%trea#-csu#i..< Ti"Entry Ue< :hile--Ue ? in .get&e6tEntry-.. 4? null. @ %yste#.out."rintln-85ea!ing file 8 K Ue.<
733
int 6< :hile--6 ? in .rea!-.. 4? -(. %yste#.out.:rite-6.< A %yste#.out."rintln-8Checksu#3 8 K csu#i.getChecksu#-..getWalue-..< in .close-.< // 0lternative :ay to o"en an! rea! // Ui" files3 Ti"Lile Uf ? ne: Ti"Lile-8test.Ui"8.< Enu#eration e ? Uf.entries-.< :hile-e.hasJoreEle#ents-.. @ Ti"Entry Ue ? -Ti"Entry.e.ne6tEle#ent-.< %yste#.out."rintln-8Lile3 8 K Ue .< // ... an! e6tract the !ata as before A A A ///3>
Eor each "ile to add to the archive, you #ust call p*t/e4t&ntryA B and %ass it a Zip&ntry ob0ect. The Zip&ntry ob0ect contains an e&tensive inter"ace that allows you to get and set all the data available on that %articular entry in your Qi% "ile= na#e, co#%ressed and unco#%ressed si1es, date, +5+ checksu#, e&tra "ield data, co##ent, co#%ression #ethod, and whether it s a directory entry. (owever, even though the Qi% "or#at has a way to set a %assword, this is not su%%orted in Java s Qi% library. 6nd although -hecke'Inp*t)tream and -hecke'.*tp*t)tream su%%ort both A'lerJI and -$-JI checksu#s, the Zip&ntry class su%%orts only an inter"ace "or +5+. This is a restriction o" the underlying Qi% "or#at, but it #ight li#it you "ro# using the "aster A'lerJI. RFSURFSTIJLT+(6PTE5MMTIIKU To e&tract "iles, ZipInp*t)tream has a get/e4t&ntryA B #ethod that returns the ne&t Zip&ntry i" there is one. 6s a #ore succinct alternative, you can read the "ile using a ZipFile ob0ect, which has a #ethod entries A B to return an &n*meration to the Zip&ntries. RFSURF STIJLT+(6PTE5MMTIILU In order to read the checksu# you #ust so#ehow have access to the associated -hecks*m ob0ect. (ere, a re"erence to the
734
-hecke'.*tp*t)tream and -hecke'Inp*t)tream ob0ects is retained, but you could also 0ust hold onto a re"erence to the -hecks*m
ob0ect. RFSURFSTIJLT+(6PTE5MMTII?U 6 ba""ling #ethod in Qi% strea#s is set-ommentA B. 6s shown above, you can set a co##ent when you re writing a "ile, but there s no way to recover the co##ent in the ZipInp*t)tream. +o##ents a%%ear to be su%%orted "ully on an entry'by'entry basis only via Zip&ntry. RFSURF STIJLT+(6PTE5MMTIIHU )" course, you are not li#ited to "iles when using the "ZI# or Zip libraries9you can co#%ress anything, including data to be sent through a network connection. RFSURFSTIJLT+(6PTE5MMTII3U
735
c t 4 4 file f
+reates a new or e#%ty archive. Dists the table o" contents. E&tracts all "iles. E&tracts the na#ed "ile. Says= !I # going to give you the na#e o" the "ile.$ I" you don t use this, 0ar assu#es that its in%ut will co#e "ro# standard in%ut, or, i" it is creating a "ile, its out%ut will go to standard out%ut. Says that the "irst argu#ent will be the na#e o" the user'created #ani"est "ile. 8enerates verbose out%ut describing what 0ar is doing. )nly store the "iles; doesn t co#%ress the "iles *use to create a J65 "ile that you can %ut in your class%ath,. 7on t auto#atically create a #ani"est "ile.
m v D 1
I" a subdirectory is included in the "iles to be %ut into the J65 "ile, that subdirectory is auto#atically added, including all o" its subdirectories, etc. Path in"or#ation is also %reserved. (ere are so#e ty%ical ways to invoke 8ar=
737
Produces a table o" contents o" the "iles in myJarFile!8ar. RFSURF STIJLT+(6PTE5MMTI2LU
CL0%%P0TM?8lib(.Har<lib .Har<8
Then Java can search lib>!8ar and libI!8ar "or class "iles. RFSURF STIJLT+(6PTE5MMTI23U The 8ar tool isn t as use"ul as a 7ip utility. Eor e&a#%le, you can t add or u%date "iles to an e&isting J65 "ile; you can create J65 "iles only "ro# scratch. 6lso, you can t #ove "iles into a J65 "ile, erasing the# as they are #oved. (owever, a J65 "ile created on one %lat"or# will be trans%arently readable by the 8ar tool on any other %lat"or# *a %roble# that so#eti#es %lagues 7ip utilities,. RFSURFSTIJLT+(6PTE5MMTI2GU 6s you will see in +ha%ter ML, J65 "iles are also used to %ackage JavaBeans. RFSURFSTIJLT+(6PTE5MMTI2IU
Ob3ect seriali?ation
Java s ob>ect seriali?ation allows you to take any ob0ect that i#%le#ents the )eriali7able inter"ace and turn it into a seAuence o" bytes that can later be "ully restored to regenerate the original ob0ect. This is even true across a network, which #eans that the seriali1ation #echanis# auto#atically co#%ensates "or di""erences in o%erating syste#s. That is, you can create an ob0ect on a :indows #achine, seriali1e it, and send it
738
across the network to a 4ni& #achine where it will be correctly reconstructed. /ou don t have to worry about the data re%resentations on the di""erent #achines, the byte ordering, or any other details. RFSURF STIJLT+(6PTE5MMTI22U By itsel", ob0ect seriali1ation is interesting because it allows you to i#%le#ent light,eight ersistence. 5e#e#ber that %ersistence #eans an ob0ect s li"eti#e is not deter#ined by whether a %rogra# is e&ecuting9 the ob0ect lives in bet,een invocations o" the %rogra#. By taking a seriali1able ob0ect and writing it to disk, then restoring that ob0ect when the %rogra# is reinvoked, you re able to %roduce the e""ect o" %ersistence. The reason it s called !lightweight$ is that you can t si#%ly de"ine an ob0ect using so#e kind o" !%ersistent$ keyword and let the syste# take care o" the details *although this #ight ha%%en in the "uture,. Instead, you #ust e&%licitly seriali1e and deseriali1e the ob0ects in your %rogra#. RFSURFSTIJLT+(6PTE5MMTIM@@U )b0ect seriali1ation was added to the language to su%%ort two #a0or "eatures. Java s remote method invocation *5MI, allows ob0ects that live on other #achines to behave as i" they live on your #achine. :hen sending #essages to re#ote ob0ects, ob0ect seriali1ation is necessary to trans%ort the argu#ents and return values. 5MI is discussed in +ha%ter MH. RFSURFSTIJLT+(6PTE5MMTIM@MU )b0ect seriali1ation is also necessary "or JavaBeans, described in +ha%ter ML. :hen a Bean is used, its state in"or#ation is generally con"igured at design'ti#e. This state in"or#ation #ust be stored and later recovered when the %rogra# is started; ob0ect seriali1ation %er"or#s this task. RF SURFSTIJLT+(6PTE5MMTIM@KU Seriali1ing an ob0ect is Auite si#%le, as long as the ob0ect i#%le#ents the
73:
need only call (rite.b8ectA B and your ob0ect is seriali1ed and sent to the .*tp*t)tream. To reverse the %rocess, you wra% an Inp*t)tream inside an .b8ectInp*t)tream and call rea'.b8ectA B. :hat co#es back is, as usual, a re"erence to an u%cast .b8ect, so you #ust downcast to set things straight. RFSURFSTIJLT+(6PTE5MMTIM@?U 6 %articularly clever as%ect o" ob0ect seriali1ation is that it not only saves an i#age o" your ob0ect but it also "ollows all the re"erences contained in your ob0ect and saves those ob0ects, and "ollows all the re"erences in each o" those ob0ects, etc. This is so#eti#es re"erred to as the !web o" ob0ects$ that a single ob0ect can be connected to, and it includes arrays o" re"erences to ob0ects as well as #e#ber ob0ects. I" you had to #aintain your own ob0ect seriali1ation sche#e, #aintaining the code to "ollow all these links would be a bit #ind'boggling. (owever, Java ob0ect seriali1ation see#s to %ull it o"" "lawlessly, no doubt using an o%ti#i1ed algorith# that traverses the web o" ob0ects. The "ollowing e&a#%le tests the seriali1ation #echanis# by #aking a !wor#$ o" linked ob0ects, each o" which has a link to the ne&t seg#ent in the wor# as well as an array o" re"erences to ob0ects o" a di""erent class, ata=
//3 c((3\or#.Hava // De#onstrates obHect serialiUation. i#"ort Hava.io.B< class Data i#"le#ents %erialiUable @ "rivate int i< Data-int 6. @ i ? 6< A "ublic %tring to%tring-. @ return $nteger.to%tring-i.< A A "ublic class \or# i#"le#ents %erialiUable @ // aenerate a ran!o# int value3 "rivate static int r-. @ return -int.-Jath.ran!o#-. B ('.< A "rivate DataNO ! ? @ ne: Data-r-.., ne: Data-r-.., ne: Data-r-.. A<
73;
"rivate \or# ne6t< "rivate char c< // Walue of i ?? nu#ber of seg#ents \or#-int i, char 6. @ %yste#.out."rintln-8 \or# constructor3 8 K i.< c ? 6< if---i Q '. ne6t ? ne: \or#-i, -char.-6 K (..< A \or#-. @ %yste#.out."rintln-8Default constructor8.< A "ublic %tring to%tring-. @ %tring s ? 838 K c K 8-8< for-int i ? '< i P !.length< iKK. s K? !NiO.to%tring-.< s K? 8.8< if-ne6t 4? null. s K? ne6t.to%tring-.< return s< A // Thro: e6ce"tions to console3 "ublic static voi! #ain-%tringNO args. thro:s Class&otLoun!E6ce"tion, $GE6ce"tion @ \or# : ? ne: \or#-+, 2a2.< %yste#.out."rintln-8: ? 8 K :.< GbHectGut"ut%trea# out ? ne: GbHectGut"ut%trea#ne: LileGut"ut%trea#-8:or#.out8..< out.:riteGbHect-8\or# storage8.< out.:riteGbHect-:.< out.close-.< // 0lso flushes out"ut GbHect$n"ut%trea# in ? ne: GbHect$n"ut%trea#ne: Lile$n"ut%trea#-8:or#.out8..< %tring s ? -%tring.in.rea!GbHect-.< \or# : ? -\or#.in.rea!GbHect-.< %yste#.out."rintln-s K 8, : ? 8 K : .< Byte0rrayGut"ut%trea# bout ? ne: Byte0rrayGut"ut%trea#-.< GbHectGut"ut%trea# out ?
74=
ne: GbHectGut"ut%trea#-bout.< out .:riteGbHect-8\or# storage8.< out .:riteGbHect-:.< out .flush-.< GbHect$n"ut%trea# in ? ne: GbHect$n"ut%trea#ne: Byte0rray$n"ut%trea#bout.toByte0rray-...< s ? -%tring.in .rea!GbHect-.< \or# :) ? -\or#.in .rea!GbHect-.< %yste#.out."rintln-s K 8, :) ? 8 K :).< A A ///3>
To #ake things interesting, the array o" ata ob0ects inside 0orm are initiali1ed with rando# nu#bers. *This way you don t sus%ect the co#%iler o" kee%ing so#e kind o" #eta'in"or#ation., Each 0orm seg#ent is labeled with a char that s auto#atically generated in the %rocess o" recursively generating the linked list o" 0orms. :hen you create a 0orm, you tell the constructor how long you want it to be. To #ake the ne4t re"erence it calls the 0orm constructor with a length o" one less, etc. The "inal ne4t re"erence is le"t as n*ll, indicating the end o" the 0orm. RFSURFSTIJLT+(6PTE5MMTIM@HU The %oint o" all this was to #ake so#ething reasonably co#%le& that couldn t easily be seriali1ed. The act o" seriali1ing, however, is Auite si#%le. )nce the .b8ect.*tp*t)tream is created "ro# so#e other strea#, (rite.b8ectA B seriali1es the ob0ect. Cotice the call to (rite.b8ectA B "or a )tring, as well. /ou can also write all the %ri#itive data ty%es using the sa#e #ethods as ata.*tp*t)tream *they share the sa#e inter"ace,. RFSURFSTIJLT+(6PTE5MMTIM@3U There are two se%arate code sections that look si#ilar. The "irst writes and reads a "ile and the second, "or variety, writes and reads a 2yteArray. /ou can read and write an ob0ect using seriali1ation to any ataInp*t)tream or ata.*tp*t)tream including, as you will see in the +ha%ter MH, a network. The out%ut "ro# one run was=
741
\or# constructor3 ) \or# constructor3 \or# constructor3 ( : ? 3a- + .3b-(''.3c-)C+.3!-I1'.3e-)(+.3f-)C1. \or# storage, : ? 3a- + .3b-(''.3c-)C+.3!-I1'.3e -)(+.3f-)C1. \or# storage, :) ? 3a- + .3b-(''.3c-)C+.3!-I1'.3e -)(+.3f-)C1.
/ou can see that the deseriali1ed ob0ect really does contain all o" the links that were in the original ob0ect. RFSURFSTIJLT+(6PTE5MMTIM@GU Cote that no constructor, not even the de"ault constructor, is called in the %rocess o" deseriali1ing a )eriali7able ob0ect. The entire ob0ect is restored by recovering data "ro# the Inp*t)tream. RFSURF STIJLT+(6PTE5MMTIM@IU )b0ect seriali1ation is byte'oriented, and thus uses the Inp*t)tream and .*tp*t)tream hierarchies. RFSURFSTIJLT+(6PTE5MMTIM@2U
//3 c((30lien.Hava // 0 serialiUable class. i#"ort Hava.io.B< "ublic class 0lien i#"le#ents %erialiUable @ A ///3>
The "ile that creates and seriali1es an Alien ob0ect goes in the sa#e directory= RFSURFSTIJLT+(6PTE5MMTIMMKU
742
//3 c((3LreeUe0lien.Hava // Create a serialiUe! out"ut file. i#"ort Hava.io.B< "ublic class LreeUe0lien @ // Thro: e6ce"tions to console3 "ublic static voi! #ain-%tringNO args. thro:s $GE6ce"tion @ GbHectGut"ut out ? ne: GbHectGut"ut%trea#ne: LileGut"ut%trea#-89.file8..< 0lien Uorcon ? ne: 0lien-.< out.:riteGbHect-Uorcon.< A A ///3>
5ather than catching and handling e&ce%tions, this %rogra# takes the Auick and dirty a%%roach o" %assing the e&ce%tions out o" mainA B, so they ll be re%orted on the co##and line. RFSURF STIJLT+(6PTE5MMTIMMLU )nce the %rogra# is co#%iled and run, co%y the resulting X!file to a subdirectory called 4files, where the "ollowing code goes= RFSURF STIJLT+(6PTE5MMTIMM?U
//3 c((36files3Tha:0lien.Hava // Try to recover a serialiUe! file :ithout the // class of obHect that2s store! in that file. i#"ort Hava.io.B< "ublic class Tha:0lien @ "ublic static voi! #ain-%tringNO args. thro:s $GE6ce"tion, Class&otLoun!E6ce"tion @ GbHect$n"ut%trea# in ? ne: GbHect$n"ut%trea#ne: Lile$n"ut%trea#-89.file8..< GbHect #ystery ? in.rea!GbHect-.< %yste#.out."rintln-#ystery.getClass-..< A A ///3>
743
This %rogra# o%ens the "ile and reads in the ob0ect mystery success"ully. (owever, as soon as you try to "ind out anything about the ob0ect9which reAuires the -lass ob0ect "or Alien9the Java Virtual Machine *JVM, cannot "ind Alien!class *unless it ha%%ens to be in the +lass%ath, which it shouldn t be in this e&a#%le,. /ou ll get a -lass/otFo*n'&4ception! *)nce again, all evidence o" alien li"e vanishes be"ore %roo" o" its e&istence can be veri"ied., RFSURF STIJLT+(6PTE5MMTIMMHU I" you e&%ect to do #uch a"ter you ve recovered an ob0ect that has been seriali1ed, you #ust #ake sure that the JVM can "ind the associated ! class "ile either in the local class %ath or so#ewhere on the Internet. RF SURFSTIJLT+(6PTE5MMTIMM3U
Controlling seriali?ation
6s you can see, the de"ault seriali1ation #echanis# is trivial to use. But what i" you have s%ecial needsO Perha%s you have s%ecial security issues and you don t want to seriali1e %ortions o" your ob0ect, or %erha%s it 0ust doesn t #ake sense "or one subob0ect to be seriali1ed i" that %art needs to be created anew when the ob0ect is recovered. RFSURF STIJLT+(6PTE5MMTIMMGU /ou can control the %rocess o" seriali1ation by i#%le#enting the
&4ternali7able inter"ace instead o" the )eriali7able inter"ace. The &4ternali7able inter"ace e&tends the )eriali7able inter"ace and adds two #ethods, (rite&4ternalA B and rea'&4ternalA B, that are
auto#atically called "or your ob0ect during seriali1ation and deseriali1ation so that you can %er"or# your s%ecial o%erations. RFSURF STIJLT+(6PTE5MMTIMMIU The "ollowing e&a#%le shows si#%le i#%le#entations o" the &4ternali7able inter"ace #ethods. Cote that 2lip> and 2lipI are nearly identical e&ce%t "or a subtle di""erence *see i" you can discover it by looking at the code,=
//3 c((3Bli"s.Hava // %i#"le use of E6ternaliUable D a "itfall. i#"ort Hava.io.B< i#"ort Hava.util.B<
744
class Bli"( i#"le#ents E6ternaliUable @ "ublic Bli"(-. @ %yste#.out."rintln-8Bli"( Constructor8.< A "ublic voi! :riteE6ternal-GbHectGut"ut out. thro:s $GE6ce"tion @ %yste#.out."rintln-8Bli"(.:riteE6ternal8.< A "ublic voi! rea!E6ternal-GbHect$n"ut in. thro:s $GE6ce"tion, Class&otLoun!E6ce"tion @ %yste#.out."rintln-8Bli"(.rea!E6ternal8.< A A class Bli" i#"le#ents E6ternaliUable @ Bli" -. @ %yste#.out."rintln-8Bli" Constructor8.< A "ublic voi! :riteE6ternal-GbHectGut"ut out. thro:s $GE6ce"tion @ %yste#.out."rintln-8Bli" .:riteE6ternal8.< A "ublic voi! rea!E6ternal-GbHect$n"ut in. thro:s $GE6ce"tion, Class&otLoun!E6ce"tion @ %yste#.out."rintln-8Bli" .rea!E6ternal8.< A A "ublic class Bli"s @ // Thro: e6ce"tions to console3 "ublic static voi! #ain-%tringNO args. thro:s $GE6ce"tion, Class&otLoun!E6ce"tion @ %yste#.out."rintln-8Constructing obHects38.< Bli"( b( ? ne: Bli"(-.< Bli" b ? ne: Bli" -.< GbHectGut"ut%trea# o ? ne: GbHectGut"ut%trea#ne: LileGut"ut%trea#-8Bli"s.out8..< %yste#.out."rintln-8%aving obHects38.< o.:riteGbHect-b(.<
745
o.:riteGbHect-b .< o.close-.< // &o: get the# back3 GbHect$n"ut%trea# in ? ne: GbHect$n"ut%trea#ne: Lile$n"ut%trea#-8Bli"s.out8..< %yste#.out."rintln-85ecovering b(38.< b( ? -Bli"(.in.rea!GbHect-.< // GGP%4 Thro:s an e6ce"tion3 //4 %yste#.out."rintln-85ecovering b 38.< //4 b ? -Bli" .in.rea!GbHect-.< A A ///3>
The out%ut "or this %rogra# is= RFSURFSTIJLT+(6PTE5MMTIMM2U
Constructing obHects3 Bli"( Constructor Bli" Constructor %aving obHects3 Bli"(.:riteE6ternal Bli" .:riteE6ternal 5ecovering b(3 Bli"( Constructor Bli"(.rea!E6ternal
The reason that the 2lipI ob0ect is not recovered is that trying to do so causes an e&ce%tion. +an you see the di""erence between 2lip> and 2lipIO The constructor "or 2lip> is p*blic, while the constructor "or 2lipI is not, and that causes the e&ce%tion u%on recovery. Try #aking 2lipI s constructor p*blic and re#oving the 55= co##ents to see the correct results. RFSURFSTIJLT+(6PTE5MMTIMK@U
747
:hen b> is recovered, the 2lip> de"ault constructor is called. This is di""erent "ro# recovering a )eriali7able ob0ect, in which the ob0ect is constructed entirely "ro# its stored bits, with no constructor calls. :ith an &4ternali7able ob0ect, all the nor#al de"ault construction behavior occurs *including the initiali1ations at the %oint o" "ield de"inition,, and then rea'&4ternalA B is called. /ou need to be aware o" this9in %articular, the "act that all the de"ault construction always takes %lace9to %roduce the correct behavior in your &4ternali7able ob0ects. RFSURF STIJLT+(6PTE5MMTIMKMU (ere s an e&a#%le that shows what you #ust do to "ully store and retrieve an &4ternali7able ob0ect= RFSURFSTIJLT+(6PTE5MMTIMKKU
//3 c((3Bli").Hava // 5econstructing an e6ternaliUable obHect. i#"ort Hava.io.B< i#"ort Hava.util.B< "ublic class Bli") i#"le#ents E6ternaliUable @ int i< %tring s< // &o initialiUation "ublic Bli")-. @ %yste#.out."rintln-8Bli") Constructor8.< // s, i not initialiUe! A "ublic Bli")-%tring 6, int a. @ %yste#.out."rintln-8Bli")-%tring 6, int a.8.< s ? 6< i ? a< // s D i initialiUe! only in non!efault // constructor. A "ublic %tring to%tring-. @ return s K i< A "ublic voi! :riteE6ternal-GbHectGut"ut out. thro:s $GE6ce"tion @ %yste#.out."rintln-8Bli").:riteE6ternal8.< // ;ou #ust !o this3 out.:riteGbHect-s.< out.:rite$nt-i.< A "ublic voi! rea!E6ternal-GbHect$n"ut in.
748
thro:s $GE6ce"tion, Class&otLoun!E6ce"tion @ %yste#.out."rintln-8Bli").rea!E6ternal8.< // ;ou #ust !o this3 s ? -%tring.in.rea!GbHect-.< i ?in.rea!$nt-.< A "ublic static voi! #ain-%tringNO args. thro:s $GE6ce"tion, Class&otLoun!E6ce"tion @ %yste#.out."rintln-8Constructing obHects38.< Bli") b) ? ne: Bli")-80 %tring 8, I*.< %yste#.out."rintln-b).< GbHectGut"ut%trea# o ? ne: GbHectGut"ut%trea#ne: LileGut"ut%trea#-8Bli").out8..< %yste#.out."rintln-8%aving obHect38.< o.:riteGbHect-b).< o.close-.< // &o: get it back3 GbHect$n"ut%trea# in ? ne: GbHect$n"ut%trea#ne: Lile$n"ut%trea#-8Bli").out8..< %yste#.out."rintln-85ecovering b)38.< b) ? -Bli").in.rea!GbHect-.< %yste#.out."rintln-b).< A A ///3>
The "ields s and i are initiali1ed only in the second constructor, but not in the de"ault constructor. This #eans that i" you don t initiali1e s and i in rea'&4ternalA B, it will be n*ll *since the storage "or the ob0ect gets wi%ed to 1ero in the "irst ste% o" ob0ect creation,. I" you co##ent out the two lines o" code "ollowing the %hrases !/ou #ust do this$ and run the %rogra#, you ll see that when the ob0ect is recovered, s is n*ll and i is 1ero. RFSURFSTIJLT+(6PTE5MMTIMKLU I" you are inheriting "ro# an &4ternali7able ob0ect, you ll ty%ically call the base'class versions o" (rite&4ternalA B and rea'&4ternalA B to %rovide %ro%er storage and retrieval o" the base'class co#%onents. RF SURFSTIJLT+(6PTE5MMTIMK?U
74:
So to #ake things work correctly you #ust not only write the i#%ortant data "ro# the ob0ect during the (rite&4ternalA B #ethod *there is no de"ault behavior that writes any o" the #e#ber ob0ects "or an &4ternali7able ob0ect,, but you #ust also recover that data in the rea'&4ternalA B #ethod. This can be a bit con"using at "irst because the de"ault construction behavior "or an &4ternali7able ob0ect can #ake it see# like so#e kind o" storage and retrieval takes %lace auto#atically. It does not. RFSURFSTIJLT+(6PTE5MMTIMKHU
74;
i#"ort Hava.io.B< i#"ort Hava.util.B< "ublic class Logon i#"le#ents %erialiUable @ "rivate Date !ate ? ne: Date-.< "rivate %tring userna#e< "rivate transient %tring "ass:or!< Logon-%tring na#e, %tring ":!. @ userna#e ? na#e< "ass:or! ? ":!< A "ublic %tring to%tring-. @ %tring ":! ? -"ass:or! ?? null. [ 8-n/a.8 3 "ass:or!< return 8logon info3 _n 8 K 8userna#e3 8 K userna#e K 8_n !ate3 8 K !ate K 8_n "ass:or!3 8 K ":!< A "ublic static voi! #ain-%tringNO args. thro:s $GE6ce"tion, Class&otLoun!E6ce"tion @ Logon a ? ne: Logon-8Mulk8, 8#yLittlePony8.< %yste#.out."rintln- 8logon a ? 8 K a.< GbHectGut"ut%trea# o ? ne: GbHectGut"ut%trea#ne: LileGut"ut%trea#-8Logon.out8..< o.:riteGbHect-a.< o.close-.< // Delay3 int secon!s ? ,< long t ? %yste#.currentTi#eJillis-. K secon!s B ('''< :hile-%yste#.currentTi#eJillis-. P t. < // &o: get the# back3 GbHect$n"ut%trea# in ? ne: GbHect$n"ut%trea#ne: Lile$n"ut%trea#-8Logon.out8..< %yste#.out."rintln85ecovering obHect at 8 K ne: Date-..< a ? -Logon.in.rea!GbHect-.<
75=
logon a ? logon info3 userna#e3 Mulk !ate3 %un Jar ) (13 ,3,) P%T (CC* "ass:or!3 #yLittlePony 5ecovering obHect at %un Jar ) (13 ,3,C P%T (CC* logon a ? logon info3 userna#e3 Mulk !ate3 %un Jar ) (13 ,3,) P%T (CC* "ass:or!3 -n/a.
:hen the ob0ect is recovered, the pass(or' "ield is n*ll. Cote that to)tringA B #ust check "or a n*ll value o" pass(or' because i" you try to asse#ble a )tring ob0ect using the overloaded [L o%erator, and that o%erator encounters a n*ll re"erence, you ll get a /*ll#ointer&4ception! *Cewer versions o" Java #ight contain code to avoid this %roble#., RFSURFSTIJLT+(6PTE5MMTIML@U /ou can also see that the 'ate "ield is stored to and recovered "ro# disk and not generated anew. RFSURFSTIJLT+(6PTE5MMTIMLMU Since &4ternali7able ob0ects do not store any o" their "ields by de"ault, the transient keyword is "or use with )eriali7able ob0ects only. RF SURFSTIJLT+(6PTE5MMTIMLKU
An alternative to E-ternali0able
I" you re not keen on i#%le#enting the &4ternali7able inter"ace, there s another a%%roach. /ou can i#%le#ent the )eriali7able inter"ace and add *notice I say !add$ and not !override$ or !i#%le#ent$, #ethods called (rite.b8ectA B and rea'.b8ectA B that will auto#atically be called when the ob0ect is seriali1ed and deseriali1ed, res%ectively. That is,
751
i" you %rovide these two #ethods they will be used instead o" the de"ault seriali1ation. RFSURFSTIJLT+(6PTE5MMTIMLLU The #ethods #ust have these e&act signatures=
"rivate voi! :riteGbHect-GbHectGut"ut%trea# strea#. thro:s $GE6ce"tion< "rivate voi! rea!GbHect-GbHect$n"ut%trea# strea#. thro:s $GE6ce"tion, Class&otLoun!E6ce"tion
Ero# a design stand%oint, things get really weird here. Eirst o" all, you #ight think that because these #ethods are not %art o" a base class or the )eriali7able inter"ace, they ought to be de"ined in their own inter"ace*s,. But notice that they are de"ined as private, which #eans they are to be called only by other #e#bers o" this class. (owever, you don t actually call the# "ro# other #e#bers o" this class, but instead the (rite.b8ect A B and rea'.b8ectA B #ethods o" the .b8ect.*tp*t)tream and .b8ectInp*t)tream ob0ects call your ob0ect s (rite.b8ectA B and rea'.b8ectA B #ethods. *Cotice #y tre#endous restraint in not launching into a long diatribe about using the sa#e #ethod na#es here. In a word= con"using., /ou #ight wonder how the .b8ect.*tp*t)tream and .b8ectInp*t)tream ob0ects have access to private #ethods o" your class. :e can only assu#e that this is %art o" the seriali1ation #agic. RFSURFSTIJLT+(6PTE5MMTIML?U In any event, anything de"ined in an interface is auto#atically p*blic so i" (rite.b8ectA B and rea'.b8ectA B #ust be private, then they can t be %art o" an interface. Since you #ust "ollow the signatures e&actly, the e""ect is the sa#e as i" you re i#%le#enting an interface. RFSURF STIJLT+(6PTE5MMTIMLHU It would a%%ear that when you call .b8ect.*tp*t)tream!(rite.b8ect A B, the )eriali7able ob0ect that you %ass it to is interrogated *using re"lection, no doubt, to see i" it i#%le#ents its own (rite.b8ectA B. I" so, the nor#al seriali1ation %rocess is ski%%ed and the (rite.b8ectA B is called. The sa#e sort o" situation e&ists "or rea'.b8ectA B. RFSURF STIJLT+(6PTE5MMTIML3U
752
There s one other twist. Inside your (rite.b8ectA B, you can choose to %er"or# the de"ault (rite.b8ectA B action by calling 'efa*lt0rite.b8ectA B. Dikewise, inside rea'.b8ectA B you can call 'efa*lt$ea'.b8ectA B. (ere is a si#%le e&a#%le that de#onstrates how you can control the storage and retrieval o" a )eriali7able ob0ect=
//3 c((3%erialCtl.Hava // Controlling serialiUation by a!!ing your o:n // :riteGbHect-. an! rea!GbHect-. #etho!s. i#"ort Hava.io.B< "ublic class %erialCtl i#"le#ents %erialiUable @ %tring a< transient %tring b< "ublic %erialCtl-%tring aa, %tring bb. @ a ? 8&ot Transient3 8 K aa< b ? 8Transient3 8 K bb< A "ublic %tring to%tring-. @ return a K 8_n8 K b< A "rivate voi! :riteGbHect-GbHectGut"ut%trea# strea#. thro:s $GE6ce"tion @ strea#.!efault\riteGbHect-.< strea#.:riteGbHect-b.< A "rivate voi! rea!GbHect-GbHect$n"ut%trea# strea#. thro:s $GE6ce"tion, Class&otLoun!E6ce"tion @ strea#.!efault5ea!GbHect-.< b ? -%tring.strea#.rea!GbHect-.< A "ublic static voi! #ain-%tringNO args. thro:s $GE6ce"tion, Class&otLoun!E6ce"tion @ %erialCtl sc ? ne: %erialCtl-8Test(8, 8Test 8.< %yste#.out."rintln-8Before3_n8 K sc.< Byte0rrayGut"ut%trea# buf ? ne: Byte0rrayGut"ut%trea#-.< GbHectGut"ut%trea# o ?
753
ne: GbHectGut"ut%trea#-buf.< o.:riteGbHect-sc.< // &o: get it back3 GbHect$n"ut%trea# in ? ne: GbHect$n"ut%trea#ne: Byte0rray$n"ut%trea#buf.toByte0rray-...< %erialCtl sc ? -%erialCtl.in.rea!GbHect-.< %yste#.out."rintln-80fter3_n8 K sc .< A A ///3>
In this e&a#%le, one )tring "ield is ordinary and the other is transient, to %rove that the non' transient "ield is saved by the 'efa*lt0rite.b8ectA B #ethod and the transient "ield is saved and restored e&%licitly. The "ields are initiali1ed inside the constructor rather than at the %oint o" de"inition to %rove that they are not being initiali1ed by so#e auto#atic #echanis# during deseriali1ation. RFSURF STIJLT+(6PTE5MMTIMLGU I" you are going to use the de"ault #echanis# to write the non' transient %arts o" your ob0ect, you #ust call 'efa*lt0rite.b8ectA B as the "irst o%eration in (rite.b8ectA B and 'efa*lt$ea'.b8ectA B as the "irst o%eration in rea'.b8ectA B. These are strange #ethod calls. It would a%%ear, "or e&a#%le, that you are calling 'efa*lt0rite.b8ectA B "or an .b8ect.*tp*t)tream and %assing it no argu#ents, and yet it so#ehow turns around and knows the re"erence to your ob0ect and how to write all the non' transient %arts. S%ooky. RFSURFSTIJLT+(6PTE5MMTIMLIU The storage and retrieval o" the transient ob0ects uses #ore "a#iliar code. 6nd yet, think about what ha%%ens here. In mainA B, a )erial-tl ob0ect is created, and then it s seriali1ed to an .b8ect.*tp*t)tream! *Cotice in this case that a bu""er is used instead o" a "ile9it s all the sa#e to the .b8ect.*tp*t)tream., The seriali1ation occurs in the line=
o.:riteGbHect-sc.<
The (rite.b8ectA B #ethod #ust be e&a#ining sc to see i" it has its own (rite.b8ectA B #ethod. *Cot by checking the inter"ace9there isn t one9 or the class ty%e, but by actually hunting "or the #ethod using re"lection., I" it does, it uses that. 6 si#ilar a%%roach holds true "or rea'.b8ectA B.
754
Perha%s this was the only %ractical way that they could solve the %roble#, but it s certainly strange. RFSURFSTIJLT+(6PTE5MMTIML2U
=ersioning
It s %ossible that you #ight want to change the version o" a seriali1able class *ob0ects o" the original class #ight be stored in a database, "or e&a#%le,. This is su%%orted but you ll %robably do it only in s%ecial cases, and it reAuires an e&tra de%th o" understanding that we will not atte#%t to achieve here. The J7> (TMD docu#ents downloadable "ro# >ava' sun'com cover this to%ic Auite thoroughly. RFSURF STIJLT+(6PTE5MMTIM?@U /ou will also notice in the J7> (TMD docu#entation #any co##ents that begin with=
,arning. Seriali?ed ob>ects o$ this class ,ill not be com atible ,ith $uture S,ing releases' The current seriali?ation su ort is a ro riate $or short term storage or -MI bet,een a lications' M
This is because the versioning #echanis# is too si#%le to work reliably in all situations, es%ecially with JavaBeans. They re working on a correction "or the design, and that s what the warning is about. RFSURF STIJLT+(6PTE5MMTIM?MU
Csing .ersistence
It s Auite a%%ealing to use seriali1ation technology to store so#e o" the state o" your %rogra# so that you can easily restore the %rogra# to the current state later. But be"ore you can do this, so#e Auestions #ust be answered. :hat ha%%ens i" you seriali1e two ob0ects that both have a re"erence to a third ob0ectO :hen you restore those two ob0ects "ro# their seriali1ed state, do you get only one occurrence o" the third ob0ectO :hat i" you seriali1e your two ob0ects to se%arate "iles and deseriali1e the# in di""erent %arts o" your codeO RFSURFSTIJLT+(6PTE5MMTIM?KU (ere s an e&a#%le that shows the %roble#=
755
class Mouse i#"le#ents %erialiUable @A class 0ni#al i#"le#ents %erialiUable @ %tring na#e< Mouse "referre!Mouse< 0ni#al-%tring n#, Mouse h. @ na#e ? n#< "referre!Mouse ? h< A "ublic %tring to%tring-. @ return na#e K 8N8 K su"er.to%tring-. K 8O, 8 K "referre!Mouse K 8_n8< A A "ublic class Jy\orl! @ "ublic static voi! #ain-%tringNO args. thro:s $GE6ce"tion, Class&otLoun!E6ce"tion @ Mouse house ? ne: Mouse-.< 0rrayList ani#als ? ne: 0rrayList-.< ani#als.a!!ne: 0ni#al-8Bosco the !og8, house..< ani#als.a!!ne: 0ni#al-85al"h the ha#ster8, house..< ani#als.a!!ne: 0ni#al-8Lronk the cat8, house..< %yste#.out."rintln-8ani#als3 8 K ani#als.< Byte0rrayGut"ut%trea# buf( ? ne: Byte0rrayGut"ut%trea#-.< GbHectGut"ut%trea# o( ? ne: GbHectGut"ut%trea#-buf(.< o(.:riteGbHect-ani#als.< o(.:riteGbHect-ani#als.< // \rite a // \rite to a !ifferent strea#3 Byte0rrayGut"ut%trea# buf ? ne: Byte0rrayGut"ut%trea#-.< GbHectGut"ut%trea# o ? ne: GbHectGut"ut%trea#-buf .< o .:riteGbHect-ani#als.<
n! set
757
// &o: get the# back3 GbHect$n"ut%trea# in( ? ne: GbHect$n"ut%trea#ne: Byte0rray$n"ut%trea#buf(.toByte0rray-...< GbHect$n"ut%trea# in ? ne: GbHect$n"ut%trea#ne: Byte0rray$n"ut%trea#buf .toByte0rray-...< 0rrayList ani#als( ? -0rrayList.in(.rea!GbHect-.< 0rrayList ani#als ? -0rrayList.in(.rea!GbHect-.< 0rrayList ani#als) ? -0rrayList.in .rea!GbHect-.< %yste#.out."rintln-8ani#als(3 8 K ani#als(.< %yste#.out."rintln-8ani#als 3 8 K ani#als .< %yste#.out."rintln-8ani#als)3 8 K ani#als).< A A ///3>
)ne thing that s interesting here is that it s %ossible to use ob0ect seriali1ation to and "ro# a byte array as a way o" doing a !dee% co%y$ o" any ob0ect that s )eriali7able! *6 dee% co%y #eans that you re du%licating the entire web o" ob0ects, rather than 0ust the basic ob0ect and its re"erences., +o%ying is covered in de%th in 6%%endi& 6. RFSURF STIJLT+(6PTE5MMTIM?LU
Animal ob0ects contain "ields o" ty%e Ho*se. In mainA B, an Array+ist o" these Animals is created and it is seriali1ed twice to one strea# and then again to a se%arate strea#. :hen these are deseriali1ed and %rinted, you see the "ollowing results "or one run *the ob0ects will be in di""erent #e#ory locations each run,= ani#als3 NBosco the !ogN0ni#alR(cc*+cO, MouseR(cc*+C , 5al"h the ha#sterN0ni#alR(cc*+!O, MouseR(cc*+C , Lronk the catN0ni#alR(cc*+eO, MouseR(cc*+C O ani#als(3 NBosco the !ogN0ni#alR(cca'cO, MouseR(cca(+ , 5al"h the ha#sterN0ni#alR(cca(*O, MouseR(cca(+ , Lronk the catN0ni#alR(cca(bO, MouseR(cca(+
758
O ani#als 3 NBosco the !ogN0ni#alR(cca'cO, MouseR(cca(+ , 5al"h the ha#sterN0ni#alR(cca(*O, MouseR(cca(+ , Lronk the catN0ni#alR(cca(bO, MouseR(cca(+ O ani#als)3 NBosco the !ogN0ni#alR(cca, O, MouseR(cca,c , 5al"h the ha#sterN0ni#alR(cca,!O, MouseR(cca,c , Lronk the catN0ni#alR(cca+(O, MouseR(cca,c O
)" course you e&%ect that the deseriali1ed ob0ects have di""erent addresses "ro# their originals. But notice that in animals> and animalsI the sa#e addresses a%%ear, including the re"erences to the Ho*se ob0ect that both share. )n the other hand, when animalsJ is recovered the syste# has no way o" knowing that the ob0ects in this other strea# are aliases o" the ob0ects in the "irst strea#, so it #akes a co#%letely di""erent web o" ob0ects. RFSURFSTIJLT+(6PTE5MMTIM??U 6s long as you re seriali1ing everything to a single strea#, you ll be able to recover the sa#e web o" ob0ects that you wrote, with no accidental du%lication o" ob0ects. )" course, you can change the state o" your ob0ects in between the ti#e you write the "irst and the last, but that s your res%onsibility9the ob0ects will be written in whatever state they are in *and with whatever connections they have to other ob0ects, at the ti#e you seriali1e the#. RFSURFSTIJLT+(6PTE5MMTIM?HU The sa"est thing to do i" you want to save the state o" a syste# is to seriali1e as an !ato#ic$ o%eration. I" you seriali1e so#e things, do so#e other work, and seriali1e so#e #ore, etc., then you will not be storing the syste# sa"ely. Instead, %ut all the ob0ects that co#%rise the state o" your syste# in a single container and si#%ly write that container out in one o%eration. Then you can restore it with a single #ethod call as well. RF SURFSTIJLT+(6PTE5MMTIM?3U The "ollowing e&a#%le is an i#aginary co#%uter'aided design *+67, syste# that de#onstrates the a%%roach. In addition, it throws in the issue o" static "ields9i" you look at the docu#entation you ll see that -lass is )eriali7able, so it should be easy to store the static "ields by si#%ly seriali1ing the -lass ob0ect. That see#s like a sensible a%%roach, anyway.
//3 c((3C0D%tate.Hava
75:
// %aving an! restoring the state of a // "reten! C0D syste#. i#"ort Hava.io.B< i#"ort Hava.util.B< abstract class %ha"e i#"le#ents %erialiUable @ "ublic static final int 5ED ? (, BLYE ? , a5EE& ? )< "rivate int 6Pos, yPos, !i#ension< "rivate static 5an!o# r ? ne: 5an!o#-.< "rivate static int counter ? '< abstract "ublic voi! setColor-int ne:Color.< abstract "ublic int getColor-.< "ublic %ha"e-int 6Wal, int yWal, int !i#. @ 6Pos ? 6Wal< yPos ? yWal< !i#ension ? !i#< A "ublic %tring to%tring-. @ return getClass-. K 8 colorN8 K getColor-. K 8O 6PosN8 K 6Pos K 8O yPosN8 K yPos K 8O !i#N8 K !i#ension K 8O_n8< A "ublic static %ha"e ran!o#Lactory-. @ int 6Wal ? r.ne6t$nt-. V (''< int yWal ? r.ne6t$nt-. V (''< int !i# ? r.ne6t$nt-. V (''< s:itch-counterKK V ). @ !efault3 case '3 return ne: Circle-6Wal, yWal, !i#.< case (3 return ne: %=uare-6Wal, yWal, !i#.< case 3 return ne: Line-6Wal, yWal, !i#.< A A A class Circle e6ten!s %ha"e @ "rivate static int color ? 5ED< "ublic Circle-int 6Wal, int yWal, int !i#. @
75;
su"er-6Wal, yWal, !i#.< A "ublic voi! setColor-int ne:Color. @ color ? ne:Color< A "ublic int getColor-. @ return color< A A class %=uare e6ten!s %ha"e @ "rivate static int color< "ublic %=uare-int 6Wal, int yWal, int !i#. @ su"er-6Wal, yWal, !i#.< color ? 5ED< A "ublic voi! setColor-int ne:Color. @ color ? ne:Color< A "ublic int getColor-. @ return color< A A class Line e6ten!s %ha"e @ "rivate static int color ? 5ED< "ublic static voi! serialiUe%tatic%tate-GbHectGut"ut%trea# os. thro:s $GE6ce"tion @ os.:rite$nt-color.< A "ublic static voi! !eserialiUe%tatic%tate-GbHect$n"ut%trea# os. thro:s $GE6ce"tion @ color ? os.rea!$nt-.< A "ublic Line-int 6Wal, int yWal, int !i#. @ su"er-6Wal, yWal, !i#.< A "ublic voi! setColor-int ne:Color. @ color ? ne:Color<
77=
A "ublic int getColor-. @ return color< A A "ublic class C0D%tate @ "ublic static voi! #ain-%tringNO args. thro:s E6ce"tion @ 0rrayList sha"eTy"es, sha"es< if-args.length ?? '. @ sha"eTy"es ? ne: 0rrayList-.< sha"es ? ne: 0rrayList-.< // 0!! references to the class obHects3 sha"eTy"es.a!!-Circle.class.< sha"eTy"es.a!!-%=uare.class.< sha"eTy"es.a!!-Line.class.< // Jake so#e sha"es3 for-int i ? '< i P ('< iKK. sha"es.a!!-%ha"e.ran!o#Lactory-..< // %et all the static colors to a5EE&3 for-int i ? '< i P ('< iKK. --%ha"e.sha"es.get-i.. .setColor-%ha"e.a5EE&.< // %ave the state vector3 GbHectGut"ut%trea# out ? ne: GbHectGut"ut%trea#ne: LileGut"ut%trea#-8C0D%tate.out8..< out.:riteGbHect-sha"eTy"es.< Line.serialiUe%tatic%tate-out.< out.:riteGbHect-sha"es.< A else @ // There2s a co##an!-line argu#ent GbHect$n"ut%trea# in ? ne: GbHect$n"ut%trea#ne: Lile$n"ut%trea#-argsN'O..< // 5ea! in the sa#e or!er they :ere :ritten3 sha"eTy"es ? -0rrayList.in.rea!GbHect-.< Line.!eserialiUe%tatic%tate-in.< sha"es ? -0rrayList.in.rea!GbHect-.< A // Dis"lay the sha"es3
771
%yste#.out."rintln-sha"es.< A A ///3>
The )hape class implements )eriali7able, so anything that is inherited "ro# )hape is auto#atically )eriali7able as well. Each )hape contains data, and each derived )hape class contains a static "ield that deter#ines the color o" all o" those ty%es o" )hapes. *Placing a static "ield in the base class would result in only one "ield, since static "ields are not du%licated in derived classes., Methods in the base class can be overridden to set the color "or the various ty%es * static #ethods are not dyna#ically bound, so these are nor#al #ethods,. The ran'omFactoryA B #ethod creates a di""erent )hape each ti#e you call it, using rando# values "or the )hape data. RFSURF STIJLT+(6PTE5MMTIM?GU
-ircle and )C*are are straight"orward e&tensions o" )hape; the only di""erence is that -ircle initiali1es color at the %oint o" de"inition and )C*are initiali1es it in the constructor. :e ll leave the discussion o" +ine "or later. RFSURFSTIJLT+(6PTE5MMTIM?IU
In mainA B, one Array+ist is used to hold the -lass ob0ects and the other to hold the sha%es. I" you don t %rovide a co##and line argu#ent the shapeTypes Array+ist is created and the -lass ob0ects are added, and then the shapes Array+ist is created and )hape ob0ects are added. Ce&t, all the static color values are set to "$&&/, and everything is seriali1ed to the "ile -A )tate!o*t. RFSURFSTIJLT+(6PTE5MMTIM?2U I" you %rovide a co##and line argu#ent *%resu#ably -A )tate!o*t,, that "ile is o%ened and used to restore the state o" the %rogra#. In both situations, the resulting Array+ist o" )hapes is %rinted. The results "ro# one run are=
QHava C0D%tate Nclass Circle colorN)O 6PosN-,(O yPosN-CCO !i#N)1O , class %=uare colorN)O 6PosN O yPosN+(O !i#N-I+O , class Line colorN)O 6PosN,(O yPosN*)O !i#N+IO , class Circle colorN)O 6PosN-*'O yPosN(O !i#N(+O , class %=uare colorN)O 6PosN)O yPosNCIO !i#N-)+O , class Line colorN)O 6PosN-1IO yPosN- (O !i#N-),O , class Circle colorN)O 6PosN-*,O yPosN-I)O !i#N O
772
, class %=uare colorN)O 6PosN1(O yPosN)'O !i#N-I,O , class Line colorN)O 6PosN- CO yPosNC O !i#N(*O , class Circle colorN)O 6PosN(*O yPosNC'O !i#N-*+O O QHava C0D%tate C0D%tate.out Nclass Circle colorN(O 6PosN-,(O yPosN-CCO !i#N)1O , class %=uare colorN'O 6PosN O yPosN+(O !i#N-I+O , class Line colorN)O 6PosN,(O yPosN*)O !i#N+IO , class Circle colorN(O 6PosN-*'O yPosN(O !i#N(+O , class %=uare colorN'O 6PosN)O yPosNCIO !i#N-)+O , class Line colorN)O 6PosN-1IO yPosN- (O !i#N-),O , class Circle colorN(O 6PosN-*,O yPosN-I)O !i#N O , class %=uare colorN'O 6PosN1(O yPosN)'O !i#N-I,O , class Line colorN)O 6PosN- CO yPosNC O !i#N(*O , class Circle colorN(O 6PosN(*O yPosNC'O !i#N-*+O O
/ou can see that the values o" 4#os, y#os, and 'im were all stored and recovered success"ully, but there s so#ething wrong with the retrieval o" the static in"or#ation. It s all !L$ going in, but it doesn t co#e out that way. -ircles have a value o" M * $& , which is the de"inition,, and )C*ares have a value o" @ *re#e#ber, they are initiali1ed in the constructor,. It s as i" the statics didn t get seriali1ed at all. That s right9 even though class -lass is )eriali7able, it doesn t do what you e&%ect. So i" you want to seriali1e statics, you #ust do it yoursel". RFSURF STIJLT+(6PTE5MMTIMH@U This is what the seriali7e)tatic)tateA B and 'eseriali7e)tatic)tate A B static #ethods in +ine are "or. /ou can see that they are e&%licitly called as %art o" the storage and retrieval %rocess. *Cote that the order o" writing to the seriali1e "ile and reading back "ro# it #ust be #aintained., Thus to #ake -A )tate!8ava run correctly you #ust= RFSURF STIJLT+(6PTE5MMTIMHMU
((7) 5e#ove the Array+ist shapeTypes and all code related to it.
773
((() 6dd calls to the new seriali1e and deseriali1e static #ethods in the
sha%es. RFSURFSTIJLT+(6PTE5MMTIMHKU 6nother issue you #ight have to think about is security, since seriali1ation also saves private data. I" you have a security issue, those "ields should be #arked as transient. But then you have to design a secure way to store that in"or#ation so that when you do a restore you can reset those private variables. RFSURFSTIJLT+(6PTE5MMTIMHLU
#okeni?ing in.ut
Tokeni?ing is the %rocess o" breaking a seAuence o" characters into a seAuence o" !tokens,$ which are bits o" te&t deli#ited by whatever you choose. Eor e&a#%le, your tokens could be words, and then they would be deli#ited by white s%ace and %unctuation. There are two classes %rovided in the standard Java library that can be used "or tokeni1ation= )treamTokeni7er and )tringTokeni7er. RFSURF STIJLT+(6PTE5MMTIMH?U
Stream&okeni0er
6lthough )treamTokeni7er is not derived "ro# Inp*t)tream or .*tp*t)tream, it works only with Inp*t)tream ob0ects, so it right"ully belongs in the IF) %ortion o" the library. RFSURF STIJLT+(6PTE5MMTIMHHU +onsider a %rogra# to count the occurrence o" words in a te&t "ile=
//3 c((3\or!Count.Hava // Counts :or!s fro# a file, out"uts // results in sorte! for#. i#"ort Hava.io.B< i#"ort Hava.util.B< class Counter @ "rivate int i ? (< int rea!-. @ return i< A voi! incre#ent-. @ iKK< A A
774
"ublic class \or!Count @ "rivate Lile5ea!er file< "rivate %trea#TokeniUer st< // 0 TreeJa" kee"s keys in sorte! or!er3 "rivate TreeJa" counts ? ne: TreeJa"-.< \or!Count-%tring filena#e. thro:s Lile&otLoun!E6ce"tion @ try @ file ? ne: Lile5ea!er-filena#e.< st ? ne: %trea#TokeniUerne: Buffere!5ea!er-file..< st.or!inaryChar-2.2.< st.or!inaryChar-2-2.< A catch-Lile&otLoun!E6ce"tion e. @ %yste#.err."rintln8Coul! not o"en 8 K filena#e.< thro: e< A A voi! cleanu"-. @ try @ file.close-.< A catch-$GE6ce"tion e. @ %yste#.err."rintln8file.close-. unsuccessful8.< A A voi! count\or!s-. @ try @ :hile-st.ne6tToken-. 4? %trea#TokeniUer.TTbEGL. @ %tring s< s:itch-st.tty"e. @ case %trea#TokeniUer.TTbEGL3 s ? ne: %tring-8EGL8.< break< case %trea#TokeniUer.TTb&YJBE53 s ? Double.to%tring-st.nval.< break< case %trea#TokeniUer.TTb\G5D3
775
s ? st.sval< // 0lrea!y a %tring break< !efault3 // single character in tty"e s ? %tring.valueGf--char.st.tty"e.< A if-counts.contains`ey-s.. --Counter.counts.get-s...incre#ent-.< else counts."ut-s, ne: Counter-..< A A catch-$GE6ce"tion e. @ %yste#.err."rintln8st.ne6tToken-. unsuccessful8.< A A Collection values-. @ return counts.values-.< A %et key%et-. @ return counts.key%et-.< A Counter getCounter-%tring s. @ return -Counter.counts.get-s.< A "ublic static voi! #ain-%tringNO args. thro:s Lile&otLoun!E6ce"tion @ \or!Count :c ? ne: \or!Count-argsN'O.< :c.count\or!s-.< $terator keys ? :c.key%et-..iterator-.< :hile-keys.has&e6t-.. @ %tring key ? -%tring.keys.ne6t-.< %yste#.out."rintln-key K 83 8 K :c.getCounter-key..rea!-..< A :c.cleanu"-.< A A ///3>
Presenting the words in sorted "or# is easy to do by storing the data in a Tree1ap, which auto#atically organi1es its keys in sorted order *see +ha%ter 2,. :hen you get a set o" keys using key)etA B, they will also be in sorted order. RFSURFSTIJLT+(6PTE5MMTIMH3U
777
To o%en the "ile, a File$ea'er is used, and to turn the "ile into words a )treamTokeni7er is created "ro# the File$ea'er wra%%ed in a 2*ffere'$ea'er. In )treamTokeni7er, there is a de"ault list o" se%arators, and you can add #ore with a set o" #ethods. (ere, or'inary-harA B is used to say !This character has no signi"icance that I # interested in,$ so the %arser doesn t include it as %art o" any o" the words that it creates. Eor e&a#%le, saying st!or'inary-harAc!cB #eans that %eriods will not be included as %arts o" the words that are %arsed. /ou can "ind #ore in"or#ation in the J7> (TMD docu#entation "ro# >ava'sun'com. RFSURFSTIJLT+(6PTE5MMTIMHGU In co*nt0or'sA B, the tokens are %ulled one at a ti#e "ro# the strea#, and the ttype in"or#ation is used to deter#ine what to do with each token, since a token can be an end'o"'line, a nu#ber, a string, or a single character. RFSURFSTIJLT+(6PTE5MMTIMHIU )nce a token is "ound, the Tree1ap co*nts is Aueried to see i" it already contains the token as a key. I" it does, the corres%onding -o*nter ob0ect is incre#ented to indicate that another instance o" this word has been "ound. I" not, a new -o*nter is created9since the -o*nter constructor initiali1es its value to one, this also acts to count the word. RFSURF STIJLT+(6PTE5MMTIMH2U
0or'-o*nt is not a ty%e o" Tree1ap, so it wasn t inherited. It %er"or#s a s%eci"ic ty%e o" "unctionality, so even though the keysA B and val*esA B #ethods #ust be ree&%osed, that still doesn t #ean that inheritance should be used since a nu#ber o" Tree1ap #ethods are ina%%ro%riate here. In addition, other #ethods like get-o*nterA B, which get the -o*nter "or a %articular )tring, and sorte'%eysA B, which %roduces an Iterator, "inish the change in the sha%e o" 0or'-o*nt s inter"ace. RFSURFSTIJLT+(6PTE5MMTIM3@U
In mainA B you can see the use o" a 0or'-o*nt to o%en and count the words in a "ile9it 0ust takes two lines o" code. Then an Iterator to a sorted list o" keys *words, is e&tracted, and this is used to %ull out each key and associated -o*nt. The call to clean*pA B is necessary to ensure that the "ile is closed. RFSURFSTIJLT+(6PTE5MMTIM3MU
778
String&okeni0er
6lthough it isn t %art o" the IF) library, the )tringTokeni7er has su""iciently si#ilar "unctionality to )treamTokeni7er that it will be described here. RFSURFSTIJLT+(6PTE5MMTIM3KU The )tringTokeni7er returns the tokens within a string one at a ti#e. These tokens are consecutive characters deli#ited by tabs, s%aces, and newlines. Thus, the tokens o" the string !:here is #y catO$ are !:here$, !is$, !#y$, and !catO$ Dike the )treamTokeni7er, you can tell the )tringTokeni7er to break u% the in%ut in any way that you want, but with )tringTokeni7er you do this by %assing a second argu#ent to the constructor, which is a )tring o" the deli#iters you wish to use. In general, i" you need #ore so%histication, use a )treamTokeni7er. RF SURFSTIJLT+(6PTE5MMTIM3LU /ou ask a )tringTokeni7er ob0ect "or the ne&t token in the string using the ne4tTokenA B #ethod, which either returns the token or an e#%ty string to indicate that no tokens re#ain. RFSURF STIJLT+(6PTE5MMTIM3?U 6s an e&a#%le, the "ollowing %rogra# %er"or#s a li#ited analysis o" a sentence, looking "or key %hrase seAuences to indicate whether ha%%iness or sadness is i#%lied.
//3 c((30nalyUe%entence.Hava // Look for "articular se=uences in sentences. i#"ort Hava.util.B< "ublic class 0nalyUe%entence @ "ublic static voi! #ain-%tringNO args. @ analyUe-8$ a# ha""y about this8.< analyUe-8$ a# not ha""y about this8.< analyUe-8$ a# not4 $ a# ha""y8.< analyUe-8$ a# sa! about this8.< analyUe-8$ a# not sa! about this8.< analyUe-8$ a# not4 $ a# sa!8.< analyUe-80re you ha""y about this[8.< analyUe-80re you sa! about this[8.< analyUe-8$t2s you4 $ a# ha""y8.< analyUe-8$t2s you4 $ a# sa!8.<
77:
A static %tringTokeniUer st< static voi! analyUe-%tring s. @ "rt-8_nne: sentence QQ 8 K s.< boolean sa! ? false< st ? ne: %tringTokeniUer-s.< :hile -st.hasJoreTokens-.. @ %tring token ? ne6t-.< // Look until you fin! one of the // t:o starting tokens3 if-4token.e=uals-8$8. DD 4token.e=uals-80re8.. continue< // To" of :hile loo" if-token.e=uals-8$8.. @ %tring tk ? ne6t-.< if-4tk .e=uals-8a#8.. // Just be after $ break< // Gut of :hile loo" else @ %tring tk) ? ne6t-.< if-tk).e=uals-8sa!8.. @ sa! ? true< break< // Gut of :hile loo" A if -tk).e=uals-8not8.. @ %tring tkI ? ne6t-.< if-tkI.e=uals-8sa!8.. break< // Leave sa! false if-tkI.e=uals-8ha""y8.. @ sa! ? true< break< A A A A if-token.e=uals-80re8.. @ %tring tk ? ne6t-.< if-4tk .e=uals-8you8.. break< // Just be after 0re %tring tk) ? ne6t-.< if-tk).e=uals-8sa!8.. sa! ? true<
77;
break< // Gut of :hile loo" A A if-sa!. "rt-8%a! !etecte!8.< A static %tring ne6t-. @ if-st.hasJoreTokens-.. @ %tring s ? st.ne6tToken-.< "rt-s.< return s< A else return 88< A static voi! "rt-%tring s. @ %yste#.out."rintln-s.< A A ///3>
Eor each string being analy1ed, a (hile loo% is entered and tokens are %ulled o"" the string. Cotice the "irst if state#ent, which says to contin*e *go back to the beginning o" the loo% and start again, i" the token is neither an !I$ nor an !6re.$ This #eans that it will get tokens until an !I$ or an !6re$ is "ound. /ou #ight think to use the PP instead o" the eC*als A B #ethod, but that won t work correctly, since PP co#%ares re"erence values while eC*alsA B co#%ares contents. RFSURF STIJLT+(6PTE5MMTIM3HU The logic o" the rest o" the analy7eA B #ethod is that the %attern that s being searched "or is !I a# sad,$ !I a# not ha%%y,$ or !6re you sadO$ :ithout the break state#ent, the code "or this would be even #essier than it is. /ou should be aware that a ty%ical %arser *this is a %ri#itive e&a#%le o" one, nor#ally has a table o" these tokens and a %iece o" code that #oves through the states in the table as new tokens are read. RFSURF STIJLT+(6PTE5MMTIM33U /ou should think o" the )tringTokeni7er only as shorthand "or a si#%le and s%eci"ic kind o" )treamTokeni7er. (owever, i" you have a )tring that you want to tokeni1e and )tringTokeni7er is too li#ited, all you have to do is turn it into a strea# with )tring2*fferInp*t)tream and
78=
//3 c((3Class%canner.Hava // %cans all files in !irectory for classes // an! i!entifiers, to check ca"italiUation. // 0ssu#es "ro"erly co#"iling co!e listings. // Doesn2t !o everything right, but is a // useful ai!. i#"ort Hava.io.B<
781
i#"ort Hava.util.B< class Julti%tringJa" e6ten!s MashJa" @ "ublic voi! a!!-%tring key, %tring value. @ if-4contains`ey-key.. "ut-key, ne: 0rrayList-..< --0rrayList.get-key...a!!-value.< A "ublic 0rrayList get0rrayList-%tring key. @ if-4contains`ey-key.. @ %yste#.err."rintln8E55G53 can2t fin! key3 8 K key.< %yste#.e6it-(.< A return -0rrayList.get-key.< A "ublic voi! "rintWalues-Print%trea# ". @ $terator k ? key%et-..iterator-.< :hile-k.has&e6t-.. @ %tring one`ey ? -%tring.k.ne6t-.< 0rrayList val ? get0rrayList-one`ey.< for-int i ? '< i P val.siUe-.< iKK. "."rintln--%tring.val.get-i..< A A A "ublic class Class%canner @ "rivate Lile "ath< "rivate %tringNO fileList< "rivate Pro"erties classes ? ne: Pro"erties-.< "rivate Julti%tringJa" classJa" ? ne: Julti%tringJa"-., i!entJa" ? ne: Julti%tringJa"-.< "rivate %trea#TokeniUer in< "ublic Class%canner-. thro:s $GE6ce"tion @ "ath ? ne: Lile-8.8.< fileList ? "ath.list-ne: JavaLilter-..< for-int i ? '< i P fileList.length< iKK. @ %yste#.out."rintln-fileListNiO.< try @
782
scanListing-fileListNiO.< A catch-Lile&otLoun!E6ce"tion e. @ %yste#.err."rintln-8Coul! not o"en 8 K fileListNiO.< A A A voi! scanListing-%tring fna#e. thro:s $GE6ce"tion @ in ? ne: %trea#TokeniUerne: Buffere!5ea!erne: Lile5ea!er-fna#e...< // Doesn2t see# to :ork3 // in.slash%tarCo##ents-true.< // in.slash%lashCo##ents-true.< in.or!inaryChar-2/2.< in.or!inaryChar-2.2.< in.:or!Chars-2b2, 2b2.< in.eol$s%ignificant-true.< :hile-in.ne6tToken-. 4? %trea#TokeniUer.TTbEGL. @ if-in.tty"e ?? 2/2. eatCo##ents-.< else if-in.tty"e ?? %trea#TokeniUer.TTb\G5D. @ if-in.sval.e=uals-8class8. XX in.sval.e=uals-8interface8.. @ // aet class na#e3 :hile-in.ne6tToken-. 4? %trea#TokeniUer.TTbEGL DD in.tty"e 4? %trea#TokeniUer.TTb\G5D. < classes."ut-in.sval, in.sval.< classJa".a!!-fna#e, in.sval.< A if-in.sval.e=uals-8i#"ort8. XX in.sval.e=uals-8"ackage8.. !iscar!Line-.< else // $t2s an i!entifier or key:or! i!entJa".a!!-fna#e, in.sval.<
783
A A A voi! !iscar!Line-. thro:s $GE6ce"tion @ :hile-in.ne6tToken-. 4? %trea#TokeniUer.TTbEGL DD in.tty"e 4? %trea#TokeniUer.TTbEGL. < // Thro: a:ay tokens to en! of line A // %trea#TokeniUer2s co##ent re#oval see#e! // to be broken. This e6tracts the#3 voi! eatCo##ents-. thro:s $GE6ce"tion @ if-in.ne6tToken-. 4? %trea#TokeniUer.TTbEGL. @ if-in.tty"e ?? 2/2. !iscar!Line-.< else if-in.tty"e 4? 2B2. in."ushBack-.< else :hile-true. @ if-in.ne6tToken-. ?? %trea#TokeniUer.TTbEGL. break< if-in.tty"e ?? 2B2. if-in.ne6tToken-. 4? %trea#TokeniUer.TTbEGL DD in.tty"e ?? 2/2. break< A A A "ublic %tringNO class&a#es-. @ %tringNO result ? ne: %tringNclasses.siUe-.O< $terator e ? classes.key%et-..iterator-.< int i ? '< :hile-e.has&e6t-.. resultNiKKO ? -%tring.e.ne6t-.< return result< A "ublic voi! checkClass&a#es-. @
784
$terator files ? classJa".key%et-..iterator-.< :hile-files.has&e6t-.. @ %tring file ? -%tring.files.ne6t-.< 0rrayList cls ? classJa".get0rrayList-file.< for-int i ? '< i P cls.siUe-.< iKK. @ %tring class&a#e ? -%tring.cls.get-i.< if-Character.isLo:erCaseclass&a#e.char0t-'... %yste#.out."rintln8class ca"italiUation error, file3 8 K file K 8, class3 8 K class&a#e.< A A A "ublic voi! check$!ent&a#es-. @ $terator files ? i!entJa".key%et-..iterator-.< 0rrayList re"ort%et ? ne: 0rrayList-.< :hile-files.has&e6t-.. @ %tring file ? -%tring.files.ne6t-.< 0rrayList i!s ? i!entJa".get0rrayList-file.< for-int i ? '< i P i!s.siUe-.< iKK. @ %tring i! ? -%tring.i!s.get-i.< if-4classes.contains-i!.. @ // $gnore i!entifiers of length ) or // longer that are all u""ercase // -"robably static final values.3 if-i!.length-. Q? ) DD i!.e=ualsi!.toY""erCase-... continue< // Check to see if first char is u""er3 if-Character.isY""erCase-i!.char0t-'...@ if-re"ort%et.in!e6Gf-file K i!. ?? -(.@ // &ot re"orte! yet re"ort%et.a!!-file K i!.< %yste#.out."rintln8$!ent ca"italiUation error in38 K file K 8, i!ent3 8 K i!.< A A
785
A A A A static final %tring usage ? 8Ysage3 _n8 K 8Class%canner classna#es -a_n8 K 8_t0!!s all the class na#es in this _n8 K 8_t!irectory to the re"ository file _n8 K 8_tcalle! 2classna#es2_n8 K 8Class%canner classna#es_n8 K 8_tChecks all the Hava files in this _n8 K 8_t!irectory for ca"italiUation errors, _n8 K 8_tusing the re"ository file 2classna#es28< "rivate static voi! usage-. @ %yste#.err."rintln-usage.< %yste#.e6it-(.< A "ublic static voi! #ain-%tringNO args. thro:s $GE6ce"tion @ if-args.length P ( XX args.length Q . usage-.< Class%canner c ? ne: Class%canner-.< Lile ol! ? ne: Lile-argsN'O.< if-ol!.e6ists-.. @ try @ // Try to o"en an e6isting // "ro"erties file3 $n"ut%trea# ol!list ? ne: Buffere!$n"ut%trea#ne: Lile$n"ut%trea#-ol!..< c.classes.loa!-ol!list.< ol!list.close-.< A catch-$GE6ce"tion e. @ %yste#.err."rintln-8Coul! not o"en 8 K ol! K 8 for rea!ing8.< %yste#.e6it-(.< A A if-args.length ?? (. @ c.checkClass&a#es-.<
787
c.check$!ent&a#es-.< A // \rite the class na#es to a re"ository3 if-args.length ?? . @ if-4argsN(O.e=uals-8-a8.. usage-.< try @ Buffere!Gut"ut%trea# out ? ne: Buffere!Gut"ut%trea#ne: LileGut"ut%trea#-argsN'O..< c.classes.store-out, 8Classes foun! by Class%canner.Hava8.< out.close-.< A catch-$GE6ce"tion e. @ %yste#.err."rintln8Coul! not :rite 8 K argsN'O.< %yste#.e6it-(.< A A A A class JavaLilter i#"le#ents Lilena#eLilter @ "ublic boolean acce"t-Lile !ir, %tring na#e. @ // %tri" "ath infor#ation3 %tring f ? ne: Lile-na#e..get&a#e-.< return f.tri#-..en!s\ith-8.Hava8.< A A ///3>
The class 1*lti)tring1ap is a tool that allows you to #a% a grou% o" strings onto each key entry. It uses a Hash1ap *this ti#e with inheritance, with the key as the single string that s #a%%ed onto the Array+ist value. The a''A B #ethod si#%ly checks to see i" there s a key already in the Hash1ap, and i" not it %uts one there. The getArray+ist A B #ethod %roduces an Array+ist "or a %articular key, and printVal*esA B, which is %ri#arily use"ul "or debugging, %rints out all the values Array+ist by Array+ist. RFSURFSTIJLT+(6PTE5MMTIMGMU To kee% li"e si#%le, the class na#es "ro# the standard Java libraries are all %ut into a #roperties ob0ect *"ro# the standard Java library,.
788
5e#e#ber that a #roperties ob0ect is a Hash1ap that holds only )tring ob0ects "or both the key and value entries. (owever, it can be saved to disk and restored "ro# disk in one #ethod call, so it s ideal "or the re%ository o" na#es. 6ctually, we need only a list o" na#es, and a Hash1ap can t acce%t n*ll "or either its key or its value entry. So the sa#e ob0ect will be used "or both the key and the value. RFSURF STIJLT+(6PTE5MMTIMGKU Eor the classes and identi"iers that are discovered "or the "iles in a %articular directory, two 1*lti)tring1aps are used= class1ap and i'ent1ap. 6lso, when the %rogra# starts u% it loads the standard class na#e re%ository into the #roperties ob0ect called classes, and when a new class na#e is "ound in the local directory that is also added to classes as well as to class1ap. This way, class1ap can be used to ste% through all the classes in the local directory, and classes can be used to see i" the current token is a class na#e *which indicates a de"inition o" an ob0ect or #ethod is beginning, so grab the ne&t tokens9until a se#icolon 9and %ut the# into i'ent1ap,. RFSURFSTIJLT+(6PTE5MMTIMGLU The de"ault constructor "or -lass)canner creates a list o" "ile na#es, using the JavaFilter i#%le#entation o" FilenameFilter, shown at the end o" the "ile. Then it calls scan+istingA B "or each "ile na#e. RFSURF STIJLT+(6PTE5MMTIMG?U Inside scan+istingA B the source code "ile is o%ened and turned into a )treamTokeni7er. In the docu#entation, %assing tr*e to slash)tar-ommentsA B and slash)lash-ommentsA B is su%%osed to stri% those co##ents out, but this see#s to be a bit "lawed, as it doesn t Auite work. Instead, those lines are co##ented out and the co##ents are e&tracted by another #ethod. To do this, the ! 5$ #ust be ca%tured as an ordinary character rather than letting the )treamTokeni7er absorb it as %art o" a co##ent, and the or'inary-harA B #ethod tells the )treamTokeni7er to do this. This is also true "or dots *! !$,, since we want to have the #ethod calls %ulled a%art into individual identi"iers. (owever, the underscore, which is ordinarily treated by )treamTokeni7er as an individual character, should be le"t as %art o" identi"iers since it a%%ears in such static final values as TTX&.F, etc., used in this very %rogra#. The (or'-harsA B #ethod takes a range o" characters you want to add to those that are le"t inside a token that is
78:
being %arsed as a word. Einally, when %arsing "or one'line co##ents or discarding a line we need to know when an end'o"'line occurs, so by calling eolIs)ignificantAtr*eB the E)D will show u% rather than being absorbed by the )treamTokeni7er. RFSURFSTIJLT+(6PTE5MMTIMGHU The rest o" scan+istingA B reads and reacts to tokens until the end o" the "ile, signi"ied when ne4tTokenA B returns the final static value )treamTokeni7er!TTX&.F. RFSURFSTIJLT+(6PTE5MMTIMG3U I" the token is a !F$ it is %otentially a co##ent, so eat-ommentsA B is called to deal with it. The only other situation we re interested in here is i" it s a word, o" which there are so#e s%ecial cases. RFSURF STIJLT+(6PTE5MMTIMGGU I" the word is class or interface then the ne&t token re%resents a class or inter"ace na#e, and it is %ut into classes and class1ap. I" the word is import or package, then we don t want the rest o" the line. 6nything else #ust be an identi"ier *which we re interested in, or a keyword *which we re not, but they re all lowercase anyway so it won t s%oil things to %ut those in,. These are added to i'ent1ap. RFSURF STIJLT+(6PTE5MMTIMGIU The 'iscar'+ineA B #ethod is a si#%le tool that looks "or the end o" a line. Cote that any ti#e you get a new token, you #ust check "or the end o" the "ile. RFSURFSTIJLT+(6PTE5MMTIMG2U The eat-ommentsA B #ethod is called whenever a "orward slash is encountered in the #ain %arsing loo%. (owever, that doesn t necessarily #ean a co##ent has been "ound, so the ne&t token #ust be e&tracted to see i" it s another "orward slash *in which case the line is discarded, or an asterisk. But i" it s neither o" those, it #eans the token you ve 0ust %ulled out is needed back in the #ain %arsing loo%. Eortunately, the p*sh2ack A B #ethod allows you to !%ush back$ the current token onto the in%ut strea# so that when the #ain %arsing loo% calls ne4tTokenA B it will get the one you 0ust %ushed back. RFSURFSTIJLT+(6PTE5MMTIMI@U Eor convenience, the class/amesA B #ethod %roduces an array o" all the na#es in the classes container. This #ethod is not used in the %rogra# but is hel%"ul "or debugging. RFSURFSTIJLT+(6PTE5MMTIMIMU
78;
The ne&t two #ethods are the ones in which the actual checking takes %lace. In check-lass/amesA B, the class na#es are e&tracted "ro# the class1ap *which, re#e#ber, contains only the na#es in this directory, organi1ed by "ile na#e so the "ile na#e can be %rinted along with the errant class na#e,. This is acco#%lished by %ulling each associated Array+ist and ste%%ing through that, looking to see i" the "irst character is lowercase. I" so, the a%%ro%riate error #essage is %rinted. RFSURF STIJLT+(6PTE5MMTIMIKU In checkI'ent/amesA B, a si#ilar a%%roach is taken= each identi"ier na#e is e&tracted "ro# i'ent1ap. I" the na#e is not in the classes list, it s assu#ed to be an identi"ier or keyword. 6 s%ecial case is checked= i" the identi"ier length is three or #ore and all the characters are u%%ercase, this identi"ier is ignored because it s %robably a static final value such as TTX&.F. )" course, this is not a %er"ect algorith#, but it assu#es that you ll eventually notice any all'u%%ercase identi"iers that are out o" %lace. RFSURFSTIJLT+(6PTE5MMTIMILU Instead o" re%orting every identi"ier that starts with an u%%ercase character, this #ethod kee%s track o" which ones have already been re%orted in an Array+ist called report)etA B. This treats the Array+ist as a !set$ that tells you whether an ite# is already in the set. The ite# is %roduced by concatenating the "ile na#e and identi"ier. I" the ele#ent isn t in the set, it s added and then the re%ort is #ade. RFSURF STIJLT+(6PTE5MMTIMI?U The rest o" the listing is co#%rised o" mainA B, which busies itsel" by handling the co##and line argu#ents and "iguring out whether you re building a re%ository o" class na#es "ro# the standard Java library or checking the validity o" code you ve written. In both cases it #akes a -lass)canner ob0ect. RFSURFSTIJLT+(6PTE5MMTIMIHU :hether you re building a re%ository or using one, you #ust try to o%en the e&isting re%ository. By #aking a File ob0ect and testing "or e&istence, you can decide whether to o%en the "ile and loa'A B the #roperties list classes inside -lass)canner. *The classes "ro# the re%ository add to, rather than overwrite, the classes "ound by the -lass)canner constructor., I" you %rovide only one co##and'line argu#ent it #eans that you want to %er"or# a check o" the class na#es and identi"ier na#es,
7:=
but i" you %rovide two argu#ents *the second being ! 6a$, you re building a class na#e re%ository. In this case, an out%ut "ile is o%ened and the #ethod #roperties!saveA B is used to write the list into a "ile, along with a string that %rovides header "ile in"or#ation. RFSURF STIJLT+(6PTE5MMTIMI3U
1ummar:
The Java IF) strea# library does satis"y the basic reAuire#ents= you can %er"or# reading and writing with the console, a "ile, a block o" #e#ory, or even across the Internet *as you will see in +ha%ter MH,. :ith inheritance, you can create new ty%es o" in%ut and out%ut ob0ects. 6nd you can even add a si#%le e&tensibility to the kinds o" ob0ects a strea# will acce%t by rede"ining the to)tringA B #ethod that s auto#atically called when you %ass an ob0ect to a #ethod that s e&%ecting a )tring *Java s li#ited !auto#atic ty%e conversion$,. RFSURF STIJLT+(6PTE5MMTIMIGU There are Auestions le"t unanswered by the docu#entation and design o" the IF) strea# library. Eor e&a#%le, it would have been nice i" you could say that you want an e&ce%tion thrown i" you try to overwrite a "ile when o%ening it "or out%ut9so#e %rogra##ing syste#s allow you to s%eci"y that you want to o%en an out%ut "ile, but only i" it doesn t already e&ist. In Java, it a%%ears that you are su%%osed to use a File ob0ect to deter#ine whether a "ile e&ists, because i" you o%en it as a File.*tp*t)tream or File0riter it will always get overwritten. RFSURF STIJLT+(6PTE5MMTIMIIU The IF) strea# library brings u% #i&ed "eelings; it does #uch o" the 0ob and it s %ortable. But i" you don t already understand the decorator %attern, the design is nonintuitive, so there s e&tra overhead in learning and teaching it. It s also inco#%lete= there s no su%%ort "or the kind o" out%ut "or#atting that al#ost every other language s IF) %ackage su%%orts. RFSURFSTIJLT+(6PTE5MMTIMI2U
7:1
(owever, once you do understand the decorator %attern and begin using the library in situations that reAuire its "le&ibility, you can begin to bene"it "ro# this design, at which %oint its cost in e&tra lines o" code #ay not bother you as #uch. RFSURFSTIJLT+(6PTE5MMTIM2@U I" you do not "ind what you re looking "or in this cha%ter *which has only been an introduction, and is not #eant to be co#%rehensive,, you can "ind in'de%th coverage in Java I/O, by Elliotte 5usty (arold *) 5eilly, M222,. RFSURFSTIJLT+(6PTE5MMTIM2MU
/0ercises
Solutions to selected e&ercises can be "ound in the electronic docu#entThe Thinking in Java "nnotated Solution @uide, available "or a s#all "ee "ro# ,,,'0ruceEckel'com.
(56) )%en a te&t "ile so that you can read the "ile one line at a ti#e.
5ead each line as a )tring and %lace that )tring ob0ect into a +inke'+ist. Print all o" the lines in the +inke'+ist in reverse order. RFSURFSTIJLT+(6PTE5MMTIM2KU
(67) Modi"y E&ercise M so that the na#e o" the "ile you read is
%rovided as a co##and'line argu#ent. RFSURF STIJLT+(6PTE5MMTIM2LU
(6() Modi"y E&ercise K to also o%en a te&t "ile so you can write te&t
into it. :rite the lines in the Array+ist, along with line nu#bers *do not atte#%t to use the !DineCu#ber$ classes,, out to the "ile. RFSURFSTIJLT+(6PTE5MMTIM2?U
(6+) Modi"y
o%ens each "ile and acce%ts the "ile based on whether any o" the
7:2
trailing argu#ents on the co##and line e&ist in that "ile. RFSURF STIJLT+(6PTE5MMTIM2GU
7:3
including the o""ending lines. Ce&t, co##ent out the de"ault constructor "or 2lip-heck. 5un it and e&%lain why it works. Cote that a"ter co#%iling, you #ust e&ecute the %rogra# with ! 8ava 2lips$ because the mainA B #ethod is still in class 2lips. RFSURF STIJLT+(6PTE5MMTIK@HU
!7*) In 2lipJ!8ava, co##ent out the two lines a"ter the %hrases
!/ou #ust do this=$ and run the %rogra#. E&%lain the result and why it di""ers "ro# when the two lines are in the %rogra#. RFSURF STIJLT+(6PTE5MMTIK@3U
7:4
7:5
Sha e draw89
$ircle
S%uare
&riangle
This is a ty%ical class hierarchy diagra#, with the base class at the to% and the derived classes growing downward. The nor#al goal in ob0ect' oriented %rogra##ing is "or the bulk o" your code to #ani%ulate re"erences to the base ty%e * )hape, in this case,, so i" you decide to e&tend the %rogra# by adding a new class * $homboi', derived "ro# )hape, "or e&a#%le,, the bulk o" the code is not a""ected. In this e&a#%le, the dyna#ically bound #ethod in the )hape inter"ace is 'ra(A B, so the intent is "or the client %rogra##er to call 'ra(A B through a generic )hape re"erence. 'ra(A B is overridden in all o" the derived classes, and because it is a dyna#ically bound #ethod, the %ro%er behavior will occur even though it is called through a generic )hape re"erence. That s %oly#or%his#. RFSURFSTIJLT+(6PTE5MKTILU Thus, you generally create a s%eci"ic ob0ect * -ircle, )C*are, or Triangle,, u%cast it to a )hape *"orgetting the s%eci"ic ty%e o" the ob0ect,, and use that anony#ous )hape re"erence in the rest o" the %rogra#. RFSURFSTIJLT+(6PTE5MKTI?U 6s a brie" review o" %oly#or%his# and u%casting, you #ight code the above e&a#%le as "ollows=
//3 c( 3%ha"es.Hava i#"ort Hava.util.B< class %ha"e @ voi! !ra:-. @ %yste#.out."rintln-this K 8.!ra:-.8.< A A class Circle e6ten!s %ha"e @
7:7
Thinking in Java
,,,'0ruceEckel'com
"ublic %tring to%tring-. @ return 8Circle8< A A class %=uare e6ten!s %ha"e @ "ublic %tring to%tring-. @ return 8%=uare8< A A class Triangle e6ten!s %ha"e @ "ublic %tring to%tring-. @ return 8Triangle8< A A "ublic class %ha"es @ "ublic static voi! #ain-%tringNO args. @ 0rrayList s ? ne: 0rrayList-.< s.a!!-ne: Circle-..< s.a!!-ne: %=uare-..< s.a!!-ne: Triangle-..< $terator e ? s.iterator-.< :hile-e.has&e6t-.. --%ha"e.e.ne6t-...!ra:-.< A A ///3>
The base class contains a 'ra(A B #ethod that indirectly uses to)tring A B to %rint an identi"ier "or the class by %assing this to )ystem!o*t! printlnA B. I" that "unction sees an ob0ect, it auto#atically calls the to)tringA B #ethod to %roduce a )tring re%resentation. RFSURF STIJLT+(6PTE5MKTIHU Each o" the derived classes overrides the to)tringA B #ethod *"ro# .b8ect, so that 'ra(A B ends u% %rinting so#ething di""erent in each case. In mainA B, s%eci"ic ty%es o" )hape are created and then added to a n Array+ist. This is the %oint at which the u%cast occurs because the Array+ist holds only .b8ects. Since everything in Java *with the e&ce%tion o" %ri#itives, is an .b8ect, a n Array+ist can also hold )hape ob0ects. But during an u%cast to .b8ect, it also loses any s%eci"ic in"or#ation, including the "act that the ob0ects are )hapes. To the Array+ist, they are 0ust .b8ects. RFSURFSTIJLT+(6PTE5MKTI3U 6t the %oint you "etch an ele#ent out o" the Array+ist with ne4tA B, things get a little busy. Since the Array+ist holds only .b8ects, ne4tA B
7:8
naturally %roduces an .b8ect reference. But we know it s really a )hape re"erence, and we want to send )hape #essages to that ob0ect. So a cast to )hape is necessary using the traditional ! A)hapeB$ cast. This is the #ost basic "or# o" 5TTI, since in Java all casts are checked at run' ti#e "or correctness. That s e&actly what 5TTI #eans= at run'ti#e, the ty%e o" an ob0ect is identi"ied. RFSURFSTIJLT+(6PTE5MKTIGU In this case, the 5TTI cast is only %artial= the .b8ect is cast to a )hape, and not all the way to a -ircle, )C*are, or Triangle. That s because the only thing we kno, at this %oint is that the Array+ist is "ull o" )hapes. 6t co#%ile'ti#e, this is en"orced only by your own sel"'i#%osed rules, but at run'ti#e the cast ensures it. RFSURFSTIJLT+(6PTE5MKTIIU Cow %oly#or%his# takes over and the e&act #ethod that s called "or the
)hape is deter#ined by whether the re"erence is "or a -ircle, )C*are, or Triangle. 6nd in general, this is how it should be; you want the bulk o" your code to know as little as %ossible about s eci$ic ty%es o" ob0ects,
and to 0ust deal with the general re%resentation o" a "a#ily o" ob0ects *in this case, )hape,. 6s a result, your code will be easier to write, read, and #aintain, and your designs will be easier to i#%le#ent, understand, and change. So %oly#or%his# is the general goal in ob0ect'oriented %rogra##ing. RFSURFSTIJLT+(6PTE5MKTI2U But what i" you have a s%ecial %rogra##ing %roble# that s easiest to solve i" you know the e&act ty%e o" a generic re"erenceO Eor e&a#%le, su%%ose you want to allow your users to highlight all the sha%es o" any %articular ty%e by turning the# %ur%le. This way, they can "ind all the triangles on the screen by highlighting the#. )r %erha%s your #ethod
needs to !rotate$ a list o" sha%es, but it #akes no sense to rotate a circle so you d like to ski% only the circle ob0ects. This is what 5TTI acco#%lishes= you can ask a )hape re"erence the e&act ty%e that it s re"erring to. RFSURFSTIJLT+(6PTE5MKTIM@U :ith 5TTI you can select and isolate s%ecial cases.
7::
Thinking in Java
,,,'0ruceEckel'com
about the class. *This is so#eti#es called a meta/class', In "act, the -lass ob0ect is used to create all o" the !regular$ ob0ects o" your class. RFSURF STIJLT+(6PTE5MKTIMMU There s a -lass ob0ect "or each class that is %art o" your %rogra#. That is, each ti#e you write and co#%ile a new class, a single -lass ob0ect is also created *and stored, a%%ro%riately enough, in an identically na#ed !class "ile,. 6t run'ti#e, when you want to #ake an ob0ect o" that class, the Java Virtual Machine *JVM, that s e&ecuting your %rogra# "irst checks to see i" the -lass ob0ect "or that ty%e is loaded. I" not, the JVM loads it by "inding the !class "ile with that na#e. Thus, a Java %rogra# isn t co#%letely loaded be"ore it begins, which is di""erent "ro# #any traditional languages. RFSURFSTIJLT+(6PTE5MKTIMKU )nce the -lass ob0ect "or that ty%e is in #e#ory, it is used to create all ob0ects o" that ty%e. RFSURFSTIJLT+(6PTE5MKTIMLU I" this see#s shadowy or i" you don t really believe it, here s a de#onstration %rogra# to %rove it=
//3 c( 3%:eet%ho".Hava // E6a#ination of the :ay the class loa!er :orks. class Can!y @ static @ %yste#.out."rintln-8Loa!ing Can!y8.< A A class au# @ static @ %yste#.out."rintln-8Loa!ing au#8.< A A class Cookie @ static @ %yste#.out."rintln-8Loa!ing Cookie8.< A A
7:;
"ublic class %:eet%ho" @ "ublic static voi! #ain-%tringNO args. @ %yste#.out."rintln-8insi!e #ain8.< ne: Can!y-.< %yste#.out."rintln-80fter creating Can!y8.< try @ Class.for&a#e-8au#8.< A catch-Class&otLoun!E6ce"tion e. @ e."rint%tackTrace-%yste#.err.< A %yste#.out."rintln80fter Class.for&a#e-_8au#_8.8.< ne: Cookie-.< %yste#.out."rintln-80fter creating Cookie8.< A A ///3>
Each o" the classes -an'y, "*m, and -ookie have a static clause that is e&ecuted as the class is loaded "or the "irst ti#e. In"or#ation will be %rinted to tell you when loading occurs "or that class. In mainA B, the ob0ect creations are s%read out between %rint state#ents to hel% detect the ti#e o" loading. RFSURFSTIJLT+(6PTE5MKTIM?U 6 %articularly interesting line is=
Class.for&a#e-8au#8.<
This #ethod is a static #e#ber o" -lass *to which all -lass ob0ects belong,. 6 -lass ob0ect is like any other ob0ect and so you can get and #ani%ulate a re"erence to it. *That s what the loader does., )ne o" the ways to get a re"erence to the -lass ob0ect is for/ameA B, which takes a )tring containing the te&tual na#e *watch the s%elling and ca%itali1ation., o" the %articular class you want a re"erence "or. It returns a -lass re"erence. RFSURFSTIJLT+(6PTE5MKTIMHU The out%ut o" this %rogra# "or one JVM is=
insi!e #ain Loa!ing Can!y 0fter creating Can!y Loa!ing au# 0fter Class.for&a#e-8au#8.
7;=
Thinking in Java
,,,'0ruceEckel'com
Class literals
Java %rovides a second way to %roduce the re"erence to the -lass ob0ect, using a class literal. In the above %rogra# this would look like=
au#.class<
which is not only si#%ler, but also sa"er since it s checked at co#%ile' ti#e. Because it eli#inates the #ethod call, it s also #ore e""icient. RF SURFSTIJLT+(6PTE5MKTIMGU +lass literals work with regular classes as well as inter"aces, arrays, and %ri#itive ty%es. In addition, there s a standard "ield called T:#& that e&ists "or each o" the %ri#itive wra%%er classes. The T:#& "ield %roduces a re"erence to the -lass ob0ect "or the associated %ri#itive ty%e, such that=
d is eC*ivalent to d boolean!class 2oolean!T:#& char!class -haracter!T:#& byte!class 2yte!T:#& short!class )hort!T:#& int!class Integer!T:#& long!class +ong!T:#& float!class Float!T:#& 'o*ble!class o*ble!T:#& voi'!class Voi'!T:#&
My %re"erence is to use the ! !class$ versions i" you can, since they re #ore consistent with regular classes. RFSURFSTIJLT+(6PTE5MKTIMIU
7;1
((!) The classic cast; e.g., ! A)hapeB,$ which uses 5TTI to #ake sure the cast is correct and throws a -lass-ast&4ception i" you ve
%er"or#ed a bad cast.
((*) The -lass ob0ect re%resenting the ty%e o" your ob0ect. The -lass
ob0ect can be Aueried "or use"ul run'ti#e in"or#ation. RFSURF STIJLT+(6PTE5MKTIM2U In +<<, the classic cast ! A)hapeB$ does not %er"or# 5TTI. It si#%ly tells the co#%iler to treat the ob0ect as the new ty%e. In Java, which does %er"or# the ty%e check, this cast is o"ten called a !ty%e sa"e downcast.$ The reason "or the ter# !downcast$ is the historical arrange#ent o" the class hierarchy diagra#. I" casting a -ircle to a )hape is an u%cast, then casting a )hape to a -ircle is a downcast. (owever, you know a -ircle is also a )hape, and the co#%iler "reely allows an u%cast assign#ent, but you donJt know that a )hape is necessarily a -ircle, so the co#%iler doesn t allow you to %er"or# a downcast assign#ent without using an e&%licit cast. RFSURFSTIJLT+(6PTE5MKTIK@U There s a third "or# o" 5TTI in Java. This is the keyword instanceof that tells you i" an ob0ect is an instance o" a %articular ty%e. It returns a boolean so you use it in the "or# o" a Auestion, like this=
//3 c( 3Pets.Hava class Pet @A class Dog e6ten!s Pet @A class Pug e6ten!s Dog @A class Cat e6ten!s Pet @A
7;2
Thinking in Java
,,,'0ruceEckel'com
class 5o!ent e6ten!s Pet @A class aerbil e6ten!s 5o!ent @A class Ma#ster e6ten!s 5o!ent @A class Counter @ int i< A ///3>
The -o*nter class is used to kee% track o" the nu#ber o" any %articular ty%e o" #et. /ou could think o" it as an Integer that can be #odi"ied. RF SURFSTIJLT+(6PTE5MKTIKKU 4sing instanceof, all the %ets can be counted=
//3 c( 3PetCount.Hava // Ysing instanceof. i#"ort Hava.util.B< "ublic class PetCount @ static %tringNO ty"ena#es ? @ 8Pet8, 8Dog8, 8Pug8, 8Cat8, 85o!ent8, 8aerbil8, 8Ma#ster8, A< // E6ce"tions thro:n out to console3 "ublic static voi! #ain-%tringNO args. thro:s E6ce"tion @ 0rrayList "ets ? ne: 0rrayList-.< try @ ClassNO "etTy"es ? @ Class.for&a#e-8Dog8., Class.for&a#e-8Pug8., Class.for&a#e-8Cat8., Class.for&a#e-85o!ent8., Class.for&a#e-8aerbil8., Class.for&a#e-8Ma#ster8., A< for-int i ? '< i P (,< iKK. "ets.a!!"etTy"esN -int.-Jath.ran!o#-.B"etTy"es.length.O .ne:$nstance-..< A catch-$nstantiationE6ce"tion e. @ %yste#.err."rintln-8Cannot instantiate8.< thro: e<
7;3
A catch-$llegal0ccessE6ce"tion e. @ %yste#.err."rintln-8Cannot access8.< thro: e< A catch-Class&otLoun!E6ce"tion e. @ %yste#.err."rintln-8Cannot fin! class8.< thro: e< A MashJa" h ? ne: MashJa"-.< for-int i ? '< i P ty"ena#es.length< iKK. h."ut-ty"ena#esNiO, ne: Counter-..< for-int i ? '< i P "ets.siUe-.< iKK. @ GbHect o ? "ets.get-i.< if-o instanceof Pet. --Counter.h.get-8Pet8...iKK< if-o instanceof Dog. --Counter.h.get-8Dog8...iKK< if-o instanceof Pug. --Counter.h.get-8Pug8...iKK< if-o instanceof Cat. --Counter.h.get-8Cat8...iKK< if-o instanceof 5o!ent. --Counter.h.get-85o!ent8...iKK< if-o instanceof aerbil. --Counter.h.get-8aerbil8...iKK< if-o instanceof Ma#ster. --Counter.h.get-8Ma#ster8...iKK< A for-int i ? '< i P "ets.siUe-.< iKK. %yste#.out."rintln-"ets.get-i..getClass-..< for-int i ? '< i P ty"ena#es.length< iKK. %yste#.out."rintlnty"ena#esNiO K 8 =uantity3 8 K --Counter.h.get-ty"ena#esNiO...i.< A A ///3>
There s a rather narrow restriction on instanceof= you can co#%are it to a na#ed ty%e only, and not to a -lass ob0ect. In the e&a#%le above you #ight "eel that it s tedious to write out all o" those instanceof e&%ressions, and you re right. But there is no way to cleverly auto#ate instanceof by creating an Array+ist o" -lass ob0ects and co#%aring it
7;4
Thinking in Java
,,,'0ruceEckel'com
to those instead *stay tuned9you ll see an alternative,. This isn t as great a restriction as you #ight think, because you ll eventually understand that your design is %robably "lawed i" you end u% writing a lot o" instanceof e&%ressions. RFSURFSTIJLT+(6PTE5MKTIKLU )" course this e&a#%le is contrived9you d %robably %ut a static data #e#ber in each ty%e and incre#ent it in the constructor to kee% track o" the counts. /ou would do so#ething like that i$ you had control o" the source code "or the class and could change it. Since this is not always the case, 5TTI can co#e in handy. RFSURFSTIJLT+(6PTE5MKTIK?U
//3 c( 3PetCount .Hava // Ysing class literals. i#"ort Hava.util.B< "ublic class PetCount @ "ublic static voi! #ain-%tringNO args. thro:s E6ce"tion @ 0rrayList "ets ? ne: 0rrayList-.< ClassNO "etTy"es ? @ // Class literals3 Pet.class, Dog.class, Pug.class, Cat.class, 5o!ent.class, aerbil.class, Ma#ster.class, A< try @ for-int i ? '< i P (,< iKK. @ // Gffset by one to eli#inate Pet.class3 int rn! ? ( K -int.Jath.ran!o#-. B -"etTy"es.length - (..< "ets.a!!"etTy"esNrn!O.ne:$nstance-..<
7;5
A A catch-$nstantiationE6ce"tion e. @ %yste#.err."rintln-8Cannot instantiate8.< thro: e< A catch-$llegal0ccessE6ce"tion e. @ %yste#.err."rintln-8Cannot access8.< thro: e< A MashJa" h ? ne: MashJa"-.< for-int i ? '< i P "etTy"es.length< iKK. h."ut-"etTy"esNiO.to%tring-., ne: Counter-..< for-int i ? '< i P "ets.siUe-.< iKK. @ GbHect o ? "ets.get-i.< if-o instanceof Pet. --Counter.h.get-8class Pet8...iKK< if-o instanceof Dog. --Counter.h.get-8class Dog8...iKK< if-o instanceof Pug. --Counter.h.get-8class Pug8...iKK< if-o instanceof Cat. --Counter.h.get-8class Cat8...iKK< if-o instanceof 5o!ent. --Counter.h.get-8class 5o!ent8...iKK< if-o instanceof aerbil. --Counter.h.get-8class aerbil8...iKK< if-o instanceof Ma#ster. --Counter.h.get-8class Ma#ster8...iKK< A for-int i ? '< i P "ets.siUe-.< iKK. %yste#.out."rintln-"ets.get-i..getClass-..< $terator keys ? h.key%et-..iterator-.< :hile-keys.has&e6t-.. @ %tring n# ? -%tring.keys.ne6t-.< Counter cnt ? -Counter.h.get-n#.< %yste#.out."rintlnn#.substring-n#.last$n!e6Gf-2.2. K (. K 8 =uantity3 8 K cnt.i.< A A A ///3>
7;7
Thinking in Java
,,,'0ruceEckel'com
(ere, the typenames array has been re#oved in "avor o" getting the ty%e na#e strings "ro# the -lass ob0ect. Cotice that the syste# can distinguish between classes and inter"aces. RFSURF STIJLT+(6PTE5MKTIKHU /ou can also see that the creation o" petTypes does not need to be surrounded by a try block since it s evaluated at co#%ile'ti#e and thus won t throw any e&ce%tions, unlike -lass!for/ameA B. RFSURF STIJLT+(6PTE5MKTIK3U :hen the #et ob0ects are dyna#ically created, you can see that the rando# nu#ber is restricted so it is between one and petTypes!length and does not include 1ero. That s because 1ero re"ers to #et!class, and %resu#ably a generic #et ob0ect is not interesting. (owever, since #et! class is %art o" petTypes the result is that all o" the %ets get counted. RF SURFSTIJLT+(6PTE5MKTIKGU
A d:namic instanceo!
The -lass isInstance #ethod %rovides a way to dyna#ically call the instanceof o%erator. Thus, all those tedious instanceof state#ents can be re#oved in the #et-o*nt e&a#%le=
//3 c( 3PetCount).Hava // Ysing is$nstance-.. i#"ort Hava.util.B< "ublic class PetCount) @ "ublic static voi! #ain-%tringNO args. thro:s E6ce"tion @ 0rrayList "ets ? ne: 0rrayList-.< ClassNO "etTy"es ? @ Pet.class, Dog.class, Pug.class, Cat.class, 5o!ent.class, aerbil.class, Ma#ster.class, A< try @
7;8
for-int i ? '< i P (,< iKK. @ // Gffset by one to eli#inate Pet.class3 int rn! ? ( K -int.Jath.ran!o#-. B -"etTy"es.length - (..< "ets.a!!"etTy"esNrn!O.ne:$nstance-..< A A catch-$nstantiationE6ce"tion e. @ %yste#.err."rintln-8Cannot instantiate8.< thro: e< A catch-$llegal0ccessE6ce"tion e. @ %yste#.err."rintln-8Cannot access8.< thro: e< A MashJa" h ? ne: MashJa"-.< for-int i ? '< i P "etTy"es.length< iKK. h."ut-"etTy"esNiO.to%tring-., ne: Counter-..< for-int i ? '< i P "ets.siUe-.< iKK. @ GbHect o ? "ets.get-i.< // Ysing is$nstance to eli#inate in!ivi!ual // instanceof e6"ressions3 for -int H ? '< H P "etTy"es.length< KKH. if -"etTy"esNHO.is$nstance-o.. @ %tring key ? "etTy"esNHO.to%tring-.< --Counter.h.get-key...iKK< A A for-int i ? '< i P "ets.siUe-.< iKK. %yste#.out."rintln-"ets.get-i..getClass-..< $terator keys ? h.key%et-..iterator-.< :hile-keys.has&e6t-.. @ %tring n# ? -%tring.keys.ne6t-.< Counter cnt ? -Counter.h.get-n#.< %yste#.out."rintlnn#.substring-n#.last$n!e6Gf-2.2. K (. K 8 =uantity3 8 K cnt.i.< A A A ///3>
7;:
Thinking in Java
,,,'0ruceEckel'com
/ou can see that the isInstanceA B #ethod has eli#inated the need "or the instanceof e&%ressions. In addition, this #eans that you can add new ty%es o" %ets si#%ly by changing the petTypes array; the rest o" the %rogra# does not need #odi"ication *as it did when using the instanceof e&%ressions,. RFSURFSTIJLT+(6PTE5MKTIKIU
//3 c( 3La#ilyWsE6actTy"e.Hava // The !ifference bet:een instanceof an! class class Base @A class Derive! e6ten!s Base @A "ublic class La#ilyWsE6actTy"e @ static voi! test-GbHect 6. @ %yste#.out."rintln-8Testing 6 of ty"e 8 K 6.getClass-..< %yste#.out."rintln-86 instanceof Base 8 K -6 instanceof Base..< %yste#.out."rintln-86 instanceof Derive! 8 K -6 instanceof Derive!..< %yste#.out."rintln-8Base.is$nstance-6. 8 K Base.class.is$nstance-6..< %yste#.out."rintln-8Derive!.is$nstance-6. 8 K Derive!.class.is$nstance-6..< %yste#.out."rintln86.getClass-. ?? Base.class 8 K -6.getClass-. ?? Base.class..< %yste#.out."rintln86.getClass-. ?? Derive!.class 8 K -6.getClass-. ?? Derive!.class..< %yste#.out."rintln86.getClass-..e=uals-Base.class.. 8 K -6.getClass-..e=uals-Base.class...< %yste#.out."rintln-
7;;
86.getClass-..e=uals-Derive!.class.. 8 K -6.getClass-..e=uals-Derive!.class...< A "ublic static voi! #ain-%tringNO args. @ test-ne: Base-..< test-ne: Derive!-..< A A ///3>
The testA B #ethod %er"or#s ty%e checking with its argu#ent using both "or#s o" instanceof. It then gets the -lass re"erence and uses PP and eC*alsA B to test "or eAuality o" the -lass ob0ects. (ere is the out%ut=
Testing 6 of ty"e class Base 6 instanceof Base true 6 instanceof Derive! false Base.is$nstance-6. true Derive!.is$nstance-6. false 6.getClass-. ?? Base.class true 6.getClass-. ?? Derive!.class false 6.getClass-..e=uals-Base.class.. true 6.getClass-..e=uals-Derive!.class.. false Testing 6 of ty"e class Derive! 6 instanceof Base true 6 instanceof Derive! true Base.is$nstance-6. true Derive!.is$nstance-6. true 6.getClass-. ?? Base.class false 6.getClass-. ?? Derive!.class true 6.getClass-..e=uals-Base.class.. false 6.getClass-..e=uals-Derive!.class.. true
5eassuringly, instanceof and isInstanceA B %roduce e&actly the sa#e results, as do eC*alsA B and PP. But the tests the#selves draw di""erent conclusions. In kee%ing with the conce%t o" ty%e, instanceof says !are you this class, or a class derived "ro# this classO$ )n the other hand, i" you co#%are the actual -lass ob0ects using PP, there is no concern with inheritance9it s either the e&act ty%e or it isn t. RFSURF STIJLT+(6PTE5MKTIK2U
8==
Thinking in Java
,,,'0ruceEckel'com
$##I s:nta0
Java %er"or#s its 5TTI using the -lass ob0ect, even i" you re doing so#ething like a cast. The class -lass also has a nu#ber o" other ways you can use 5TTI. RFSURFSTIJLT+(6PTE5MKTIL@U Eirst, you #ust get a re"erence to the a%%ro%riate -lass ob0ect. )ne way to do this, as shown in the %revious e&a#%le, is to use a string and the -lass!for/ameA B #ethod. This is convenient because you don t need an ob0ect o" that ty%e in order to get the -lass re"erence. (owever, i" you do already have an ob0ect o" the ty%e you re interested in, you can "etch the -lass re"erence by calling a #ethod that s %art o" the .b8ect root class= get-lassA B. This returns the -lass re"erence re%resenting the actual ty%e o" the ob0ect. -lass has #any interesting #ethods, de#onstrated in the "ollowing e&a#%le=
//3 c( 3ToyTest.Hava // Testing class Class. interface MasBatteries @A interface \ater"roof @A interface %hootsThings @A class Toy @ // Co##ent out the follo:ing !efault // constructor to see // &o%uchJetho!Error fro# -B(B. Toy-. @A Toy-int i. @A A class LancyToy e6ten!s Toy i#"le#ents MasBatteries, \ater"roof, %hootsThings @ LancyToy-. @ su"er-(.< A A "ublic class ToyTest @ "ublic static voi! #ain-%tringNO args. thro:s E6ce"tion @ Class c ? null<
8=1
try @ c ? Class.for&a#e-8LancyToy8.< A catch-Class&otLoun!E6ce"tion e. @ %yste#.err."rintln-8Can2t fin! LancyToy8.< thro: e< A "rint$nfo-c.< ClassNO faces ? c.get$nterfaces-.< for-int i ? '< i P faces.length< iKK. "rint$nfo-facesNiO.< Class cy ? c.get%u"erclass-.< GbHect o ? null< try @ // 5e=uires !efault constructor3 o ? cy.ne:$nstance-.< // -B(B. A catch-$nstantiationE6ce"tion e. @ %yste#.err."rintln-8Cannot instantiate8.< thro: e< A catch-$llegal0ccessE6ce"tion e. @ %yste#.err."rintln-8Cannot access8.< thro: e< A "rint$nfo-o.getClass-..< A static voi! "rint$nfo-Class cc. @ %yste#.out."rintln8Class na#e3 8 K cc.get&a#e-. K 8 is interface[ N8 K cc.is$nterface-. K 8O8.< A A ///3>
/ou can see that class FancyToy is Auite co#%licated, since it inherits "ro# Toy and implements the interfaces o" Has2atteries, 0aterproof, and )hootsThings. In mainA B, a -lass re"erence is created and initiali1ed to the FancyToy -lass using for/ameA B inside an a%%ro%riate try block. RFSURFSTIJLT+(6PTE5MKTILMU The -lass!getInterfacesA B #ethod returns an array o" -lass ob0ects re%resenting the inter"aces that are contained in the -lass ob0ect o" interest. RFSURFSTIJLT+(6PTE5MKTILKU
8=2
Thinking in Java
,,,'0ruceEckel'com
I" you have a -lass ob0ect you can also ask it "or its direct base class using get)*perclassA B. This, o" course, returns a -lass re"erence that you can "urther Auery. This #eans that, at run'ti#e, you can discover an ob0ect s entire class hierarchy. RFSURFSTIJLT+(6PTE5MKTILLU The ne(InstanceA B #ethod o" -lass can, at "irst, see# like 0ust another way to cloneA B an ob0ect. (owever, you can create a new ob0ect with ne(InstanceA B ,ithout an e&isting ob0ect, as seen here, because there is no Toy ob0ect9only cy, which is a re"erence to y s -lass ob0ect. This is a way to i#%le#ent a !virtual constructor,$ which allows you to say !I don t know e&actly what ty%e you are, but create yoursel" %ro%erly anyway.$ In the e&a#%le above, cy is 0ust a -lass re"erence with no "urther ty%e in"or#ation known at co#%ile'ti#e. 6nd when you create a new instance, you get back an .b8ect reference. But that re"erence is %ointing to a Toy ob0ect. )" course, be"ore you can send any #essages other than those acce%ted by .b8ect, you have to investigate it a bit and do so#e casting. In addition, the class that s being created with ne(InstanceA B #ust have a de"ault constructor. In the ne&t section, you ll see how to dyna#ically create ob0ects o" classes using any constructor, with the Java re$lection 6PI. RFSURF STIJLT+(6PTE5MKTIL?U The "inal #ethod in the listing is printInfoA B, which takes a -lass re"erence and gets its na#e with get/ameA B, and "inds out whether it s an inter"ace with isInterfaceA B. RFSURFSTIJLT+(6PTE5MKTILHU The out%ut "ro# this %rogra# is=
LancyToy is interface[ NfalseO MasBatteries is interface[ NtrueO \ater"roof is interface[ NtrueO %hootsThings is interface[ NtrueO Toy is interface[ NfalseO
Thus, with the -lass ob0ect you can "ind out 0ust about everything you want to know about an ob0ect. RFSURFSTIJLT+(6PTE5MKTIL3U
8=3
8=4
Thinking in Java
,,,'0ruceEckel'com
6nother co#%elling #otivation "or discovering class in"or#ation at run' ti#e is to %rovide the ability to create and e&ecute ob0ects on re#ote %lat"or#s across a network. This is called -emote Method Invocation *5MI, and it allows a Java %rogra# to have ob0ects distributed across #any #achines. This distribution can ha%%en "or a nu#ber o" reasons= "or e&a#%le, %erha%s you re doing a co#%utation'intensive task and you want to break it u% and %ut %ieces on #achines that are idle in order to s%eed things u%. In so#e situations you #ight want to %lace code that handles %articular ty%es o" tasks *e.g., !Business 5ules$ in a #ultitier clientFserver architecture, on a %articular #achine, so that #achine beco#es a co##on re%ository describing those actions and it can be easily changed to a""ect everyone in the syste#. *This is an interesting develo%#ent, since the #achine e&ists solely to #ake so"tware changes easy., 6long these lines, distributed co#%uting also su%%orts s%eciali1ed hardware that #ight be good at a %articular task9#atri& inversions, "or e&a#%le9but ina%%ro%riate or too e&%ensive "or general %ur%ose %rogra##ing. RFSURFSTIJLT+(6PTE5MKTI?@U The class -lass *described %reviously in this cha%ter, su%%orts the conce%t o" re$lection, and there s an additional library, 8ava!lang! reflect, with classes Fiel', 1etho', and -onstr*ctor *each o" which i#%le#ent the 1ember interface,. )b0ects o" these ty%es are created by the JVM at run'ti#e to re%resent the corres%onding #e#ber in the unknown class. /ou can then use the -onstr*ctors to create new ob0ects, the getA B and setA B #ethods to read and #odi"y the "ields associated with Fiel' ob0ects, and the invokeA B #ethod to call a #ethod associated with a 1etho' ob0ect. In addition, you can call the convenience #ethods getFiel'sA B, get1etho'sA B, get-onstr*ctors A B, etc., to return arrays o" the ob0ects re%resenting the "ields, #ethods, and constructors. */ou can "ind out #ore by looking u% the class -lass in your online docu#entation., Thus, the class in"or#ation "or anony#ous ob0ects can be co#%letely deter#ined at run'ti#e, and nothing need be known at co#%ile'ti#e. RFSURFSTIJLT+(6PTE5MKTI?MU It s i#%ortant to reali1e that there s nothing #agic about re"lection. :hen you re using re"lection to interact with an ob0ect o" an unknown ty%e, the JVM will si#%ly look at the ob0ect and see that it belongs to a %articular class *0ust like ordinary 5TTI, but then, be"ore it can do anything else, the -lass ob0ect #ust be loaded. Thus, the !class "ile "or that %articular ty%e
8=5
#ust still be available to the JVM, either on the local #achine or across the network. So the true di""erence between 5TTI and re"lection is that with 5TTI, the co#%iler o%ens and e&a#ines the !class "ile at co#%ile' ti#e. Put another way, you can call all the #ethods o" an ob0ect in the !nor#al$ way. :ith re"lection, the !class "ile is unavailable at co#%ile' ti#e; it is o%ened and e&a#ined by the run'ti#e environ#ent. RFSURF STIJLT+(6PTE5MKTI?KU
//3 c( 3%ho:Jetho!s.Hava // Ysing reflection to sho: all the #etho!s of // a class, even if the #etho!s are !efine! in // the base class. i#"ort Hava.lang.reflect.B< "ublic class %ho:Jetho!s @ static final %tring usage ? 8usage3 _n8 K 8%ho:Jetho!s =ualifie!.class.na#e_n8 K 8To sho: all #etho!s in class or3 _n8 K 8%ho:Jetho!s =ualifie!.class.na#e :or!_n8 K 8To search for #etho!s involving 2:or!28< "ublic static voi! #ain-%tringNO args. @
@ Es%ecially in the %ast. (owever, Sun has greatly i#%roved its (TMD Java docu#entation
8=7
Thinking in Java
,,,'0ruceEckel'com
if-args.length P (. @ %yste#.out."rintln-usage.< %yste#.e6it-'.< A try @ Class c ? Class.for&a#e-argsN'O.< Jetho!NO # ? c.getJetho!s-.< ConstructorNO ctor ? c.getConstructors-.< if-args.length ?? (. @ for -int i ? '< i P #.length< iKK. %yste#.out."rintln-#NiO.< for -int i ? '< i P ctor.length< iKK. %yste#.out."rintln-ctorNiO.< A else @ for -int i ? '< i P #.length< iKK. if-#NiO.to%tring-. .in!e6Gf-argsN(O.4? -(. %yste#.out."rintln-#NiO.< for -int i ? '< i P ctor.length< iKK. if-ctorNiO.to%tring-. .in!e6Gf-argsN(O.4? -(. %yste#.out."rintln-ctorNiO.< A A catch-Class&otLoun!E6ce"tion e. @ %yste#.err."rintln-8&o such class3 8 K e.< A A A ///3>
The -lass #ethods get1etho'sA B and get-onstr*ctorsA B return an array o" 1etho' and -onstr*ctor, res%ectively. Each o" these classes has "urther #ethods to dissect the na#es, argu#ents, and return values o" the #ethods they re%resent. But you can also 0ust use to)tringA B, as is done here, to %roduce a )tring with the entire #ethod signature. The rest o" the code is 0ust "or e&tracting co##and line in"or#ation, deter#ining i" a %articular signature #atches with your target string *using in'e4.fA B,, and %rinting the results. RFSURF STIJLT+(6PTE5MKTI?LU This shows re"lection in action, since the result %roduced by -lass! for/ameA B cannot be known at co#%ile'ti#e, and there"ore all the
8=8
#ethod signature in"or#ation is being e&tracted at run'ti#e. I" you investigate your online docu#entation on re"lection, you ll see that there is enough su%%ort to actually set u% and #ake a #ethod call on an ob0ect that s totally unknown at co#%ile'ti#e *there will be e&a#%les o" this later in this book,. 6gain, this is so#ething you #ay never need to do yoursel"9the su%%ort is there "or 5MI and so a %rogra##ing environ#ent can #ani%ulate JavaBeans9but it s interesting. RFSURF STIJLT+(6PTE5MKTI??U 6n enlightening e&%eri#ent is to run
//3 co#3bruceeckel3util3%tri"/ualifiers.Hava "ackage co#.bruceeckel.util< i#"ort Hava.io.B< "ublic class %tri"/ualifiers @ "rivate %trea#TokeniUer st<
8=:
Thinking in Java
,,,'0ruceEckel'com
"ublic %tri"/ualifiers-%tring =ualifie!. @ st ? ne: %trea#TokeniUerne: %tring5ea!er-=ualifie!..< st.or!inaryChar-2 2.< // `ee" the s"aces A "ublic %tring get&e6t-. @ %tring s ? null< try @ int token ? st.ne6tToken-.< if-token 4? %trea#TokeniUer.TTbEGL. @ s:itch-st.tty"e. @ case %trea#TokeniUer.TTbEGL3 s ? null< break< case %trea#TokeniUer.TTb&YJBE53 s ? Double.to%tring-st.nval.< break< case %trea#TokeniUer.TTb\G5D3 s ? ne: %tring-st.sval.< break< !efault3 // single character in tty"e s ? %tring.valueGf--char.st.tty"e.< A A A catch-$GE6ce"tion e. @ %yste#.err."rintln-8Error fetching token8.< A return s< A "ublic static %tring stri"-%tring =ualifie!. @ %tri"/ualifiers s= ? ne: %tri"/ualifiers-=ualifie!.< %tring s ? 88, si< :hile--si ? s=.get&e6t-.. 4? null. @ int lastDot ? si.last$n!e6Gf-2.2.< if-lastDot 4? -(. si ? si.substring-lastDot K (.< s K? si< A return s< A
8=;
A ///3>
To "acilitate reuse, this class is %laced in com!br*ceeckel!*til. 6s you can see, this uses the )treamTokeni7er and )tring #ani%ulation to do its work. RFSURFSTIJLT+(6PTE5MKTI?3U The new version o" the %rogra# uses the above class to clean u% the out%ut=
//3 c( 3%ho:Jetho!sClean.Hava // %ho:Jetho!s :ith the =ualifiers stri""e! // to #ake the results easier to rea!. i#"ort Hava.lang.reflect.B< i#"ort co#.bruceeckel.util.B< "ublic class %ho:Jetho!sClean @ static final %tring usage ? 8usage3 _n8 K 8%ho:Jetho!sClean =ualifie!.class.na#e_n8 K 8To sho: all #etho!s in class or3 _n8 K 8%ho:Jetho!sClean =ualif.class.na#e :or!_n8 K 8To search for #etho!s involving 2:or!28< "ublic static voi! #ain-%tringNO args. @ if-args.length P (. @ %yste#.out."rintln-usage.< %yste#.e6it-'.< A try @ Class c ? Class.for&a#e-argsN'O.< Jetho!NO # ? c.getJetho!s-.< ConstructorNO ctor ? c.getConstructors-.< // Convert to an array of cleane! %trings3 %tringNO n ? ne: %tringN#.length K ctor.lengthO< for-int i ? '< i P #.length< iKK. @ %tring s ? #NiO.to%tring-.< nNiO ? %tri"/ualifiers.stri"-s.< A for-int i ? '< i P ctor.length< iKK. @ %tring s ? ctorNiO.to%tring-.< nNi K #.lengthO ? %tri"/ualifiers.stri"-s.<
81=
Thinking in Java
,,,'0ruceEckel'com
A if-args.length ?? (. for -int i ? '< i P n.length< iKK. %yste#.out."rintln-nNiO.< else for -int i ? '< i P n.length< iKK. if-nNiO.in!e6Gf-argsN(O.4? -(. %yste#.out."rintln-nNiO.< A catch-Class&otLoun!E6ce"tion e. @ %yste#.err."rintln-8&o such class3 8 K e.< A A A ///3>
The class )ho(1etho's-lean is Auite si#ilar to the %revious )ho(1etho's, e&ce%t that it takes the arrays o" 1etho' and -onstr*ctor and converts the# into a single array o" )tring. Each o" these )tring ob0ects is then %assed through )trip3*alifiers!)tripA B to re#ove all the #ethod Auali"ication. RFSURFSTIJLT+(6PTE5MKTI?GU This tool can be a real ti#e'saver while you re %rogra##ing, when you can t re#e#ber i" a class has a %articular #ethod and you don t want to go walking through the class hierarchy in the online docu#entation, or i" you don t know whether that class can do anything with, "or e&a#%le, -olor ob0ects. RFSURFSTIJLT+(6PTE5MKTI?IU +ha%ter ML contains a 84I version o" this %rogra# *custo#i1ed to e&tract in"or#ation "or Swing co#%onents, so you can leave it running while you re writing code, to allow Auick looku%s. RFSURF STIJLT+(6PTE5MKTI?2U
1ummar:
5TTI allows you to discover ty%e in"or#ation "ro# an anony#ous base' class re"erence. Thus, it s ri%e "or #isuse by the novice since it #ight #ake sense be"ore %oly#or%hic #ethod calls do. Eor #any %eo%le co#ing "ro# a %rocedural background, it s di""icult not to organi1e their %rogra#s into sets o" s(itch state#ents. They could acco#%lish this with 5TTI and thus lose the i#%ortant value o" %oly#or%his# in code
811
develo%#ent and #aintenance. The intent o" Java is that you use %oly#or%hic #ethod calls throughout your code, and you use 5TTI only when you #ust. RFSURFSTIJLT+(6PTE5MKTIH@U (owever, using %oly#or%hic #ethod calls as they are intended reAuires that you have control o" the base'class de"inition because at so#e %oint in the e&tension o" your %rogra# you #ight discover that the base class doesn t include the #ethod you need. I" the base class co#es "ro# a library or is otherwise controlled by so#eone else, a solution to the %roble# is 5TTI= /ou can inherit a new ty%e and add your e&tra #ethod. Elsewhere in the code you can detect your %articular ty%e and call that s%ecial #ethod. This doesn t destroy the %oly#or%his# and e&tensibility o" the %rogra# because adding a new ty%e will not reAuire you to hunt "or switch state#ents in your %rogra#. (owever, when you add new code in your #ain body that reAuires your new "eature, you #ust use 5TTI to detect your %articular ty%e. RFSURFSTIJLT+(6PTE5MKTIHMU Putting a "eature in a base class #ight #ean that, "or the bene"it o" one %articular class, all o" the other classes derived "ro# that base reAuire so#e #eaningless stub o" a #ethod. This #akes the inter"ace less clear and annoys those who #ust override abstract #ethods when they derive "ro# that base class. Eor e&a#%le, consider a class hierarchy re%resenting #usical instru#ents. Su%%ose you wanted to clear the s%it valves o" all the a%%ro%riate instru#ents in your orchestra. )ne o%tion is to %ut a clear)pitValveA B #ethod in the base class Instr*ment, but this is con"using because it i#%lies that #erc*ssion and &lectronic instru#ents also have s%it valves. 5TTI %rovides a #uch #ore reasonable solution in this case because you can %lace the #ethod in the s%eci"ic class * 0in' in this case,, where it s a%%ro%riate. (owever, a #ore a%%ro%riate solution is to %ut a prepareInstr*mentA B #ethod in the base class, but you #ight not see this when you re "irst solving the %roble# and could #istakenly assu#e that you #ust use 5TTI. RFSURF STIJLT+(6PTE5MKTIHKU Einally, 5TTI will so#eti#es solve e""iciency %roble#s. I" your code nicely uses %oly#or%his#, but it turns out that one o" your ob0ects reacts to this general %ur%ose code in a horribly ine""icient way, you can %ick out that ty%e using 5TTI and write case's%eci"ic code to i#%rove the e""iciency. Be wary, however, o" %rogra##ing "or e""iciency too soon. It s
812
Thinking in Java
,,,'0ruceEckel'com
a seductive tra%. It s best to get the %rogra# working $irst, then decide i" it s running "ast enough, and only then should you attack e""iciency issues 9with a %ro"iler. RFSURFSTIJLT+(6PTE5MKTIHLU
/0ercises
Solutions to selected e&ercises can be "ound in the electronic docu#entThe Thinking in Java "nnotated Solution @uide, available "or a s#all "ee "ro# ,,,'0ruceEckel'com.
!(7) :rite a #ethod that takes an ob0ect and recursively %rints all
the classes in that ob0ect s hierarchy. RFSURF STIJLT+(6PTE5MKTIH2U
813
!(+) +reate a new ty%e o" container that uses a private Array+ist
to hold the ob0ects. +a%ture the ty%e o" the "irst ob0ect you %ut in it, and then allow the user to insert ob0ects o" only that ty%e "ro# then on. RFSURFSTIJLT+(6PTE5MKTI3LU
814
Thinking in Java
,,,'0ruceEckel'com
class. Test your %rogra# with a standard library class and a class you create. RFSU
815
The original design goal o" the gra%hical user inter"ace *84I, library in Java M.@ was to allow the %rogra##er to build a 84I that looks good on all %lat"or#s. That goal was not achieved. Instead, the Java M.@ "bstract Bindo, Toolkit *6:T, %roduces a 84I that looks eAually #ediocre on all syste#s. In addition, it s restrictive= you can use only "our "onts and you cannot access any o" the #ore so%histicated 84I ele#ents that e&ist in your o%erating syste#. The Java M.@ 6:T %rogra##ing #odel is also awkward and non'ob0ect'oriented. 6 student in one o" #y se#inars *who had been at Sun during the creation o" Java, e&%lained why= the original 6:T had been conce%tuali1ed, designed, and i#%le#ented in a #onth. +ertainly a #arvel o" %roductivity, and also an ob0ect lesson in why design is i#%ortant. RFSURFSTIJLT+(6PTE5MLTIMU The situation i#%roved with the Java M.M 6:T event #odel, which takes a #uch clearer, ob0ect'oriented a%%roach, along with the addition o" JavaBeans, a co#%onent %rogra##ing #odel that is oriented toward the easy creation o" visual %rogra##ing environ#ents. Java K "inishes the trans"or#ation away "ro# the old Java M.@ 6:T by essentially re%lacing everything with the Java 9oundation Classes *JE+,, the 84I %ortion o" which is called !Swing.$ These are a rich set o" easy'to'use, easy'to' understand JavaBeans that can be dragged and dro%%ed *as well as hand
@ 6 variation on this is called !the %rinci%le o" least astonish#ent,$ which essentially says= !don t sur%rise the user.$
817
%rogra##ed, to create a 84I that you can *"inally, be satis"ied with. The !revision L$ rule o" the so"tware industry *a %roduct isn t good until revision L, see#s to hold true with %rogra##ing languages as well. RF SURFSTIJLT+(6PTE5MLTIKU This cha%ter does not cover anything but the #odern, Java K Swing library, and #akes the reasonable assu#%tion that Swing is the "inal destination 84I library "or Java. I" "or so#e reason you need to use the original !old$ 6:T *because you re su%%orting old code or you have browser li#itations,, you can "ind that introduction in the "irst edition o" this book, downloadable at ,,,'0ruceEckel'com *also included on the +7 5)M bound with this book,. RFSURFSTIJLT+(6PTE5MLTILU Early in this cha%ter, you ll see how things are di""erent when you want to create an a%%let vs. a regular a%%lication using Swing, and how to create %rogra#s that are both a%%lets and a%%lications so they can be run either inside a browser or "ro# the co##and line. 6l#ost all the 84I e&a#%les in this book will be e&ecutable as either a%%lets or a%%lications. RFSURF STIJLT+(6PTE5MLTI?U Please be aware that this is not a co#%rehensive glossary o" either all the Swing co#%onents, or all the #ethods "or the described classes. :hat you see here is intended to be si#%le. The Swing library is vast, and the goal o" this cha%ter is only to get you started with the essentials and co#"ortable with the conce%ts. I" you need to do #ore, then Swing can %robably give you what you want i" you re willing to do the research. RF SURFSTIJLT+(6PTE5MLTIHU I assu#e here that you have downloaded and installed the *"ree, Java library docu#ents in (TMD "or#at "ro# >ava'sun'com and will browse the 8ava4!s(ing classes in that docu#entation to see the "ull details and #ethods o" the Swing library. Because o" the si#%licity o" the Swing design, this will o"ten be enough in"or#ation to solve your %roble#. There are nu#erous *rather thick, books dedicated solely to Swing and you ll want to go to those i" you need #ore de%th, or i" you want to #odi"y the de"ault Swing behavior. RFSURFSTIJLT+(6PTE5MLTI3U 6s you learn about Swing you ll discover= RFSURF STIJLT+(6PTE5MLTIGU
lets
818
((,) !84I builders$ *visual %rogra##ing environ#ents, are a de rigueur as%ect o" a co#%lete Java develo%#ent environ#ent.
JavaBeans and Swing allow the 84I builder to write code "or you as you %lace co#%onents onto "or#s using gra%hical tools. This not only ra%idly s%eeds develo%#ent during 84I building, but it allows "or greater e&%eri#entation and thus the ability to try out #ore designs and %resu#ably co#e u% with a better one. RFSURF STIJLT+(6PTE5MLTI2U
((-) The si#%licity and well'designed nature o" Swing #eans that even
i" you do use a 84I builder rather than coding by hand, the resulting code will still be co#%rehensible9this solves a big %roble# with 84I builders "ro# the %ast, which could easily generate unreadable code. RFSURFSTIJLT+(6PTE5MLTIM@U Swing contains all the co#%onents that you e&%ect to see in a #odern 4I, everything "ro# buttons that contain %ictures to trees and tables. It s a big library, but it s designed to have a%%ro%riate co#%le&ity "or the task at hand9i" so#ething is si#%le, you don t have to write #uch code but as you try to do #ore co#%le& things, your code beco#es %ro%ortionally #ore co#%le&. This #eans an easy entry %oint, but you ve got the %ower i" you need it. RFSURFSTIJLT+(6PTE5MLTIMMU Much o" what you ll like about Swing could be called !orthogonality o" use.$ That is, once you %ick u% the general ideas about the library you can a%%ly the# everywhere. Pri#arily because o" the standard na#ing conventions, #uch o" the ti#e that I was writing these e&a#%les I could guess at the #ethod na#es and get it right the "irst ti#e, without looking anything u%. This is certainly the hall#ark o" a good library design. In addition, you can generally %lug co#%onents into other co#%onents and things will work correctly. RFSURFSTIJLT+(6PTE5MLTIMKU Eor s%eed, all the co#%onents are !lightweight,$ and Swing is written entirely in Java "or %ortability. RFSURFSTIJLT+(6PTE5MLTIMLU
81:
>eyboard navigation is auto#atic9you can run a Swing a%%lication without using the #ouse, and this doesn t reAuire any e&tra %rogra##ing. Scrolling su%%ort is e""ortless9you si#%ly wra% your co#%onent in a J)croll#ane as you add it to your "or#. Eeatures such as tool ti%s ty%ically reAuire a single line o" code to use. RFSURF STIJLT+(6PTE5MLTIM?U Swing also su%%orts a rather radical "eature called !%luggable look and "eel,$ which #eans that the a%%earance o" the 4I can be dyna#ically changed to suit the e&%ectations o" users working under di""erent %lat"or#s and o%erating syste#s. It s even %ossible *albeit di""icult, to invent your own look and "eel. RFSURFSTIJLT+(6PTE5MLTIMHU
A..let restrictions
Progra##ing within an a%%let is so restrictive that it s o"ten re"erred to as being !inside the sandbo&,$ since you always have so#eone9that is, the Java run'ti#e security syste#9watching over you. RFSURF STIJLT+(6PTE5MLTIMGU (owever, you can also ste% outside the sandbo& and write regular a%%lications rather than a%%lets, in which case you can access the other "eatures o" your )S. :e ve been writing regular a%%lications all along in this book, but they ve been console a lications without any gra%hical co#%onents. Swing can also be used to build 84I inter"aces "or regular a%%lications. RFSURFSTIJLT+(6PTE5MLTIMIU /ou can generally answer the Auestion o" what an a%%let is able to do by looking at what it is su osed to do= e&tend the "unctionality o" a :eb %age in a browser. Since, as a Cet sur"er, you never really know i" a :eb
lets
81;
%age is "ro# a "riendly %lace or not, you want any code that it runs to be sa"e. So the biggest restrictions you ll notice are %robably= RFSURF STIJLT+(6PTE5MLTIM2U
((4) "n a
let canJt touch the local disk. This #eans writing or reading,
since you wouldn t want an a%%let to read and trans#it %rivate in"or#ation over the Internet without your %er#ission. :riting is %revented, o" course, since that would be an o%en invitation to a virus. Java o""ers digital signing "or a%%lets. Many a%%let restrictions are rela&ed when you choose to allow trusted a lets *those signed by a trusted source, to have access to your #achine. RFSURFSTIJLT+(6PTE5MLTIK@U
((5) "
lets can take longer to dis la)D since you #ust download the whole thing every ti#e, including a se%arate server hit "or each di""erent class. /our browser can cache the a%%let, but there are no guarantees. Because o" this, you should always %ackage your a%%lets in a J65 *Java 65chive, "ile that co#bines all the a%%let co#%onents *including other !class "iles as well as i#ages and sounds, together into a single co#%ressed "ile that can be downloaded in a single server transaction. !7igital signing$ is available "or each individual entry in the J65 "ile. RFSURF STIJLT+(6PTE5MLTIKMU
A..let advantages
I" you can live within the restrictions, a%%lets have de"inite advantages, es%ecially when building clientFserver or other networked a%%lications= RFSURFSTIJLT+(6PTE5MLTIKKU
82=
(!7) Lou donJt have to ,orr) about bad code causing damage to someoneJs s)stemD because o" the security built into the core Java
language and a%%let structure. This, along with the %revious %oint, #akes Java %o%ular "or so'called intranet clientFserver a%%lications that live only within a co#%any or restricted arena o" o%eration where the user environ#ent *:eb browser and add'ins, can be s%eci"ied andFor controlled. RFSURF STIJLT+(6PTE5MLTIK?U Because a%%lets are auto#atically integrated with (TMD, you have a built'in %lat"or#'inde%endent docu#entation syste# to su%%ort the a%%let. It s an interesting twist, since we re used to having the docu#entation %art o" the %rogra# rather than vice versa. RFSURF STIJLT+(6PTE5MLTIKHU
A..lication frameworks
Dibraries are o"ten grou%ed according to their "unctionality. So#e libraries, "or e&a#%le, are used as is, o"" the shel". The standard Java library )tring and Array+ist classes are e&a#%les o" these. )ther libraries are designed s%eci"ically as building blocks to create other classes. 6 certain category o" library is the a lication $rame,ork, whose goal is to hel% you build a%%lications by %roviding a class or set o" classes that %roduces the basic behavior that you need in every a%%lication o" a %articular ty%e. Then, to custo#i1e the behavior to your own needs, you inherit "ro# the a%%lication class and override the #ethods o" interest. The a%%lication "ra#ework s de"ault control #echanis# will call your overridden #ethods at the a%%ro%riate ti#e. 6n a%%lication "ra#ework is a good e&a#%le o" !se%arating the things that change "ro# the things that stay the sa#e,$ since it atte#%ts to locali1e all the uniAue %arts o" a %rogra# in the overridden #ethods @. RFSURFSTIJLT+(6PTE5MLTIK3U 6%%lets are built using an a%%lication "ra#ework. /ou inherit "ro# class JApplet and override the a%%ro%riate #ethods. There are a "ew #ethods that control the creation and e&ecution o" an a%%let on a :eb %age=
@ This is an e&a#%le o" the design %attern called the tem late method.
lets
821
.peration
6uto#atically called to %er"or# "irst'ti#e initiali1ation o" the a%%let, including co#%onent layout. /ou ll always override this #ethod. +alled every ti#e the a%%let #oves into sight on the :eb browser to allow the a%%let to start u% its nor#al o%erations *es%ecially those that are shut o"" by stop A B,. 6lso called a"ter initA B. +alled every ti#e the a%%let #oves out o" sight on the :eb browser to allow the a%%let to shut o"" e&%ensive o%erations. 6lso called right be"ore 'estroyA B. +alled when the a%%let is being unloaded "ro# the %age to %er"or# "inal release o" resources when the a%%let is no longer used
stopA B 'estroy AB
//3 c()30""let(.Hava // Wery si#"le a""let. i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.B< "ublic class 0""let( e6ten!s J0""let @ "ublic voi! init-. @ getContentPane-..a!!-ne: JLabel-80""let48..< A A ///3>
Cote that a%%lets are not reAuired to have a mainA B. That s all wired into the a%%lication "ra#ework; you %ut any startu% code in initA B. RFSURF STIJLT+(6PTE5MLTIKGU In this %rogra#, the only activity is %utting a te&t label on the a%%let, via the J+abel class *the old 6:T a%%ro%riated the na#e +abel as well as other na#es o" co#%onents, so you will o"ten see a leading ! J$ used with Swing co#%onents,. The constructor "or this class takes a )tring and uses it to create the label. In the above %rogra# this label is %laced on the "or#. RFSURFSTIJLT+(6PTE5MLTIKIU The initA B #ethod is res%onsible "or %utting all the co#%onents on the "or# using the a''A B #ethod. /ou #ight think that you ought to be able
822
to si#%ly call a''A B by itsel", and in "act that s the way it used to be in the old 6:T. (owever, Swing reAuires you to add all co#%onents to the !content %ane$ o" a "or#, and so you #ust call get-ontent#aneA B as %art o" the a''A B %rocess. RFSURFSTIJLT+(6PTE5MLTIK2U
@ It is assu#ed that the reader is "a#iliar with the basics o" (TMD. It s not too hard to "igure out, and there are lots o" books and resources.
lets
823
//34 c()30""let(.ht#l Pht#lQPhea!QPtitleQ0""let(P/titleQP/hea!QPhrQ PGBJECT classi!?8clsi!310DCC1I'-'IIE-((D(-B)EC''1',LICCDC)8 :i!th?8(''8 height?8,'8 align?8baseline8 co!ebase?8htt"3//Hava.sun.co#/"ro!ucts/"lugin/(. . / Hinstall-(b b -:in.cabSWersion?(, , ,'8Q PP050J &0JE?8co!e8 W0LYE?80""let(.class8Q PP050J &0JE?8co!ebase8 W0LYE?8.8Q PP050J &0JE?8ty"e8 W0LYE?8a""lication/6-Hava-a""let< version?(. . 8Q PCGJJE&TQ PEJBED ty"e? 8a""lication/6-Hava-a""let<version?(. . 8 :i!th?8 ''8 height?8 ''8 align?8baseline8 co!e?80""let(.class8 co!ebase?8.8 "lugins"age?8htt"3//Hava.sun.co#/"ro!ucts/"lugin/(. / "lugin-install.ht#l8Q P&GEJBEDQ P/CGJJE&TQ &o Java su""ort for 0PPLET44 P/&GEJBEDQ P/EJBEDQ P/GBJECTQ PhrQP/bo!yQP/ht#lQ ///3>
So#e o" these lines were too long and had to be wra%%ed to "it on the %age. The code in this book s source code *on the book s +7 5)M, and downloadable "ro# ,,,'0ruceEckel'com, will work without having to worry about correcting line wra%s. RFSURFSTIJLT+(6PTE5MLTILKU The co'e value gives the na#e o" the !class "ile where the a%%let resides. The (i'th and height s%eci"y the initial si1e o" the a%%let *in %i&els, as be"ore,. There are other ite#s you can %lace within the a%%let tag= a %lace to "ind other !class "iles on the Internet * co'ebase,, align#ent in"or#ation * align,, a s%ecial identi"ier that #akes it %ossible "or a%%lets
@ This %age9in %articular, the [clsid %ortion9see#ed to work "ine with both J7>M.K.K and J7>M.L rc'M. (owever, you #ay "ind that you have to change the tag so#eti#e in the "uture. 7etails can be "ound at >ava'sun'com.
824
to co##unicate with each other * name,, and a%%let %ara#eters to %rovide in"or#ation that the a%%let can retrieve. Para#eters are in the "or#=
Csing Appletviewer
Sun s J7> *"reely downloadable "ro# >ava'sun'com, contains a tool called the " letvie,er that %icks the NappletO tags out o" the (TMD "ile and runs the a%%lets without dis%laying the surrounding (TMD te&t. Because the 6%%letviewer ignores everything but 6PPDET tags, you can %ut those tags in the Java source "ile as co##ents=
//3 c()30""let(b.Hava // E#be!!ing the a""let tag for 0""letvie:er. // Pa""let co!e?0""let(b :i!th?('' height?,'Q // P/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.B< "ublic class 0""let(b e6ten!s J0""let @ "ublic voi! init-. @ getContentPane-..a!!-ne: JLabel-80""let48..< A A ///3>
Cow you can invoke the a%%let with the co##and
lets
825
a""letvie:er 0""let(b.Hava
In this book, this "or# will be used "or easy testing o" a%%lets. Shortly, you ll see another coding a%%roach which will allow you to e&ecute a%%lets "ro# the co##and line without the 6%%letviewer. RFSURF STIJLT+(6PTE5MLTILHU
#esting a..lets
/ou can %er"or# a si#%le test without any network connection by starting u% your :eb browser and o%ening the (TMD "ile containing the a%%let tag. 6s the (TMD "ile is loaded, the browser will discover the a%%let tag and go hunt "or the !class "ile s%eci"ied by the co'e value. )" course, it looks at the +D6SSP6T( to "ind out where to hunt, and i" your ! class "ile isn t in the +D6SSP6T( then it will give an error #essage on the status line o" the browser to the e""ect that it couldn t "ind that !class "ile. RFSURFSTIJLT+(6PTE5MLTIL3U :hen you want to try this out on your :eb site things are a little #ore co#%licated. Eirst o" all, you #ust have a :eb site, which "or #ost %eo%le #eans a third'%arty Internet Service Provider *ISP, at a re#ote location. Since the a%%let is 0ust a "ile or set o" "iles, the ISP does not have to %rovide any s%ecial su%%ort "or Java. /ou #ust also have a way to #ove the (TMD "iles and the !class "iles "ro# your site to the correct directory on the ISP #achine. This is ty%ically done with a Eile Trans"er Protocol *ETP, %rogra#, o" which there are #any di""erent ty%es available "or "ree or as shareware. So it would see# that all you need to do is #ove the "iles to the ISP #achine with ETP, then connect to the site and (TMD "ile using your browser; i" the a%%let co#es u% and works, then everything checks out, rightO RFSURFSTIJLT+(6PTE5MLTILGU (ere s where you can get "ooled. I" the browser on the client #achine cannot locate the !class "ile on the server, it will hunt through the +D6SSP6T( on your local #achine. Thus, the a%%let #ight not be loading %ro%erly "ro# the server, but to you it looks "ine during your testing %rocess because the browser "inds it on your #achine. :hen so#eone else connects, however, his or her browser can t "ind it. So when you re testing, #ake sure you erase the relevant !class "iles *or !8ar "ile,
827
on your local #achine to veri"y that they e&ist in the %ro%er location on the server. RFSURFSTIJLT+(6PTE5MLTILIU )ne o" the #ost insidious %laces where this ha%%ened to #e is when I innocently %laced an a%%let inside a package. 6"ter u%loading the (TMD "ile and a%%let, it turned out that the server %ath to the a%%let was con"used because o" the %ackage na#e. (owever, #y browser "ound it in the local +D6SSP6T(. So I was the only one who could %ro%erly load the a%%let. It took so#e ti#e to discover that the package state#ent was the cul%rit. In general, you ll want to leave the package state#ent out o" an a%%let. RFSURFSTIJLT+(6PTE5MLTIL2U
@ In #y o%inion. 6nd a"ter you learn about Swing, you won t want to waste your ti#e on the earlier stu"".
lets
828
)"ten you ll want to be able to create a class that can be invoked as either a window or an a%%let. This is es%ecially convenient when you re testing the a%%lets, since it s ty%ically #uch "aster and easier to run the resulting a%%let'a%%lication "ro# the co##and line than it is to start u% a :eb browser or the 6%%letviewer. RFSURFSTIJLT+(6PTE5MLTI?KU To create an a%%let that can be run "ro# the console co##and line, you si#%ly add a mainA B to your a%%let that builds an instance o" the a%%let inside a JFrame.D 6s a si#%le e&a#%le, let s look at Applet>b!8ava #odi"ied to work as both an a%%lication and an a%%let=
//3 c()30""let(c.Hava // 0n a""lication an! an a""let. // Pa""let co!e?0""let(c :i!th?('' height?,'Q // P/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.B< i#"ort co#.bruceeckel.s:ing.B< "ublic class 0""let(c e6ten!s J0""let @ "ublic voi! init-. @ getContentPane-..a!!-ne: JLabel-80""let48..< A // 0 #ain-. for the a""lication3 "ublic static voi! #ain-%tringNO args. @ J0""let a""let ? ne: 0""let(c-.< JLra#e fra#e ? ne: JLra#e-80""let(c8.< // To close the a""lication3 Console.setu"Closing-fra#e.< fra#e.getContentPane-..a!!-a""let.< fra#e.set%iUe-('',,'.< a""let.init-.< a""let.start-.< fra#e.setWisible-true.< A A ///3> mainA B is the only ele#ent added to the a%%let, and the rest o" the a%%let is untouched. The a%%let is created and added to a JFrame so that it can be dis%layed. RFSURFSTIJLT+(6PTE5MLTI?LU
@ 6s described earlier, !Era#e$ was already taken by the 6:T, so Swing uses JEra#e.
82:
The line=
Console.setu"Closing-fra#e.<
+auses the window to be %ro%erly closed. -onsole co#es "ro# com! br*ceeckel!s(ing and will be e&%lained a little later. RFSURF STIJLT+(6PTE5MLTI??U /ou can see that in mainA B, the a%%let is e&%licitly initiali1ed and started since in this case the browser isn t available to do it "or you. )" course, this doesn t %rovide the "ull behavior o" the browser, which also calls stop A B and 'estroyA B, but "or #ost situations it s acce%table. I" it s a %roble#, you can "orce the calls yoursel". @ RFSURF STIJLT+(6PTE5MLTI?HU Cotice the last line=
fra#e.setWisible-true.<
:ithout this, you won t see anything on the screen. RFSURF STIJLT+(6PTE5MLTI?3U
A dis.la: framework
6lthough the code that turns %rogra#s into both a%%lets and a%%lications %roduces valuable results, i" used everywhere it beco#es distracting and wastes %a%er. Instead, the "ollowing dis%lay "ra#ework will be used "or the Swing e&a#%les in the rest o" this book=
//3 co#3bruceeckel3s:ing3Console.Hava // Tool for running %:ing !e#os fro# the // console, both a""lets an! JLra#es. "ackage co#.bruceeckel.s:ing< i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.event.B< "ublic class Console @ // Create a title string fro# the class na#e3
@ This will #ake sense a"ter you ve read "urther in this cha%ter. Eirst, #ake the re"erence
JApplet a static #e#ber o" the class *instead o" a local variable o" mainA B,, and then call applet!stopA B and applet!'estroyA B inside 0in'o(A'apter!(in'o(-losing A B be"ore you call )ystem!e4itA B.
lets
82;
"ublic static %tring title-GbHect o. @ %tring t ? o.getClass-..to%tring-.< // 5e#ove the :or! 8class83 if-t.in!e6Gf-8class8. 4? -(. t ? t.substring-+.< return t< A "ublic static voi! setu"Closing-JLra#e fra#e. @ // The JD` (. %olution as an // anony#ous inner class3 fra#e.a!!\in!o:Listener-ne: \in!o:0!a"ter-. @ "ublic voi! :in!o:Closing-\in!o:Event e. @ %yste#.e6it-'.< A A.< // The i#"rove! solution in JD` (.)3 // fra#e.setDefaultCloseG"eration// E9$TbG&bCLG%E.< A "ublic static voi! run-JLra#e fra#e, int :i!th, int height. @ setu"Closing-fra#e.< fra#e.set%iUe-:i!th, height.< fra#e.setWisible-true.< A "ublic static voi! run-J0""let a""let, int :i!th, int height. @ JLra#e fra#e ? ne: JLra#e-title-a""let..< setu"Closing-fra#e.< fra#e.getContentPane-..a!!-a""let.< fra#e.set%iUe-:i!th, height.< a""let.init-.< a""let.start-.< fra#e.setWisible-true.< A "ublic static voi! run-JPanel "anel, int :i!th, int height. @ JLra#e fra#e ? ne: JLra#e-title-"anel..< setu"Closing-fra#e.< fra#e.getContentPane-..a!!-"anel.< fra#e.set%iUe-:i!th, height.<
83=
fra#e.setWisible-true.< A A ///3>
This is a tool you #ay want to use yoursel", so it s %laced in the library com!br*ceeckel!s(ing. The -onsole class consists entirely o" static #ethods. The "irst is used to e&tract the class na#e *using 5TTI, "ro# any ob0ect and to re#ove the word !class,$ which is ty%ically %re%ended by get-lassA B. This uses the )tring #ethods in'e4.fA B to deter#ine whether the word !class$ is there, and s*bstringA B to %roduce the new string without !class$ or the trailing s%ace. This na#e is used to label the window that is dis%layed by the r*nA B #ethods. RFSURF STIJLT+(6PTE5MLTI?GU
set*p-losingA B is used to hide the code that causes a JFrame to e&it a %rogra# when that JFrame is closed. The de"ault behavior is to do nothing, so i" you don t call set*p-losingA B or write the eAuivalent code "or your JFrame, the a%%lication won t close. The reason this code is hidden rather than %lacing it directly in the subseAuent r*nA B #ethods is %artly because it allows you to use the #ethod by itsel" when what you want to do is #ore co#%licated than what r*nA B %rovides. (owever, it also isolates a change "actor= Java K has two ways o" causing certain ty%es o" windows to close. In J7> M.K, the solution is to create a new 0in'o(A'apter class and i#%le#ent (in'o(-losingA B, as seen above *the #eaning o" this will be "ully e&%lained later in this cha%ter,. (owever, during the creation o" J7> M.L the library designers observed that you ty%ically need to close windows whenever you re creating a non' a%%let, and so they added the set efa*lt-lose.perationA B to JFrame and J ialog. Ero# the stand%oint o" writing code, the new #ethod is #uch nicer to use but this book was written while there was still no J7> M.L i#%le#ented on Dinu& and other %lat"or#s, so in the interest o" cross'version %ortability the change was isolated inside set*p-losingA B. RFSURFSTIJLT+(6PTE5MLTI?IU
The r*nA B #ethod is overloaded to work with JApplets, J#anels, and JFrames. Cote that only i" it s a JApplet are initA B and startA B called. RFSURFSTIJLT+(6PTE5MLTI?2U Cow any a%%let can be run "ro# the console by creating a mainA B containing a line like this=
lets
831
Applet>c!8ava #odi"ied to use -onsole= //3 c()30""let(!.Hava // Console runs a""lets fro# the co##an! line. // Pa""let co!e?0""let(! :i!th?('' height?,'Q // P/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.B< i#"ort co#.bruceeckel.s:ing.B< "ublic class 0""let(! e6ten!s J0""let @ "ublic voi! init-. @ getContentPane-..a!!-ne: JLabel-80""let48..< A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: 0""let(!-., ('', ,'.< A A ///3>
This allows the eli#ination o" re%eated code while %roviding the greatest "le&ibility in running the e&a#%les. RFSURFSTIJLT+(6PTE5MLTIH@U
832
Recho off "erl -6 -% 8V'8 V( V V) VI V, V+ V* V1 VC goto en!of"erl Rre# 2< S4"erl cfile ? c05aWN'O< cfile ?> s/-.B._..B/_(/< cfile ?> s/-.B__.B-.B./cK/< dHava cfiled< bbE&Dbb 3en!of"erl ///3>
Cow, o%en the :indows E&%lorer, select !View,$ !Eolder )%tions,$ then click on the !Eile Ty%es$ tab. Press the !Cew Ty%e$ button. Eor !7escri%tion o" Ty%e$ enter !Java class "ile.$ Eor !6ssociated E&tension,$ enter !class.$ 4nder !6ctions$ %ress the !Cew$ button. Eor !6ction$ enter !)%en,$ and "or !6%%lication used to %er"or# action$ enter a line like this=
8c3_aaa_Perl_5unJava.bat8 8VL8
/ou #ust custo#i1e the %ath be"ore !5unJava.bat$ to con"or# to the location where you %laced the batch "ile. RFSURF STIJLT+(6PTE5MLTIHLU )nce you %er"or# this installation, you #ay run any Java %rogra# by si#%ly double'clicking on the !class "ile containing a mainA B. RFSURF STIJLT+(6PTE5MLTIH?U
Making a button
Making a button is Auite si#%le= you 0ust call the J2*tton constructor with the label you want on the button. /ou ll see later that you can do "ancier things, like %utting gra%hic i#ages on buttons. RFSURF STIJLT+(6PTE5MLTIHHU 4sually you ll want to create a "ield "or the button inside your class so that you can re"er to it later. RFSURFSTIJLT+(6PTE5MLTIH3U The J2*tton is a co#%onent9its own little window9that will auto#atically get re%ainted as %art o" an u%date. This #eans that you
lets
833
don t e&%licitly %aint a button or any other kind o" control; you si#%ly %lace the# on the "or# and let the# auto#atically take care o" %ainting the#selves. So to %lace a button on a "or#, you do it inside initA B=
//3 c()3Button(.Hava // Putting buttons on an a""let. // Pa""let co!e?Button( :i!th? '' height?,'Q // P/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.B< i#"ort co#.bruceeckel.s:ing.B< "ublic class Button( e6ten!s J0""let @ JButton b( ? ne: JButton-8Button (8., b ? ne: JButton-8Button 8.< "ublic voi! init-. @ Container c" ? getContentPane-.< c".setLayout-ne: Llo:Layout-..< c".a!!-b(.< c".a!!-b .< A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: Button(-., '', ,'.< A A ///3>
So#ething new has been added here= be"ore any ele#ents are %laced on the content %ane, it is given a new !layout #anager,$ o" ty%e Flo(+ayo*t. The layout #anager is the way that the %ane i#%licitly decides where to %lace the control on the "or#. The nor#al behavior o" an a%%let is to use the 2or'er+ayo*t, but that won t work here because *as you will learn later in this cha%ter when controlling the layout o" a "or# is e&a#ined in #ore detail, it de"aults to covering each control entirely with every new one that is added. (owever, Flo(+ayo*t causes the controls to "low evenly onto the "or#, le"t to right and to% to botto#. RFSURF STIJLT+(6PTE5MLTIHGU
834
Ca.turing an event
/ou ll notice that i" you co#%ile and run the a%%let above, nothing ha%%ens when you %ress the buttons. This is where you #ust ste% in and write so#e code to deter#ine what will ha%%en. The basis o" event'driven %rogra##ing, which co#%rises a lot o" what a 84I is about, is tying events to code that res%onds to those events. RFSURF STIJLT+(6PTE5MLTIHIU The way that this is acco#%lished in Swing is by cleanly se%arating the inter"ace *the gra%hical co#%onents, and the i#%le#entation *the code that you want to run when an event ha%%ens to a co#%onent,. Each Swing co#%onent can re%ort all the events that #ight ha%%en to it, and it can re%ort each kind o" event individually. So i" you re not interested in, "or e&a#%le, whether the #ouse is being #oved over your button, you don t register your interest in that event. It s a very straight"orward and elegant way to handle event'driven %rogra##ing, and once you understand the basic conce%ts you can easily use Swing co#%onents that you haven t seen be"ore9in "act, this #odel e&tends to anything that can be classi"ied as a JavaBean *which you ll learn about later in the cha%ter,. RFSURFSTIJLT+(6PTE5MLTIH2U 6t "irst, we will 0ust "ocus on the #ain event o" interest "or the co#%onents being used. In the case o" a J2*tton, this !event o" interest$ is that the button is %ressed. To register your interest in when a button is %ressed, you call the J2*tton s a''Action+istenerA B #ethod. This #ethod e&%ects an argu#ent that is an ob0ect that i#%le#ents the Action+istener inter"ace, which contains a single #ethod called action#erforme'A B. So all you have to do to attach code to a J2*tton is to i#%le#ent the Action+istener inter"ace in a class, and register an ob0ect o" that class with the J2*tton via a''Action+istenerA B. The #ethod will be called when the button is %ressed *this is nor#ally re"erred to as a callback,. RFSURFSTIJLT+(6PTE5MLTI3@U But what should the result o" %ressing that button beO :e d like to see so#ething change on the screen, so a new Swing co#%onent will be introduced= the JTe4tFiel'. This is a %lace where te&t can be ty%ed, or in this case #odi"ied by the %rogra#. 6lthough there are a nu#ber o" ways
lets
835
to create a JTe4tFiel', the si#%lest is 0ust to tell the constructor how wide you want that "ield to be. )nce the JTe4tFiel' is %laced on the "or#, you can #odi"y its contents by using the setTe4tA B #ethod *there are #any other #ethods in JTe4tFiel', but you #ust look these u% in the (TMD docu#entation "or the J7> "ro# >ava'sun'com,. (ere is what it looks like=
//3 c()3Button .Hava // 5es"on!ing to button "resses. // Pa""let co!e?Button :i!th? '' height?*,Q // P/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.event.B< i#"ort Hava.a:t.B< i#"ort co#.bruceeckel.s:ing.B< "ublic class Button e6ten!s J0""let @ JButton b( ? ne: JButton-8Button (8., b ? ne: JButton-8Button 8.< JTe6tLiel! t6t ? ne: JTe6tLiel!-('.< class BL i#"le#ents 0ctionListener @ "ublic voi! actionPerfor#e!-0ctionEvent e.@ %tring na#e ? --JButton.e.get%ource-...getTe6t-.< t6t.setTe6t-na#e.< A A BL al ? ne: BL-.< "ublic voi! init-. @ b(.a!!0ctionListener-al.< b .a!!0ctionListener-al.< Container c" ? getContentPane-.< c".setLayout-ne: Llo:Layout-..< c".a!!-b(.< c".a!!-b .< c".a!!-t6t.< A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: Button -., '', *,.< A
837
A ///3>
+reating a JTe4tFiel' and %lacing it on the canvas takes the sa#e ste%s as "or J2*ttons, or "or any Swing co#%onent. The di""erence in the above %rogra# is in the creation o" the a"ore#entioned Action+istener class 2+. The argu#ent to action#erforme'A B is o" ty%e Action&vent, which contains all the in"or#ation about the event and where it ca#e "ro#. In this case, I wanted to describe the button that was %ressed= get)o*rceA B %roduces the ob0ect where the event originated, and I assu#ed that is a J2*tton. getTe4tA B returns the te&t that s on the button, and this is %laced in the JTe4tFiel' to %rove that the code was actually called when the button was %ressed. RFSURF STIJLT+(6PTE5MLTI3MU In initA B, a''Action+istenerA B is used to register the 2+ ob0ect with both the buttons. RFSURFSTIJLT+(6PTE5MLTI3KU It is o"ten #ore convenient to code the Action+istener as an anony#ous inner class, es%ecially since you tend to only use a single instance o" each listener class. 2*ttonI!8ava can be #odi"ied to use an anony#ous inner class as "ollows= RFSURFSTIJLT+(6PTE5MLTI3LU
//3 c()3Button b.Hava // Ysing anony#ous inner classes. // Pa""let co!e?Button b :i!th? '' height?*,Q // P/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.event.B< i#"ort Hava.a:t.B< i#"ort co#.bruceeckel.s:ing.B< "ublic class Button b e6ten!s J0""let @ JButton b( ? ne: JButton-8Button (8., b ? ne: JButton-8Button 8.< JTe6tLiel! t6t ? ne: JTe6tLiel!-('.< 0ctionListener al ? ne: 0ctionListener-. @ "ublic voi! actionPerfor#e!-0ctionEvent e.@ %tring na#e ? --JButton.e.get%ource-...getTe6t-.< t6t.setTe6t-na#e.<
lets
838
A A< "ublic voi! init-. @ b(.a!!0ctionListener-al.< b .a!!0ctionListener-al.< Container c" ? getContentPane-.< c".setLayout-ne: Llo:Layout-..< c".a!!-b(.< c".a!!-b .< c".a!!-t6t.< A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: Button b-., '', *,.< A A ///3>
The a%%roach o" using an anony#ous inner class will be %re"erred *when %ossible, "or the e&a#%les in this book. RFSURF STIJLT+(6PTE5MLTI3?U
#e0t areas
6 JTe4tArea is like a JTe4tFiel' e&ce%t that it can have #ulti%le lines and has #ore "unctionality. 6 %articularly use"ul #ethod is appen'A B; with this you can easily %our out%ut into the JTe4tArea, thus #aking a Swing %rogra# an i#%rove#ent *since you can scroll backward, over what has been acco#%lished thus "ar using co##and'line %rogra#s that %rint to standard out%ut. 6s an e&a#%le, the "ollowing %rogra# "ills a JTe4tArea with the out%ut "ro# the geography generator in +ha%ter 2=
//3 c()3Te6t0rea.Hava // Ysing the JTe6t0rea control. // Pa""let co!e?Te6t0rea :i!th?I*, height?I ,Q // P/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.event.B< i#"ort Hava.a:t.B< i#"ort Hava.util.B< i#"ort co#.bruceeckel.s:ing.B< i#"ort co#.bruceeckel.util.B<
83:
"ublic class Te6t0rea e6ten!s J0""let @ JButton b ? ne: JButton-80!! Data8., c ? ne: JButton-8Clear Data8.< JTe6t0rea t ? ne: JTe6t0rea- ', I'.< Ja" # ? ne: MashJa"-.< "ublic voi! init-. @ // Yse u" all the !ata3 Collections .fill-#, Collections .geogra"hy, CountryCa"itals."airs.length.< b.a!!0ctionListener-ne: 0ctionListener-. @ "ublic voi! actionPerfor#e!-0ctionEvent e.@ for-$terator it? #.entry%et-..iterator-.< it.has&e6t-.<.@ Ja".Entry #e ? -Ja".Entry.-it.ne6t-..< t.a""en!-#e.get`ey-. K 83 8 K #e.getWalue-. K 8_n8.< A A A.< c.a!!0ctionListener-ne: 0ctionListener-. @ "ublic voi! actionPerfor#e!-0ctionEvent e.@ t.setTe6t-88.< A A.< Container c" ? getContentPane-.< c".setLayout-ne: Llo:Layout-..< c".a!!-ne: J%crollPane-t..< c".a!!-b.< c".a!!-c.< A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: Te6t0rea-., I*,, I ,.< A A ///3>
In initA B, the 1ap is "illed with all the countries and their ca%itals. Cote that "or both buttons the Action+istener is created and added without de"ining an inter#ediate variable, since you never need to re"er to that
lets
83;
listener again during the %rogra#. The !6dd 7ata$ button "or#ats and a%%ends all the data, while the !+lear 7ata$ button uses setTe4tA B to re#ove all the te&t "ro# the JTe4tArea. RFSURF STIJLT+(6PTE5MLTI3HU 6s the JTe4tArea is added to the a%%let, it is wra%%ed in a J)croll#ane, to control scrolling when too #uch te&t is %laced on the screen. That s all you #ust do in order to %roduce "ull scrolling ca%abilities. (aving tried to "igure out how to do the eAuivalent in so#e other 84I %rogra##ing environ#ents, I a# very i#%ressed with the si#%licity and good design o" co#%onents like J)croll#ane. RFSURF STIJLT+(6PTE5MLTI33U
Controlling la:out
The way that you %lace co#%onents on a "or# in Java is %robably di""erent "ro# any other 84I syste# you ve used. Eirst, it s all code; there are no !resources$ that control %lace#ent o" co#%onents. Second, the way co#%onents are %laced on a "or# is controlled not by absolute %ositioning but by a !layout #anager$ that decides how the co#%onents lie based on the order that you a''A B the#. The si1e, sha%e, and %lace#ent o" co#%onents will be re#arkably di""erent "ro# one layout #anager to another. In addition, the layout #anagers ada%t to the di#ensions o" your a%%let or a%%lication window, so i" the window di#ension is changed, the si1e, sha%e, and %lace#ent o" the co#%onents can change in res%onse. RFSURFSTIJLT+(6PTE5MLTI3GU
JApplet, JFrame J0in'o(, and J ialog can all %roduce a -ontainer with get-ontent#aneA B that can contain and dis%lay -omponents. In -ontainer, there s a #ethod called set+ayo*tA B that
allows you to choose a di""erent layout #anager. )ther classes, such as J#anel, contain and dis%lay co#%onents directly and so you also set the layout #anager directly, without using the content %ane. RFSURF STIJLT+(6PTE5MLTI3IU In this section we ll e&%lore the various layout #anagers by %lacing buttons in the# *since that s the si#%lest thing to do,. There won t be any
84=
ca%turing o" button events since these e&a#%les are 0ust intended to show how the buttons are laid out. RFSURFSTIJLT+(6PTE5MLTI32U
;order&a:out
The a%%let uses a de"ault layout sche#e= the 2or'er+ayo*t *a nu#ber o" the %revious e&a#%le have changed the layout #anager to Flo(+ayo*t,. :ithout any other instruction, this takes whatever you a''A B to it and %laces it in the center, stretching the ob0ect all the way out to the edges. RFSURFSTIJLT+(6PTE5MLTIG@U (owever, there s #ore to the 2or'er+ayo*t. This layout #anager has the conce%t o" "our border regions and a center area. :hen you add so#ething to a %anel that s using a 2or'er+ayo*t you can use the overloaded a''A B #ethod that takes a constant value as its "irst argu#ent. This value can be any o" the "ollowing=
2or'er+ayo*t! /.$TH *to%, 2or'er+ayo*t! ).UTH *botto#, 2or'er+ayo*t! &A)T *right, 2or'er+ayo*t! 0&)T *le"t, 2or'er+ayo*t!-&/T&$ *"ill the #iddle, u% to the other
co#%onents or to the edges, RFSURFSTIJLT+(6PTE5MLTIGMU I" you don t s%eci"y an area to %lace the ob0ect, it de"aults to -&/T&$. RF SURFSTIJLT+(6PTE5MLTIGKU (ere s a si#%le e&a#%le. The de"ault layout is used, since JApplet de"aults to 2or'er+ayo*t=
//3 c()3Bor!erLayout(.Hava // De#onstrates Bor!erLayout. // Pa""let co!e?Bor!erLayout( // :i!th?)'' height? ,'Q P/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.B< i#"ort co#.bruceeckel.s:ing.B< "ublic class Bor!erLayout( e6ten!s J0""let @ "ublic voi! init-. @ Container c" ? getContentPane-.<
lets
841
c".a!!-Bor!erLayout.&G5TM, ne: JButton-8&orth8..< c".a!!-Bor!erLayout.%GYTM, ne: JButton-8%outh8..< c".a!!-Bor!erLayout.E0%T, ne: JButton-8East8..< c".a!!-Bor!erLayout.\E%T, ne: JButton-8\est8..< c".a!!-Bor!erLayout.CE&TE5, ne: JButton-8Center8..< A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: Bor!erLayout(-., )'', ,'.< A A ///3>
Eor every %lace#ent but -&/T&$, the ele#ent that you add is co#%ressed to "it in the s#allest a#ount o" s%ace along one di#ension while it is stretched to the #a&i#u# along the other di#ension. -&/T&$, however, s%reads out in both di#ensions to occu%y the #iddle. RFSURFSTIJLT+(6PTE5MLTIGLU
<low&a:out
This si#%ly !"lows$ the co#%onents onto the "or#, "ro# le"t to right until the to% s%ace is "ull, then #oves down a row and continues "lowing. RF SURFSTIJLT+(6PTE5MLTIG?U (ere s an e&a#%le that sets the layout #anager to Flo(+ayo*t and then %laces buttons on the "or#. /ou ll notice that with Flo(+ayo*t the co#%onents take on their !natural$ si1e. 6 J2*tton, "or e&a#%le, will be the si1e o" its string. RFSURFSTIJLT+(6PTE5MLTIGHU
//3 c()3Llo:Layout(.Hava // De#onstrates Llo:Layout. // Pa""let co!e?Llo:Layout( // :i!th?)'' height? ,'Q P/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.B< i#"ort co#.bruceeckel.s:ing.B<
842
"ublic class Llo:Layout( e6ten!s J0""let @ "ublic voi! init-. @ Container c" ? getContentPane-.< c".setLayout-ne: Llo:Layout-..< for-int i ? '< i P '< iKK. c".a!!-ne: JButton-8Button 8 K i..< A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: Llo:Layout(-., )'', ,'.< A A ///3>
6ll co#%onents will be co#%acted to their s#allest si1e in a Flo(+ayo*t, so you #ight get a little bit o" sur%rising behavior. Eor e&a#%le, because a J+abel will be the si1e o" its string, atte#%ting to right'0usti"y its te&t yields an unchanged dis%lay when using Flo(+ayo*t. RFSURFSTIJLT+(6PTE5MLTIG3U
'rid&a:out
6 "ri'+ayo*t allows you to build a table o" co#%onents, and as you add the# they are %laced le"t'to'right and to%'to'botto# in the grid. In the constructor you s%eci"y the nu#ber o" rows and colu#ns that you need and these are laid out in eAual %ro%ortions. RFSURF STIJLT+(6PTE5MLTIGGU
//3 c()3ari!Layout(.Hava // De#onstrates ari!Layout. // Pa""let co!e?ari!Layout( // :i!th?)'' height? ,'Q P/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.B< i#"ort co#.bruceeckel.s:ing.B< "ublic class ari!Layout( e6ten!s J0""let @ "ublic voi! init-. @ Container c" ? getContentPane-.< c".setLayout-ne: ari!Layout-*,)..< for-int i ? '< i P '< iKK. c".a!!-ne: JButton-8Button 8 K i..< A
lets
843
"ublic static voi! #ain-%tringNO args. @ Console.run-ne: ari!Layout(-., )'', ,'.< A A ///3>
In this case there are KM slots but only K@ buttons. The last slot is le"t e#%ty because no !balancing$ goes on with a "ri'+ayo*t. RFSURF STIJLT+(6PTE5MLTIGIU
'rid;ag&a:out
The "ri'2ag+ayo*t %rovides you with tre#endous control in deciding e&actly how the regions o" your window will lay the#selves out and re"or#at the#selves when the window is resi1ed. (owever, it s also the #ost co#%licated layout #anager, and Auite di""icult to understand. It is intended %ri#arily "or auto#atic code generation by a 84I builder *good 84I builders will use "ri'2ag+ayo*t instead o" absolute %lace#ent,. I" your design is so co#%licated that you "eel you need to use "ri'2ag+ayo*t, then you should be using a 84I builder tool to generate that design. I" you "eel you #ust know the intricate details, I ll re"er you to Core Java 2 by (orst#ann N +ornell *Prentice'(all, M222,, or a dedicated Swing book, as a starting %oint. RFSURF STIJLT+(6PTE5MLTIG2U
Absolute .ositioning
It is also %ossible to set the absolute %osition o" the gra%hical co#%onents in this way=
844
So#e 84I builders use this a%%roach e&tensively, but this is usually not the best way to generate code. More use"ul 84I builders will use "ri'2ag+ayo*t instead. RFSURFSTIJLT+(6PTE5MLTIIKU
;o0&a:out
Because %eo%le had so #uch trouble understanding and working with
"ri'2ag+ayo*t, Swing also includes the 2o4+ayo*t, which gives you #any o" the bene"its o" "ri'2ag+ayo*t without the co#%le&ity, so you
can o"ten use it when you need to do hand'coded layouts *again, i" your design beco#es too co#%le&, use a 84I builder that generates "ri'2ag+ayo*ts "or you,. 2o4+ayo*t allows you to control the %lace#ent o" co#%onents either vertically or hori1ontally, and to control the s%ace between the co#%onents using so#ething called !struts and glue.$ Eirst, let s see how to use the 2o4+ayo*t directly, in the sa#e way that the other layout #anagers have been de#onstrated=
//3 c()3Bo6Layout(.Hava // Wertical an! horiUontal Bo6Layouts. // Pa""let co!e?Bo6Layout( // :i!th?I,' height? ''Q P/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.B< i#"ort co#.bruceeckel.s:ing.B< "ublic class Bo6Layout( e6ten!s J0""let @ "ublic voi! init-. @ JPanel H"v ? ne: JPanel-.< H"v.setLayoutne: Bo6Layout-H"v, Bo6Layout.;b09$%..< for-int i ? '< i P ,< iKK. H"v.a!!-ne: JButton-88 K i..< JPanel H"h ? ne: JPanel-.< H"h.setLayoutne: Bo6Layout-H"h, Bo6Layout.9b09$%..< for-int i ? '< i P ,< iKK. H"h.a!!-ne: JButton-88 K i..< Container c" ? getContentPane-.< c".a!!-Bor!erLayout.E0%T, H"v.< c".a!!-Bor!erLayout.%GYTM, H"h.<
lets
845
A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: Bo6Layout(-., I,', ''.< A A ///3>
The constructor "or 2o4+ayo*t is a bit di""erent than the other layout #anagers9you %rovide the -ontainer that is to be controlled by the 2o4+ayo*t as the "irst argu#ent, and the direction o" the layout as the second argu#ent. RFSURFSTIJLT+(6PTE5MLTIILU To si#%li"y #atters, there s a s%ecial container called 2o4 that uses 2o4+ayo*t as its native #anager. The "ollowing e&a#%le lays out co#%onents hori1ontally and vertically using 2o4, which has two static #ethods to create bo&es with vertical and hori1ontal align#ent=
//3 c()3Bo6(.Hava // Wertical an! horiUontal Bo6Layouts. // Pa""let co!e?Bo6( // :i!th?I,' height? ''Q P/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.B< i#"ort co#.bruceeckel.s:ing.B< "ublic class Bo6( e6ten!s J0""let @ "ublic voi! init-. @ Bo6 bv ? Bo6.createWerticalBo6-.< for-int i ? '< i P ,< iKK. bv.a!!-ne: JButton-88 K i..< Bo6 bh ? Bo6.createMoriUontalBo6-.< for-int i ? '< i P ,< iKK. bh.a!!-ne: JButton-88 K i..< Container c" ? getContentPane-.< c".a!!-Bor!erLayout.E0%T, bv.< c".a!!-Bor!erLayout.%GYTM, bh.< A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: Bo6(-., I,', ''.< A A ///3>
847
)nce you have a 2o4, you %ass it as a second argu#ent when adding co#%onents to the content %ane. RFSURFSTIJLT+(6PTE5MLTII?U Struts add s%ace between co#%onents, #easured in %i&els. To use a strut, you si#%ly add it in between the addition o" the co#%onents that you want s%aced a%art=
//3 c()3Bo6 .Hava // 0!!ing struts. // Pa""let co!e?Bo6 // :i!th?I,' height?)''Q P/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.B< i#"ort co#.bruceeckel.s:ing.B< "ublic class Bo6 e6ten!s J0""let @ "ublic voi! init-. @ Bo6 bv ? Bo6.createWerticalBo6-.< for-int i ? '< i P ,< iKK. @ bv.a!!-ne: JButton-88 K i..< bv.a!!-Bo6.createWertical%trut-iB('..< A Bo6 bh ? Bo6.createMoriUontalBo6-.< for-int i ? '< i P ,< iKK. @ bh.a!!-ne: JButton-88 K i..< bh.a!!-Bo6.createMoriUontal%trut-iB('..< A Container c" ? getContentPane-.< c".a!!-Bor!erLayout.E0%T, bv.< c".a!!-Bor!erLayout.%GYTM, bh.< A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: Bo6 -., I,', )''.< A A ///3>
Struts se%arate co#%onents by a "i&ed a#ount, but glue is the o%%osite= it se%arates co#%onents by as #uch as %ossible. Thus it s #ore o" a !s%ring$ than !glue$ *and the design on which this was based was called !s%rings and struts$ so the choice o" the ter# is a bit #ysterious,. RFSURF STIJLT+(6PTE5MLTIIHU
lets
848
//3 c()3Bo6).Hava // Ysing alue. // Pa""let co!e?Bo6) // :i!th?I,' height?)''Q P/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.B< i#"ort co#.bruceeckel.s:ing.B< "ublic class Bo6) e6ten!s J0""let @ "ublic voi! init-. @ Bo6 bv ? Bo6.createWerticalBo6-.< bv.a!!-ne: JLabel-8Mello8..< bv.a!!-Bo6.createWerticalalue-..< bv.a!!-ne: JLabel-80""let8..< bv.a!!-Bo6.createWerticalalue-..< bv.a!!-ne: JLabel-8\orl!8..< Bo6 bh ? Bo6.createMoriUontalBo6-.< bh.a!!-ne: JLabel-8Mello8..< bh.a!!-Bo6.createMoriUontalalue-..< bh.a!!-ne: JLabel-80""let8..< bh.a!!-Bo6.createMoriUontalalue-..< bh.a!!-ne: JLabel-8\orl!8..< bv.a!!-Bo6.createWerticalalue-..< bv.a!!-bh.< bv.a!!-Bo6.createWerticalalue-..< getContentPane-..a!!-bv.< A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: Bo6)-., I,', )''.< A A ///3>
6 strut works in one direction, but a rigid area "i&es the s%acing between co#%onents in both directions=
//3 c()3Bo6I.Hava // 5igi! 0reas are like "airs of struts. // Pa""let co!e?Bo6I // :i!th?I,' height?)''Q P/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.B< i#"ort co#.bruceeckel.s:ing.B<
84:
"ublic class Bo6I e6ten!s J0""let @ "ublic voi! init-. @ Bo6 bv ? Bo6.createWerticalBo6-.< bv.a!!-ne: JButton-8To"8..< bv.a!!-Bo6.create5igi!0reane: Di#ension-( ', C'...< bv.a!!-ne: JButton-8Botto#8..< Bo6 bh ? Bo6.createMoriUontalBo6-.< bh.a!!-ne: JButton-8Left8..< bh.a!!-Bo6.create5igi!0reane: Di#ension-(+', 1'...< bh.a!!-ne: JButton-85ight8..< bv.a!!-bh.< getContentPane-..a!!-bv.< A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: Bo6I-., I,', )''.< A A ///3>
/ou should be aware that rigid areas are a bit controversial. Since they use absolute values, so#e %eo%le "eel that they cause #ore trouble than they are worth. RFSURFSTIJLT+(6PTE5MLTII3U
lets
84;
*Java is, a"ter all, designed to increase %rogra##er %roductivity,. RFSURF STIJLT+(6PTE5MLTIIGU
85=
6ll the e&a#%les so "ar in this cha%ter have been using the Swing event #odel, but the re#ainder o" this section will "ill out the details o" that #odel. RFSURFSTIJLT+(6PTE5MLTI2MU
lets
851
&vent, listener interface an' a''6 an' remove6metho's Foc*s&vent Foc*s+istener a''Foc*s+istenerA B removeFoc*s+istenerA B %ey&vent %ey+istener a''%ey+istenerA B remove%ey+istenerA B 1o*se&vent *"or both clicks and #otion, 1o*se+istener a''1o*se+istenerA B remove1o*se+istenerA B 1o*se&ventD *"or both clicks and #otion, 1o*se1otion+istener a''1o*se1otion+istenerA B remove1o*se1otion+istener AB 0in'o(&vent 0in'o(+istener a''0in'o(+istenerA B remove0in'o(+istenerA B Item&vent Item+istener a''Item+istenerA B removeItem+istenerA B Te4t&vent Te4t+istener a''Te4t+istenerA B removeTe4t+istenerA B
0in'o( and its derivatives, including J ialog, JFile ialog, an' JFrame! J-heck2o4, J-heck2o41en*Item, J-ombo2o4, J+ist, and anything that i#%le#ents the Item)electable interface! 6nything derived "ro# JTe4t-omponent, including JTe4tArea and JTe4tFiel'!
/ou can see that each ty%e o" co#%onent su%%orts only certain ty%es o" events. It turns out to be rather di""icult to look u% all the events su%%orted by each co#%onent. 6 si#%ler a%%roach is to #odi"y the )ho(1etho's-lean!8ava %rogra# "ro# +ha%ter MK so that it dis%lays all the event listeners su%%orted by any Swing co#%onent that you enter.
@ There is no 1o*se1otion&vent even though it see#s like there ought to be. +licking and #otion is co#bined into 1o*se&vent, so this second a%%earance o" 1o*se&vent in the table is not an error.
852
+ha%ter MK introduced re$lection and used that "eature to look u% #ethods "or a %articular class9either the entire list o" #ethods or a subset o" those whose na#es #atch a keyword that you %rovide. The #agic o" this is that it can auto#atically show you all the #ethods "or a class without "orcing you to walk u% the inheritance hierarchy e&a#ining the base classes at each level. Thus, it %rovides a valuable ti#esaving tool "or %rogra##ing= because the na#es o" #ost Java #ethods are #ade nicely verbose and descri%tive, you can search "or the #ethod na#es that contain a %articular word o" interest. :hen you "ind what you think you re looking "or, check the online docu#entation. RFSURF STIJLT+(6PTE5MLTI2KU (owever, by +ha%ter MK you hadn t seen Swing, so the tool in that cha%ter was develo%ed as a co##and'line a%%lication. (ere is the #ore use"ul 84I version, s%eciali1ed to look "or the !addDistener$ #ethods in Swing co#%onents=
//3 c()3%ho:0!!Listeners.Hava // Dis"lay the 8a!!999Listener8 #etho!s of any // %:ing class. // Pa""let co!e ? %ho:0!!Listeners // :i!th?,'' height?I''QP/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava6.s:ing.event.B< i#"ort Hava.a:t.B< i#"ort Hava.a:t.event.B< i#"ort Hava.lang.reflect.B< i#"ort Hava.io.B< i#"ort co#.bruceeckel.s:ing.B< i#"ort co#.bruceeckel.util.B< "ublic class %ho:0!!Listeners e6ten!s J0""let @ Class cl< Jetho!NO #< ConstructorNO ctor< %tringNO n ? ne: %tringN'O< JTe6tLiel! na#e ? ne: JTe6tLiel!- ,.< JTe6t0rea results ? ne: JTe6t0rea-I', +,.< class &a#eL i#"le#ents 0ctionListener @ "ublic voi! actionPerfor#e!-0ctionEvent e. @
lets
853
%tring n# ? na#e.getTe6t-..tri#-.< if-n#.length-. ?? '. @ results.setTe6t-8&o #atch8.< n ? ne: %tringN'O< return< A try @ cl ? Class.for&a#e-8Hava6.s:ing.8 K n#.< A catch-Class&otLoun!E6ce"tion e6. @ results.setTe6t-8&o #atch8.< return< A # ? cl.getJetho!s-.< // Convert to an array of %trings3 n ? ne: %tringN#.lengthO< for-int i ? '< i P #.length< iKK. nNiO ? #NiO.to%tring-.< reDis"lay-.< A A voi! reDis"lay-. @ // Create the result set3 %tringNO rs ? ne: %tringNn.lengthO< int H ? '< for -int i ? '< i P n.length< iKK. if-nNiO.in!e6Gf-8a!!8. 4? -( DD nNiO.in!e6Gf-8Listener8. 4? -(. rsNHKKO ? nNiO.substring-nNiO.in!e6Gf-8a!!8..< results.setTe6t-88.< for -int i ? '< i P H< iKK. results.a""en!%tri"/ualifiers.stri"-rsNiO. K 8_n8.< A "ublic voi! init-. @ na#e.a!!0ctionListener-ne: &a#eL-..< JPanel to" ? ne: JPanel-.< to".a!!-ne: JLabel8%:ing class na#e -"ress E&TE5.38..< to".a!!-na#e.< Container c" ? getContentPane-.<
854
c".a!!-Bor!erLayout.&G5TM, to".< c".a!!-ne: J%crollPane-results..< A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: %ho:0!!Listeners-., ,'',I''.< A A ///3>
The )trip3*alifiers class de"ined in +ha%ter MK is reused here by i#%orting the com!br*ceeckel!*til library. RFSURF STIJLT+(6PTE5MLTI2LU The 84I contains a JTe4tFiel' name in which you can enter the Swing class na#e you want to look u%. The results are dis%layed in a JTe4tArea. RFSURFSTIJLT+(6PTE5MLTI2?U /ou ll notice that there are no buttons or other co#%onents by which to indicate that you want the search to begin. That s because the JTe4tFiel' is #onitored by an Action+istener. :henever you #ake a change and %ress ECTE5, the list is i##ediately u%dated. I" the te&t isn t e#%ty, it is used inside -lass!for/ameA B to try to look u% the class. I" the na#e is incorrect, -lass!for/ameA B will "ail, which #eans that it throws an e&ce%tion. This is tra%%ed and the JTe4tArea is set to !Co #atch.$ But i" you ty%e in a correct na#e *ca%itali1ation counts,, -lass! for/ameA B is success"ul and get1etho'sA B will return an array o" 1etho' ob0ects. Each o" the ob0ects in the array is turned into a )tring via to)tringA B *this %roduces the co#%lete #ethod signature, and added to n, a )tring array. The array n is a #e#ber o" class )ho(A''+isteners and is used in u%dating the dis%lay whenever re isplayA B is called. RFSURFSTIJLT+(6PTE5MLTI2HU
re isplayA B creates an array o" )tring called rs *"or !result set$,. The result set is conditionally co%ied "ro# the )trings in n that contain !add$ and !Distener.$ in'e4.fA B and s*bstringA B are then used to re#ove the Auali"iers like p*blic, static, etc. Einally, )trip3*alifiers!stripA B re#oves the e&tra na#e Auali"iers. RFSURFSTIJLT+(6PTE5MLTI23U
This %rogra# is a convenient way to investigate the ca%abilities o" a Swing co#%onent. )nce you know which events a %articular co#%onent
lets
855
su%%orts, you don t need to look anything u% to react to that event. /ou si#%ly=
(!*) Take the na#e o" the event class and re#ove the word !&vent.$ 6dd the word ! +istener$ to what re#ains. This is the listener
inter"ace you #ust i#%le#ent in your inner class. RFSURF STIJLT+(6PTE5MLTI2GU
(!+) I#%le#ent the inter"ace above and write out the #ethods "or the
events you want to ca%ture. Eor e&a#%le, you #ight be looking "or #ouse #ove#ents, so you write code "or the mo*se1ove'A B #ethod o" the 1o*se1otion+istener inter"ace. */ou #ust i#%le#ent the other #ethods, o" course, but there s o"ten a shortcut "or that which you ll see soon., RFSURF STIJLT+(6PTE5MLTI2IU
(!,) +reate an ob0ect o" the listener class in Ste% K. 5egister it with your co#%onent with the #ethod %roduced by %re"i&ing ! a''$ to your listener na#e. Eor e&a#%le, a''1o*se1otion+istenerA B. RF
SURFSTIJLT+(6PTE5MLTI22U (ere are so#e o" the listener inter"aces=
1etho's in interface action#erforme'AAction&ventB a'8*stmentVal*e-hange'A A'8*stment&ventB componentHi''en A-omponent&ventB component)ho(nA-omponent&ventB component1ove'A-omponent&ventB component$esi7e' A-omponent&ventB componentA''e'A-ontainer&ventB component$emove' A-ontainer&ventB foc*s"aine'AFoc*s&ventB foc*s+ostAFoc*s&ventB
857
1etho's in interface key#resse'A%ey&ventB key$elease'A%ey&ventB keyType'A%ey&ventB mo*se-licke'A1o*se&ventB mo*se&ntere'A1o*se&ventB mo*se&4ite'A1o*se&ventB mo*se#resse'A1o*se&ventB mo*se$elease'A1o*se&ventB mo*se ragge'A1o*se&ventB mo*se1ove'A1o*se&ventB (in'o(.pene'A0in'o(&ventB (in'o(-losingA0in'o(&ventB (in'o(-lose'A0in'o(&ventB (in'o(Activate'A0in'o(&ventB (in'o( eactivate'A0in'o(&ventB (in'o(Iconifie'A0in'o(&ventB (in'o( eiconifie'A0in'o(&ventB item)tate-hange'AItem&ventB
Item+istener
This is not an e&haustive listing, %artly because the event #odel allows you to create your own event ty%es and associated listeners. Thus, you ll regularly co#e across libraries that have invented their own events, and the knowledge gained in this cha%ter will allow you to "igure out how to use these events.
lets
858
i#%le#ent all o" the other #ethods even i" they don t do anything. This can be annoying. RFSURFSTIJLT+(6PTE5MLTIM@@U To solve the %roble#, so#e *but not all, o" the listener inter"aces that have #ore than one #ethod are %rovided with ada ters, the na#es o" which you can see in the table above. Each ada%ter %rovides de"ault e#%ty #ethods "or each o" the inter"ace #ethods. Then all you need to do is inherit "ro# the ada%ter and override only the #ethods you need to change. Eor e&a#%le, the ty%ical 0in'o(+istener you ll use looks like this *re#e#ber that this has been wra%%ed inside the -onsole class in com!br*ceeckel!s(ing,=
85:
//3 c()3TrackEvent.Hava // %ho: events as they ha""en. // Pa""let co!e?TrackEvent // :i!th?*'' height?,''QP/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.B< i#"ort Hava.a:t.event.B< i#"ort Hava.util.B< i#"ort co#.bruceeckel.s:ing.B< "ublic class TrackEvent e6ten!s J0""let @ MashJa" h ? ne: MashJa"-.< %tringNO event ? @ 8focusaaine!8, 8focusLost8, 8keyPresse!8, 8key5elease!8, 8keyTy"e!8, 8#ouseClicke!8, 8#ouseEntere!8, 8#ouseE6ite!8,8#ousePresse!8, 8#ouse5elease!8, 8#ouseDragge!8, 8#ouseJove!8 A< JyButton b( ? ne: JyButton-Color.blue, 8test(8., b ? ne: JyButton-Color.re!, 8test 8.< class JyButton e6ten!s JButton @
@ In Java [email protected] you could not use"ully inherit "ro# the button ob0ect. This was only one o" nu#erous "unda#ental design "laws.
lets
85;
voi! re"ort-%tring fiel!, %tring #sg. @ --JTe6tLiel!.h.get-fiel!...setTe6t-#sg.< A LocusListener fl ? ne: LocusListener-. @ "ublic voi! focusaaine!-LocusEvent e. @ re"ort-8focusaaine!8, e."ara#%tring-..< A "ublic voi! focusLost-LocusEvent e. @ re"ort-8focusLost8, e."ara#%tring-..< A A< `eyListener kl ? ne: `eyListener-. @ "ublic voi! keyPresse!-`eyEvent e. @ re"ort-8keyPresse!8, e."ara#%tring-..< A "ublic voi! key5elease!-`eyEvent e. @ re"ort-8key5elease!8, e."ara#%tring-..< A "ublic voi! keyTy"e!-`eyEvent e. @ re"ort-8keyTy"e!8, e."ara#%tring-..< A A< JouseListener #l ? ne: JouseListener-. @ "ublic voi! #ouseClicke!-JouseEvent e. @ re"ort-8#ouseClicke!8, e."ara#%tring-..< A "ublic voi! #ouseEntere!-JouseEvent e. @ re"ort-8#ouseEntere!8, e."ara#%tring-..< A "ublic voi! #ouseE6ite!-JouseEvent e. @ re"ort-8#ouseE6ite!8, e."ara#%tring-..< A "ublic voi! #ousePresse!-JouseEvent e. @ re"ort-8#ousePresse!8, e."ara#%tring-..< A "ublic voi! #ouse5elease!-JouseEvent e. @ re"ort-8#ouse5elease!8, e."ara#%tring-..< A A< JouseJotionListener ##l ? ne: JouseJotionListener-. @
87=
"ublic voi! #ouseDragge!-JouseEvent e. @ re"ort-8#ouseDragge!8, e."ara#%tring-..< A "ublic voi! #ouseJove!-JouseEvent e. @ re"ort-8#ouseJove!8, e."ara#%tring-..< A A< "ublic JyButton-Color color, %tring label. @ su"er-label.< setBackgroun!-color.< a!!LocusListener-fl.< a!!`eyListener-kl.< a!!JouseListener-#l.< a!!JouseJotionListener-##l.< A A "ublic voi! init-. @ Container c ? getContentPane-.< c.setLayout-ne: ari!Layout-event.lengthK(, ..< for-int i ? '< i P event.length< iKK. @ JTe6tLiel! t ? ne: JTe6tLiel!-.< t.setE!itable-false.< c.a!!-ne: JLabel-eventNiO, JLabel.5$aMT..< c.a!!-t.< h."ut-eventNiO, t.< A c.a!!-b(.< c.a!!-b .< A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: TrackEvent-., *'', ,''.< A A ///3>
In the 1y2*tton constructor, the button s color is set with a call to )et2ackgro*n'A B. The listeners are all installed with si#%le #ethod calls. RFSURFSTIJLT+(6PTE5MLTIM@?U The Track&vent class contains a Hash1ap to hold the strings re%resenting the ty%e o" event and JTe4tFiel's where in"or#ation about that event is held. )" course, these could have been created statically
lets
871
rather than %utting the# in a Hash1ap, but I think you ll agree that it s a lot easier to use and change. In %articular, i" you need to add or re#ove a new ty%e o" event in Track&vent, you si#%ly add or re#ove a string in the event array9everything else ha%%ens auto#atically. RFSURF STIJLT+(6PTE5MLTIM@HU :hen reportA B is called it is given the na#e o" the event and the %ara#eter string "ro# the event. It uses the Hash1ap h in the outer class to look u% the actual JTe4tFiel' associated with that event na#e, and then %laces the %ara#eter string into that "ield. RFSURF STIJLT+(6PTE5MLTIM@3U This e&a#%le is "un to %lay with since you can really see what s going on with the events in your %rogra#. RFSURFSTIJLT+(6PTE5MLTIM@GU
>ee% in #ind= (!-) The (TMD docu#entation "ro# >ava'sun'com contains all o" the
Swing classes and #ethods *only a "ew are shown here,. RFSURF STIJLT+(6PTE5MLTIMM@U
(!4) Because o" the na#ing convention used "or Swing events, it s "airly
easy to guess how to write and install a handler "or a %articular ty%e o" event. 4se the looku% %rogra# )ho(A''+isteners!8ava
872
"ro# earlier in this cha%ter to aid in your investigation o" a %articular co#%onent. RFSURFSTIJLT+(6PTE5MLTIMMMU
(!5) :hen things start to get co#%licated you should graduate to a 84I
builder. RFSURFSTIJLT+(6PTE5MLTIMMKU
;uttons
Swing includes a nu#ber o" di""erent ty%es o" buttons. 6ll buttons, check bo&es, radio buttons, and even #enu ite#s are inherited "ro# Abstract2*tton *which, since #enu ite#s are included, would %robably have been better na#ed !6bstract+hooser$ or so#ething eAually general,. /ou ll see the use o" #enu ite#s shortly, but the "ollowing e&a#%le shows the various ty%es o" buttons available= RFSURF STIJLT+(6PTE5MLTIMMLU
//3 c()3Buttons.Hava // Warious %:ing buttons. // Pa""let co!e?Buttons // :i!th?),' height?(''QP/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.B< i#"ort Hava.a:t.event.B< i#"ort Hava6.s:ing."laf.basic.B< i#"ort Hava6.s:ing.bor!er.B< i#"ort co#.bruceeckel.s:ing.B< "ublic class Buttons e6ten!s J0""let @ JButton Hb ? ne: JButton-8JButton8.< Basic0rro:Button u" ? ne: Basic0rro:ButtonBasic0rro:Button.&G5TM., !o:n ? ne: Basic0rro:ButtonBasic0rro:Button.%GYTM., right ? ne: Basic0rro:ButtonBasic0rro:Button.E0%T., left ? ne: Basic0rro:ButtonBasic0rro:Button.\E%T.< "ublic voi! init-. @ Container c" ? getContentPane-.< c".setLayout-ne: Llo:Layout-..<
lets
873
c".a!!-Hb.< c".a!!-ne: JToggleButton-8JToggleButton8..< c".a!!-ne: JCheckBo6-8JCheckBo68..< c".a!!-ne: J5a!ioButton-8J5a!ioButton8..< JPanel H" ? ne: JPanel-.< H".setBor!er-ne: Title!Bor!er-8Directions8..< H".a!!-u".< H".a!!-!o:n.< H".a!!-left.< H".a!!-right.< c".a!!-H".< A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: Buttons-., ),', (''.< A A ///3>
This begins with the 2asicArro(2*tton "ro# 8ava4!s(ing!plaf! basic, then continues with the various s%eci"ic ty%es o" buttons. :hen you run the e&a#%le, you ll see that the toggle button holds its last %osition, in or out. But the check bo&es and radio buttons behave identically to each other, 0ust clicking on or o"" *they are inherited "ro# JToggle2*tton,. RFSURFSTIJLT+(6PTE5MLTIMM?U
;utton grou.s
I" you want radio buttons to behave in an !e&clusive or$ "ashion, you #ust add the# to a !button grou%.$ But, as the e&a#%le below de#onstrates, any Abstract2*tton can be added to a 2*tton"ro*p. RFSURF STIJLT+(6PTE5MLTIMMHU To avoid re%eating a lot o" code, this e&a#%le uses re"lection to generate the grou%s o" di""erent ty%es o" buttons. This is seen in make2#anelA B, which creates a button grou% and a J#anel. The second argu#ent to make2#anelA B is an array o" )tring. Eor each )tring, a button o" the class re%resented by the "irst argu#ent is added to the J#anel=
//3 c()3Buttonarou"s.Hava // Yses reflection to create grou"s // of !ifferent ty"es of 0bstractButton. // Pa""let co!e?Buttonarou"s
874
// :i!th?,'' height?)''QP/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.B< i#"ort Hava.a:t.event.B< i#"ort Hava6.s:ing.bor!er.B< i#"ort Hava.lang.reflect.B< i#"ort co#.bruceeckel.s:ing.B< "ublic class Buttonarou"s e6ten!s J0""let @ static %tringNO i!s ? @ 8June8, 8\ar!8, 8Beaver8, 8\ally8, 8E!!ie8, 8Lu#"y8, A< static JPanel #akeBPanel-Class bClass, %tringNO i!s. @ Buttonarou" bg ? ne: Buttonarou"-.< JPanel H" ? ne: JPanel-.< %tring title ? bClass.get&a#e-.< title ? title.substringtitle.last$n!e6Gf-2.2. K (.< H".setBor!er-ne: Title!Bor!er-title..< for-int i ? '< i P i!s.length< iKK. @ 0bstractButton ab ? ne: JButton-8faile!8.< try @ // aet the !yna#ic constructor #etho! // that takes a %tring argu#ent3 Constructor ctor ? bClass.getConstructorne: ClassNO @ %tring.class A.< // Create a ne: obHect3 ab ? -0bstractButton.ctor.ne:$nstancene: GbHectNO@i!sNiOA.< A catch-E6ce"tion e6. @ %yste#.err."rintln-8can2t create 8 K bClass.< A bg.a!!-ab.< H".a!!-ab.< A return H"< A "ublic voi! init-. @
lets
875
Container c" ? getContentPane-.< c".setLayout-ne: Llo:Layout-..< c".a!!-#akeBPanel-JButton.class, i!s..< c".a!!-#akeBPanel-JToggleButton.class, i!s..< c".a!!-#akeBPanel-JCheckBo6.class, i!s..< c".a!!-#akeBPanel-J5a!ioButton.class, i!s..< A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: Buttonarou"s-., ,'', )''.< A A ///3>
The title "or the border is taken "ro# the na#e o" the class, stri%%ing o"" all the %ath in"or#ation. The Abstract2*tton is initiali1ed to a J2*tton that has the label !Eailed$ so i" you ignore the e&ce%tion #essage, you ll still see the %roble# on screen. The get-onstr*ctorA B #ethod %roduces a -onstr*ctor ob0ect that takes the array o" argu#ents o" the ty%es in the -lass array %assed to get-onstr*ctorA B. Then all you do is call ne(InstanceA B, %assing it an array o" .b8ect containing your actual argu#ents9in this case, 0ust the )tring "ro# the i's array. RFSURFSTIJLT+(6PTE5MLTIMM3U This adds a little co#%le&ity to what is a si#%le %rocess. To get !e&clusive or$ behavior with buttons, you create a button grou% and add each button "or which you want that behavior to the grou%. :hen you run the %rogra#, you ll see that all the buttons e&ce%t J2*tton e&hibit this !e&clusive or$ behavior. RFSURFSTIJLT+(6PTE5MLTIMMGU
Icons
/ou can use an Icon inside a J+abel or anything that inherits "ro# Abstract2*tton *including J2*tton, J-heck2o4, J$a'io2*tton, and the di""erent kinds o" J1en*Item,. 4sing Icons with J+abels is Auite straight"orward *you ll see an e&a#%le later,. The "ollowing e&a#%le e&%lores all the additional ways you can use Icons with buttons and their descendants. RFSURFSTIJLT+(6PTE5MLTIMMIU /ou can use any gif "iles you want, but the ones used in this e&a#%le are %art o" this book s code distribution, available at ,,,'0ruceEckel'com. To o%en a "ile and bring in the i#age, si#%ly create an ImageIcon and
877
hand it the "ile na#e. Ero# then on, you can use the resulting Icon in your %rogra#. RFSURFSTIJLT+(6PTE5MLTIMM2U Cote that %ath in"or#ation is hard'coded into this e&a#%le; you will need to change the %ath to corres%ond to the location o" the i#age "iles.
//3 c()3Laces.Hava // $con behavior in Jbuttons. // Pa""let co!e?Laces // :i!th? ,' height?(''QP/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.B< i#"ort Hava.a:t.event.B< i#"ort co#.bruceeckel.s:ing.B< "ublic class Laces e6ten!s J0""let @ // The follo:ing "ath infor#ation is necessary // to run via an a""let !irectly fro# the !isk3 static %tring "ath ? 8C3/aaa-T$J -!istribution/co!e/c()/8< static $conNO faces ? @ ne: $#age$con-"ath K 8face'.gif8., ne: $#age$con-"ath K 8face(.gif8., ne: $#age$con-"ath K 8face .gif8., ne: $#age$con-"ath K 8face).gif8., ne: $#age$con-"ath K 8faceI.gif8., A< JButton Hb ? ne: JButton-8JButton8, facesN)O., Hb ? ne: JButton-8Disable8.< boolean #a! ? false< "ublic voi! init-. @ Container c" ? getContentPane-.< c".setLayout-ne: Llo:Layout-..< Hb.a!!0ctionListener-ne: 0ctionListener-. @ "ublic voi! actionPerfor#e!-0ctionEvent e.@ if-#a!. @ Hb.set$con-facesN)O.< #a! ? false< A else @ Hb.set$con-facesN'O.<
lets
878
#a! ? true< A Hb.setWertical0lign#ent-JButton.TGP.< Hb.setMoriUontal0lign#ent-JButton.LELT.< A A.< Hb.set5olloverEnable!-true.< Hb.set5ollover$con-facesN(O.< Hb.setPresse!$con-facesN O.< Hb.setDisable!$con-facesNIO.< Hb.setToolTi"Te6t-8;o:48.< c".a!!-Hb.< Hb .a!!0ctionListener-ne: 0ctionListener-. @ "ublic voi! actionPerfor#e!-0ctionEvent e.@ if-Hb.isEnable!-.. @ Hb.setEnable!-false.< Hb .setTe6t-8Enable8.< A else @ Hb.setEnable!-true.< Hb .setTe6t-8Disable8.< A A A.< c".a!!-Hb .< A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: Laces-., I'', ''.< A A ///3>
6n Icon can be used in #any constructors, but you can also use setIcon A B to add or change an Icon. This e&a#%le also shows how a J2*tton *or any Abstract2*tton, can set the various di""erent sorts o" icons that a%%ear when things ha%%en to that button= when it s %ressed, disabled, or !rolled over$ *the #ouse #oves over it without clicking,. /ou ll see that this gives the button a nice ani#ated "eel. RFSURF STIJLT+(6PTE5MLTIMK@U
87:
#ool ti.s
The %revious e&a#%le added a !tool ti%$ to the button. 6l#ost all o" the classes that you ll be using to create your user inter"aces are derived "ro# J-omponent, which contains a #ethod called setToolTipTe4t A)tringB. So, "or virtually anything you %lace on your "or#, all you need to do is say *"or an ob0ect 8c o" any J-omponent'derived class,=
Hc.setToolTi"Te6t-8Jy ti"8.<
and when the #ouse stays over that J-omponent "or a %redeter#ined %eriod o" ti#e, a tiny bo& containing your te&t will %o% u% ne&t to the #ouse. RFSURFSTIJLT+(6PTE5MLTIMKMU
#e0t fields
This e&a#%le shows the e&tra behavior that JTe4tFiel's are ca%able o"=
//3 c()3Te6tLiel!s.Hava // Te6t fiel!s an! Java events. // Pa""let co!e?Te6tLiel!s :i!th?)*, // height?( ,QP/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava6.s:ing.event.B< i#"ort Hava6.s:ing.te6t.B< i#"ort Hava.a:t.B< i#"ort Hava.a:t.event.B< i#"ort co#.bruceeckel.s:ing.B< "ublic class Te6tLiel!s e6ten!s J0""let @ JButton b( ? ne: JButton-8aet Te6t8., b ? ne: JButton-8%et Te6t8.< JTe6tLiel! t( ? ne: JTe6tLiel!-)'., t ? ne: JTe6tLiel!-)'., t) ? ne: JTe6tLiel!-)'.< %tring s ? ne: %tring-.< Y""erCaseDocu#ent uc! ? ne: Y""erCaseDocu#ent-.< "ublic voi! init-. @
lets
87;
t(.setDocu#ent-uc!.< uc!.a!!Docu#entListener-ne: T(-..< b(.a!!0ctionListener-ne: B(-..< b .a!!0ctionListener-ne: B -..< Docu#entListener !l ? ne: T(-.< t(.a!!0ctionListener-ne: T(0-..< Container c" ? getContentPane-.< c".setLayout-ne: Llo:Layout-..< c".a!!-b(.< c".a!!-b .< c".a!!-t(.< c".a!!-t .< c".a!!-t).< A class T( i#"le#ents Docu#entListener @ "ublic voi! change!Y"!ate-Docu#entEvent e.@A "ublic voi! insertY"!ate-Docu#entEvent e.@ t .setTe6t-t(.getTe6t-..< t).setTe6t-8Te6t3 8K t(.getTe6t-..< A "ublic voi! re#oveY"!ate-Docu#entEvent e.@ t .setTe6t-t(.getTe6t-..< A A class T(0 i#"le#ents 0ctionListener @ "rivate int count ? '< "ublic voi! actionPerfor#e!-0ctionEvent e. @ t).setTe6t-8t( 0ction Event 8 K countKK.< A A class B( i#"le#ents 0ctionListener @ "ublic voi! actionPerfor#e!-0ctionEvent e. @ if-t(.get%electe!Te6t-. ?? null. s ? t(.getTe6t-.< else s ? t(.get%electe!Te6t-.< t(.setE!itable-true.< A A class B i#"le#ents 0ctionListener @ "ublic voi! actionPerfor#e!-0ctionEvent e. @
88=
3 8 K s.<
A A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: Te6tLiel!s-., )*,, ( ,.< A A class Y""erCaseDocu#ent e6ten!s PlainDocu#ent @ boolean u""erCase ? true< "ublic voi! setY""erCase-boolean flag. @ u""erCase ? flag< A "ublic voi! insert%tring-int offset, %tring string, 0ttribute%et attribute%et. thro:s Ba!LocationE6ce"tion @ if-u""erCase. string ? string.toY""erCase-.< su"er.insert%tring-offset, string, attribute%et.< A A ///3>
The JTe4tFiel' tJ is included as a %lace to re%ort when the action listener "or the JTe4tFiel' t> is "ired. /ou ll see that the action listener "or a JTe4tFiel' is "ired only when you %ress the !enter$ key. RFSURF STIJLT+(6PTE5MLTIMKKU The JTe4tFiel' t> has several listeners attached to it. The T> listener is a oc*ment+istener that res%onds to any change in the !docu#ent$ *the contents o" the JTe4tFiel', in this case,. It auto#atically co%ies all te&t "ro# t> into tI. In addition, t> s docu#ent is set to a derived class o" #lain oc*ment, called Upper-ase oc*ment, which "orces all characters to u%%ercase. It auto#atically detects backs%aces and %er"or#s the deletion, ad0usting the caret and handling everything as you would e&%ect. RFSURFSTIJLT+(6PTE5MLTIMKLU
lets
881
;orders
J-omponent contains a #ethod called set2or'erA B, which allows you
to %lace various interesting borders on any visible co#%onent. The "ollowing e&a#%le de#onstrates a nu#ber o" the di""erent borders that are available, using a #ethod called sho(2or'erA B that creates a J#anel and %uts on the border in each case. 6lso, it uses 5TTI to "ind the na#e o" the border that you re using *stri%%ing o"" all the %ath in"or#ation,, then %uts that na#e in a J+abel in the #iddle o" the %anel=
//3 c()3Bor!ers.Hava // Different %:ing bor!ers. // Pa""let co!e?Bor!ers // :i!th?,'' height?)''QP/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.B< i#"ort Hava.a:t.event.B< i#"ort Hava6.s:ing.bor!er.B< i#"ort co#.bruceeckel.s:ing.B< "ublic class Bor!ers e6ten!s J0""let @ static JPanel sho:Bor!er-Bor!er b. @ JPanel H" ? ne: JPanel-.< H".setLayout-ne: Bor!erLayout-..< %tring n# ? b.getClass-..to%tring-.< n# ? n#.substring-n#.last$n!e6Gf-2.2. K (.< H".a!!-ne: JLabel-n#, JLabel.CE&TE5., Bor!erLayout.CE&TE5.< H".setBor!er-b.< return H"< A "ublic voi! init-. @ Container c" ? getContentPane-.< c".setLayout-ne: Llo:Layout-..< c".setLayout-ne: ari!Layout- ,I..< c".a!!-sho:Bor!er-ne: Title!Bor!er-8Title8...< c".a!!-sho:Bor!er-ne: Etche!Bor!er-...< c".a!!-sho:Bor!er-ne: LineBor!er-Color.blue...< c".a!!-sho:Bor!erne: JatteBor!er-,,,,)',)',Color.green...< c".a!!-sho:Bor!er-
882
ne: BevelBor!er-BevelBor!er.50$%ED...< c".a!!-sho:Bor!erne: %oftBevelBor!er-BevelBor!er.LG\E5ED...< c".a!!-sho:Bor!er-ne: Co#"oun!Bor!erne: Etche!Bor!er-., ne: LineBor!er-Color.re!....< A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: Bor!ers-., ,'', )''.< A A ///3>
/ou can also create your own borders and %ut the# inside buttons, labels, etc.9anything derived "ro# J-omponent. RFSURF STIJLT+(6PTE5MLTIMK?U
"1croll anes
Most o" the ti#e you ll 0ust want to let a J)croll#ane do it s 0ob, but you can also control which scroll bars are allowed9vertical, hori1ontal, both, or neither=
//3 c()3J%crollPanes.Hava // Controlling the scrollbars in a J%crollPane. // Pa""let co!e?J%crollPanes :i!th?)'' height?* ,Q // P/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.B< i#"ort Hava.a:t.event.B< i#"ort Hava6.s:ing.bor!er.B< i#"ort co#.bruceeckel.s:ing.B< "ublic class JButton b( ? ne: b ? ne: b) ? ne: bI ? ne: JTe6t0rea t( ? ne: t ? ne: J%crollPanes e6ten!s J0""let @ JButton-8Te6t 0rea (8., JButton-8Te6t 0rea 8., JButton-85e"lace Te6t8., JButton-8$nsert Te6t8.< JTe6t0rea-8t(8, (, JTe6t0rea-8t 8, I, '., '.,
lets
883
t) ? ne: JTe6t0rea-8t)8, (, '., tI ? ne: JTe6t0rea-8tI8, (', ('., t, ? ne: JTe6t0rea-8t,8, I, '., t+ ? ne: JTe6t0rea-8t+8, (', ('.< J%crollPane s") ? ne: J%crollPane-t), J%crollPane.WE5T$C0Lb%C5GLLB05b&EWE5, J%crollPane.MG5$TG&T0Lb%C5GLLB05b&EWE5., s"I ? ne: J%crollPane-tI, J%crollPane.WE5T$C0Lb%C5GLLB05b0L\0;%, J%crollPane.MG5$TG&T0Lb%C5GLLB05b&EWE5., s", ? ne: J%crollPane-t,, J%crollPane.WE5T$C0Lb%C5GLLB05b&EWE5, J%crollPane.MG5$TG&T0Lb%C5GLLB05b0L\0;%., s"+ ? ne: J%crollPane-t+, J%crollPane.WE5T$C0Lb%C5GLLB05b0L\0;%, J%crollPane.MG5$TG&T0Lb%C5GLLB05b0L\0;%.< class B(L i#"le#ents 0ctionListener @ "ublic voi! actionPerfor#e!-0ctionEvent e. @ t,.a""en!-t(.getTe6t-. K 8_n8.< A A class B L i#"le#ents 0ctionListener @ "ublic voi! actionPerfor#e!-0ctionEvent e. @ t .setTe6t-8$nserte! by Button 8.< t .a""en!-83 8 K t(.getTe6t-..< t,.a""en!-t .getTe6t-. K 8_n8.< A A class B)L i#"le#ents 0ctionListener @ "ublic voi! actionPerfor#e!-0ctionEvent e. @ %tring s ? 8 5e"lace#ent 8< t .re"lace5ange-s, ), ) K s.length-..< A A class BIL i#"le#ents 0ctionListener @ "ublic voi! actionPerfor#e!-0ctionEvent e. @ t .insert-8 $nserte! 8, ('.< A A "ublic voi! init-. @
884
Container c" ? getContentPane-.< c".setLayout-ne: Llo:Layout-..< // Create Bor!ers for co#"onents3 Bor!er br! ? Bor!erLactory.createJatteBor!er(, (, (, (, Color.black.< t(.setBor!er-br!.< t .setBor!er-br!.< s").setBor!er-br!.< s"I.setBor!er-br!.< s",.setBor!er-br!.< s"+.setBor!er-br!.< // $nitialiUe listeners an! a!! co#"onents3 b(.a!!0ctionListener-ne: B(L-..< c".a!!-b(.< c".a!!-t(.< b .a!!0ctionListener-ne: B L-..< c".a!!-b .< c".a!!-t .< b).a!!0ctionListener-ne: B)L-..< c".a!!-b).< bI.a!!0ctionListener-ne: BIL-..< c".a!!-bI.< c".a!!-s").< c".a!!-s"I.< c".a!!-s",.< c".a!!-s"+.< A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: J%crollPanes-., )'', * ,.< A A ///3>
4sing di""erent argu#ents in the J)croll#ane constructor controls the scrollbars that are available. This e&a#%le also dresses things u% a bit using borders. RFSURFSTIJLT+(6PTE5MLTIMKHU
A mini@editor
The JTe4t#ane control %rovides a great deal o" su%%ort "or editing, without #uch e""ort. The "ollowing e&a#%le #akes very si#%le use o" this, ignoring the bulk o" the "unctionality o" the class=
lets
885
//3 c()3Te6tPane.Hava // The JTe6tPane control is a little e!itor. // Pa""let co!e?Te6tPane :i!th?I*, height?I ,Q // P/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.B< i#"ort Hava.a:t.event.B< i#"ort co#.bruceeckel.s:ing.B< i#"ort co#.bruceeckel.util.B< "ublic class Te6tPane e6ten!s J0""let @ JButton b ? ne: JButton-80!! Te6t8.< JTe6tPane t" ? ne: JTe6tPane-.< static aenerator sg ? ne: 0rrays .5an!%tringaenerator-*.< "ublic voi! init-. @ b.a!!0ctionListener-ne: 0ctionListener-. @ "ublic voi! actionPerfor#e!-0ctionEvent e.@ for-int i ? (< i P ('< iKK. t".setTe6t-t".getTe6t-. K sg.ne6t-. K 8_n8.< A A.< Container c" ? getContentPane-.< c".a!!-ne: J%crollPane-t"..< c".a!!-Bor!erLayout.%GYTM, b.< A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: Te6tPane-., I*,, I ,.< A A ///3>
The button 0ust adds rando#ly generated te&t. The intent o" the JTe4t#ane is to allow te&t to be edited in %lace, so you will see that there is no appen'A B #ethod. In this case *ad#ittedly, a %oor use o" the ca%abilities o" JTe4t#ane,, the te&t #ust be ca%tured, #odi"ied, and %laced back into the %ane using setTe4tA B. RFSURF STIJLT+(6PTE5MLTIMK3U 6s #entioned be"ore, the de"ault layout behavior o" an a%%let is to use the 2or'er+ayo*t. I" you add so#ething to the %ane without s%eci"ying any
887
details, it 0ust "ills the center o" the %ane out to the edges. (owever, i" you s%eci"y one o" the surrounding regions *C)5T(, S)4T(, E6ST, or :EST, as is done here, the co#%onent will "it itsel" into that region9in this case, the button will nest down at the botto# o" the screen. RFSURF STIJLT+(6PTE5MLTIMKGU Cotice the built'in "eatures o" JTe4t#ane, such as auto#atic line wra%%ing. There are lots o" other "eatures that you can look u% using the J7> docu#entation. RFSURFSTIJLT+(6PTE5MLTIMKIU
Check bo0es
6 check bo& %rovides a way to #ake a single onFo"" choice; it consists o" a tiny bo& and a label. The bo& ty%ically holds a little !&$ *or so#e other indication that it is set, or is e#%ty, de%ending on whether that ite# was selected. RFSURFSTIJLT+(6PTE5MLTIMK2U /ou ll nor#ally create a J-heck2o4 using a constructor that takes the label as an argu#ent. /ou can get and set the state, and also get and set the label i" you want to read or change it a"ter the J-heck2o4 has been created. RFSURFSTIJLT+(6PTE5MLTIML@U :henever a J-heck2o4 is set or cleared, an event occurs, which you can ca%ture the sa#e way you do a button, by using an Action+istener. The "ollowing e&a#%le uses a JTe4tArea to enu#erate all the check bo&es that have been checked=
//3 c()3CheckBo6es.Hava // Ysing JCheckBo6es. // Pa""let co!e?CheckBo6es :i!th? '' height? ''Q // P/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.event.B< i#"ort Hava.a:t.B< i#"ort co#.bruceeckel.s:ing.B< "ublic class CheckBo6es e6ten!s J0""let @ JTe6t0rea t ? ne: JTe6t0rea-+, (,.< JCheckBo6 cb( ? ne: JCheckBo6-8Check Bo6 (8.,
lets
888
cb ? ne: JCheckBo6-8Check Bo6 8., cb) ? ne: JCheckBo6-8Check Bo6 )8.< "ublic voi! init-. @ cb(.a!!0ctionListener-ne: 0ctionListener-. @ "ublic voi! actionPerfor#e!-0ctionEvent e.@ trace-8(8, cb(.< A A.< cb .a!!0ctionListener-ne: 0ctionListener-. @ "ublic voi! actionPerfor#e!-0ctionEvent e.@ trace-8 8, cb .< A A.< cb).a!!0ctionListener-ne: 0ctionListener-. @ "ublic voi! actionPerfor#e!-0ctionEvent e.@ trace-8)8, cb).< A A.< Container c" ? getContentPane-.< c".setLayout-ne: Llo:Layout-..< c".a!!-ne: J%crollPane-t..< c".a!!-cb(.< c".a!!-cb .< c".a!!-cb).< A voi! trace-%tring b, JCheckBo6 cb. @ if-cb.is%electe!-.. t.a""en!-8Bo6 8 K b K 8 %et_n8.< else t.a""en!-8Bo6 8 K b K 8 Cleare!_n8.< A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: CheckBo6es-., '', ''.< A A ///3>
The traceA B #ethod sends the na#e o" the selected J-heck2o4 and its current state to the JTe4tArea using appen'A B, so you ll see a cu#ulative list o" the checkbo&es that were selected and what their state is. RFSURFSTIJLT+(6PTE5MLTIMLMU
88:
$adio buttons
The conce%t o" a radio button in 84I %rogra##ing co#es "ro# %re' electronic car radios with #echanical buttons= when you %ush one in, any other button that was %ressed %o%s out. Thus, it allows you to "orce a single choice a#ong #any. RFSURFSTIJLT+(6PTE5MLTIMLKU 6ll you need to do to set u% an associated grou% o" J$a'io2*ttons is to add the# to a 2*tton"ro*p *you can have any nu#ber o" 2*tton"ro*ps on a "or#,. )ne o" the buttons can o%tionally have its starting state set to tr*e *using the second argu#ent in the constructor,. I" you try to set #ore than one radio button to tr*e then only the "inal one set will be tr*e. RFSURFSTIJLT+(6PTE5MLTIMLLU (ere s a si#%le e&a#%le o" the use o" radio buttons. Cote that you ca%ture radio button events like all others=
//3 c()35a!ioButtons.Hava // Ysing J5a!ioButtons. // Pa""let co!e?5a!ioButtons // :i!th? '' height?(''Q P/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.event.B< i#"ort Hava.a:t.B< i#"ort co#.bruceeckel.s:ing.B< "ublic class 5a!ioButtons e6ten!s J0""let @ JTe6tLiel! t ? ne: JTe6tLiel!-(,.< Buttonarou" g ? ne: Buttonarou"-.< J5a!ioButton rb( ? ne: J5a!ioButton-8one8, false., rb ? ne: J5a!ioButton-8t:o8, false., rb) ? ne: J5a!ioButton-8three8, false.< 0ctionListener al ? ne: 0ctionListener-. @ "ublic voi! actionPerfor#e!-0ctionEvent e. @ t.setTe6t-85a!io button 8 K --J5a!ioButton.e.get%ource-...getTe6t-..< A A< "ublic voi! init-. @ rb(.a!!0ctionListener-al.<
lets
88;
rb .a!!0ctionListener-al.< rb).a!!0ctionListener-al.< g.a!!-rb(.< g.a!!-rb .< g.a!!-rb).< t.setE!itable-false.< Container c" ? getContentPane-.< c".setLayout-ne: Llo:Layout-..< c".a!!-t.< c".a!!-rb(.< c".a!!-rb .< c".a!!-rb).< A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: 5a!ioButtons-., '', (''.< A A ///3>
To dis%lay the state, a te&t "ield is used. This "ield is set to noneditable because it s used only to dis%lay data, not to collect it. Thus it is an alternative to using a J+abel. RFSURFSTIJLT+(6PTE5MLTIML?U
//3 c()3Co#boBo6es.Hava // Ysing !ro"-!o:n lists. // Pa""let co!e?Co#boBo6es // :i!th? '' height?(''Q P/a""letQ i#"ort Hava6.s:ing.B<
8:=
i#"ort Hava.a:t.event.B< i#"ort Hava.a:t.B< i#"ort co#.bruceeckel.s:ing.B< "ublic class Co#boBo6es e6ten!s J0""let @ %tringNO !escri"tion ? @ 8Ebullient8, 8Gbtuse8, 85ecalcitrant8, 8Brilliant8, 8%o#nescent8, 8Ti#orous8, 8Llori!8, 8Putrescent8 A< JTe6tLiel! t ? ne: JTe6tLiel!-(,.< JCo#boBo6 c ? ne: JCo#boBo6-.< JButton b ? ne: JButton-80!! ite#s8.< int count ? '< "ublic voi! init-. @ for-int i ? '< i P I< iKK. c.a!!$te#-!escri"tionNcountKKO.< t.setE!itable-false.< b.a!!0ctionListener-ne: 0ctionListener-. @ "ublic voi! actionPerfor#e!-0ctionEvent e.@ if-count P !escri"tion.length. c.a!!$te#-!escri"tionNcountKKO.< A A.< c.a!!0ctionListener-ne: 0ctionListener-. @ "ublic voi! actionPerfor#e!-0ctionEvent e.@ t.setTe6t-8in!e63 8K c.get%electe!$n!e6-. K 8 8 K --JCo#boBo6.e.get%ource-.. .get%electe!$te#-..< A A.< Container c" ? getContentPane-.< c".setLayout-ne: Llo:Layout-..< c".a!!-t.< c".a!!-c.< c".a!!-b.< A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: Co#boBo6es-., '', (''.< A A ///3>
lets
8:1
The JTe4tFiel' dis%lays the !selected inde&,$ which is the seAuence nu#ber o" the currently selected ele#ent, as well as the label on the radio button. RFSURFSTIJLT+(6PTE5MLTIMLGU
&ist bo0es
Dist bo&es are signi"icantly di""erent "ro# J-ombo2o4 bo&es, and not 0ust in a%%earance. :hile a J-ombo2o4 bo& dro%s down when you activate it, a J+ist occu%ies so#e "i&ed nu#ber o" lines on a screen all the ti#e and doesn t change. I" you want to see the ite#s in a list, you si#%ly call get)electe'Val*esA B, which %roduces an array o" )tring o" the ite#s that have been selected. RFSURFSTIJLT+(6PTE5MLTIMLIU 6 J+ist allows #ulti%le selection= i" you control'click on #ore than one ite# *holding down the !control$ key while %er"or#ing additional #ouse clicks, the original ite# stays highlighted and you can select as #any as you want. I" you select an ite#, then shi"t'click on another ite#, all the ite#s in the s%an between the two are selected. To re#ove an ite# "ro# a grou% you can control'click it. RFSURFSTIJLT+(6PTE5MLTIML2U
//3 c()3List.Hava // Pa""let co!e?List :i!th? ,' // height?)*,Q P/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava6.s:ing.event.B< i#"ort Hava.a:t.B< i#"ort Hava.a:t.event.B< i#"ort Hava6.s:ing.bor!er.B< i#"ort co#.bruceeckel.s:ing.B< "ublic class List e6ten!s J0""let @ %tringNO flavors ? @ 8Chocolate8, 8%tra:berry8, 8Wanilla Lu!ge %:irl8, 8Jint Chi"8, 8Jocha 0l#on! Lu!ge8, 85u# 5aisin8, 8Praline Crea#8, 8Ju! Pie8 A< DefaultListJo!el l$te#s?ne: DefaultListJo!el-.< JList lst ? ne: JList-l$te#s.< JTe6t0rea t ? ne: JTe6t0rea-flavors.length, '.< JButton b ? ne: JButton-80!! $te#8.< 0ctionListener bl ? ne: 0ctionListener-. @
8:2
"ublic voi! actionPerfor#e!-0ctionEvent e. @ if-count P flavors.length. @ l$te#s.a!!-', flavorsNcountKKO.< A else @ // Disable, since there are no #ore // flavors left to be a!!e! to the List b.setEnable!-false.< A A A< List%electionListener ll ? ne: List%electionListener-. @ "ublic voi! valueChange!List%electionEvent e. @ t.setTe6t-88.< GbHectNO ite#s?lst.get%electe!Walues-.< for-int i ? '< i P ite#s.length< iKK. t.a""en!-ite#sNiO K 8_n8.< A A< int count ? '< "ublic voi! init-. @ Container c" ? getContentPane-.< t.setE!itable-false.< c".setLayout-ne: Llo:Layout-..< // Create Bor!ers for co#"onents3 Bor!er br! ? Bor!erLactory.createJatteBor!er(, (, , , Color.black.< lst.setBor!er-br!.< t.setBor!er-br!.< // 0!! the first four ite#s to the List for-int i ? '< i P I< iKK. l$te#s.a!!Ele#ent-flavorsNcountKKO.< // 0!! ite#s to the Content Pane for Dis"lay c".a!!-t.< c".a!!-lst.< c".a!!-b.< // 5egister event listeners lst.a!!List%electionListener-ll.< b.a!!0ctionListener-bl.< A
lets
8:3
"ublic static voi! #ain-%tringNO args. @ Console.run-ne: List-., ,', )*,.< A A ///3>
:hen you %ress the button it adds ite#s to the to o" the list *because a''ItemA B s second argu#ent is @,. RFSURF STIJLT+(6PTE5MLTIM?@U /ou can see that borders have also been added to the lists. RFSURF STIJLT+(6PTE5MLTIM?MU I" you 0ust want to %ut an array o" )trings into a J+ist, there s a #uch si#%ler solution= you %ass the array to the J+ist constructor, and it builds the list auto#atically. The only reason "or using the !list #odel$ in the above e&a#%le is so that the list could be #ani%ulated during the e&ecution o" the %rogra#. RFSURFSTIJLT+(6PTE5MLTIM?KU
J+ists do not auto#atically %rovide direct su%%ort "or scrolling. )" course, all you need to do is wra% the J+ist in a J)croll#ane and all the
details are auto#atically #anaged "or you. RFSURF STIJLT+(6PTE5MLTIM?LU
#abbed .anes
The JTabbe'#ane allows you to create a !tabbed dialog,$ which has "ile' "older tabs running across one edge, and all you have to do is %ress a tab to bring "orward a di""erent dialog.
//3 c()3Tabbe!Pane(.Hava // De#onstrates the Tabbe! Pane. // Pa""let co!e?Tabbe!Pane( // :i!th?),' height? ''Q P/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava6.s:ing.event.B< i#"ort Hava.a:t.B< i#"ort co#.bruceeckel.s:ing.B< "ublic class Tabbe!Pane( e6ten!s J0""let @ %tringNO flavors ? @ 8Chocolate8, 8%tra:berry8, 8Wanilla Lu!ge %:irl8, 8Jint Chi"8,
8:4
8Jocha 0l#on! Lu!ge8, 85u# 5aisin8, 8Praline Crea#8, 8Ju! Pie8 A< JTabbe!Pane tabs ? ne: JTabbe!Pane-.< JTe6tLiel! t6t ? ne: JTe6tLiel!- '.< "ublic voi! init-. @ for-int i ? '< i P flavors.length< iKK. tabs.a!!Tab-flavorsNiO, ne: JButton-8Tabbe! "ane 8 K i..< tabs.a!!ChangeListener-ne: ChangeListener-.@ "ublic voi! stateChange!-ChangeEvent e. @ t6t.setTe6t-8Tab selecte!3 8 K tabs.get%electe!$n!e6-..< A A.< Container c" ? getContentPane-.< c".a!!-Bor!erLayout.%GYTM, t6t.< c".a!!-tabs.< A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: Tabbe!Pane(-., ),', ''.< A A ///3>
In Java, the use o" so#e sort o" !tabbed %anel$ #echanis# is Auite i#%ortant because in a%%let %rogra##ing the use o" %o%'u% dialogs is discouraged by auto#atically adding a little warning to any dialog that %o%s u% out o" an a%%let. RFSURFSTIJLT+(6PTE5MLTIM??U :hen you run the %rogra# you ll see that the JTabbe'#ane auto#atically stacks the tabs i" there are too #any o" the# to "it on one row. /ou can see this by resi1ing the window when you run the %rogra# "ro# the console co##and line. RFSURFSTIJLT+(6PTE5MLTIM?HU
Message bo0es
:indowing environ#ents co##only contain a standard set o" #essage bo&es that allow you to Auickly %ost in"or#ation to the user or to ca%ture in"or#ation "ro# the user. In Swing, these #essage bo&es are contained in J.ption#ane. /ou have #any di""erent %ossibilities *so#e Auite so%histicated,, but the ones you ll #ost co##only use are %robably the
lets
8:5
#essage dialog and con"ir#ation dialog, invoked using the static J.ption#ane!sho(1essage ialogA B and J.ption#ane! sho(-onfirm ialogA B. The "ollowing e&a#%le shows a subset o" the #essage bo&es available with J.ption#ane=
//3 c()3JessageBo6es.Hava // De#onstrates Jo"tionPane. // Pa""let co!e?JessageBo6es // :i!th? '' height?(,'Q P/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.event.B< i#"ort Hava.a:t.B< i#"ort co#.bruceeckel.s:ing.B< "ublic class JessageBo6es e6ten!s J0""let @ JButtonNO b ? @ ne: JButton-80lert8., ne: JButton-8;es/&o8., ne: JButton-8Color8., ne: JButton-8$n"ut8., ne: JButton-8) Wals8. A< JTe6tLiel! t6t ? ne: JTe6tLiel!-(,.< 0ctionListener al ? ne: 0ctionListener-. @ "ublic voi! actionPerfor#e!-0ctionEvent e.@ %tring i! ? --JButton.e.get%ource-...getTe6t-.< if-i!.e=uals-80lert8.. JG"tionPane.sho:JessageDialog-null, 8There2s a bug on you48, 8Mey48, JG"tionPane.E55G5bJE%%0aE.< else if-i!.e=uals-8;es/&o8.. JG"tionPane.sho:Confir#Dialog-null, 8or no8, 8choose yes8, JG"tionPane.;E%b&GbGPT$G&.< else if-i!.e=uals-8Color8.. @ GbHectNO o"tions ? @ 85e!8, 8areen8 A< int sel ? JG"tionPane.sho:G"tionDialognull, 8Choose a Color48, 8\arning8, JG"tionPane.DEL0YLTbGPT$G&, JG"tionPane.\05&$&abJE%%0aE, null, o"tions, o"tionsN'O.< if-sel 4? JG"tionPane.CLG%EDbGPT$G&. t6t.setTe6t-
8:7
8Color %electe!3 8 K o"tionsNselO.< A else if-i!.e=uals-8$n"ut8.. @ %tring val ? JG"tionPane.sho:$n"utDialog8Mo: #any fingers !o you see[8.< t6t.setTe6t-val.< A else if-i!.e=uals-8) Wals8.. @ GbHectNO selections ? @ 8Lirst8, 8%econ!8, 8Thir!8 A< GbHect val ? JG"tionPane.sho:$n"utDialognull, 8Choose one8, 8$n"ut8, JG"tionPane.$&LG5J0T$G&bJE%%0aE, null, selections, selectionsN'O.< if-val 4? null. t6t.setTe6tval.to%tring-..< A A A< "ublic voi! init-. @ Container c" ? getContentPane-.< c".setLayout-ne: Llo:Layout-..< for-int i ? '< i P b.length< iKK. @ bNiO.a!!0ctionListener-al.< c".a!!-bNiO.< A c".a!!-t6t.< A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: JessageBo6es-., '', ''.< A A ///3>
To be able to write a single Action+istener, I ve used the so#ewhat risky a%%roach o" checking the )tring labels on the buttons. The %roble# with this is that it s easy to get the label a little bit wrong, ty%ically in ca%itali1ation, and this bug can be hard to s%ot. RFSURF STIJLT+(6PTE5MLTIM?3U Cote that sho(.ption ialogA B and sho(Inp*t ialogA B %rovide return ob0ects that contain the value entered by the user. RFSURF STIJLT+(6PTE5MLTIM?GU
lets
8:8
Menus
Each co#%onent ca%able o" holding a #enu, including JApplet, JFrame, J ialog, and their descendants, has a setJ1en*2arA B #ethod that acce%ts a J1en*2ar *you can have only one J1en*2ar on a %articular co#%onent,. /ou add J1en*s to the J1en*2ar, and J1en*Items to the J1en*s. Each J1en*Item can have an Action+istener attached to it, to be "ired when that #enu ite# is selected. RFSURFSTIJLT+(6PTE5MLTIM?IU
4nlike a syste# that uses resources, with Java and Swing you #ust hand asse#ble all the #enus in source code. (ere is a very si#%le #enu e&a#%le= //3 c()3%i#"leJenus.Hava // Pa""let co!e?%i#"leJenus // :i!th? '' height?*,Q P/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.event.B< i#"ort Hava.a:t.B< i#"ort co#.bruceeckel.s:ing.B< "ublic class %i#"leJenus e6ten!s J0""let @ JTe6tLiel! t ? ne: JTe6tLiel!-(,.< 0ctionListener al ? ne: 0ctionListener-. @ "ublic voi! actionPerfor#e!-0ctionEvent e.@ t.setTe6t--JJenu$te#.e.get%ource-...getTe6t-..< A A< JJenuNO #enus ? @ ne: JJenu-8\inken8., ne: JJenu-8Blinken8., ne: JJenu-8&o!8. A< JJenu$te#NO ite#s ? @ ne: JJenu$te#-8Lee8., ne: JJenu$te#-8Li8., ne: JJenu$te#-8Lo8., ne: JJenu$te#-8Ti"8., ne: JJenu$te#-8Ta"8., ne: JJenu$te#-8Tot8., ne: JJenu$te#-8Glly8., ne: JJenu$te#-8G6en8., ne: JJenu$te#-8Lree8. A< "ublic voi! init-. @ for-int i ? '< i P ite#s.length< iKK. @ ite#sNiO.a!!0ctionListener-al.<
8::
#enusNiV)O.a!!-ite#sNiO.< A JJenuBar #b ? ne: JJenuBar-.< for-int i ? '< i P #enus.length< iKK. #b.a!!-#enusNiO.< setJJenuBar-#b.< Container c" ? getContentPane-.< c".setLayout-ne: Llo:Layout-..< c".a!!-t.< A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: %i#"leJenus-., '', *,.< A A ///3>
The use o" the #odulus o%erator in ! iSJ$ distributes the #enu ite#s a#ong the three J1en*s. Each J1en*Item #ust have an Action+istener attached to it; here, the sa#e Action+istener is used everywhere but you ll usually need an individual one "or each J1en*Item. RFSURFSTIJLT+(6PTE5MLTIM?2U
J1en*Item inherits Abstract2*tton, so it has so#e buttonlike behaviors. By itsel", it %rovides an ite# that can be %laced on a dro%'down #enu. There are also three ty%es inherited "ro# J1en*Item= J1en* to hold other J1en*Items *so you can have cascading #enus,, J-heck2o41en*Item, which %roduces a check#ark to indicate whether that #enu ite# is selected, and J$a'io2*tton1en*Item, which contains a radio button. RFSURFSTIJLT+(6PTE5MLTIMH@U
6s a #ore so%histicated e&a#%le, here are the ice crea# "lavors again, used to create #enus. This e&a#%le also shows cascading #enus, keyboard #ne#onics, J-heck2o41en*Items, and the way you can dyna#ically change #enus=
//3 c()3Jenus.Hava // %ub#enus, checkbo6 #enu ite#s, s:a""ing #enus, // #ne#onics -shortcuts. an! action co##an!s. // Pa""let co!e?Jenus :i!th?)'' // height?(''Q P/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.B<
lets
8:;
i#"ort Hava.a:t.event.B< i#"ort co#.bruceeckel.s:ing.B< "ublic class Jenus e6ten!s J0""let @ %tringNO flavors ? @ 8Chocolate8, 8%tra:berry8, 8Wanilla Lu!ge %:irl8, 8Jint Chi"8, 8Jocha 0l#on! Lu!ge8, 85u# 5aisin8, 8Praline Crea#8, 8Ju! Pie8 A< JTe6tLiel! t ? ne: JTe6tLiel!-8&o flavor8, )'.< JJenuBar #b( ? ne: JJenuBar-.< JJenu f ? ne: JJenu-8Lile8., # ? ne: JJenu-8Llavors8., s ? ne: JJenu-8%afety8.< // 0lternative a""roach3 JCheckBo6Jenu$te#NO safety ? @ ne: JCheckBo6Jenu$te#-8auar!8., ne: JCheckBo6Jenu$te#-8Mi!e8. A< JJenu$te#NO file ? @ ne: JJenu$te#-8G"en8., A< // 0 secon! #enu bar to s:a" to3 JJenuBar #b ? ne: JJenuBar-.< JJenu fooBar ? ne: JJenu-8fooBar8.< JJenu$te#NO other ? @ // 0!!ing a #enu shortcut -#ne#onic. is very // si#"le, but only JJenu$te#s can have the# // in their constructors3 ne: JJenu$te#-8Loo8, `eyEvent.W`bL., ne: JJenu$te#-8Bar8, `eyEvent.W`b0., // &o shortcut3 ne: JJenu$te#-8BaU8., A< JButton b ? ne: JButton-8%:a" Jenus8.< class BL i#"le#ents 0ctionListener @ "ublic voi! actionPerfor#e!-0ctionEvent e. @ JJenuBar # ? getJJenuBar-.< setJJenuBar-# ?? #b( [ #b 3 #b(.< vali!ate-.< // 5efresh the fra#e A
8;=
A class JL i#"le#ents 0ctionListener @ "ublic voi! actionPerfor#e!-0ctionEvent e. @ JJenu$te# target ? -JJenu$te#.e.get%ource-.< %tring actionCo##an! ? target.get0ctionCo##an!-.< if-actionCo##an!.e=uals-8G"en8.. @ %tring s ? t.getTe6t-.< boolean chosen ? false< for-int i ? '< i P flavors.length< iKK. if-s.e=uals-flavorsNiO.. chosen ? true< if-4chosen. t.setTe6t-8Choose a flavor first48.< else t.setTe6t-8G"ening 8K s K8. J##, ##48.< A A A class LL i#"le#ents 0ctionListener @ "ublic voi! actionPerfor#e!-0ctionEvent e. @ JJenu$te# target ? -JJenu$te#.e.get%ource-.< t.setTe6t-target.getTe6t-..< A A // 0lternatively, you can create a !ifferent // class for each !ifferent Jenu$te#. Then you // Don2t have to figure out :hich one it is3 class LooL i#"le#ents 0ctionListener @ "ublic voi! actionPerfor#e!-0ctionEvent e. @ t.setTe6t-8Loo selecte!8.< A A class BarL i#"le#ents 0ctionListener @ "ublic voi! actionPerfor#e!-0ctionEvent e. @ t.setTe6t-8Bar selecte!8.< A A class BaUL i#"le#ents 0ctionListener @ "ublic voi! actionPerfor#e!-0ctionEvent e. @ t.setTe6t-8BaU selecte!8.< A
lets
8;1
A class CJ$L i#"le#ents $te#Listener @ "ublic voi! ite#%tateChange!-$te#Event e. @ JCheckBo6Jenu$te# target ? -JCheckBo6Jenu$te#.e.get%ource-.< %tring actionCo##an! ? target.get0ctionCo##an!-.< if-actionCo##an!.e=uals-8auar!8.. t.setTe6t-8auar! the $ce Crea#4 8 K 8auar!ing is 8 K target.get%tate-..< else if-actionCo##an!.e=uals-8Mi!e8.. t.setTe6t-8Mi!e the $ce Crea#4 8 K 8$s it col![ 8 K target.get%tate-..< A A "ublic voi! init-. @ JL #l ? ne: JL-.< CJ$L c#il ? ne: CJ$L-.< safetyN'O.set0ctionCo##an!-8auar!8.< safetyN'O.setJne#onic-`eyEvent.W`ba.< safetyN'O.a!!$te#Listener-c#il.< safetyN(O.set0ctionCo##an!-8Mi!e8.< safetyN'(O.setJne#onic-`eyEvent.W`bM.< safetyN(O.a!!$te#Listener-c#il.< otherN'O.a!!0ctionListener-ne: LooL-..< otherN(O.a!!0ctionListener-ne: BarL-..< otherN O.a!!0ctionListener-ne: BaUL-..< LL fl ? ne: LL-.< for-int i ? '< i P flavors.length< iKK. @ JJenu$te# #i ? ne: JJenu$te#-flavorsNiO.< #i.a!!0ctionListener-fl.< #.a!!-#i.< // 0!! se"arators at intervals3 if--iK(. V ) ?? '. #.a!!%e"arator-.< A for-int i ? '< i P safety.length< iKK. s.a!!-safetyNiO.< s.setJne#onic-`eyEvent.W`b0.< f.a!!-s.< f.setJne#onic-`eyEvent.W`bL.<
8;2
for-int i ? '< i P file.length< iKK. @ fileNiO.a!!0ctionListener-fl.< f.a!!-fileNiO.< A #b(.a!!-f.< #b(.a!!-#.< setJJenuBar-#b(.< t.setE!itable-false.< Container c" ? getContentPane-.< c".a!!-t, Bor!erLayout.CE&TE5.< // %et u" the syste# for s:a""ing #enus3 b.a!!0ctionListener-ne: BL-..< b.setJne#onic-`eyEvent.W`b%.< c".a!!-b, Bor!erLayout.&G5TM.< for-int i ? '< i P other.length< iKK. fooBar.a!!-otherNiO.< fooBar.setJne#onic-`eyEvent.W`bB.< #b .a!!-fooBar.< A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: Jenus-., )'', (''.< A A ///3>
In this %rogra# I %laced the #enu ite#s into arrays and then ste%%ed through each array calling a''A B "or each J1en*Item. This #akes adding or subtracting a #enu ite# so#ewhat less tedious. RFSURF STIJLT+(6PTE5MLTIMHMU This %rogra# creates not one but two J1en*2ars to de#onstrate that #enu bars can be actively swa%%ed while the %rogra# is running. /ou can see how a J1en*2ar is #ade u% o" J1en*s, and each J1en* is #ade u% o" J1en*Items, J-heck2o41en*Items, or even other J1en*s *which %roduce sub#enus,. :hen a J1en*2ar is asse#bled it can be installed into the current %rogra# with the setJ1en*2arA B #ethod. Cote that when the button is %ressed, it checks to see which #enu is currently installed by calling getJ1en*2arA B, then it %uts the other #enu bar in its %lace. RFSURFSTIJLT+(6PTE5MLTIMHKU :hen testing "or !)%en,$ notice that s%elling and ca%itali1ation are critical, but Java signals no error i" there is no #atch with !)%en.$ This
lets
8;3
kind o" string co#%arison is a source o" %rogra##ing errors. RFSURF STIJLT+(6PTE5MLTIMHLU The checking and unchecking o" the #enu ite#s is taken care o" auto#atically. The code handling the J-heck2o41en*Items shows two di""erent ways to deter#ine what was checked= string #atching *which, as #entioned above, isn t a very sa"e a%%roach although you ll see it used, and #atching on the event target ob0ect. 6s shown, the get)tate A B #ethod can be used to reveal the state. /ou can also change the state o" a J-heck2o41en*Item with set)tateA B. RFSURF STIJLT+(6PTE5MLTIMH?U The events "or #enus are a bit inconsistent and can lead to con"usion= J1en*Items use Action+isteners, but J-heckbo41en*Items use Item+isteners. The J1en* ob0ects can also su%%ort Action+isteners, but that s not usually hel%"ul. In general, you ll attach listeners to each J1en*Item, J-heck2o41en*Item, or J$a'io2*tton1en*Item, but the e&a#%le shows Item+isteners and Action+isteners attached to the various #enu co#%onents. RFSURF STIJLT+(6PTE5MLTIMHHU Swing su%%orts #ne#onics, or !keyboard shortcuts,$ so you can select anything derived "ro# Abstract2*tton *button, #enu ite#, etc., using the keyboard instead o" the #ouse. These are Auite si#%le= "or J1en*Item you can use the overloaded constructor that takes as a second argu#ent the identi"ier "or the key. (owever, #ost Abstract2*ttons do not have constructors like this so the #ore general way to solve the %roble# is to use the set1nemonicA B #ethod. The e&a#%le above adds #ne#onics to the button and so#e o" the #enu ite#s; shortcut indicators auto#atically a%%ear on the co#%onents. RF SURFSTIJLT+(6PTE5MLTIMH3U /ou can also see the use o" setAction-omman'A B. This see#s a bit strange because in each case the !action co##and$ is e&actly the sa#e as the label on the #enu co#%onent. :hy not 0ust use the label instead o" this alternative stringO The %roble# is internationali1ation. I" you retarget this %rogra# to another language, you want to change only the label in the #enu, and not change the code *which would no doubt introduce new errors,. So to #ake this easy "or code that checks the te&t
8;4
string associated with a #enu co#%onent, the !action co##and$ can be i##utable while the #enu label can change. 6ll the code works with the !action co##and,$ so it s una""ected by changes to the #enu labels. Cote that in this %rogra#, not all the #enu co#%onents are e&a#ined "or their action co##ands, so those that aren t don t have their action co##and set. RFSURFSTIJLT+(6PTE5MLTIMHGU The bulk o" the work ha%%ens in the listeners. 2+ %er"or#s the J1en*2ar swa%%ing. In 1+, the !"igure out who rang$ a%%roach is taken by getting the source o" the Action&vent and casting it to a J1en*Item, then getting the action co##and string to %ass it through a cascaded if state#ent. RFSURFSTIJLT+(6PTE5MLTIMHIU The F+ listener is si#%le even though it s handling all the di""erent "lavors in the "lavor #enu. This a%%roach is use"ul i" you have enough si#%licity in your logic, but in general, you ll want to take the a%%roach used with Foo+, 2ar+, and 2a7+, in which they are each attached to only a single #enu co#%onent so no e&tra detection logic is necessary and you know e&actly who called the listener. Even with the %ro"usion o" classes generated this way, the code inside tends to be s#aller and the %rocess is #ore "ool%roo". RFSURFSTIJLT+(6PTE5MLTIMH2U /ou can see that #enu code Auickly gets long'winded and #essy. This is another case where the use o" a 84I builder is the a%%ro%riate solution. 6 good tool will also handle the #aintenance o" the #enus. RFSURF STIJLT+(6PTE5MLTIM3@U
o.@u. menus
The #ost straight"orward way to i#%le#ent a J#op*p1en* is to create an inner class that e&tends 1o*seA'apter, then add an ob0ect o" that inner class to each co#%onent that you want to %roduce %o%'u% behavior=
//3 c()3Po"u".Hava // Creating "o"u" #enus :ith %:ing. // Pa""let co!e?Po"u" // :i!th?)'' height? ''QP/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.B< i#"ort Hava.a:t.event.B<
lets
8;5
i#"ort co#.bruceeckel.s:ing.B< "ublic class Po"u" e6ten!s J0""let @ JPo"u"Jenu "o"u" ? ne: JPo"u"Jenu-.< JTe6tLiel! t ? ne: JTe6tLiel!-('.< "ublic voi! init-. @ Container c" ? getContentPane-.< c".setLayout-ne: Llo:Layout-..< c".a!!-t.< 0ctionListener al ? ne: 0ctionListener-. @ "ublic voi! actionPerfor#e!-0ctionEvent e.@ t.setTe6t--JJenu$te#.e.get%ource-...getTe6t-..< A A< JJenu$te# # ? ne: JJenu$te#-8Mither8.< #.a!!0ctionListener-al.< "o"u".a!!-#.< # ? ne: JJenu$te#-8;on8.< #.a!!0ctionListener-al.< "o"u".a!!-#.< # ? ne: JJenu$te#-80far8.< #.a!!0ctionListener-al.< "o"u".a!!-#.< "o"u".a!!%e"arator-.< # ? ne: JJenu$te#-8%tay Mere8.< #.a!!0ctionListener-al.< "o"u".a!!-#.< Po"u"Listener "l ? ne: Po"u"Listener-.< a!!JouseListener-"l.< t.a!!JouseListener-"l.< A class Po"u"Listener e6ten!s Jouse0!a"ter @ "ublic voi! #ousePresse!-JouseEvent e. @ #aybe%ho:Po"u"-e.< A "ublic voi! #ouse5elease!-JouseEvent e. @ #aybe%ho:Po"u"-e.< A "rivate voi! #aybe%ho:Po"u"-JouseEvent e. @ if-e.isPo"u"Trigger-.. @
8;7
"o"u".sho:e.getCo#"onent-., e.get9-., e.get;-..< A A A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: Po"u"-., )'', ''.< A A ///3>
The sa#e Action+istener is added to each J1en*Item, so that it "etches the te&t "ro# the #enu label and inserts it into the JTe4tFiel'. RFSURFSTIJLT+(6PTE5MLTIM3MU
Drawing
In a good 84I "ra#ework, drawing should be reasonably easy9and it is, in the Swing library. The %roble# with any drawing e&a#%le is that the calculations that deter#ine where things go are ty%ically a lot #ore co#%licated that the calls to the drawing routines, and these calculations are o"ten #i&ed together with the drawing calls so it can see# that the inter"ace is #ore co#%licated than it actually is. RFSURF STIJLT+(6PTE5MLTIM3KU Eor si#%licity, consider the %roble# o" re%resenting data on the screen9 here, the data will be %rovided by the built'in 1ath!sinA B #ethod which is a #athe#atical sine "unction. To #ake things a little #ore interesting, and to "urther de#onstrate how easy it is to use Swing co#%onents, a slider will be %laced at the botto# o" the "or# to dyna#ically control the nu#ber o" sine wave cycles that are dis%layed. In addition, i" you resi1e the window, you ll see that the sine wave re"its itsel" to the new window si1e. RFSURFSTIJLT+(6PTE5MLTIM3LU 6lthough any J-omponent #ay be %ainted and thus used as a canvas, i" you 0ust want a straight"orward drawing sur"ace you will ty%ically inherit "ro# a J#anel. The only #ethod you need to override is paint-omponentA B, which is called whenever that co#%onent #ust be re%ainted *you nor#ally don t need to worry about this, as the decision is #anaged by Swing,. :hen it is called, Swing %asses a "raphics ob0ect to
lets
8;8
the #ethod, and you can then use this ob0ect to draw or %aint on the sur"ace. RFSURFSTIJLT+(6PTE5MLTIM3?U In the "ollowing e&a#%le, all the intelligence concerning %ainting is in the
)ine ra( class; the )ine0ave class si#%ly con"igures the %rogra# and the slider control. Inside )ine ra(, the set-yclesA B #ethod
%rovides a hook to allow another ob0ect9the slider control, in this case9 to control the nu#ber o" cycles.
//3 c()3%ine\ave.Hava // Dra:ing :ith %:ing, using a J%li!er. // Pa""let co!e?%ine\ave // :i!th?*'' height?I''QP/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava6.s:ing.event.B< i#"ort Hava.a:t.B< i#"ort co#.bruceeckel.s:ing.B< class %ineDra: e6ten!s JPanel @ static final int %C0LEL0CTG5 ? ''< int cycles< int "oints< !oubleNO sines< intNO "ts< %ineDra:-. @ setCycles-,.< A "ublic voi! setCycles-int ne:Cycles. @ cycles ? ne:Cycles< "oints ? %C0LEL0CTG5 B cycles B < sines ? ne: !oubleN"ointsO< "ts ? ne: intN"ointsO< for-int i ? '< i P "oints< iKK. @ !ouble ra!ians ? -Jath.P$/%C0LEL0CTG5. B i< sinesNiO ? Jath.sin-ra!ians.< A re"aint-.< A "ublic voi! "aintCo#"onent-ara"hics g. @ su"er."aintCo#"onent-g.< int #a6\i!th ? get\i!th-.< !ouble hste" ? -!ouble.#a6\i!th/-!ouble."oints< int #a6Meight ? getMeight-.<
8;:
"ts ? ne: intN"ointsO< for-int i ? '< i P "oints< iKK. "tsNiO ? -int.-sinesNiO B #a6Meight/ K #a6Meight/ .< g.setColor-Color.re!.< for-int i ? (< i P "oints< iKK. @ int 6( ? -int.--i - (. B hste".< int 6 ? -int.-i B hste".< int y( ? "tsNi-(O< int y ? "tsNiO< g.!ra:Line-6(, y(, 6 , y .< A A A
B .C,
"ublic class %ine\ave e6ten!s J0""let @ %ineDra: sines ? ne: %ineDra:-.< J%li!er cycles a!HustCycles ? ne: J%li!er-(, )', ,.< "ublic voi! init-. @ Container c" ? getContentPane-.< c".a!!-sines.< a!HustCyclescycles.a!!ChangeListenerne: ChangeListener-.@ "ublic voi! stateChange!-ChangeEvent e. @ sines.setCycles--J%li!er.e.get%ource-...getWalue-..< A A.< c".a!!-Bor!erLayout.%GYTM, cyclesa!HustCycles.< A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: %ine\ave-., *'', I''.< A A ///3> 6ll o" the data #e#bers and arrays are used in the calculation o" the sine wave %oints= cycles indicates the nu#ber o" co#%lete sine waves desired, points contains the total nu#ber o" %oints that will be gra%hed, sines contains the sine "unction values, and pts contains the y'coordinates o" the %oints that will be drawn on the J#anel. The set-yclesA B #ethod
lets
8;;
creates the arrays according to the nu#ber o" %oints needed and "ills the sines array with nu#bers. By calling repaintA B , set-yclesA B "orces paint-omponentA B to be called so the rest o" the calculation and redraw will take %lace. RFSURFSTIJLT+(6PTE5MLTIM3HU The "irst thing you #ust do when you override paint-omponentA B is to call the base'class version o" the #ethod. Then you are "ree to do whatever you like; nor#ally, this #eans using the "raphics #ethods that you can "ind in the docu#entation "or 8ava!a(t!"raphics *in the (TMD docu#entation "ro# >ava'sun'com, to draw and %aint %i&els onto the J#anel. (ere, you can see that al#ost all the code is involved in %er"or#ing the calculations; the only two #ethod calls that actually #ani%ulate the screen are set-olorA B and 'ra(+ineA B. /ou will %robably have a si#ilar e&%erience when creating your own %rogra# that dis%lays gra%hical data9you ll s%end #ost o" your ti#e "iguring out what it is you want to draw, but the actual drawing %rocess will be Auite si#%le. RFSURFSTIJLT+(6PTE5MLTIM33U :hen I created this %rogra#, the bulk o" #y ti#e was s%ent in getting the sine wave to dis%lay. )nce I did that, I thought it would be nice to be able to dyna#ically change the nu#ber o" cycles. My %rogra##ing e&%eriences when trying to do such things in other languages #ade #e a bit reluctant to try this, but it turned out to be the easiest %art o" the %ro0ect. I created a J)li'er *the argu#ents are the le"t'#ost value o" the J)li'er, the right'#ost value, and the starting value, res%ectively, but there are other constructors as well, and dro%%ed it into the JApplet. Then I looked at the (TMD docu#entation and noticed that the only listener was the a''-hange+istener, which was triggered whenever the slider was changed enough "or it to %roduce a di""erent value. The only #ethod "or this was the obviously na#ed state-hange'A B, which %rovided a -hange&vent ob0ect so that I could look backward to the source o" the change and "ind the new value. By calling the sines ob0ect s set-yclesA B, the new value was incor%orated and the J#anel redrawn. RFSURFSTIJLT+(6PTE5MLTIM3GU In general, you will "ind that #ost o" your Swing %roble#s can be solved by "ollowing a si#ilar %rocess, and you ll "ind that it s generally Auite si#%le, even i" you haven t used a %articular co#%onent be"ore. RFSURF STIJLT+(6PTE5MLTIM3IU
:==
I" your %roble# is #ore co#%le&, there are other #ore so%histicated alternatives "or drawing, including third'%arty JavaBeans co#%onents and the Java K7 6PI. These solutions are beyond the sco%e o" this book, but you should look the# u% i" your drawing code beco#es too onerous. RFSURFSTIJLT+(6PTE5MLTIM32U
Dialog ;o0es
6 dialog bo& is a window that %o%s u% out o" another window. Its %ur%ose is to deal with so#e s%eci"ic issue without cluttering the original window with those details. 7ialog bo&es are heavily used in windowed %rogra##ing environ#ents, but less "reAuently used in a%%lets. RFSURF STIJLT+(6PTE5MLTIMG@U To create a dialog bo&, you inherit "ro# J ialog, which is 0ust another kind o" 0in'o(, like a JFrame. 6 J ialog has a layout #anager *which de"aults to 2or'er+ayo*t, and you add event listeners to deal with events. )ne signi"icant di""erence when (in'o(-losingA B is called is that you don t want to shut down the a%%lication. Instead, you release the resources used by the dialog s window by calling 'isposeA B. (ere s a very si#%le e&a#%le=
//3 c()3Dialogs.Hava // Creating an! using Dialog Bo6es. // Pa""let co!e?Dialogs :i!th?( , height?*,Q // P/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.event.B< i#"ort Hava.a:t.B< i#"ort co#.bruceeckel.s:ing.B< class JyDialog e6ten!s JDialog @ "ublic JyDialog-JLra#e "arent. @ su"er-"arent, 8Jy !ialog8, true.< Container c" ? getContentPane-.< c".setLayout-ne: Llo:Layout-..< c".a!!-ne: JLabel-8Mere is #y !ialog8..< JButton ok ? ne: JButton-8G`8.< ok.a!!0ctionListener-ne: 0ctionListener-. @ "ublic voi! actionPerfor#e!-0ctionEvent e.@
lets
:=1
!is"ose-.< // Closes the !ialog A A.< c".a!!-ok.< set%iUe-(,',( ,.< A A "ublic class Dialogs e6ten!s J0""let @ JButton b( ? ne: JButton-8Dialog Bo68.< JyDialog !lg ? ne: JyDialog-null.< "ublic voi! init-. @ b(.a!!0ctionListener-ne: 0ctionListener-. @ "ublic voi! actionPerfor#e!-0ctionEvent e.@ !lg.sho:-.< A A.< getContentPane-..a!!-b(.< A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: Dialogs-., ( ,, *,.< A A ///3>
)nce the J ialog is created, the sho(A B #ethod #ust be called to dis%lay and activate it. Eor the dialog to close, it #ust call 'isposeA B. RF SURFSTIJLT+(6PTE5MLTIMGMU /ou ll see that anything that %o%s u% out o" an a%%let, including dialog bo&es, is !untrusted.$ That is, you get a warning in the window that s been %o%%ed u%. This is because, in theory, it would be %ossible to "ool the user into thinking that they re dealing with a regular native a%%lication and to get the# to ty%e in their credit card nu#ber, which then goes across the :eb. 6n a%%let is always attached to a :eb %age and visible within your :eb browser, while a dialog bo& is detached9so in theory, it could be %ossible. 6s a result it is not so co##on to see an a%%let that uses a dialog bo&. RFSURFSTIJLT+(6PTE5MLTIMGKU The "ollowing e&a#%le is #ore co#%le&; the dialog bo& is #ade u% o" a grid *using "ri'+ayo*t, o" a s%ecial kind o" button that is de"ined here as class Toe2*tton. This button draws a "ra#e around itsel" and,
:=2
de%ending on its state, a blank, an !&,$ or an !o$ in the #iddle. It starts out blank, and then de%ending on whose turn it is, changes to an !&$ or an !o.$ (owever, it will also "li% back and "orth between !&$ and !o$ when you click on the button. *This #akes the tic'tac'toe conce%t only slightly #ore annoying than it already is., In addition, the dialog bo& can be set u% "or any nu#ber o" rows and colu#ns by changing nu#bers in the #ain a%%lication window.
//3 c()3TicTacToe.Hava // De#onstration of !ialog bo6es // an! creating your o:n co#"onents. // Pa""let co!e?TicTacToe // :i!th? '' height?(''QP/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.B< i#"ort Hava.a:t.event.B< i#"ort co#.bruceeckel.s:ing.B< "ublic class TicTacToe e6ten!s J0""let @ JTe6tLiel! ro:s ? ne: JTe6tLiel!-8)8., cols ? ne: JTe6tLiel!-8)8.< static final int BL0&` ? ', 99 ? (, GG ? < class ToeDialog e6ten!s JDialog @ int turn ? 99< // %tart :ith 62s turn // : ? nu#ber of cells :i!e // h ? nu#ber of cells high "ublic ToeDialog-int :, int h. @ setTitle-8The ga#e itself8.< Container c" ? getContentPane-.< c".setLayout-ne: ari!Layout-:, h..< for-int i ? '< i P : B h< iKK. c".a!!-ne: ToeButton-..< set%iUe-: B ,', h B ,'.< // JD` (.) close !ialog3 //SsetDefaultCloseG"eration//S D$%PG%EbG&bCLG%E.< // JD` (. close !ialog3 a!!\in!o:Listener-ne: \in!o:0!a"ter-. @ "ublic voi! :in!o:Closing-\in!o:Event e.@ !is"ose-.<
lets
:=3
A A.< A class ToeButton e6ten!s JPanel @ int state ? BL0&`< "ublic ToeButton-. @ a!!JouseListener-ne: JL-..< A "ublic voi! "aintCo#"onent-ara"hics g. @ su"er."aintCo#"onent-g.< int 6( ? '< int y( ? '< int 6 ? get%iUe-..:i!th - (< int y ? get%iUe-..height - (< g.!ra:5ect-6(, y(, 6 , y .< 6( ? 6 /I< y( ? y /I< int :i!e ? 6 / < int high ? y / < if-state ?? 99. @ g.!ra:Line-6(, y(, 6( K :i!e, y( K high.< g.!ra:Line-6(, y( K high, 6( K :i!e, y(.< A if-state ?? GG. @ g.!ra:Gval-6(, y(, 6( K :i!e/ , y( K high/ .< A A class JL e6ten!s Jouse0!a"ter @ "ublic voi! #ousePresse!-JouseEvent e. @ if-state ?? BL0&`. @ state ? turn< turn ? -turn ?? 99 [ GG 3 99.< A else state ? -state ?? 99 [ GG 3 99.< re"aint-.< A A
:=4
A A class BL i#"le#ents 0ctionListener @ "ublic voi! actionPerfor#e!-0ctionEvent e. @ JDialog ! ? ne: ToeDialog$nteger."arse$nt-ro:s.getTe6t-.., $nteger."arse$nt-cols.getTe6t-...< !.setWisible-true.< A A "ublic voi! init-. @ JPanel " ? ne: JPanel-.< ".setLayout-ne: ari!Layout- , ..< ".a!!-ne: JLabel-85o:s8, JLabel.CE&TE5..< ".a!!-ro:s.< ".a!!-ne: JLabel-8Colu#ns8, JLabel.CE&TE5..< ".a!!-cols.< Container c" ? getContentPane-.< c".a!!-", Bor!erLayout.&G5TM.< JButton b ? ne: JButton-8go8.< b.a!!0ctionListener-ne: BL-..< c".a!!-b, Bor!erLayout.%GYTM.< A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: TicTacToe-., '', (''.< A A ///3>
Because statics can only be at the outer level o" the class, inner classes cannot have static data or static inner classes. RFSURF STIJLT+(6PTE5MLTIMGLU The paint-omponentA B #ethod draws the sAuare around the %anel, and the !&$ or the !o.$ This is "ull o" tedious calculations, but it s straight"orward. RFSURFSTIJLT+(6PTE5MLTIMG?U 6 #ouse click is ca%tured by the 1o*se+istener, which "irst checks to see i" the %anel has anything written on it. I" not, the %arent window is Aueried to "ind out whose turn it is and that is used to establish the state o" the Toe2*tton. Via the inner class #echanis#, the Toe2*tton then reaches back into the %arent and changes the turn. I" the button is already
lets
:=5
dis%laying an !&$ or an !o$ then that is "lo%%ed. /ou can see in these calculations the convenient use o" the ternary i"'else described in +ha%ter L. 6"ter a state change, the Toe2*tton is re%ainted. RFSURF STIJLT+(6PTE5MLTIMGHU The constructor "or Toe ialog is Auite si#%le= it adds into a "ri'+ayo*t as #any buttons as you reAuest, then resi1es it "or H@ %i&els on a side "or each button. RFSURFSTIJLT+(6PTE5MLTIMG3U
TicTacToe sets u% the whole a%%lication by creating the JTe4tFiel's *"or in%utting the rows and colu#ns o" the button grid, and the !go$ button with its Action+istener. :hen the button is %ressed, the data in the JTe4tFiel's #ust be "etched, and, since they are in )tring "or#, turned into ints using the static Integer!parseIntA B #ethod. RFSURF STIJLT+(6PTE5MLTIMGGU
<ile dialogs
So#e o%erating syste#s have a nu#ber o" s%ecial built'in dialog bo&es to handle the selection o" things such as "onts, colors, %rinters, and the like. Virtually all gra%hical o%erating syste#s su%%ort the o%ening and saving o" "iles, however, and so Java s JFile-hooser enca%sulates these "or easy use. RFSURFSTIJLT+(6PTE5MLTIMGIU The "ollowing a%%lication e&ercises two "or#s o" JFile-hooser dialogs, one "or o%ening and one "or saving. Most o" the code should by now be "a#iliar, and all the interesting activities ha%%en in the action listeners "or the two di""erent button clicks=
//3 c()3LileChooserTest.Hava // De#onstration of Lile !ialog bo6es. i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.B< i#"ort Hava.a:t.event.B< i#"ort co#.bruceeckel.s:ing.B< "ublic class LileChooserTest e6ten!s JLra#e @ JTe6tLiel! filena#e ? ne: JTe6tLiel!-., !ir ? ne: JTe6tLiel!-.<
:=7
JButton o"en ? ne: JButton-8G"en8., save ? ne: JButton-8%ave8.< "ublic LileChooserTest-. @ JPanel " ? ne: JPanel-.< o"en.a!!0ctionListener-ne: G"enL-..< ".a!!-o"en.< save.a!!0ctionListener-ne: %aveL-..< ".a!!-save.< Container c" ? getContentPane-.< c".a!!-", Bor!erLayout.%GYTM.< !ir.setE!itable-false.< filena#e.setE!itable-false.< " ? ne: JPanel-.< ".setLayout-ne: ari!Layout- ,(..< ".a!!-filena#e.< ".a!!-!ir.< c".a!!-", Bor!erLayout.&G5TM.< A class G"enL i#"le#ents 0ctionListener @ "ublic voi! actionPerfor#e!-0ctionEvent e. @ JLileChooser c ? ne: JLileChooser-.< // De#onstrate 8G"en8 !ialog3 int rWal ? c.sho:G"enDialog-LileChooserTest.this.< if-rWal ?? JLileChooser.0PP5GWEbGPT$G&. @ filena#e.setTe6tc.get%electe!Lile-..get&a#e-..< !ir.setTe6tc.getCurrentDirectory-..to%tring-..< A if-rWal ?? JLileChooser.C0&CELbGPT$G&. @ filena#e.setTe6t-8;ou "resse! cancel8.< !ir.setTe6t-88.< A A A class %aveL i#"le#ents 0ctionListener @ "ublic voi! actionPerfor#e!-0ctionEvent e. @ JLileChooser c ? ne: JLileChooser-.< // De#onstrate 8%ave8 !ialog3
lets
:=8
int rWal ? c.sho:%aveDialog-LileChooserTest.this.< if-rWal ?? JLileChooser.0PP5GWEbGPT$G&. @ filena#e.setTe6tc.get%electe!Lile-..get&a#e-..< !ir.setTe6tc.getCurrentDirectory-..to%tring-..< A if-rWal ?? JLileChooser.C0&CELbGPT$G&. @ filena#e.setTe6t-8;ou "resse! cancel8.< !ir.setTe6t-88.< A A A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: LileChooserTest-., ,', (('.< A A ///3>
Cote that there are #any variations you can a%%ly to JFile-hooser, including "ilters to narrow the "ile na#es that you will allow. RFSURF STIJLT+(6PTE5MLTIMG2U Eor an !o%en "ile$ dialog, you call sho(.pen ialogA B, and "or a !save "ile$ dialog you call sho()ave ialogA B. These co##ands don t return until the dialog is closed. The JFile-hooser ob0ect still e&ists, so you can read data "ro# it. The #ethods get)electe'FileA B and get-*rrent irectoryA B are two ways you can interrogate the results o" the o%eration. I" these return n*ll it #eans the user canceled out o" the dialog. RFSURFSTIJLT+(6PTE5MLTIMI@U
//3 c()3MTJLButton.Hava // Putting MTJL te6t on %:ing co#"onents. // Pa""let co!e?MTJLButton :i!th? '' height?,''Q // P/a""letQ
:=:
"ublic class MTJLButton e6ten!s J0""let @ JButton b ? ne: JButton-8Pht#lQPbQPfont siUe?K Q8 K 8PcenterQMello4PbrQPiQPress #e no:48.< "ublic voi! init-. @ b.a!!0ctionListener-ne: 0ctionListener-. @ "ublic voi! actionPerfor#e!-0ctionEvent e.@ getContentPane-..a!!-ne: JLabel-8Pht#lQ8K 8PiQPfont siUe?KIQ`a"o:48..< // Lorce a re-layout to // inclu!e the ne: label3 vali!ate-.< A A.< Container c" ? getContentPane-.< c".setLayout-ne: Llo:Layout-..< c".a!!-b.< A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: MTJLButton-., '', ,''.< A A ///3>
/ou #ust start the te&t with !Rht#lU,$ and then you can use nor#al (TMD tags. Cote that you are not "orced to include the nor#al closing tags. RFSURFSTIJLT+(6PTE5MLTIMIMU The Action+istener adds a new J+abel to the "or#, which also contains (TMD te&t. (owever, this label is not added during initA B so you #ust call the container s vali'ateA B #ethod in order to "orce a re' layout o" the co#%onents *and thus the dis%lay o" the new label,. RFSURF STIJLT+(6PTE5MLTIMIKU /ou can also use (TMD te&t "or JTabbe'#ane, J1en*Item, JToolTip, J$a'io2*tton and J-heck2o4. RFSURF STIJLT+(6PTE5MLTIMILU
lets
:=;
//3 c()3Progress.Hava // Ysing "rogress bars an! sli!ers. // Pa""let co!e?Progress // :i!th?)'' height? ''QP/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.B< i#"ort Hava.a:t.event.B< i#"ort Hava6.s:ing.event.B< i#"ort Hava6.s:ing.bor!er.B< i#"ort co#.bruceeckel.s:ing.B< "ublic class Progress e6ten!s J0""let @ JProgressBar "b ? ne: JProgressBar-.< J%li!er sb ? ne: J%li!er-J%li!er.MG5$TG&T0L, ', ('', +'.< "ublic voi! init-. @ Container c" ? getContentPane-.< c".setLayout-ne: ari!Layout- ,(..< c".a!!-"b.< sb.setWalue-'.< sb.setPaintTicks-true.< sb.setJaHorTick%"acing- '.< sb.setJinorTick%"acing-,.< sb.setBor!er-ne: Title!Bor!er-8%li!e Je8..< "b.setJo!el-sb.getJo!el-..< // %hare #o!el c".a!!-sb.< A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: Progress-., )'', ''.< A A ///3>
:1=
The key to hooking the two co#%onents together is in sharing their #odel, in the line= RFSURFSTIJLT+(6PTE5MLTIMI?U
"b.setJo!el-sb.getJo!el-..< )" course, you could also control the two using a listener, but this is #ore straight"orward "or si#%le situations.
The J#rogress2ar is "airly straight"orward, but the J)li'er has a lot o" o%tions, such as the orientation and #a0or and #inor tick #arks. Cotice how straight"orward it is to add a titled border. N5WON5
WTIJJX-HA#T&$>JXI>Y@O
#rees
4sing a JTree can be as si#%le as saying=
//3 c()3Trees.Hava // %i#"le %:ing tree e6a#"le. Trees can // be #a!e vastly #ore co#"le6 than this. // Pa""let co!e?Trees // :i!th? ,' height? ,'QP/a""letQ
lets
:11
// Takes an array of %trings an! #akes the first // ele#ent a no!e an! the rest leaves3 class Branch @ DefaultJutableTree&o!e r< "ublic Branch-%tringNO !ata. @ r ? ne: DefaultJutableTree&o!e-!ataN'O.< for-int i ? (< i P !ata.length< iKK. r.a!!-ne: DefaultJutableTree&o!e-!ataNiO..< A "ublic DefaultJutableTree&o!e no!e-. @ return r< A A "ublic class Trees e6ten!s J0""let @ %tringNONO !ata ? @ @ 8Colors8, 85e!8, 8Blue8, 8areen8 A, @ 8Llavors8, 8Tart8, 8%:eet8, 8Blan!8 A, @ 8Length8, 8%hort8, 8Je!iu#8, 8Long8 A, @ 8Wolu#e8, 8Migh8, 8Je!iu#8, 8Lo:8 A, @ 8Te#"erature8, 8Migh8, 8Je!iu#8, 8Lo:8 A, @ 8$ntensity8, 8Migh8, 8Je!iu#8, 8Lo:8 A, A< static int i ? '< DefaultJutableTree&o!e root, chil!, chosen< JTree tree< DefaultTreeJo!el #o!el< "ublic voi! init-. @ Container c" ? getContentPane-.< root ? ne: DefaultJutableTree&o!e-8root8.< tree ? ne: JTree-root.< // 0!! it an! #ake it take care of scrolling3 c".a!!-ne: J%crollPane-tree., Bor!erLayout.CE&TE5.< // Ca"ture the tree2s #o!el3
:12
#o!el ?-DefaultTreeJo!el.tree.getJo!el-.< JButton test ? ne: JButton-8Press #e8.< test.a!!0ctionListener-ne: 0ctionListener-. @ "ublic voi! actionPerfor#e!-0ctionEvent e.@ if-i P !ata.length. @ chil! ? ne: Branch-!ataNiKKO..no!e-.< // \hat2s the last one you clicke![ chosen ? -DefaultJutableTree&o!e. tree.getLast%electe!PathCo#"onent-.< if-chosen ?? null. chosen ? root< // The #o!el :ill create the // a""ro"riate event. $n res"onse, the // tree :ill u"!ate itself3 #o!el.insert&o!e$nto-chil!, chosen, '.< // This "uts the ne: no!e on the // currently chosen no!e. A A A.< // Change the button2s colors3 test.setBackgroun!-Color.blue.< test.setLoregroun!-Color.:hite.< JPanel " ? ne: JPanel-.< ".a!!-test.< c".a!!-", Bor!erLayout.%GYTM.< A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: Trees-., ,', ,'.< A A ///3>
The "irst class, 2ranch, is a tool to take an array o" )tring and build a efa*lt1*tableTree/o'e with the "irst )tring as the root and the rest o" the )trings in the array as leaves. Then no'eA B can be called to %roduce the root o" this !branch.$ RFSURFSTIJLT+(6PTE5MLTIMI2U The Trees class contains a two'di#ensional array o" )trings "ro# which 2ranches can be #ade and a static int i to count through this array. The efa*lt1*tableTree/o'e ob0ects hold the nodes, but the %hysical re%resentation on screen is controlled by the JTree and its associated #odel, the efa*ltTree1o'el. Cote that when the JTree is
lets
:13
added to the a%%let, it is wra%%ed in a J)croll#ane9this is all it takes to %rovide auto#atic scrolling. RFSURFSTIJLT+(6PTE5MLTIM2@U The JTree is controlled through its model. :hen you #ake a change to the #odel, the #odel generates an event that causes the JTree to %er"or# any necessary u%dates to the visible re%resentation o" the tree. In initA B, the #odel is ca%tured by calling get1o'elA B. :hen the button is %ressed, a new !branch$ is created. Then the currently selected co#%onent is "ound *or the root is used i" nothing is selected, and the #odel s insert/o'eIntoA B #ethod does all the work o" changing the tree and causing it to be u%dated. RFSURFSTIJLT+(6PTE5MLTIM2MU 6n e&a#%le like the one above #ay give you what you need in a tree. (owever, trees have the %ower to do 0ust about anything you can i#agine 9everywhere you see the word !de"ault$ in the e&a#%le above, you can substitute your own class to get di""erent behavior. But beware= al#ost all o" these classes have a large inter"ace, so you could s%end a lot o" ti#e struggling to understand the intricacies o" trees. 7es%ite this, it s a good design and the alternatives are usually #uch worse. RFSURF STIJLT+(6PTE5MLTIM2KU
#ables
Dike trees, tables in Swing are vast and %ower"ul. They are %ri#arily intended to be the %o%ular !grid$ inter"ace to databases via Java 7atabase +onnectivity *J7B+, discussed in +ha%ter MH, and thus they have a tre#endous a#ount o" "le&ibility, which you %ay "or in co#%le&ity. There s easily enough here to be the basis o" a "ull'blown s%readsheet and could %robably 0usti"y an entire book. (owever, it is also %ossible to create a relatively si#%le JTable i" you understand the basics. RFSURF STIJLT+(6PTE5MLTIM2LU The JTable controls how the data is dis%layed, but the Table1o'el controls the data itsel". So to create a JTable you ll ty%ically create a Table1o'el "irst. /ou can "ully i#%le#ent the Table1o'el inter"ace, but it s usually si#%ler to inherit "ro# the hel%er class AbstractTable1o'el=
:14
// Pa""let co!e?Table // :i!th?),' height? ''QP/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.B< i#"ort Hava.a:t.event.B< i#"ort Hava6.s:ing.table.B< i#"ort Hava6.s:ing.event.B< i#"ort co#.bruceeckel.s:ing.B< "ublic class Table e6ten!s J0""let @ JTe6t0rea t6t ? ne: JTe6t0rea-I, '.< // The TableJo!el controls all the !ata3 class DataJo!el e6ten!s 0bstractTableJo!el @ GbHectNONO !ata ? @ @8one8, 8t:o8, 8three8, 8four8A, @8five8, 8si68, 8seven8, 8eight8A, @8nine8, 8ten8, 8eleven8, 8t:elve8A, A< // Prints !ata :hen table changes3 class TJL i#"le#ents TableJo!elListener @ "ublic voi! tableChange!-TableJo!elEvent e.@ t6t.setTe6t-88.< // Clear it for-int i ? '< i P !ata.length< iKK. @ for-int H ? '< H P !ataN'O.length< HKK. t6t.a""en!-!ataNiONHO K 8 8.< t6t.a""en!-8_n8.< A A A "ublic DataJo!el-. @ a!!TableJo!elListener-ne: TJL-..< A "ublic int getColu#nCount-. @ return !ataN'O.length< A "ublic int get5o:Count-. @ return !ata.length< A "ublic GbHect getWalue0t-int ro:, int col. @ return !ataNro:ONcolO< A
lets
:15
"ublic voi! setWalue0t-GbHect val, int ro:, int col. @ !ataNro:ONcolO ? val< // $n!icate the change has ha""ene!3 fireTableDataChange!-.< A "ublic boolean isCellE!itable-int ro:, int col. @ return true< A A "ublic voi! init-. @ Container c" ? getContentPane-.< JTable table ? ne: JTable-ne: DataJo!el-..< c".a!!-ne: J%crollPane-table..< c".a!!-Bor!erLayout.%GYTM, t6t.< A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: Table-., ),', ''.< A A ///3> ata1o'el contains an array o" data, but you could also get the data "ro# so#e other source such as a database. The constructor adds a Table1o'el+istener that %rints the array every ti#e the table is changed. The rest o" the #ethods "ollow the Beans na#ing convention, and are used by JTable when it wants to %resent the in"or#ation in ata1o'el. AbstractTable1o'el %rovides de"ault #ethods "or setVal*eAtA B and is-ell&'itableA B that %revent changes to the data, so i" you want to be able to edit the data, you #ust override these #ethods. RFSURFSTIJLT+(6PTE5MLTIM2?U
)nce you have a Table1o'el, you only need to hand it to the JTable constructor. 6ll the details o" dis%laying, editing, and u%dating will be taken care o" "or you. This e&a#%le also %uts the JTable in a J)croll#ane. RFSURFSTIJLT+(6PTE5MLTIM2HU
:17
//3 c()3Look0n!Leel.Hava
lets
:18
// %electing !ifferent looks D feels. i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.B< i#"ort Hava.a:t.event.B< i#"ort Hava.util.B< i#"ort co#.bruceeckel.s:ing.B< "ublic class Look0n!Leel e6ten!s JLra#e @ %tringNO choices ? @ 8eeny8, 8#eeny8, 8#inie8, 8#oe8, 8toe8, 8you8 A< Co#"onentNO sa#"les ? @ ne: JButton-8JButton8., ne: JTe6tLiel!-8JTe6tLiel!8., ne: JLabel-8JLabel8., ne: JCheckBo6-8JCheckBo68., ne: J5a!ioButton-85a!io8., ne: JCo#boBo6-choices., ne: JList-choices., A< "ublic Look0n!Leel-. @ su"er-8Look 0n! Leel8.< Container c" ? getContentPane-.< c".setLayout-ne: Llo:Layout-..< for-int i ? '< i P sa#"les.length< iKK. c".a!!-sa#"lesNiO.< A "rivate static voi! usageError-. @ %yste#.out."rintln8Ysage3Look0n!Leel NcrossXsyste#X#otifO8.< %yste#.e6it-(.< A "ublic static voi! #ain-%tringNO args. @ if-args.length ?? '. usageError-.< if-argsN'O.e=uals-8cross8.. @ try @ Y$Janager.setLook0n!Leel-Y$Janager. getCrossPlatfor#Look0n!LeelClass&a#e-..< A catch-E6ce"tion e. @ e."rint%tackTrace-%yste#.err.< A
:1:
A else if-argsN'O.e=uals-8syste#8.. @ try @ Y$Janager.setLook0n!Leel-Y$Janager. get%yste#Look0n!LeelClass&a#e-..< A catch-E6ce"tion e. @ e."rint%tackTrace-%yste#.err.< A A else if-argsN'O.e=uals-8#otif8.. @ try @ Y$Janager.setLook0n!Leel-8co#.sun.Hava.8K 8s:ing."laf.#otif.JotifLook0n!Leel8.< A catch-E6ce"tion e. @ e."rint%tackTrace-%yste#.err.< A A else usageError-.< // &ote the look D feel #ust be set before // any co#"onents are create!. Console.run-ne: Look0n!Leel-., )'', ''.< A A ///3>
/ou can see that one o%tion is to e&%licitly s%eci"y a string "or a look and "eel, as seen with 1otif+ookAn'Feel. (owever, that one and the de"ault !#etal$ look and "eel are the only ones that can legally be used on any %lat"or#; even though there are strings "or :indows and Macintosh look and "eels, those can only be used on their res%ective %lat"or#s *these are %roduced when you call get)ystem+ookAn'Feel-lass/ameA B and you re on that %articular %lat"or#,. RFSURF STIJLT+(6PTE5MLTIM2IU It is also %ossible to create a custo# look and "eel %ackage, "or e&a#%le, i" you are building a "ra#ework "or a co#%any that wants a distinctive a%%earance. This is a big 0ob and is "ar beyond the sco%e o" this book *in "act, you ll discover it is beyond the sco%e o" #any dedicated Swing books.,. RFSURFSTIJLT+(6PTE5MLTIM22U
#he cli.board
The JE+ su%%orts li#ited o%erations with the syste# cli%board *in the
lets
:1;
cli%board as te&t, and you can %aste te&t "ro# the cli%board into )tring ob0ects. )" course, the cli%board is designed to hold any ty%e o" data, but how this data is re%resented on the cli%board is u% to the %rogra# doing the cutting and %asting. The Java cli%board 6PI %rovides "or e&tensibility through the conce%t o" a !"lavor.$ :hen data co#es o"" the cli%board, it has an associated set o" "lavors that it can be converted to *"or e&a#%le, a gra%h #ight be re%resented as a string o" nu#bers or as an i#age, and you can see i" that %articular cli%board data su%%orts the "lavor you re interested in. RFSURFSTIJLT+(6PTE5MLTIK@@U The "ollowing %rogra# is a si#%le de#onstration o" cut, co%y, and %aste with )tring data in a JTe4tArea. )ne thing you ll notice is that the keyboard seAuences you nor#ally use "or cutting, co%ying, and %asting also work. But i" you look at any JTe4tFiel' or JTe4tArea in any other %rogra# you ll "ind that they also auto#atically su%%ort the cli%board key seAuences. This e&a#%le si#%ly adds %rogra##atic control o" the cli%board, and you could use these techniAues i" you want to ca%ture cli%board te&t into so#ething other than a JTe4t-omponent.
//3 c()3Cut0n!Paste.Hava // Ysing the cli"boar!. i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.B< i#"ort Hava.a:t.event.B< i#"ort Hava.a:t.!atatransfer.B< i#"ort co#.bruceeckel.s:ing.B< "ublic class Cut0n!Paste e6ten!s JLra#e @ JJenuBar #b ? ne: JJenuBar-.< JJenu e!it ? ne: JJenu-8E!it8.< JJenu$te# cut ? ne: JJenu$te#-8Cut8., co"y ? ne: JJenu$te#-8Co"y8., "aste ? ne: JJenu$te#-8Paste8.< JTe6t0rea te6t ? ne: JTe6t0rea- ', '.< Cli"boar! cli"b! ? getToolkit-..get%yste#Cli"boar!-.< "ublic Cut0n!Paste-. @ cut.a!!0ctionListener-ne: CutL-..< co"y.a!!0ctionListener-ne: Co"yL-..<
:2=
"aste.a!!0ctionListener-ne: PasteL-..< e!it.a!!-cut.< e!it.a!!-co"y.< e!it.a!!-"aste.< #b.a!!-e!it.< setJJenuBar-#b.< getContentPane-..a!!-te6t.< A class Co"yL i#"le#ents 0ctionListener @ "ublic voi! actionPerfor#e!-0ctionEvent e. @ %tring selection ? te6t.get%electe!Te6t-.< if -selection ?? null. return< %tring%election cli"%tring ? ne: %tring%election-selection.< cli"b!.setContents-cli"%tring,cli"%tring.< A A class CutL i#"le#ents 0ctionListener @ "ublic voi! actionPerfor#e!-0ctionEvent e. @ %tring selection ? te6t.get%electe!Te6t-.< if -selection ?? null. return< %tring%election cli"%tring ? ne: %tring%election-selection.< cli"b!.setContents-cli"%tring, cli"%tring.< te6t.re"lace5ange-88, te6t.get%election%tart-., te6t.get%electionEn!-..< A A class PasteL i#"le#ents 0ctionListener @ "ublic voi! actionPerfor#e!-0ctionEvent e. @ Transferable cli"Data ? cli"b!.getContents-Cut0n!Paste.this.< try @ %tring cli"%tring ? -%tring.cli"Data. getTransferDataDataLlavor.stringLlavor.< te6t.re"lace5ange-cli"%tring,
lets
:21
te6t.get%election%tart-., te6t.get%electionEn!-..< A catch-E6ce"tion e6. @ %yste#.err."rintln-8&ot %tring flavor8.< A A A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: Cut0n!Paste-., )'', ''.< A A ///3>
The creation and addition o" the #enu and JTe4tArea should by now see# a %edestrian activity. :hat s di""erent is the creation o" the -lipboar' "ield clipb', which is done through the Toolkit. RFSURF STIJLT+(6PTE5MLTIK@MU 6ll the action takes %lace in the listeners. The -opy+ and -*t+ listeners are the sa#e e&ce%t "or the last line o" -*t+, which erases the line that s been co%ied. The s%ecial two lines are the creation o" a )tring)election ob0ect "ro# the )tring and the call to set-ontentsA B with this )tring)election. That s all there is to %utting a )tring on the cli%board. RFSURFSTIJLT+(6PTE5MLTIK@KU In #aste+, data is %ulled o"" the cli%board using get-ontentsA B. :hat co#es back is a "airly anony#ous Transferable ob0ect, and you don t really know what it contains. )ne way to "ind out is to call getTransfer ataFlavorsA B, which returns an array o" ataFlavor ob0ects indicating which "lavors are su%%orted by this %articular ob0ect. /ou can also ask it directly with is ataFlavor)*pporte'A B, %assing in the "lavor you re interested in. (ere, however, the bold a%%roach is taken= getTransfer ataA B is called assu#ing that the contents su%%orts the )tring "lavor, and i" it doesn t the %roble# is sorted out in the e&ce%tion handler. RFSURFSTIJLT+(6PTE5MLTIK@LU In the "uture you can e&%ect #ore data "lavors to be su%%orted.
:22
Phea!QPtitleQTicTacToe E6a#"le 0""let P/titleQP/hea!Q Pbo!yQ Pa""let co!e?TicTacToe.class archive?TicTacToe.Har :i!th? '' height?(''Q P/a""letQ P/bo!yQ
lets
:23
/ou ll need to %ut it into the new *#essy, co#%licated, "or# shown earlier in the cha%ter in order to get it to work.
rogramming techni%ues
Because 84I %rogra##ing in Java has been an evolving technology with so#e very signi"icant changes between Java [email protected] and the Swing library in Java K, there have been so#e old %rogra##ing idio#s that have see%ed through to e&a#%les that you #ight see given "or Swing. In addition, Swing allows you to %rogra# in #ore and better ways than were allowed by the old #odels. In this section, so#e o" these issues will be de#onstrated by introducing and e&a#ining so#e %rogra##ing idio#s. RFSURFSTIJLT+(6PTE5MLTIK@GU
//3 c()3Dyna#icEvents.Hava // ;ou can change event behavior !yna#ically. // 0lso sho:s #ulti"le actions for an event. // Pa""let co!e?Dyna#icEvents // :i!th? ,' height?I''QP/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.B< i#"ort Hava.a:t.event.B< i#"ort Hava.util.B< i#"ort co#.bruceeckel.s:ing.B< "ublic class Dyna#icEvents e6ten!s J0""let @ 0rrayList v ? ne: 0rrayList-.< int i ? '< JButton b( ? ne: JButton-8Button(8., b ? ne: JButton-8Button 8.<
:24
JTe6t0rea t6t ? ne: JTe6t0rea-.< class B i#"le#ents 0ctionListener @ "ublic voi! actionPerfor#e!-0ctionEvent e. @ t6t.a""en!-80 button :as "resse!_n8.< A A class CountListener i#"le#ents 0ctionListener @ int in!e6< "ublic CountListener-int i. @ in!e6 ? i< A "ublic voi! actionPerfor#e!-0ctionEvent e. @ t6t.a""en!-8Counte! Listener 8Kin!e6K8_n8.< A A class B( i#"le#ents 0ctionListener @ "ublic voi! actionPerfor#e!-0ctionEvent e. @ t6t.a""en!-8Button ( "resse!_n8.< 0ctionListener a ? ne: CountListener-iKK.< v.a!!-a.< b .a!!0ctionListener-a.< A A class B i#"le#ents 0ctionListener @ "ublic voi! actionPerfor#e!-0ctionEvent e. @ t6t.a""en!-8Button "resse!_n8.< int en! ? v.siUe-. - (< if-en! Q? '. @ b .re#ove0ctionListener-0ctionListener.v.get-en!..< v.re#ove-en!.< A A A "ublic voi! init-. @ Container c" ? getContentPane-.< b(.a!!0ctionListener-ne: B-..< b(.a!!0ctionListener-ne: B(-..< b .a!!0ctionListener-ne: B-..< b .a!!0ctionListener-ne: B -..< JPanel " ? ne: JPanel-.< ".a!!-b(.< ".a!!-b .<
lets
:25
c".a!!-Bor!erLayout.&G5TM, ".< c".a!!-ne: J%crollPane-t6t..< A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: Dyna#icEvents-., ,', I''.< A A ///3>
The new twists in this e&a#%le are= RFSURFSTIJLT+(6PTE5MLTIK@IU
(!6) There is #ore than one listener attached to each 2*tton. 4sually, co#%onents handle events as multicast, #eaning that you can
register #any listeners "or a single event. In the s%ecial co#%onents in which an event is handled as unicast, you ll get a Too1any+isteners&4ception. RFSURF STIJLT+(6PTE5MLTIK@2U
(*7) 7uring the e&ecution o" the %rogra#, listeners are dyna#ically added and re#oved "ro# the 2*tton bI. 6dding is acco#%lished
in the way you ve seen be"ore, but each co#%onent also has a removeXXX+istenerA B #ethod to re#ove each ty%e o" listener. RFSURFSTIJLT+(6PTE5MLTIKM@U This kind o" "le&ibility %rovides #uch greater %ower in your %rogra##ing. RFSURFSTIJLT+(6PTE5MLTIKMMU /ou should notice that event listeners are not guaranteed to be called in the order they are added *although #ost i#%le#entations do in "act work that way,. RFSURFSTIJLT+(6PTE5MLTIKMKU
:27
6nother issue is multitiered syste#s, where the !business ob0ects$ reside on a co#%letely se%arate #achine. This central location o" the business rules allows changes to be instantly e""ective "or all new transactions, and is thus a co#%elling way to set u% a syste#. (owever, these business ob0ects can be used in #any di""erent a%%lications and so should not be tied to any %articular #ode o" dis%lay. They should 0ust %er"or# the business o%erations and nothing #ore. RFSURF STIJLT+(6PTE5MLTIKMLU The "ollowing e&a#%le shows how easy it is to se%arate the business logic "ro# the 84I code=
//3 c()3%e"aration.Hava // %e"arating aY$ logic an! business obHects. // Pa""let co!e?%e"aration // :i!th? ,' height?(,'Q P/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.B< i#"ort Hava6.s:ing.event.B< i#"ort Hava.a:t.event.B< i#"ort Hava.a""let.B< i#"ort co#.bruceeckel.s:ing.B< class BusinessLogic @ "rivate int #o!ifier< "ublic BusinessLogic-int #o!. @ #o!ifier ? #o!< A "ublic voi! setJo!ifier-int #o!. @ #o!ifier ? #o!< A "ublic int getJo!ifier-. @ return #o!ifier< A // %o#e business o"erations3 "ublic int calculation(-int arg. @ return arg B #o!ifier< A "ublic int calculation -int arg. @ return arg K #o!ifier< A
lets
:28
A "ublic class %e"aration e6ten!s J0""let @ JTe6tLiel! t ? ne: JTe6tLiel!-(,., #o! ? ne: JTe6tLiel!-(,.< BusinessLogic bl ? ne: BusinessLogic- .< JButton calc( ? ne: JButton-8Calculation (8., calc ? ne: JButton-8Calculation 8.< static int getWalue-JTe6tLiel! tf. @ try @ return $nteger."arse$nt-tf.getTe6t-..< A catch-&u#berLor#atE6ce"tion e. @ return '< A A class Calc(L i#"le#ents 0ctionListener @ "ublic voi! actionPerfor#e!-0ctionEvent e. @ t.setTe6t-$nteger.to%tringbl.calculation(-getWalue-t....< A A class Calc L i#"le#ents 0ctionListener @ "ublic voi! actionPerfor#e!-0ctionEvent e. @ t.setTe6t-$nteger.to%tringbl.calculation -getWalue-t....< A A // $f you :ant so#ething to ha""en :henever // a JTe6tLiel! changes, a!! this listener3 class Jo!L i#"le#ents Docu#entListener @ "ublic voi! change!Y"!ate-Docu#entEvent e. @A "ublic voi! insertY"!ate-Docu#entEvent e. @ bl.setJo!ifier-getWalue-#o!..< A "ublic voi! re#oveY"!ate-Docu#entEvent e. @ bl.setJo!ifier-getWalue-#o!..< A A "ublic voi! init-. @
:2:
Container c" ? getContentPane-.< c".setLayout-ne: Llo:Layout-..< c".a!!-t.< calc(.a!!0ctionListener-ne: Calc(L-..< calc .a!!0ctionListener-ne: Calc L-..< JPanel "( ? ne: JPanel-.< "(.a!!-calc(.< "(.a!!-calc .< c".a!!-"(.< #o!.getDocu#ent-.. a!!Docu#entListener-ne: Jo!L-..< JPanel " ? ne: JPanel-.< " .a!!-ne: JLabel-8Jo!ifier38..< " .a!!-#o!.< c".a!!-" .< A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: %e"aration-., ,', (''.< A A ///3>
/ou can see that 2*siness+ogic is a straight"orward class that %er"or#s its o%erations without even a hint that it #ight be used in a 84I environ#ent. It 0ust does its 0ob. RFSURFSTIJLT+(6PTE5MLTIKM?U
)eparation kee%s track o" all the 4I details, and it talks to 2*siness+ogic only through its p*blic inter"ace. 6ll the o%erations are
centered around getting in"or#ation back and "orth through the 4I and the 2*siness+ogic ob0ect. So )eparation, in turn, 0ust does its 0ob. Since )eparation knows only that it s talking to a 2*siness+ogic ob0ect *that is, it isn t highly cou%led,, it could be #assaged into talking to other ty%es o" ob0ects without #uch trouble. RFSURF STIJLT+(6PTE5MLTIKMHU Thinking in ter#s o" se%arating 4I "ro# business logic also #akes li"e easier when you re ada%ting legacy code to work with Java. RFSURF STIJLT+(6PTE5MLTIKM3U
lets
:2;
A canonical form
Inner classes, the Swing event #odel, and the "act that the old event #odel is still su%%orted along with new library "eatures that rely on old' style %rogra##ing has added a new ele#ent o" con"usion to the code design %rocess. Cow there are even #ore di""erent ways "or %eo%le to write un%leasant code. RFSURFSTIJLT+(6PTE5MLTIKMGU E&ce%t in e&tenuating circu#stances you can always use the si#%lest and clearest a%%roach= listener classes *ty%ically written as inner classes, to solve your event'handling needs. This is the "or# used in #ost o" the e&a#%les in this cha%ter. RFSURFSTIJLT+(6PTE5MLTIKMIU By "ollowing this #odel you should be able to reduce the state#ents in your %rogra#s that say= !I wonder what caused this event.$ Each %iece o" code is concerned with doing, not ty%e'checking. This is the best way to write your code; not only is it easier to conce%tuali1e, but #uch easier to read and #aintain. RFSURFSTIJLT+(6PTE5MLTIKM2U
:3=
!Visual %rogra##ing$ "irst beca#e success"ul9 ver) success"ul9with Microso"t s Visual Basic *VB,, "ollowed by a second'generation design in Borland s 7el%hi *the %ri#ary ins%iration "or the JavaBeans design,. :ith these %rogra##ing tools the co#%onents are re%resented visually, which #akes sense since they usually dis%lay so#e kind o" visual co#%onent such as a button or a te&t "ield. The visual re%resentation, in "act, is o"ten e&actly the way the co#%onent will look in the running %rogra#. So %art o" the %rocess o" visual %rogra##ing involves dragging a co#%onent "ro# a %alette and dro%%ing it onto your "or#. The a%%lication builder tool writes code as you do this, and that code will cause the co#%onent to be created in the running %rogra#. RFSURF STIJLT+(6PTE5MLTIKKKU Si#%ly dro%%ing the co#%onent onto a "or# is usually not enough to co#%lete the %rogra#. )"ten, you #ust change the characteristics o" a co#%onent, such as what color it is, what te&t is on it, what database it s connected to, etc. +haracteristics that can be #odi"ied at design ti#e are re"erred to as ro erties. /ou can #ani%ulate the %ro%erties o" your co#%onent inside the a%%lication builder tool, and when you create the %rogra# this con"iguration data is saved so that it can be re0uvenated when the %rogra# is started. RFSURFSTIJLT+(6PTE5MLTIKKLU By now you re %robably used to the idea that an ob0ect is #ore than characteristics; it s also a set o" behaviors. 6t design'ti#e, the behaviors o" a visual co#%onent are %artially re%resented by events, #eaning !(ere s so#ething that can ha%%en to the co#%onent.$ )rdinarily, you decide what you want to ha%%en when an event occurs by tying code to that event. RFSURFSTIJLT+(6PTE5MLTIKK?U (ere s the critical %art= the a%%lication builder tool uses re"lection to dyna#ically interrogate the co#%onent and "ind out which %ro%erties and events the co#%onent su%%orts. )nce it knows what they are, it can dis%lay the %ro%erties and allow you to change those *saving the state when you build the %rogra#,, and also dis%lay the events. In general, you do so#ething like double'clicking on an event and the a%%lication builder tool creates a code body and ties it to that %articular event. 6ll you have to do at that %oint is write the code that e&ecutes when the event occurs. RF SURFSTIJLT+(6PTE5MLTIKKHU
lets
:31
6ll this adds u% to a lot o" work that s done "or you by the a%%lication builder tool. 6s a result you can "ocus on what the %rogra# looks like and what it is su%%osed to do, and rely on the a%%lication builder tool to #anage the connection details "or you. The reason that visual %rogra##ing tools have been so success"ul is that they dra#atically s%eed u% the %rocess o" building an a%%lication9certainly the user inter"ace, but o"ten other %ortions o" the a%%lication as well. RFSURF STIJLT+(6PTE5MLTIKK3U
What is a ;eanA
6"ter the dust settles, then, a co#%onent is really 0ust a block o" code, ty%ically e#bodied in a class. The key issue is the ability "or the a%%lication builder tool to discover the %ro%erties and events "or that co#%onent. To create a VB co#%onent, the %rogra##er had to write a "airly co#%licated %iece o" code "ollowing certain conventions to e&%ose the %ro%erties and events. 7el%hi was a second'generation visual %rogra##ing tool and the language was actively designed around visual %rogra##ing so it is #uch easier to create a visual co#%onent. (owever, Java has brought the creation o" visual co#%onents to its #ost advanced state with JavaBeans, because a Bean is 0ust a class. /ou don t have to write any e&tra code or use s%ecial language e&tensions in order to #ake so#ething a Bean. The only thing you need to do, in "act, is slightly #odi"y the way that you na#e your #ethods. It is the #ethod na#e that tells the a%%lication builder tool whether this is a %ro%erty, an event, or 0ust an ordinary #ethod. RFSURFSTIJLT+(6PTE5MLTIKKGU In the Java docu#entation, this na#ing convention is #istakenly ter#ed a !design %attern.$ This is un"ortunate, since design %atterns *see Thinking in Patterns ,ith Java, downloadable at ,,,'0ruceEckel'com, are challenging enough without this sort o" con"usion. It s not a design %attern, it s 0ust a na#ing convention and it s "airly si#%le=
(*() Eor a %ro%erty na#ed 444, you ty%ically create two #ethods= getX44A B and setX44A B. Cote that the "irst letter a"ter !get$ or
!set$ is auto#atically lowercased to %roduce the %ro%erty na#e. The ty%e %roduced by the !get$ #ethod is the sa#e as the ty%e o" the argu#ent to the !set$ #ethod. The na#e o" the %ro%erty and
:32
the ty%e "or the !get$ and !set$ are not related. RFSURF STIJLT+(6PTE5MLTIKKIU
(*!) Eor a boolean %ro%erty, you can use the !get$ and !set$ a%%roach
above, but you can also use !is$ instead o" !get.$ RFSURF STIJLT+(6PTE5MLTIKK2U
(**) )rdinary #ethods o" the Bean don t con"or# to the above na#ing convention, but they re p*blic. RFSURF
STIJLT+(6PTE5MLTIKL@U
(*+) Eor events, you use the Swing !listener$ a%%roach. It s e&actly the sa#e as you ve been seeing= a''Foo2ar+istener AFoo2ar+istenerB and removeFoo2ar+istener AFoo2ar+istenerB to handle a Foo2ar&vent. Most o" the ti#e
the built'in events and listeners will satis"y your needs, but you can also create your own events and listener inter"aces. RFSURF STIJLT+(6PTE5MLTIKLMU Point M above answers a Auestion about so#ething you #ight have noticed when looking at older code vs. newer code= a nu#ber o" #ethod na#es have had s#all, a%%arently #eaningless na#e changes. Cow you can see that #ost o" those changes had to do with ada%ting to the !get$ and !set$ na#ing conventions in order to #ake that %articular co#%onent into a Bean. RFSURFSTIJLT+(6PTE5MLTIKLKU
:e can use these guidelines to create a si#%le Bean= //3 frogbean3Lrog.Hava // 0 trivial JavaBean. "ackage frogbean< i#"ort Hava.a:t.B< i#"ort Hava.a:t.event.B< class %"ots @A "ublic class Lrog @ "rivate int Hu#"s< "rivate Color color< "rivate %"ots s"ots< "rivate boolean H#"r<
lets
:33
"ublic int getJu#"s-. @ return Hu#"s< A "ublic voi! setJu#"s-int ne:Ju#"s. @ Hu#"s ? ne:Ju#"s< A "ublic Color getColor-. @ return color< A "ublic voi! setColor-Color ne:Color. @ color ? ne:Color< A "ublic %"ots get%"ots-. @ return s"ots< A "ublic voi! set%"ots-%"ots ne:%"ots. @ s"ots ? ne:%"ots< A "ublic boolean isJu#"er-. @ return H#"r< A "ublic voi! setJu#"er-boolean H. @ H#"r ? H< A "ublic voi! a!!0ctionListener0ctionListener l. @ //... A "ublic voi! re#ove0ctionListener0ctionListener l. @ // ... A "ublic voi! a!!`eyListener-`eyListener l. @ // ... A "ublic voi! re#ove`eyListener-`eyListener l. @ // ... A // 0n 8or!inary8 "ublic #etho!3 "ublic voi! croak-. @ %yste#.out."rintln-85ibbet48.< A A ///3>
Eirst, you can see that it s 0ust a class. 4sually, all your "ields will be
private, and accessible only through #ethods. Eollowing the na#ing convention, the %ro%erties are 8*mps, color, spots, and 8*mper
*notice the case change o" the "irst letter in the %ro%erty na#e,. 6lthough the na#e o" the internal identi"ier is the sa#e as the na#e o" the %ro%erty in the "irst three cases, in 8*mper you can see that the %ro%erty na#e does not "orce you to use any %articular identi"ier "or internal variables
:34
*or, indeed, to even have any internal variables "or that %ro%erty,. RF SURFSTIJLT+(6PTE5MLTIKLLU The events this Bean handles are Action&vent and %ey&vent, based on the na#ing o" the !add$ and !re#ove$ #ethods "or the associated listener. Einally, you can see that the ordinary #ethod croakA B is still %art o" the Bean si#%ly because it s a p*blic #ethod, not because it con"or#s to any na#ing sche#e. RFSURFSTIJLT+(6PTE5MLTIKL?U
lets
:35
4sually you won t care about any o" this9you ll %robably get #ost o" your Beans o"" the shel" "ro# vendors, and you don t need to know all the #agic that s going on underneath. /ou ll si#%ly drag your Beans onto your "or#, then con"igure their %ro%erties and write handlers "or the events you re interested in. (owever, it s an interesting and educational e&ercise to use the Introspector to dis%lay in"or#ation about a Bean, so here s a tool that does it=
//3 c()3BeanDu#"er.Hava // $ntros"ecting a Bean. // Pa""let co!e?BeanDu#"er :i!th?+'' height?,''Q // P/a""letQ i#"ort Hava.beans.B< i#"ort Hava.lang.reflect.B< i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.B< i#"ort Hava.a:t.event.B< i#"ort co#.bruceeckel.s:ing.B< "ublic class BeanDu#"er e6ten!s J0""let @ JTe6tLiel! =uery ? ne: JTe6tLiel!- '.< JTe6t0rea results ? ne: JTe6t0rea-.< "ublic voi! "rt-%tring s. @ results.a""en!-s K 8_n8.< A "ublic voi! !u#"-Class bean.@ results.setTe6t-88.< Bean$nfo bi ? null< try @ bi ? $ntros"ector.getBean$nfobean, Hava.lang.GbHect.class.< A catch-$ntros"ectionE6ce"tion e. @ "rt-8Coul!n2t intros"ect 8 K bean.get&a#e-..< return< A Pro"ertyDescri"torNO "ro"erties ? bi.getPro"ertyDescri"tors-.< for-int i ? '< i P "ro"erties.length< iKK. @ Class " ? "ro"ertiesNiO.getPro"ertyTy"e-.<
:37
"rt-8Pro"erty ty"e3_n 8 K ".get&a#e-. K 8Pro"erty na#e3_n 8 K "ro"ertiesNiO.get&a#e-..< Jetho! rea!Jetho! ? "ro"ertiesNiO.get5ea!Jetho!-.< if-rea!Jetho! 4? null. "rt-85ea! #etho!3_n 8 K rea!Jetho!.< Jetho! :riteJetho! ? "ro"ertiesNiO.get\riteJetho!-.< if-:riteJetho! 4? null. "rt-8\rite #etho!3_n 8 K :riteJetho!.< "rt-8????????????????????8.< A "rt-8Public #etho!s38.< Jetho!Descri"torNO #etho!s ? bi.getJetho!Descri"tors-.< for-int i ? '< i P #etho!s.length< iKK. "rt-#etho!sNiO.getJetho!-..to%tring-..< "rt-8??????????????????????8.< "rt-8Event su""ort38.< Event%etDescri"torNO events ? bi.getEvent%etDescri"tors-.< for-int i ? '< i P events.length< iKK. @ "rt-8Listener ty"e3_n 8 K eventsNiO.getListenerTy"e-..get&a#e-..< Jetho!NO l# ? eventsNiO.getListenerJetho!s-.< for-int H ? '< H P l#.length< HKK. "rt-8Listener #etho!3_n 8 K l#NHO.get&a#e-..< Jetho!Descri"torNO l#! ? eventsNiO.getListenerJetho!Descri"tors-.< for-int H ? '< H P l#!.length< HKK. "rt-8Jetho! !escri"tor3_n 8 K l#!NHO.getJetho!-..< Jetho! a!!Listener ? eventsNiO.get0!!ListenerJetho!-.< "rt-80!! Listener Jetho!3_n 8 K a!!Listener.< Jetho! re#oveListener ? eventsNiO.get5e#oveListenerJetho!-.<
lets
:38
8 K
A A class Du#"er i#"le#ents 0ctionListener @ "ublic voi! actionPerfor#e!-0ctionEvent e. @ %tring na#e ? =uery.getTe6t-.< Class c ? null< try @ c ? Class.for&a#e-na#e.< A catch-Class&otLoun!E6ce"tion e6. @ results.setTe6t-8Coul!n2t fin! 8 K na#e.< return< A !u#"-c.< A A "ublic voi! init-. @ Container c" ? getContentPane-.< JPanel " ? ne: JPanel-.< ".setLayout-ne: Llo:Layout-..< ".a!!-ne: JLabel-8/ualifie! bean na#e38..< ".a!!-=uery.< c".a!!-Bor!erLayout.&G5TM, ".< c".a!!-ne: J%crollPane-results..< Du#"er !#"r ? ne: Du#"er-.< =uery.a!!0ctionListener-!#"r.< =uery.setTe6t-8frogbean.Lrog8.< // Lorce evaluation !#"r.actionPerfor#e!ne: 0ctionEvent-!#"r, ', 88..< A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: BeanDu#"er-., +'', ,''.< A A ///3> 2ean *mper!'*mpA B is the #ethod that does all the work. Eirst it tries to create a 2eanInfo ob0ect, and i" success"ul calls the #ethods o" 2eanInfo that %roduce in"or#ation about %ro%erties, #ethods, and
:3:
events. In Introspector!get2eanInfoA B, you ll see there is a second argu#ent. This tells the Introspector where to sto% in the inheritance hierarchy. (ere, it sto%s be"ore it %arses all the #ethods "ro# .b8ect, since we re not interested in seeing those. RFSURF STIJLT+(6PTE5MLTIKLIU Eor %ro%erties, get#roperty escriptorsA B returns an array o" #roperty escriptors. Eor each #roperty escriptor you can call get#ropertyTypeA B to "ind the class o" ob0ect that is %assed in and out via the %ro%erty #ethods. Then, "or each %ro%erty you can get its %seudony# *e&tracted "ro# the #ethod na#es, with get/ameA B, the #ethod "or reading with get$ea'1etho'A B, and the #ethod "or writing with get0rite1etho'A B. These last two #ethods return a 1etho' ob0ect that can actually be used to invoke the corres%onding #ethod on the ob0ect *this is %art o" re"lection,. RFSURF STIJLT+(6PTE5MLTIKL2U Eor the p*blic #ethods *including the %ro%erty #ethods,, get1etho' escriptorsA B returns an array o" 1etho' escriptors. Eor each one you can get the associated 1etho' ob0ect and %rint its na#e. RFSURFSTIJLT+(6PTE5MLTIK?@U Eor the events, get&vent)et escriptorsA B returns an array o" *what elseO, &vent)et escriptors. Each o" these can be Aueried to "ind out the class o" the listener, the #ethods o" that listener class, and the add' and re#ove'listener #ethods. The 2ean *mper %rogra# %rints out all o" this in"or#ation. RFSURFSTIJLT+(6PTE5MLTIK?MU 4%on startu%, the %rogra# "orces the evaluation o" frogbean!Frog. The out%ut, a"ter re#oving e&tra details that are unnecessary here, is=
class na#e3 Lrog Pro"erty ty"e3 Color Pro"erty na#e3 color 5ea! #etho!3 "ublic Color getColor-. \rite #etho!3 "ublic voi! setColor-Color. ????????????????????
lets
:3;
Pro"erty ty"e3 %"ots Pro"erty na#e3 s"ots 5ea! #etho!3 "ublic %"ots get%"ots-. \rite #etho!3 "ublic voi! set%"ots-%"ots. ???????????????????? Pro"erty ty"e3 boolean Pro"erty na#e3 Hu#"er 5ea! #etho!3 "ublic boolean isJu#"er-. \rite #etho!3 "ublic voi! setJu#"er-boolean. ???????????????????? Pro"erty ty"e3 int Pro"erty na#e3 Hu#"s 5ea! #etho!3 "ublic int getJu#"s-. \rite #etho!3 "ublic voi! setJu#"s-int. ???????????????????? Public #etho!s3 "ublic voi! setJu#"s-int. "ublic voi! croak-. "ublic voi! re#ove0ctionListener-0ctionListener. "ublic voi! a!!0ctionListener-0ctionListener. "ublic int getJu#"s-. "ublic voi! setColor-Color. "ublic voi! set%"ots-%"ots. "ublic voi! setJu#"er-boolean. "ublic boolean isJu#"er-. "ublic voi! a!!`eyListener-`eyListener. "ublic Color getColor-. "ublic voi! re#ove`eyListener-`eyListener. "ublic %"ots get%"ots-.
:4=
?????????????????????? Event su""ort3 Listener ty"e3 `eyListener Listener #etho!3 keyTy"e! Listener #etho!3 keyPresse! Listener #etho!3 key5elease! Jetho! !escri"tor3 "ublic voi! keyTy"e!-`eyEvent. Jetho! !escri"tor3 "ublic voi! keyPresse!-`eyEvent. Jetho! !escri"tor3 "ublic voi! key5elease!-`eyEvent. 0!! Listener Jetho!3 "ublic voi! a!!`eyListener-`eyListener. 5e#ove Listener Jetho!3 "ublic voi! re#ove`eyListener-`eyListener. ???????????????????? Listener ty"e3 0ctionListener Listener #etho!3 actionPerfor#e! Jetho! !escri"tor3 "ublic voi! actionPerfor#e!-0ctionEvent. 0!! Listener Jetho!3 "ublic voi! a!!0ctionListener-0ctionListener. 5e#ove Listener Jetho!3 "ublic voi! re#ove0ctionListener-0ctionListener. ????????????????????
This reveals #ost o" what the Introspector sees as it %roduces a 2eanInfo ob0ect "ro# your Bean. /ou can see that the ty%e o" the %ro%erty and its na#e are inde%endent. Cotice the lowercasing o" the %ro%erty na#e. *The only ti#e this doesn t occur is when the %ro%erty na#e begins with #ore than one ca%ital letter in a row., 6nd re#e#ber that the #ethod na#es you re seeing here *such as the read and write #ethods, are actually %roduced "ro# a 1etho' ob0ect that can be used
lets
:41
to invoke the associated #ethod on the ob0ect. RFSURF STIJLT+(6PTE5MLTIK?KU The p*blic #ethod list includes the #ethods that are not associated with a %ro%erty or event, such as croakA B, as well as those that are. These are all the #ethods that you can call %rogra##atically "or a Bean, and the a%%lication builder tool can choose to list all o" these while you re #aking #ethod calls, to ease your task. RFSURFSTIJLT+(6PTE5MLTIK?LU Einally, you can see that the events are "ully %arsed out into the listener, its #ethods, and the add' and re#ove'listener #ethods. Basically, once you have the 2eanInfo, you can "ind out everything o" i#%ortance "or the Bean. /ou can also call the #ethods "or that Bean, even though you don t have any other in"or#ation e&ce%t the ob0ect *again, a "eature o" re"lection,. RFSURFSTIJLT+(6PTE5MLTIK??U
//3 bangbean3BangBean.Hava // 0 gra"hical Bean. "ackage bangbean< i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.B< i#"ort Hava.a:t.event.B< i#"ort Hava.io.B< i#"ort Hava.util.B< i#"ort co#.bruceeckel.s:ing.B<
:42
"ublic class BangBean e6ten!s JPanel i#"le#ents %erialiUable @ "rotecte! int 6#, y#< "rotecte! int c%iUe ? '< // Circle siUe "rotecte! %tring te6t ? 8Bang48< "rotecte! int font%iUe ? I1< "rotecte! Color tColor ? Color.re!< "rotecte! 0ctionListener actionListener< "ublic BangBean-. @ a!!JouseListener-ne: JL-..< a!!JouseJotionListener-ne: JJL-..< A "ublic int getCircle%iUe-. @ return c%iUe< A "ublic voi! setCircle%iUe-int ne:%iUe. @ c%iUe ? ne:%iUe< A "ublic %tring getBangTe6t-. @ return te6t< A "ublic voi! setBangTe6t-%tring ne:Te6t. @ te6t ? ne:Te6t< A "ublic int getLont%iUe-. @ return font%iUe< A "ublic voi! setLont%iUe-int ne:%iUe. @ font%iUe ? ne:%iUe< A "ublic Color getTe6tColor-. @ return tColor< A "ublic voi! setTe6tColor-Color ne:Color. @ tColor ? ne:Color< A "ublic voi! "aintCo#"onent-ara"hics g. @ su"er."aintCo#"onent-g.< g.setColor-Color.black.< g.!ra:Gval-6# - c%iUe/ , y# - c%iUe/ , c%iUe, c%iUe.< A // This is a unicast listener, :hich is // the si#"lest for# of listener #anage#ent3 "ublic voi! a!!0ctionListener 0ctionListener l. thro:s TooJanyListenersE6ce"tion @ if-actionListener 4? null.
lets
:43
thro: ne: TooJanyListenersE6ce"tion-.< actionListener ? l< A "ublic voi! re#ove0ctionListener0ctionListener l. @ actionListener ? null< A class JL e6ten!s Jouse0!a"ter @ "ublic voi! #ousePresse!-JouseEvent e. @ ara"hics g ? getara"hics-.< g.setColor-tColor.< g.setLontne: Lont8Ti#es5o#an8, Lont.BGLD, font%iUe..< int :i!th ? g.getLontJetrics-..string\i!th-te6t.< g.!ra:%tring-te6t, -get%iUe-..:i!th - :i!th. / , get%iUe-..height/ .< g.!is"ose-.< // Call the listener2s #etho!3 if-actionListener 4? null. actionListener.actionPerfor#e!ne: 0ctionEvent-BangBean.this, 0ctionEvent.0CT$G&bPE5LG5JED, null..< A A class JJL e6ten!s JouseJotion0!a"ter @ "ublic voi! #ouseJove!-JouseEvent e. @ 6# ? e.get9-.< y# ? e.get;-.< re"aint-.< A A "ublic Di#ension getPreferre!%iUe-. @ return ne: Di#ension- '', ''.< A A ///3>
The "irst thing you ll notice is that 2ang2ean i#%le#ents the )eriali7able inter"ace. This #eans that the a%%lication builder tool can
:44
!%ickle$ all the in"or#ation "or the 2ang2ean using seriali1ation a"ter the %rogra# designer has ad0usted the values o" the %ro%erties. :hen the Bean is created as %art o" the running a%%lication, these !%ickled$ %ro%erties are restored so that you get e&actly what you designed. RFSURF STIJLT+(6PTE5MLTIK?3U /ou can see that all the "ields are private, which is what you ll usually do with a Bean9allow access only through #ethods, usually using the !%ro%erty$ sche#e. RFSURFSTIJLT+(6PTE5MLTIK?GU :hen you look at the signature "or a''Action+istenerA B, you ll see that it can throw a Too1any+isteners&4ception. This indicates that it is unicast, which #eans it noti"ies only one listener when the event occurs. )rdinarily, you ll use multicast events so that #any listeners can be noti"ied o" an event. (owever, that runs into issues that you won t be ready "or until the ne&t cha%ter, so it will be revisited there *under the heading !JavaBeans revisited$,. 6 unicast event sideste%s the %roble#. RF SURFSTIJLT+(6PTE5MLTIK?IU :hen you click the #ouse, the te&t is %ut in the #iddle o" the 2ang2ean, and i" the action+istener "ield is not n*ll, its action#erforme'A B is called, creating a new Action&vent ob0ect in the %rocess. :henever the #ouse is #oved, its new coordinates are ca%tured and the canvas is re%ainted *erasing any te&t that s on the canvas, as you ll see,. RFSURFSTIJLT+(6PTE5MLTIK?2U (ere is the 2ang2eanTest class to allow you to test the bean as either an a%%let or an a%%lication=
//3 c()3BangBeanTest.Hava // Pa""let co!e?BangBeanTest // :i!th?I'' height?,''QP/a""letQ i#"ort bangbean.B< i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.B< i#"ort Hava.a:t.event.B< i#"ort Hava.util.B< i#"ort co#.bruceeckel.s:ing.B< "ublic class BangBeanTest e6ten!s J0""let @ JTe6tLiel! t6t ? ne: JTe6tLiel!- '.<
lets
:45
// During testing, re"ort actions3 class BBL i#"le#ents 0ctionListener @ int count ? '< "ublic voi! actionPerfor#e!-0ctionEvent e.@ t6t.setTe6t-8BangBean action 8K countKK.< A A "ublic voi! init-. @ BangBean bb ? ne: BangBean-.< try @ bb.a!!0ctionListener-ne: BBL-..< A catch-TooJanyListenersE6ce"tion e. @ t6t.setTe6t-8Too #any listeners8.< A Container c" ? getContentPane-.< c".a!!-bb.< c".a!!-Bor!erLayout.%GYTM, t6t.< A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: BangBeanTest-., I'', ,''.< A A ///3>
:hen a Bean is in a develo%#ent environ#ent, this class will not be used, but it s hel%"ul to %rovide a ra%id testing #ethod "or each o" your Beans. 2ang2eanTest %laces a 2ang2ean within the a%%let, attaching a si#%le Action+istener to the 2ang2ean to %rint an event count to the JTe4tFiel' whenever an Action&vent occurs. 4sually, o" course, the a%%lication builder tool would create #ost o" the code that uses the Bean. RFSURFSTIJLT+(6PTE5MLTIKH@U :hen you run the 2ang2ean through 2ean *mper or %ut the 2ang2ean inside a Bean'enabled develo%#ent environ#ent, you ll notice that there are #any #ore %ro%erties and actions than are evident "ro# the above code. That s because 2ang2ean is inherited "ro# J#anel, and J#anel is also Bean, so you re seeing its %ro%erties and events as well. RFSURFSTIJLT+(6PTE5MLTIKHMU
:47
ackaging a ;ean
Be"ore you can bring a Bean into a Bean'enabled visual builder tool, it #ust be %ut into the standard Bean container, which is a J65 "ile that includes all the Bean classes as well as a !#ani"est$ "ile that says !This is a Bean.$ 6 #ani"est "ile is si#%ly a te&t "ile that "ollows a %articular "or#. Eor the 2ang2ean, the #ani"est "ile looks like this *without the "irst and last lines,=
2ang2ean!8ar and that you ve %ut the #ani"est in a "ile called 2ang2ean!mf. RFSURFSTIJLT+(6PTE5MLTIKHLU
/ou #ight wonder !:hat about all the other classes that were generated when I co#%iled 2ang2ean!8avaO$ :ell, they all ended u% inside the bangbean subdirectory, and you ll see that the last argu#ent "or the
lets
:48
above 8ar co##and line is the bangbean subdirectory. :hen you give 8ar the na#e o" a subdirectory, it %ackages that entire subdirectory into the 0ar "ile *including, in this case, the original 2ang2ean!8ava source' code "ile9you #ight not choose to include the source with your own Beans,. In addition, i" you turn around and un%ack the J65 "ile you ve 0ust created, you ll discover that your #ani"est "ile isn t inside, but that 8ar has created its own #ani"est "ile *based %artly on yours, called 1A/IF&)T!1F and %laced it inside the subdirectory 1&TA6I/F *"or !#eta'in"or#ation$,. I" you o%en this #ani"est "ile you ll also notice that digital signature in"or#ation has been added by 8ar "or each "ile, o" the "or#=
:4:
(*,) /ou can %rovide a custo# %ro%erty sheet "or your %articular Bean.
The ordinary %ro%erty sheet will be used "or all other Beans, but yours is auto#atically invoked when your Bean is selected. RFSURF STIJLT+(6PTE5MLTIK3KU
(*-) /ou can create a custo# editor "or a %articular %ro%erty, so the
ordinary %ro%erty sheet is used, but when your s%ecial %ro%erty is being edited, your editor will auto#atically be invoked. RFSURF STIJLT+(6PTE5MLTIK3LU
lets
:4;
(*4) /ou can %rovide a custo# 2eanInfo class "or your Bean that
%roduces in"or#ation that s di""erent "ro# the de"ault created by the Introspector. RFSURFSTIJLT+(6PTE5MLTIK3?U
(*5) It s also %ossible to turn !e&%ert$ #ode on and o"" in all Feat*re escriptors to distinguish between basic "eatures and
#ore co#%licated ones. RFSURFSTIJLT+(6PTE5MLTIK3HU
More to ;eans
There s another issue that couldn t be addressed here. :henever you create a Bean, you should e&%ect that it will be run in a #ultithreaded environ#ent. This #eans that you #ust understand the issues o" threading, which will be introduced in +ha%ter M?. /ou ll "ind a section there called !JavaBeans revisited$ that will look at the %roble# and its solution. RFSURFSTIJLT+(6PTE5MLTIK33U There are a nu#ber o" books about JavaBeans; "or e&a#%le, Java0eans by Elliotte 5usty (arold *I78, M22I,. RFSURFSTIJLT+(6PTE5MLTIK3GU
1ummar:
)" all the libraries in Java, the 84I library has seen the #ost dra#atic changes "ro# Java M.@ to Java K. The Java M.@ 6:T was roundly critici1ed as being one o" the worst designs seen, and while it would allow you to create %ortable %rogra#s, the resulting 84I was !eAually #ediocre on all %lat"or#s.$ It was also li#iting, awkward, and un%leasant to use co#%ared with the native a%%lication develo%#ent tools available on a %articular %lat"or#. RFSURFSTIJLT+(6PTE5MLTIK3IU :hen Java M.M introduced the new event #odel and JavaBeans, the stage was set9now it was %ossible to create 84I co#%onents that could be easily dragged and dro%%ed inside visual a%%lication builder tools. In addition, the design o" the event #odel and Beans clearly shows strong consideration "or ease o" %rogra##ing and #aintainable code *so#ething that was not evident in the M.@ 6:T,. But it wasn t until the JE+FSwing classes a%%eared that the 0ob was "inished. :ith the Swing
:5=
co#%onents, cross'%lat"or# 84I %rogra##ing can be a civili1ed e&%erience. RFSURFSTIJLT+(6PTE5MLTIK32U 6ctually, the only thing that s #issing is the a%%lication builder tool, and this is where the real revolution lies. Microso"t s Visual Basic and Visual +<< reAuire Microso"t s a%%lication builder tools, as does Borland s 7el%hi and +<< Builder. I" you want the a%%lication builder tool to get better, you have to cross your "ingers and ho%e the vendor will give you what you want. But Java is an o%en environ#ent, and so not only does it allow "or co#%eting a%%lication builder environ#ents, it encourages the#. 6nd "or these tools to be taken seriously, they #ust su%%ort JavaBeans. This #eans a leveled %laying "ield= i" a better a%%lication builder tool co#es along, you re not tied to the one you ve been using9 you can %ick u% and #ove to the new one and increase your %roductivity. This kind o" co#%etitive environ#ent "or 84I a%%lication builder tools has not been seen be"ore, and the resulting #arket%lace can generate only %ositive results "or the %roductivity o" the %rogra##er. RFSURF STIJLT+(6PTE5MLTIKG@U
This cha%ter was #eant only to give you an introduction to the %ower o" Swing and to get you started so you could see how relatively si#%le it is to "eel your way through the libraries. :hat you ve seen so "ar will %robably su""ice "or a good %ortion o" your 4I design needs. (owever, there s a lot #ore to Swing9it s intended to be a "ully %owered 4I design tool kit. There s %robably a way to acco#%lish 0ust about everything you can i#agine.
I" you don t see what you need here, delve into the online docu#entation "ro# Sun and search the :eb, and i" that s not enough then "ind a dedicated Swing book9a good %lace to start is The J9C S,ing Tutorial, by :alrath N +a#%ione *6ddison :esley, M222,. RFSURF STIJLT+(6PTE5MLTIKGMU
/0ercises
Solutions to selected e&ercises can be "ound in the electronic docu#entThe Thinking in Java "nnotated Solution @uide, available "or a s#all "ee "ro# ,,,'0ruceEckel'com.
lets
:51
!!*) 6dd a check bo& to the a%%let created in E&ercise M, ca%ture the
event, and insert di""erent te&t into the te&t "ield. RFSURF STIJLT+(6PTE5MLTIKGLU
!!6) Docate and download one or #ore o" the "ree 84I builder
develo%#ent environ#ents available on the Internet, or buy a co##ercial %roduct. 7iscover what is necessary to add 2ang2ean to this environ#ent and to use it. RFSURF STIJLT+(6PTE5MLTIKG2U
:52
!*() +reate your own JavaBean called Valve that contains two
%ro%erties= a boolean called !on$ and an int called !level.$ +reate a #ani"est "ile, use 8ar to %ackage your Bean, then load it into the beanbo& or into a Beans'enabled %rogra# builder tool so that you can test it. RFSURFSTIJLT+(6PTE5MLTIKIMU
!*+) Inherit a new ty%e o" button "ro# J2*tton. Each ti#e you
%ress this button, it should change its color to a rando#ly'selected value. See -olor2o4es!8ava in +ha%ter M? "or an e&a#%le o" how to generate a rando# color value. RFSURF STIJLT+(6PTE5MLTIKI?U
lets
:53
!*6) 5e#e#ber the !sketching bo&$ toy with two knobs, one that
controls the vertical #ove#ent o" the drawing %oint, and one that controls the hori1ontal #ove#entO +reate one o" those, using )ine0ave!8ava to get you started. Instead o" knobs, use sliders. 6dd a button that will erase the entire sketch. RFSURF STIJLT+(6PTE5MLTIKI2U
:54
lets
:55
:57
//3 c(I3Counter(.Hava // 0 non-res"onsive user interface. // Pa""let co!e?Counter( :i!th?)'' height?(''Q // P/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.event.B< i#"ort Hava.a:t.B< i#"ort co#.bruceeckel.s:ing.B< "ublic class Counter( e6ten!s J0""let @ "rivate int count ? '< "rivate JButton start ? ne: JButton-8%tart8., onGff ? ne: JButton-8Toggle8.< "rivate JTe6tLiel! t ? ne: JTe6tLiel!-('.< "rivate boolean runLlag ? true< "ublic voi! init-. @ Container c" ? getContentPane-.< c".setLayout-ne: Llo:Layout-..< c".a!!-t.< start.a!!0ctionListener-ne: %tartL-..< c".a!!-start.< onGff.a!!0ctionListener-ne: GnGffL-..< c".a!!-onGff.< A "ublic voi! go-. @ :hile -true. @ try @ Threa!.slee"-(''.< A catch-$nterru"te!E6ce"tion e. @ %yste#.err."rintln-8$nterru"te!8.<
:58
A if -runLlag. t.setTe6t-$nteger.to%tring-countKK..< A A class %tartL i#"le#ents 0ctionListener @ "ublic voi! actionPerfor#e!-0ctionEvent e. @ go-.< A A class GnGffL i#"le#ents 0ctionListener @ "ublic voi! actionPerfor#e!-0ctionEvent e. @ runLlag ? 4runLlag< A A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: Counter(-., )'', (''.< A A ///3>
6t this %oint, the Swing and a%%let code should be reasonably "a#iliar "ro# +ha%ter ML. The goA B #ethod is where the %rogra# stays busy= it %uts the current value o" co*nt into the JTe4tFiel' t, then incre#ents co*nt. RFSURFSTIJLT+(6PTE5M?TI?U Part o" the in"inite loo% inside goA B is to call sleepA B. sleepA B #ust be associated with a Threa' ob0ect, and it turns out that every a%%lication has some thread associated with it. *Indeed, Java is based on threads and there are always so#e running along with your a%%lication., So regardless o" whether you re e&%licitly using threads, you can %roduce the current thread used by your %rogra# with Threa' and the static sleepA B #ethod. RFSURFSTIJLT+(6PTE5M?TIHU Cote that sleepA B can throw an Interr*pte'&4ception, although throwing such an e&ce%tion is considered a hostile way to break "ro# a thread and should be discouraged. *)nce again, e&ce%tions are "or e&ce%tional conditions, not nor#al "low o" control., Interru%ting a slee%ing thread is included to su%%ort a "uture language "eature. RFSURF STIJLT+(6PTE5M?TI3U
:5:
:hen the start button is %ressed, goA B is invoked. )n e&a#ining goA B, you #ight naively think *as I did, that it should allow #ultithreading because it goes to slee%. That is, while the #ethod is aslee%, it see#s like the +P4 could be busy #onitoring other button %resses. But it turns out that the real %roble# is that goA B never returns, since it s in an in"inite loo%, and this #eans that action#erforme'A B never returns. Since you re stuck inside action#erforme'A B "or the "irst key%ress, the %rogra# can t handle any other events. *To get out, you #ust so#ehow kill the %rocess; the easiest way to do this is to %ress +ontrol'+ in the console window, i" you started it "ro# the console. I" you start it via the browser, you have to kill the browser window., RFSURF STIJLT+(6PTE5M?TIGU The basic %roble# here is that goA B needs to continue %er"or#ing its o%erations, and at the sa#e ti#e it needs to return so that action#erforme'A B can co#%lete and the user inter"ace can continue res%onding to the user. But in a conventional #ethod like goA B it cannot continue and at the sa#e ti#e return control to the rest o" the %rogra#. This sounds like an i#%ossible thing to acco#%lish, as i" the +P4 #ust be in two %laces at once, but this is %recisely the illusion that threading %rovides. RFSURFSTIJLT+(6PTE5M?TIIU The thread #odel *and its %rogra##ing su%%ort in Java, is a %rogra##ing convenience to si#%li"y 0uggling several o%erations at the sa#e ti#e within a single %rogra#. :ith threads, the +P4 will %o% around and give each thread so#e o" its ti#e. Each thread has the consciousness o" constantly having the +P4 to itsel", but the +P4 s ti#e is actually sliced between all the threads. The e&ce%tion to this is i" your %rogra# is running on #ulti%le +P4s. But one o" the great things about threading is that you are abstracted away "ro# this layer, so your code does not need to know whether it is actually running on a single +P4 or #any. Thus, threads are a way to create trans%arently scalable %rogra#s. RFSURFSTIJLT+(6PTE5M?TI2U Threading reduces co#%uting e""iciency so#ewhat, but the net i#%rove#ent in %rogra# design, resource balancing, and user convenience is o"ten Auite valuable. )" course, i" you have #ore than one +P4, then the o%erating syste# can dedicate each +P4 to a set o" threads or even a single thread and the whole %rogra# can run #uch "aster.
:5;
Multitasking and #ultithreading tend to be the #ost reasonable ways to utili1e #ulti%rocessor syste#s. RFSURFSTIJLT+(6PTE5M?TIM@U
//3 c(I3%i#"leThrea!.Hava // Wery si#"le Threa!ing e6a#"le. "ublic class %i#"leThrea! e6ten!s Threa! @ "rivate int countDo:n ? ,< "rivate static int threa!Count ? '< "rivate int threa!&u#ber ? KKthrea!Count< "ublic %i#"leThrea!-. @ %yste#.out."rintln-8Jaking 8 K threa!&u#ber.< A "ublic voi! run-. @ :hile-true. @ %yste#.out."rintln-8Threa! 8 K threa!&u#ber K 8-8 K countDo:n K 8.8.< if---countDo:n ?? '. return< A A "ublic static voi! #ain-%tringNO args. @ for-int i ? '< i P ,< iKK. ne: %i#"leThrea!-..start-.< %yste#.out."rintln-80ll Threa!s %tarte!8.< A
:7=
A ///3>
6 r*nA B #ethod virtually always has so#e kind o" loo% that continues until the thread is no longer necessary, so you #ust establish the condition on which to break out o" this loo% *or, in the case above, si#%ly ret*rn "ro# r*nA B,. )"ten, r*nA B is cast in the "or# o" an in"inite loo%, which #eans that, barring so#e e&ternal "actor that causes r*nA B to ter#inate, it will continue "orever. RFSURFSTIJLT+(6PTE5M?TIMKU In mainA B you can see a nu#ber o" threads being created and run. The startA B #ethod in the Threa' class %er"or#s s%ecial initiali1ation "or the thread and then calls r*nA B. So the ste%s are= the constructor is called to build the ob0ect, then startA B con"igures the thread and calls r*nA B. I" you don t call startA B *which you can do in the constructor, i" that s a%%ro%riate, the thread will never be started. RFSURF STIJLT+(6PTE5M?TIMLU The out%ut "or one run o" this %rogra# *it will be di""erent "ro# one run to another, is=
Jaking ( Jaking Jaking ) Jaking I Jaking , Threa! (-,. Threa! (-I. Threa! (-). Threa! (- . Threa! -,. Threa! -I. Threa! -). Threa! - . Threa! -(. Threa! (-(. 0ll Threa!s %tarte! Threa! )-,. Threa! I-,. Threa! I-I. Threa! I-). Threa! I- .
:71
Threa! Threa! Threa! Threa! Threa! Threa! Threa! Threa! Threa! Threa!
/ou ll notice that nowhere in this e&a#%le is sleepA B called, and yet the out%ut indicates that each thread gets a %ortion o" the +P4 s ti#e in which to e&ecute. This shows that sleepA B, while it relies on the e&istence o" a thread in order to e&ecute, is not involved with either enabling or disabling threading. It s si#%ly another #ethod. RFSURF STIJLT+(6PTE5M?TIM?U /ou can also see that the threads are not run in the order that they re created. In "act, the order that the +P4 attends to an e&isting set o" threads is indeter#inate, unless you go in and ad0ust the %riorities using Threa' s set#riorityA B #ethod. RFSURFSTIJLT+(6PTE5M?TIMHU :hen mainA B creates the Threa' ob0ects it isn t ca%turing the re"erences "or any o" the#. 6n ordinary ob0ect would be "air ga#e "or garbage collection, but not a Threa'. Each Threa' !registers$ itsel" so there is actually a re"erence to it so#e%lace and the garbage collector can t clean it u%. RFSURFSTIJLT+(6PTE5M?TIM3U
:72
//3 c(I3Counter .Hava // 0 res"onsive user interface :ith threa!s. // Pa""let co!e?Counter :i!th?)'' height?(''Q // P/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.B< i#"ort Hava.a:t.event.B< i#"ort co#.bruceeckel.s:ing.B< "ublic class Counter e6ten!s J0""let @ "rivate class %e"arate%ubTask e6ten!s Threa! @ "rivate int count ? '< "rivate boolean runLlag ? true< %e"arate%ubTask-. @ su"er.start-.< A voi! invertLlag-. @ runLlag ? 4runLlag< A "ublic voi! run-. @ :hile -true. @ try @ slee"-(''.< A catch-$nterru"te!E6ce"tion e. @ %yste#.err."rintln-8$nterru"te!8.< A if-runLlag. t.setTe6t-$nteger.to%tring-countKK..< A A A "rivate %e"arate%ubTask s" ? null< "rivate JTe6tLiel! t ? ne: JTe6tLiel!-('.< "rivate JButton start ? ne: JButton-8%tart8., onGff ? ne: JButton-8Toggle8.< class %tartL i#"le#ents 0ctionListener @ "ublic voi! actionPerfor#e!-0ctionEvent e. @ if-s" ?? null. s" ? ne: %e"arate%ubTask-.< A A class GnGffL i#"le#ents 0ctionListener @ "ublic voi! actionPerfor#e!-0ctionEvent e. @ if-s" 4? null.
:73
s".invertLlag-.< A A "ublic voi! init-. @ Container c" ? getContentPane-.< c".setLayout-ne: Llo:Layout-..< c".a!!-t.< start.a!!0ctionListener-ne: %tartL-..< c".a!!-start.< onGff.a!!0ctionListener-ne: GnGffL-..< c".a!!-onGff.< A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: Counter -., )'', (''.< A A ///3> -o*nterI is a straight"orward %rogra#, whose only 0ob is to set u% and #aintain the user inter"ace. But now, when the user %resses the start
button, the event'handling code does not call a #ethod. Instead a thread o" class )eparate)*bTask is created, and then the -o*nterI event loo% continues. RFSURFSTIJLT+(6PTE5M?TIMGU The class )eparate)*bTask is a si#%le e&tension o" Threa' with a constructor that runs the thread by calling startA B, and a r*nA B that essentially contains the ! goA B$ code "ro# -o*nter>!8ava. RFSURF STIJLT+(6PTE5M?TIMIU Because )eparate)*bTask is an inner class, it can directly access the JTe4tFiel' t in -o*nterI; you can see this ha%%ening inside r*nA B. The t "ield in the outer class is private since )eparate)*bTask can access it without getting any s%ecial %er#ission9and it s always good to #ake "ields !as private as %ossible$ so they cannot be accidentally changed by "orces outside your class. RFSURFSTIJLT+(6PTE5M?TIM2U :hen you %ress the on.ff button it toggles the r*nFlag inside the )eparate)*bTask ob0ect. That thread *when it looks at the "lag, can then start and sto% itsel". Pressing the on.ff button %roduces an a%%arently instant res%onse. )" course, the res%onse isn t really instant, not like that o" a syste# that s driven by interru%ts. The counter sto%s
:74
only when the thread has the +P4 and notices that the "lag has changed. RFSURFSTIJLT+(6PTE5M?TIK@U /ou can see that the inner class )eparate)*bTask is private, which #eans that its "ields and #ethods can be given de"ault access *e&ce%t "or r*nA B, which #ust be p*blic since it is p*blic in the base class,. The private inner class is not accessible to anyone but -o*nterI, and the two classes are tightly cou%led. 6nyti#e you notice classes that a%%ear to have high cou%ling with each other, consider the coding and #aintenance i#%rove#ents you #ight get by using inner classes. RFSURF STIJLT+(6PTE5M?TIKMU
//3 c(I3Counter).Hava // Ysing the 5unnable interface to turn the // #ain class into a threa!. // Pa""let co!e?Counter) :i!th?)'' height?(''Q // P/a""letQ i#"ort Hava6.s:ing.B<
:75
i#"ort Hava.a:t.B< i#"ort Hava.a:t.event.B< i#"ort co#.bruceeckel.s:ing.B< "ublic class Counter) e6ten!s J0""let i#"le#ents 5unnable @ "rivate int count ? '< "rivate boolean runLlag ? true< "rivate Threa! selfThrea! ? null< "rivate JButton start ? ne: JButton-8%tart8., onGff ? ne: JButton-8Toggle8.< "rivate JTe6tLiel! t ? ne: JTe6tLiel!-('.< "ublic voi! run-. @ :hile -true. @ try @ selfThrea!.slee"-(''.< A catch-$nterru"te!E6ce"tion e. @ %yste#.err."rintln-8$nterru"te!8.< A if-runLlag. t.setTe6t-$nteger.to%tring-countKK..< A A class %tartL i#"le#ents 0ctionListener @ "ublic voi! actionPerfor#e!-0ctionEvent e. @ if-selfThrea! ?? null. @ selfThrea! ? ne: Threa!-Counter).this.< selfThrea!.start-.< A A A class GnGffL i#"le#ents 0ctionListener @ "ublic voi! actionPerfor#e!-0ctionEvent e. @ runLlag ? 4runLlag< A A "ublic voi! init-. @ Container c" ? getContentPane-.< c".setLayout-ne: Llo:Layout-..< c".a!!-t.<
:77
start.a!!0ctionListener-ne: %tartL-..< c".a!!-start.< onGff.a!!0ctionListener-ne: GnGffL-..< c".a!!-onGff.< A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: Counter)-., )'', (''.< A A ///3>
Cow the r*nA B is inside the class, but it s still dor#ant a"ter initA B co#%letes. :hen you %ress the start button, the thread is created *i" it doesn t already e&ist, in the so#ewhat obscure e&%ression= RFSURF STIJLT+(6PTE5M?TIKLU
ne: Threa!-Counter).this.<
:hen so#ething has a $*nnable inter"ace, it si#%ly #eans that it has a r*nA B #ethod, but there s nothing s%ecial about that9it doesn t %roduce any innate threading abilities, like those o" a class inherited "ro# Threa'. So to %roduce a thread "ro# a $*nnable ob0ect, you #ust create a se%arate Threa' ob0ect as shown above, handing the $*nnable ob0ect to the s%ecial Threa' constructor. /ou can then call startA B "or that thread= RFSURFSTIJLT+(6PTE5M?TIK?U
selfThrea!.start-.<
This %er"or#s the usual initiali1ation and then calls r*nA B. RFSURF STIJLT+(6PTE5M?TIKHU The convenient as%ect about the $*nnable interface is that everything belongs to the sa#e class. I" you need to access so#ething, you si#%ly do it without going through a se%arate ob0ect. (owever, as you saw in the %revious e&a#%le, this access is 0ust as easy using an inner class @. RFSURF STIJLT+(6PTE5M?TIK3U
@ $*nnable was in Java M.@, while inner classes were not introduced until Java M.M, which
#ay %artially account "or the e&istence o" $*nnable. 6lso, traditional #ultithreading architectures "ocused on a "unction to be run rather than an ob0ect. My %re"erence is always to inherit "ro# Threa' i" I can; it see#s cleaner and #ore "le&ible to #e.
:78
//3 c(I3CounterI.Hava // By kee"ing your threa! as a !istinct class, // you can have as #any threa!s as you :ant. // Pa""let co!e?CounterI :i!th? '' height?+''Q // P"ara# na#e?siUe value?8( 8QP/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.B< i#"ort Hava.a:t.event.B< i#"ort co#.bruceeckel.s:ing.B< "ublic class CounterI e6ten!s J0""let @ "rivate JButton start ? ne: JButton-8%tart8.< "rivate boolean starte! ? false< "rivate TickerNO s< "rivate boolean is0""let ? true< "rivate int siUe ? ( < class Ticker e6ten!s Threa! @ "rivate JButton b ? ne: JButton-8Toggle8.< "rivate JTe6tLiel! t ? ne: JTe6tLiel!-('.< "rivate int count ? '< "rivate boolean runLlag ? true<
:7:
"ublic Ticker-. @ b.a!!0ctionListener-ne: ToggleL-..< JPanel " ? ne: JPanel-.< ".a!!-t.< ".a!!-b.< // Calls J0""let.getContentPane-..a!!-.3 getContentPane-..a!!-".< A class ToggleL i#"le#ents 0ctionListener @ "ublic voi! actionPerfor#e!-0ctionEvent e. @ runLlag ? 4runLlag< A A "ublic voi! run-. @ :hile -true. @ if -runLlag. t.setTe6t-$nteger.to%tring-countKK..< try @ slee"-(''.< A catch-$nterru"te!E6ce"tion e. @ %yste#.err."rintln-8$nterru"te!8.< A A A A class %tartL i#"le#ents 0ctionListener @ "ublic voi! actionPerfor#e!-0ctionEvent e. @ if-4starte!. @ starte! ? true< for -int i ? '< i P s.length< iKK. sNiO.start-.< A A A "ublic voi! init-. @ Container c" ? getContentPane-.< c".setLayout-ne: Llo:Layout-..< // aet "ara#eter 8siUe8 fro# \eb "age3 if -is0""let. @ %tring sU ? getPara#eter-8siUe8.< if-sU 4? null.
:7;
siUe ? $nteger."arse$nt-sU.< A s ? ne: TickerNsiUeO< for -int i ? '< i P s.length< iKK. sNiO ? ne: Ticker-.< start.a!!0ctionListener-ne: %tartL-..< c".a!!-start.< A "ublic static voi! #ain-%tringNO args. @ CounterI a""let ? ne: CounterI-.< // This isn2t an a""let, so set the flag an! // "ro!uce the "ara#eter values fro# args3 a""let.is0""let ? false< if-args.length 4? '. a""let.siUe ? $nteger."arse$nt-argsN'O.< Console.run-a""let, '', a""let.siUe B ,'.< A A ///3> Ticker contains not only its threading eAui%#ent but also the way to control and dis%lay the thread. /ou can create as #any threads as you want without e&%licitly creating the windowing co#%onents. RFSURF STIJLT+(6PTE5M?TIKIU
In -o*nterQ there s an array o" Ticker ob0ects called s. Eor #a&i#u# "le&ibility, the si1e o" this array is initiali1ed by reaching out into the :eb %age using a%%let %ara#eters. (ere s what the si1e %ara#eter looks like on the %age, e#bedded inside the a%%let tag=
:8=
/ou can co#%ile this, but you ll get a strange !null'%ointer e&ce%tion$ at run'ti#e. It works "ine i" you #ove the get#arameterA B initiali1ation inside o" initA B. The a%%let "ra#ework %er"or#s the necessary startu% to grab the %ara#eters be"ore entering initA B. RFSURF STIJLT+(6PTE5M?TIL@U In addition, this code is set u% to be either an a%%let or an a%%lication. :hen it s an a%%lication the si7e argu#ent is e&tracted "ro# the co##and line *or a de"ault value is %rovided,. RFSURF STIJLT+(6PTE5M?TILMU )nce the si1e o" the array is established, new Ticker ob0ects are created; as %art o" the Ticker constructor the button and te&t "ield "or each Ticker is added to the a%%let. RFSURFSTIJLT+(6PTE5M?TILKU Pressing the start button #eans loo%ing through the entire array o" Tickers and calling startA B "or each one. 5e#e#ber, startA B %er"or#s necessary thread initiali1ation and then calls r*nA B "or that thread. RF SURFSTIJLT+(6PTE5M?TILLU The Toggle+ listener si#%ly inverts the "lag in Ticker and when the associated thread ne&t takes note it can react accordingly. RFSURF STIJLT+(6PTE5M?TIL?U )ne value o" this e&a#%le is that it allows you to easily create large sets o" inde%endent subtasks and to #onitor their behavior. In this case, you ll see that as the nu#ber o" subtasks gets larger, your #achine will %robably show #ore divergence in the dis%layed nu#bers because o" the way that the threads are served. RFSURFSTIJLT+(6PTE5M?TILHU /ou can also e&%eri#ent to discover how i#%ortant the sleepA>DDB is inside Ticker!r*nA B. I" you re#ove the sleepA B, things will work "ine until you %ress a toggle button. Then that %articular thread has a "alse r*nFlag and the r*nA B is 0ust tied u% in a tight in"inite loo%, which a%%ears di""icult to break during #ultithreading, so the res%onsiveness and s%eed o" the %rogra# really bogs down. RFSURF STIJLT+(6PTE5M?TIL3U
:81
Daemon threads
6 !dae#on$ thread is one that is su%%osed to %rovide a general service in the background as long as the %rogra# is running, but is not %art o" the essence o" the %rogra#. Thus, when all o" the non'dae#on threads co#%lete, the %rogra# is ter#inated. +onversely, i" there are any non' dae#on threads still running, the %rogra# doesn t ter#inate. *There is, "or instance, a thread that runs mainA B., RFSURF STIJLT+(6PTE5M?TILGU /ou can "ind out i" a thread is a dae#on by calling is aemonA B, and you can turn the !dae#onhood$ o" a thread on and o"" with set aemonA B. I" a thread is a dae#on, then any threads it creates will auto#atically be dae#ons. RFSURFSTIJLT+(6PTE5M?TILIU The "ollowing e&a#%le de#onstrates dae#on threads=
//3 c(I3Dae#ons.Hava // Dae#onic behavior. i#"ort Hava.io.B< class Dae#on e6ten!s Threa! @ "rivate static final int %$TE ? ('< "rivate Threa!NO t ? ne: Threa!N%$TEO< "ublic Dae#on-. @ setDae#on-true.< start-.< A "ublic voi! run-. @ for-int i ? '< i P %$TE< iKK. tNiO ? ne: Dae#on%"a:n-i.< for-int i ? '< i P %$TE< iKK. %yste#.out."rintln8tN8 K i K 8O.isDae#on-. ? 8 K tNiO.isDae#on-..< :hile-true. yiel!-.< A A class Dae#on%"a:n e6ten!s Threa! @
:82
"ublic Dae#on%"a:n-int i. @ %yste#.out."rintln8Dae#on%"a:n 8 K i K 8 starte!8.< start-.< A "ublic voi! run-. @ :hile-true. yiel!-.< A A "ublic class Dae#ons @ "ublic static voi! #ain-%tringNO args. thro:s $GE6ce"tion @ Threa! ! ? ne: Dae#on-.< %yste#.out."rintln8!.isDae#on-. ? 8 K !.isDae#on-..< // 0llo: the !ae#on threa!s to // finish their startu" "rocesses3 %yste#.out."rintln-8Press any key8.< %yste#.in.rea!-.< A A ///3>
The aemon thread sets its dae#on "lag to !true$ and then s%awns a bunch o" other threads to show that they are also dae#ons. Then it goes into an in"inite loo% that calls yiel'A B to give u% control to the other %rocesses. In an earlier version o" this %rogra#, the in"inite loo%s would incre#ent int counters, but this see#ed to bring the whole %rogra# to a sto%. 4sing yiel'A B #akes the %rogra# Auite %e%%y. RFSURF STIJLT+(6PTE5M?TIL2U There s nothing to kee% the %rogra# "ro# ter#inating once mainA B "inishes its 0ob, since there are nothing but dae#on threads running. So that you can see the results o" starting all the dae#on threads, )ystem! in is set u% to read so the %rogra# waits "or a key%ress be"ore ter#inating. :ithout this you see only so#e o" the results "ro# the creation o" the dae#on threads. *Try re%lacing the rea'A B code with sleepA B calls o" various lengths to see this behavior., RFSURF STIJLT+(6PTE5M?TI?@U
:83
//3 c(I3%haring(.Hava // Proble#s :ith resource sharing :hile threa!ing. // Pa""let co!e?%haring( :i!th?),' height?,''Q // P"ara# na#e?siUe value?8( 8Q // P"ara# na#e?:atchers value?8(,8Q // P/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.B<
:84
i#"ort Hava.a:t.event.B< i#"ort co#.bruceeckel.s:ing.B< "ublic class %haring( e6ten!s J0""let @ "rivate static int accessCount ? '< "rivate static JTe6tLiel! aCount ? ne: JTe6tLiel!-8'8, *.< "ublic static voi! incre#ent0ccess-. @ accessCountKK< aCount.setTe6t-$nteger.to%tring-accessCount..< A "rivate JButton start ? ne: JButton-8%tart8., :atcher ? ne: JButton-8\atch8.< "rivate boolean is0""let ? true< "rivate int nu#Counters ? ( < "rivate int nu#\atchers ? (,< "rivate T:oCounterNO s< class T:oCounter e6ten!s Threa! @ "rivate boolean starte! ? false< "rivate JTe6tLiel! t( ? ne: JTe6tLiel!-,., t ? ne: JTe6tLiel!-,.< "rivate JLabel l ? ne: JLabel-8count( ?? count 8.< "rivate int count( ? ', count ? '< // 0!! the !is"lay co#"onents as a "anel3 "ublic T:oCounter-. @ JPanel " ? ne: JPanel-.< ".a!!-t(.< ".a!!-t .< ".a!!-l.< getContentPane-..a!!-".< A "ublic voi! start-. @ if-4starte!. @ starte! ? true< su"er.start-.< A A "ublic voi! run-. @
:85
:hile -true. @ t(.setTe6t-$nteger.to%tring-count(KK..< t .setTe6t-$nteger.to%tring-count KK..< try @ slee"-,''.< A catch-$nterru"te!E6ce"tion e. @ %yste#.err."rintln-8$nterru"te!8.< A A A "ublic voi! synchTest-. @ incre#ent0ccess-.< if-count( 4? count . l.setTe6t-8Ynsynche!8.< A A class \atcher e6ten!s Threa! @ "ublic \atcher-. @ su"er.start-.< A "ublic voi! run-. @ :hile-true. @ for-int i ? '< i P s.length< iKK. sNiO.synchTest-.< try @ slee"-,''.< A catch-$nterru"te!E6ce"tion e. @ %yste#.err."rintln-8$nterru"te!8.< A A A A class %tartL i#"le#ents 0ctionListener @ "ublic voi! actionPerfor#e!-0ctionEvent e. @ for-int i ? '< i P s.length< iKK. sNiO.start-.< A A class \atcherL i#"le#ents 0ctionListener @ "ublic voi! actionPerfor#e!-0ctionEvent e. @ for-int i ? '< i P nu#\atchers< iKK. ne: \atcher-.< A
:87
A "ublic voi! init-. @ if-is0""let. @ %tring counters ? getPara#eter-8siUe8.< if-counters 4? null. nu#Counters ? $nteger."arse$nt-counters.< %tring :atchers ? getPara#eter-8:atchers8.< if-:atchers 4? null. nu#\atchers ? $nteger."arse$nt-:atchers.< A s ? ne: T:oCounterNnu#CountersO< Container c" ? getContentPane-.< c".setLayout-ne: Llo:Layout-..< for-int i ? '< i P s.length< iKK. sNiO ? ne: T:oCounter-.< JPanel " ? ne: JPanel-.< start.a!!0ctionListener-ne: %tartL-..< ".a!!-start.< :atcher.a!!0ctionListener-ne: \atcherL-..< ".a!!-:atcher.< ".a!!-ne: JLabel-80ccess Count8..< ".a!!-aCount.< c".a!!-".< A "ublic static voi! #ain-%tringNO args. @ %haring( a""let ? ne: %haring(-.< // This isn2t an a""let, so set the flag an! // "ro!uce the "ara#eter values fro# args3 a""let.is0""let ? false< a""let.nu#Counters ? -args.length ?? ' [ ( 3 $nteger."arse$nt-argsN'O..< a""let.nu#\atchers ? -args.length P [ (, 3 $nteger."arse$nt-argsN(O..< Console.run-a""let, ),', a""let.nu#Counters B ,'.< A A ///3>
:88
6s be"ore, each counter contains its own dis%lay co#%onents= two te&t "ields and a label that initially indicates that the counts are eAuivalent. These co#%onents are added to the content %ane o" the outer class ob0ect in the T(o-o*nter constructor. RFSURFSTIJLT+(6PTE5M?TI?LU Because a T(o-o*nter thread is started via a key%ress by the user, it s %ossible that startA B could be called #ore than once. It s illegal "or Threa'!startA B to be called #ore than once "or a thread *an e&ce%tion is thrown,. /ou can see the #achinery to %revent this in the starte' "lag and the overridden startA B #ethod. RFSURFSTIJLT+(6PTE5M?TI??U In r*nA B, co*nt> and co*ntI are incre#ented and dis%layed in a #anner that would see# to kee% the# identical. Then sleepA B is called; without this call the %rogra# balks because it beco#es hard "or the +P4 to swa% tasks. RFSURFSTIJLT+(6PTE5M?TI?HU The synchTestA B #ethod %er"or#s the a%%arently useless activity o" checking to see i" co*nt> is eAuivalent to co*ntI; i" they are not eAuivalent it sets the label to !4nsynched$ to indicate this. But "irst, it calls a static #e#ber o" the class )haring> that incre#ents and dis%lays an access counter to show how #any ti#es this check has occurred success"ully. *The reason "or this will beco#e a%%arent in later variations o" this e&a#%le., RFSURFSTIJLT+(6PTE5M?TI?3U The 0atcher class is a thread whose 0ob is to call synchTestA B "or all o" the T(o-o*nter ob0ects that are active. It does this by ste%%ing through the array that s ke%t in the )haring> ob0ect. /ou can think o" the 0atcher as constantly %eeking over the shoulders o" the T(o-o*nter ob0ects. RFSURFSTIJLT+(6PTE5M?TI?GU
)haring> contains an array o" T(o-o*nter ob0ects that it initiali1es in initA B and starts as threads when you %ress the !start$ button. Dater,
when you %ress the !:atch$ button, one or #ore watchers are created and "reed u%on the unsus%ecting T(o-o*nter threads. RFSURF STIJLT+(6PTE5M?TI?IU Cote that to run this as an a%%let in a browser, your a%%let tag will need to contain the lines=
:8:
/ou can e&%eri#ent by changing the width, height, and %ara#eters to suit your tastes. By changing the si7e and (atchers you ll change the behavior o" the %rogra#. This %rogra# is set u% to run as a stand'alone a%%lication by %ulling the argu#ents "ro# the co##and line *or %roviding de"aults,. RFSURFSTIJLT+(6PTE5M?TI?2U (ere s the sur%rising %art. In T(o-o*nter!r*nA B, the in"inite loo% is 0ust re%eatedly %assing over the ad0acent lines=
:8;
::=
//3 c(I3%haring .Hava // Ysing the synchroniUe! key:or! to "revent // #ulti"le access to a "articular resource. // Pa""let co!e?%haring :i!th?),' height?,''Q // P"ara# na#e?siUe value?8( 8Q // P"ara# na#e?:atchers value?8(,8Q // P/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.B< i#"ort Hava.a:t.event.B< i#"ort co#.bruceeckel.s:ing.B< "ublic class %haring e6ten!s J0""let @ T:oCounterNO s< "rivate static int accessCount ? '< "rivate static JTe6tLiel! aCount ? ne: JTe6tLiel!-8'8, *.< "ublic static voi! incre#ent0ccess-. @ accessCountKK< aCount.setTe6t-$nteger.to%tring-accessCount..< A "rivate JButton start ? ne: JButton-8%tart8., :atcher ? ne: JButton-8\atch8.< "rivate boolean is0""let ? true< "rivate int nu#Counters ? ( < "rivate int nu#\atchers ? (,< class T:oCounter e6ten!s Threa! @ "rivate boolean starte! ? false< "rivate JTe6tLiel! t( ? ne: JTe6tLiel!-,., t ? ne: JTe6tLiel!-,.< "rivate JLabel l ? ne: JLabel-8count( ?? count 8.< "rivate int count( ? ', count ? '< "ublic T:oCounter-. @ JPanel " ? ne: JPanel-.<
::1
".a!!-t(.< ".a!!-t .< ".a!!-l.< getContentPane-..a!!-".< A "ublic voi! start-. @ if-4starte!. @ starte! ? true< su"er.start-.< A A "ublic synchroniUe! voi! run-. @ :hile -true. @ t(.setTe6t-$nteger.to%tring-count(KK..< t .setTe6t-$nteger.to%tring-count KK..< try @ slee"-,''.< A catch-$nterru"te!E6ce"tion e. @ %yste#.err."rintln-8$nterru"te!8.< A A A "ublic synchroniUe! voi! synchTest-. @ incre#ent0ccess-.< if-count( 4? count . l.setTe6t-8Ynsynche!8.< A A class \atcher e6ten!s Threa! @ "ublic \atcher-. @ su"er.start-.< A "ublic voi! run-. @ :hile-true. @ for-int i ? '< i P s.length< iKK. sNiO.synchTest-.< try @ slee"-,''.< A catch-$nterru"te!E6ce"tion e. @ %yste#.err."rintln-8$nterru"te!8.< A A
::2
A A class %tartL i#"le#ents 0ctionListener @ "ublic voi! actionPerfor#e!-0ctionEvent e. @ for-int i ? '< i P s.length< iKK. sNiO.start-.< A A class \atcherL i#"le#ents 0ctionListener @ "ublic voi! actionPerfor#e!-0ctionEvent e. @ for-int i ? '< i P nu#\atchers< iKK. ne: \atcher-.< A A "ublic voi! init-. @ if-is0""let. @ %tring counters ? getPara#eter-8siUe8.< if-counters 4? null. nu#Counters ? $nteger."arse$nt-counters.< %tring :atchers ? getPara#eter-8:atchers8.< if-:atchers 4? null. nu#\atchers ? $nteger."arse$nt-:atchers.< A s ? ne: T:oCounterNnu#CountersO< Container c" ? getContentPane-.< c".setLayout-ne: Llo:Layout-..< for-int i ? '< i P s.length< iKK. sNiO ? ne: T:oCounter-.< JPanel " ? ne: JPanel-.< start.a!!0ctionListener-ne: %tartL-..< ".a!!-start.< :atcher.a!!0ctionListener-ne: \atcherL-..< ".a!!-:atcher.< ".a!!-ne: Label-80ccess Count8..< ".a!!-aCount.< c".a!!-".< A "ublic static voi! #ain-%tringNO args. @ %haring a""let ? ne: %haring -.< // This isn2t an a""let, so set the flag an! // "ro!uce the "ara#eter values fro# args3
::3
a""let.is0""let ? false< a""let.nu#Counters ? -args.length ?? ' [ ( 3 $nteger."arse$nt-argsN'O..< a""let.nu#\atchers ? -args.length P [ (, 3 $nteger."arse$nt-argsN(O..< Console.run-a""let, ),', a""let.nu#Counters B ,'.< A A ///3>
/ou ll notice that both r*nA B and synchTestA B are synchroni7e'. I" you synchroni1e only one o" the #ethods, then the other is "ree to ignore the ob0ect lock and can be called with i#%unity. This is an i#%ortant %oint= Every #ethod that accesses a critical shared resource #ust be synchroni7e' or it won t work right. RFSURFSTIJLT+(6PTE5M?TIHGU Cow a new issue arises. The 0atcher can never get a %eek at what s going on because the entire r*nA B #ethod has been synchroni7e', and since r*nA B is always running "or each ob0ect the lock is always tied u% and synchTestA B can never be called. /ou can see this because the access-o*nt never changes. RFSURFSTIJLT+(6PTE5M?TIHIU :hat we d like "or this e&a#%le is a way to isolate only art o" the code inside r*nA B. The section o" code you want to isolate this way is called a critical section and you use the synchroni7e' keyword in a di""erent way to set u% a critical section. Java su%%orts critical sections with the s)nchroni?ed blockE this ti#e synchroni7e' is used to s%eci"y the ob0ect whose lock is being used to synchroni1e the enclosed code= RFSURF STIJLT+(6PTE5M?TIH2U
::4
The )haringI e&a#%le can be #odi"ied by re#oving the synchroni7e' keyword "ro# the entire r*nA B #ethod and instead %utting a synchroni7e' block around the two critical lines. But what ob0ect should be used as the lockO The one that is already res%ected by synchTestA B, which is the current ob0ect * this,. So the #odi"ied r*nA B looks like this=
"ublic voi! run-. @ :hile -true. @ synchroniUe!-this. @ t(.setTe6t-$nteger.to%tring-count(KK..< t .setTe6t-$nteger.to%tring-count KK..< A try @ slee"-,''.< A catch-$nterru"te!E6ce"tion e. @ %yste#.err."rintln-8$nterru"te!8.< A A A
This is the only change that #ust be #ade to )haringI!8ava, and you ll see that while the two counters are never out o" synch *according to when the 0atcher is allowed to look at the#,, there is still adeAuate access %rovided to the 0atcher during the e&ecution o" r*nA B. RFSURF STIJLT+(6PTE5M?TI3MU )" course, all synchroni1ation de%ends on %rogra##er diligence= every %iece o" code that can access a shared resource #ust be wra%%ed in an a%%ro%riate synchroni1ed block. RFSURFSTIJLT+(6PTE5M?TI3KU
1:nchroni?ed efficienc:
Since having two #ethods write to the sa#e %iece o" data never sounds like a %articularly good idea, it #ight see# to #ake sense "or all #ethods to be auto#atically synchroni7e' and eli#inate the synchroni7e' keyword altogether. *)" course, the e&a#%le with a synchroni7e' r*n A B shows that this wouldn t work either., But it turns out that acAuiring a lock is not a chea% o%eration9it #ulti%lies the cost o" a #ethod call *that is, entering and e&iting "ro# the #ethod, not e&ecuting the body o" the #ethod, by a #ini#u# o" "our ti#es, and could be #uch #ore
::5
de%ending on your i#%le#entation. So i" you know that a %articular #ethod will not cause contention %roble#s it is e&%edient to leave o"" the synchroni7e' keyword. )n the other hand, leaving o"" the synchroni7e' keyword because you think it is a %er"or#ance bottleneck, and ho%ing that there aren t any collisions is an invitation to disaster. RFSURFSTIJLT+(6PTE5M?TI3LU
"ava;eans revisited
Cow that you understand synchroni1ation, you can take another look at JavaBeans. :henever you create a Bean, you #ust assu#e that it will run in a #ultithreaded environ#ent. This #eans that=
(*6) :henever %ossible, all the p*blic #ethods o" a Bean should be synchroni7e'. )" course, this incurs the synchroni7e' run'
ti#e overhead. I" that s a %roble#, #ethods that will not cause %roble#s in critical sections can be le"t un' synchroni7e', but kee% in #ind that this is not always obvious. Methods that Auali"y tend to be s#all *such as get-ircle)i7eA B in the "ollowing e&a#%le, andFor !ato#ic,$ that is, the #ethod call e&ecutes in such a short a#ount o" code that the ob0ect cannot be changed during e&ecution. Making such #ethods un' synchroni7e' #ight not have a signi"icant e""ect on the e&ecution s%eed o" your %rogra#. /ou #ight as well #ake all p*blic #ethods o" a Bean synchroni7e' and re#ove the synchroni7e' keyword only when you know "or sure that it s necessary and that it #akes a di""erence. RFSURFSTIJLT+(6PTE5M?TI3?U
::7
//3 c(I3BangBean .Hava // ;ou shoul! :rite your Beans this :ay so they // can run in a #ultithrea!e! environ#ent. i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.B< i#"ort Hava.a:t.event.B< i#"ort Hava.util.B< i#"ort Hava.io.B< i#"ort co#.bruceeckel.s:ing.B< "ublic class BangBean e6ten!s JPanel i#"le#ents %erialiUable @ "rivate int 6#, y#< "rivate int c%iUe ? '< // Circle siUe "rivate %tring te6t ? 8Bang48< "rivate int font%iUe ? I1< "rivate Color tColor ? Color.re!< "rivate 0rrayList actionListeners ? ne: 0rrayList-.< "ublic BangBean -. @ a!!JouseListener-ne: JL-..< a!!JouseJotionListener-ne: JJ-..< A "ublic synchroniUe! int getCircle%iUe-. @ return c%iUe< A "ublic synchroniUe! voi! setCircle%iUe-int ne:%iUe. @ c%iUe ? ne:%iUe< A "ublic synchroniUe! %tring getBangTe6t-. @ return te6t< A "ublic synchroniUe! voi! setBangTe6t-%tring ne:Te6t. @ te6t ? ne:Te6t< A "ublic synchroniUe! int getLont%iUe-. @ return font%iUe< A "ublic synchroniUe! voi!
::8
setLont%iUe-int ne:%iUe. @ font%iUe ? ne:%iUe< A "ublic synchroniUe! Color getTe6tColor-. @ return tColor< A "ublic synchroniUe! voi! setTe6tColor-Color ne:Color. @ tColor ? ne:Color< A "ublic voi! "aintCo#"onent-ara"hics g. @ su"er."aintCo#"onent-g.< g.setColor-Color.black.< g.!ra:Gval-6# - c%iUe/ , y# - c%iUe/ , c%iUe, c%iUe.< A // This is a #ulticast listener, :hich is // #ore ty"ically use! than the unicast // a""roach taken in BangBean.Hava3 "ublic synchroniUe! voi! a!!0ctionListener-0ctionListener l. @ actionListeners.a!!-l.< A "ublic synchroniUe! voi! re#ove0ctionListener-0ctionListener l. @ actionListeners.re#ove-l.< A // &otice this isn2t synchroniUe!3 "ublic voi! notifyListeners-. @ 0ctionEvent a ? ne: 0ctionEvent-BangBean .this, 0ctionEvent.0CT$G&bPE5LG5JED, null.< 0rrayList lv ? null< // Jake a shallo: co"y of the List in case // so#eone a!!s a listener :hile :e2re // calling listeners3 synchroniUe!-this. @ lv ? -0rrayList.actionListeners.clone-.< A // Call all the listener #etho!s3 for-int i ? '< i P lv.siUe-.< iKK.
:::
--0ctionListener.lv.get-i.. .actionPerfor#e!-a.< A class JL e6ten!s Jouse0!a"ter @ "ublic voi! #ousePresse!-JouseEvent e. @ ara"hics g ? getara"hics-.< g.setColor-tColor.< g.setLontne: Lont8Ti#es5o#an8, Lont.BGLD, font%iUe..< int :i!th ? g.getLontJetrics-..string\i!th-te6t.< g.!ra:%tring-te6t, -get%iUe-..:i!th - :i!th. / , get%iUe-..height/ .< g.!is"ose-.< notifyListeners-.< A A class JJ e6ten!s JouseJotion0!a"ter @ "ublic voi! #ouseJove!-JouseEvent e. @ 6# ? e.get9-.< y# ? e.get;-.< re"aint-.< A A "ublic static voi! #ain-%tringNO args. @ BangBean bb ? ne: BangBean -.< bb.a!!0ctionListener-ne: 0ctionListener-. @ "ublic voi! actionPerfor#e!-0ctionEvent e.@ %yste#.out."rintln-80ctionEvent8 K e.< A A.< bb.a!!0ctionListener-ne: 0ctionListener-. @ "ublic voi! actionPerfor#e!-0ctionEvent e.@ %yste#.out."rintln-8BangBean action8.< A A.< bb.a!!0ctionListener-ne: 0ctionListener-. @ "ublic voi! actionPerfor#e!-0ctionEvent e.@ %yste#.out."rintln-8Jore action8.<
::;
(+() 7oes the #ethod #odi"y the state o" !critical$ variables within the
ob0ectO To discover whether the variables are !critical$ you #ust deter#ine whether they will be read or set by other threads in the %rogra#. *In this case, the reading or setting is virtually always acco#%lished via synchroni7e' #ethods, so you can 0ust e&a#ine those., In the case o" paintA B, no #odi"ication takes %lace. RFSURFSTIJLT+(6PTE5M?TI3IU
(+!) 7oes the #ethod de%end on the state o" these !critical$ variablesO I" a synchroni7e' #ethod #odi"ies a variable that your #ethod
uses, then you #ight very well want to #ake your #ethod synchroni7e' as well. Based on this, you #ight observe that
:;=
c)i7e is changed by synchroni7e' #ethods and there"ore paint A B should be synchroni7e'. (ere, however, you can ask !:hat s the worst thing that will ha%%en i" c)i7e is changed during a paint A BO$ :hen you see that it s nothing too bad, and a transient e""ect at that, you can decide to leave paintA B un' synchroni7e' to %revent the e&tra overhead "ro# the synchroni7e' #ethod call.
RFSURFSTIJLT+(6PTE5M?TI32U
(+*) 6 third clue is to notice whether the base'class version o" paintA B is synchroni7e', which it isn t. This isn t an airtight argu#ent, 0ust a clue. In this case, "or e&a#%le, a "ield that is changed via synchroni7e' #ethods *that is c)i7e, has been #i&ed into the paintA B "or#ula and #ight have changed the situation. Cotice, however, that synchroni7e' doesn t inherit9that is, i" a #ethod is synchroni7e' in the base class then it is not auto#atically synchroni7e' in the derived class overridden version. RFSURF
STIJLT+(6PTE5M?TIG@U The test code in Test2ang2eanI has been #odi"ied "ro# that in the %revious cha%ter to de#onstrate the #ulticast ability o" 2ang2eanI by adding e&tra listeners. RFSURFSTIJLT+(6PTE5M?TIGMU
;locking
6 thread can be in any one o" "our states=
(++) +e,= The thread ob0ect has been created but it hasn t been started
yet so it cannot run. RFSURFSTIJLT+(6PTE5M?TIGKU
(+,) -unnable= This #eans that a thread can be run when the ti#e'
slicing #echanis# has +P4 cycles available "or the thread. Thus, the thread #ight or #ight not be running, but there s nothing to %revent it "ro# being run i" the scheduler can arrange it; it s not dead or blocked. RFSURFSTIJLT+(6PTE5M?TIGLU
(+-) %ead= The nor#al way "or a thread to die is by returning "ro# its r*nA B #ethod. /ou can also call stopA B, but this throws an e&ce%tion that s a subclass o" &rror *which #eans you aren t "orced to %ut the call in a try block,. 5e#e#ber that throwing an
:;1
e&ce%tion should be a s%ecial event and not %art o" nor#al %rogra# e&ecution; thus the use o" stopA B is de%recated in Java K. There s also a 'estroyA B #ethod *which has never been i#%le#ented, that you should never call i" you can avoid it since it s drastic and doesn t release ob0ect locks. RFSURF STIJLT+(6PTE5M?TIG?U
(+4) 0locked= The thread could be run but there s so#ething that
%revents it. :hile a thread is in the blocked state the scheduler will si#%ly ski% over it and not give it any +P4 ti#e. 4ntil a thread reenters the runnable state it won t %er"or# any o%erations. RF SURFSTIJLT+(6PTE5M?TIGHU
;ecoming blocked
The blocked state is the #ost interesting one, and is worth "urther e&a#ination. 6 thread can beco#e blocked "or "ive reasons= RFSURF STIJLT+(6PTE5M?TIG3U
(+6) /ou ve sus%ended the e&ecution o" the thread with s*spen'A B. It will not beco#e runnable again until the thread gets the res*me A B #essage *these are de%recated in Java K, and will be e&a#ined
"urther,. RFSURFSTIJLT+(6PTE5M?TIGIU
(,7) /ou ve sus%ended the e&ecution o" the thread with (aitA B. It will not beco#e runnable again until the thread gets the notifyA B or notifyAllA B #essage. */es, this looks 0ust like nu#ber K, but
there s a distinct di""erence that will be revealed., RFSURF STIJLT+(6PTE5M?TIG2U
:;2
/ou can also call yiel'A B *a #ethod o" the Threa' class, to voluntarily give u% the +P4 so that other threads can run. (owever, the sa#e thing ha%%ens i" the scheduler decides that your thread has had enough ti#e and 0u#%s to another thread. That is, nothing %revents the scheduler "ro# #oving your thread and giving ti#e to so#e other thread. :hen a thread is blocked, there s so#e reason that it cannot continue running. RF SURFSTIJLT+(6PTE5M?TIIKU The "ollowing e&a#%le shows all "ive ways o" beco#ing blocked. It all e&ists in a single "ile called 2locking!8ava, but it will be e&a#ined here in discrete %ieces. */ou ll notice the !+ontinued$ and !+ontinuing$ tags that allow the code e&traction tool to %iece everything together., RFSURF STIJLT+(6PTE5M?TIILU Because this e&a#%le de#onstrates so#e de%recated #ethods, you ,ill get de%recation #essages when it is co#%iled. RFSURF STIJLT+(6PTE5M?TII?U Eirst, the basic "ra#ework=
//3 c(I3Blocking.Hava // De#onstrates the various :ays a threa! // can be blocke!. // Pa""let co!e?Blocking :i!th?),' height?,,'Q // P/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.B< i#"ort Hava.a:t.event.B< i#"ort Hava.io.B< i#"ort co#.bruceeckel.s:ing.B< //////////// The basic fra#e:ork /////////// class Blockable e6ten!s Threa! @ "rivate Peeker "eeker< "rotecte! JTe6tLiel! state ? ne: JTe6tLiel!-)'.< "rotecte! int i< "ublic Blockable-Container c. @ c.a!!-state.< "eeker ? ne: Peeker-this, c.< A "ublic synchroniUe! int rea!-. @ return i< A
:;3
"rotecte! synchroniUe! voi! u"!ate-. @ state.setTe6t-getClass-..get&a#e-. K 8 state3 i ? 8 K i.< A "ublic voi! sto"Peeker-. @ // "eeker.sto"-.< De"recate! in Java (. "eeker.ter#inate-.< // The "referre! a""roach A A class Peeker e6ten!s Threa! @ "rivate Blockable b< "rivate int session< "rivate JTe6tLiel! status ? ne: JTe6tLiel!-)'.< "rivate boolean sto" ? false< "ublic Peeker-Blockable b, Container c. @ c.a!!-status.< this.b ? b< start-.< A "ublic voi! ter#inate-. @ sto" ? true< A "ublic voi! run-. @ :hile -4sto". @ status.setTe6t-b.getClass-..get&a#e-. K 8 Peeker 8 K -KKsession. K 8< value ? 8 K b.rea!-..< try @ slee"-(''.< A catch-$nterru"te!E6ce"tion e. @ %yste#.err."rintln-8$nterru"te!8.< A A A A ///3Continue!
The 2lockable class is #eant to be a base class "or all the classes in this e&a#%le that de#onstrate blocking. 6 2lockable ob0ect contains a JTe4tFiel' called state that is used to dis%lay in"or#ation about the ob0ect. The #ethod that dis%lays this in"or#ation is *p'ateA B. /ou can see it uses get-lassA B!get/ameA B to %roduce the na#e o" the class instead o" 0ust %rinting it out; this is because *p'ateA B cannot know the
:;4
e&act na#e o" the class it is called "or, since it will be a class derived "ro# 2lockable. RFSURFSTIJLT+(6PTE5M?TIIHU The indicator o" change in 2lockable is an int i, which will be incre#ented by the r*nA B #ethod o" the derived class. RFSURF STIJLT+(6PTE5M?TII3U There s a thread o" class #eeker that is started "or each 2lockable ob0ect, and the #eeker s 0ob is to watch its associated 2lockable ob0ect to see changes in i by calling rea'A B and re%orting the# in its stat*s JTe4tFiel'. This is i#%ortant= Cote that rea'A B and *p'ateA B are both synchroni7e', which #eans they reAuire that the ob0ect lock be "ree. RFSURFSTIJLT+(6PTE5M?TIIGU
1lee.ing
The "irst test in this %rogra# is with sleepA B<
///3Continuing ///////////// Blocking via slee"-. /////////// class %lee"er( e6ten!s Blockable @ "ublic %lee"er(-Container c. @ su"er-c.< A "ublic synchroniUe! voi! run-. @ :hile-true. @ iKK< u"!ate-.< try @ slee"-('''.< A catch-$nterru"te!E6ce"tion e. @ %yste#.err."rintln-8$nterru"te!8.< A A A A class %lee"er e6ten!s Blockable @ "ublic %lee"er -Container c. @ su"er-c.< A "ublic voi! run-. @ :hile-true. @ change-.< try @
:;5
slee"-('''.< A catch-$nterru"te!E6ce"tion e. @ %yste#.err."rintln-8$nterru"te!8.< A A A "ublic synchroniUe! voi! change-. @ iKK< u"!ate-.< A A ///3Continue!
In )leeper> the entire r*nA B #ethod is synchroni7e'. /ou ll see that the #eeker associated with this ob0ect will run along #errily until you start the thread, and then the #eeker sto%s cold. This is one "or# o" blocking= since )leeper>!r*nA B is synchroni7e', and once the thread starts it s always inside r*nA B, the #ethod never gives u% the ob0ect lock and the #eeker is blocked. RFSURFSTIJLT+(6PTE5M?TIIIU
)leeperI %rovides a solution by #aking r*nA B un' synchroni7e'. )nly the changeA B #ethod is synchroni7e', which #eans that while r*nA B is in sleepA B, the #eeker can access the synchroni7e' #ethod it needs, na#ely rea'A B. (ere you ll see that the #eeker continues running when you start the )leeperI thread. RFSURF
STIJLT+(6PTE5M?TII2U
Threa' class has a #ethod s*spen'A B to te#%orarily sto% the thread and res*meA B that restarts it at the %oint it was halted. res*meA B #ust
be called by so#e thread outside the sus%ended one, and in this case there s a se%arate class called $es*mer that does 0ust that. Each o" the classes de#onstrating sus%endFresu#e has an associated resu#er=
///3Continuing /////////// Blocking via sus"en!-. /////////// class %us"en!5esu#e e6ten!s Blockable @ "ublic %us"en!5esu#e-Container c. @ su"er-c.< ne: 5esu#er-this.<
:;7
A A class %us"en!5esu#e( e6ten!s %us"en!5esu#e @ "ublic %us"en!5esu#e(-Container c. @ su"er-c.<A "ublic synchroniUe! voi! run-. @ :hile-true. @ iKK< u"!ate-.< sus"en!-.< // De"recate! in Java (. A A A class %us"en!5esu#e e6ten!s %us"en!5esu#e @ "ublic %us"en!5esu#e -Container c. @ su"er-c.<A "ublic voi! run-. @ :hile-true. @ change-.< sus"en!-.< // De"recate! in Java (. A A "ublic synchroniUe! voi! change-. @ iKK< u"!ate-.< A A class 5esu#er e6ten!s Threa! @ "rivate %us"en!5esu#e sr< "ublic 5esu#er-%us"en!5esu#e sr. @ this.sr ? sr< start-.< A "ublic voi! run-. @ :hile-true. @ try @ slee"-('''.< A catch-$nterru"te!E6ce"tion e. @ %yste#.err."rintln-8$nterru"te!8.< A
:;8
sr.resu#e-.< // De"recate! in Java (. A A A ///3Continue! )*spen'$es*me> also has a synchroni7e' r*nA B #ethod. 6gain, when you start this thread you ll see that its associated #eeker gets
blocked waiting "or the lock to beco#e available, which never ha%%ens. This is "i&ed as be"ore in )*spen'$es*meI, which does not synchroni7e the entire r*nA B #ethod but instead uses a se%arate synchroni7e' changeA B #ethod. RFSURFSTIJLT+(6PTE5M?TI2@U /ou should be aware that Java K de%recates the use o" s*spen'A B and res*meA B, because s*spen'A B holds the ob0ect s lock and is thus deadlock'%rone. That is, you can easily get a nu#ber o" locked ob0ects waiting on each other, and this will cause your %rogra# to "ree1e. 6lthough you #ight see the# used in older %rogra#s you should not use s*spen'A B and res*meA B. The %ro%er solution is described later in this cha%ter. RFSURFSTIJLT+(6PTE5M?TI2MU
:;:
The second "or# takes no argu#ents, and #eans that the (aitA B will continue until a notifyA B co#es along and will not auto#atically ter#inate a"ter a ti#e. RFSURFSTIJLT+(6PTE5M?TI2?U )ne "airly uniAue as%ect o" (aitA B and notifyA B is that both #ethods are %art o" the base class .b8ect and not %art o" Threa' as are sleepA B, s*spen'A B, and res*meA B. 6lthough this see#s a bit strange at "irst9 to have so#ething that s e&clusively "or threading as %art o" the universal base class9it s essential because they #ani%ulate the lock that s also %art o" every ob0ect. 6s a result, you can %ut a (aitA B inside any synchroni7e' #ethod, regardless o" whether there s any threading going on inside that %articular class. In "act, the onl) %lace you can call (aitA B is within a synchroni7e' #ethod or block. I" you call (aitA B or notifyA B within a #ethod that s not synchroni7e', the %rogra# will co#%ile, but when you run it you ll get an Illegal1onitor)tate&4ception with the so#ewhat nonintuitive #essage !current thread not owner.$ Cote that sleepA B, s*spen'A B, and res*meA B can all be called within non' synchroni7e' #ethods since they don t #ani%ulate the lock. RFSURFSTIJLT+(6PTE5M?TI2HU /ou can call (aitA B or notifyA B only "or your own lock. 6gain, you can co#%ile code that tries to use the wrong lock, but it will %roduce the sa#e Illegal1onitor)tate&4ception #essage as be"ore. /ou can t "ool with so#eone else s lock, but you can ask another ob0ect to %er"or# an o%eration that #ani%ulates its own lock. So one a%%roach is to create a synchroni7e' #ethod that calls notifyA B "or its own ob0ect. (owever, in /otifier you ll see the notifyA B call inside a synchroni7e' block=
synchroniUe!-:n . @ :n .notify-.< A
where (nI is the ob0ect o" ty%e 0ait/otifyI. This #ethod, which is not %art o" 0ait/otifyI, acAuires the lock on the (nI ob0ect, at which %oint it s legal "or it to call notifyA B "or (nI and you won t get the Illegal1onitor)tate&4ception. RFSURFSTIJLT+(6PTE5M?TI23U
///3Continuing /////////// Blocking via :ait-. /////////// class \ait&otify( e6ten!s Blockable @
:;;
"ublic \ait&otify(-Container c. @ su"er-c.< A "ublic synchroniUe! voi! run-. @ :hile-true. @ iKK< u"!ate-.< try @ :ait-('''.< A catch-$nterru"te!E6ce"tion e. @ %yste#.err."rintln-8$nterru"te!8.< A A A A class \ait&otify e6ten!s Blockable @ "ublic \ait&otify -Container c. @ su"er-c.< ne: &otifier-this.< A "ublic synchroniUe! voi! run-. @ :hile-true. @ iKK< u"!ate-.< try @ :ait-.< A catch-$nterru"te!E6ce"tion e. @ %yste#.err."rintln-8$nterru"te!8.< A A A A class &otifier e6ten!s Threa! @ "rivate \ait&otify :n < "ublic &otifier-\ait&otify :n . @ this.:n ? :n < start-.< A "ublic voi! run-. @ :hile-true. @ try @
;==
slee"- '''.< A catch-$nterru"te!E6ce"tion e. @ %yste#.err."rintln-8$nterru"te!8.< A synchroniUe!-:n . @ :n .notify-.< A A A A ///3Continue! (aitA B is ty%ically used when you ve gotten to the %oint where you re waiting "or so#e other condition, under the control o" "orces outside your thread, to change and you don t want to idly wait by inside the thread. So (aitA B allows you to %ut the thread to slee% while waiting "or the world to change, and only when a notifyA B or notifyAllA B occurs does the thread wake u% and check "or changes. Thus, it %rovides a way to synchroni1e between threads. RFSURFSTIJLT+(6PTE5M?TI2GU
;locking on IDO
I" a strea# is waiting "or so#e IF) activity, it will auto#atically block. In the "ollowing %ortion o" the e&a#%le, the two classes work with generic $ea'er and 0riter ob0ects, but in the test "ra#ework a %i%ed strea# will be set u% to allow the two threads to sa"ely %ass data to each other *which is the %ur%ose o" %i%ed strea#s,. RFSURF STIJLT+(6PTE5M?TI2IU The )en'er %uts data into the 0riter and slee%s "or a rando# a#ount o" ti#e. (owever, $eceiver has no sleepA B, s*spen'A B, or (aitA B. But when it does a rea'A B it auto#atically blocks when there is no #ore data.
///3Continuing class %en!er e6ten!s Blockable @ // sen! "rivate \riter out< "ublic %en!er-Container c, \riter out. @ su"er-c.< this.out ? out< A "ublic voi! run-. @
;=1
:hile-true. @ for-char c ? 202< c P? 2U2< cKK. @ try @ iKK< out.:rite-c.< state.setTe6t-8%en!er sent3 8 K -char.c.< slee"--int.-)''' B Jath.ran!o#-...< A catch-$nterru"te!E6ce"tion e. @ %yste#.err."rintln-8$nterru"te!8.< A catch-$GE6ce"tion e. @ %yste#.err."rintln-8$G "roble#8.< A A A A A class 5eceiver e6ten!s Blockable @ "rivate 5ea!er in< "ublic 5eceiver-Container c, 5ea!er in. @ su"er-c.< this.in ? in< A "ublic voi! run-. @ try @ :hile-true. @ iKK< // %ho: "eeker it2s alive // Blocks until characters are there3 state.setTe6t-85eceiver rea!3 8 K -char.in.rea!-..< A A catch-$GE6ce"tion e. @ %yste#.err."rintln-8$G "roble#8.< A A A ///3Continue!
Both classes also %ut in"or#ation into their state "ields and change i so the #eeker can see that the thread is running. RFSURF STIJLT+(6PTE5M?TI22U
;=2
#esting
The #ain a%%let class is sur%risingly si#%le because #ost o" the work has been %ut into the 2lockable "ra#ework. Basically, an array o" 2lockable ob0ects is created, and since each one is a thread, they %er"or# their own activities when you %ress the !start$ button. There s also a button and action#erforme'A B clause to sto% all o" the #eeker ob0ects, which %rovides a de#onstration o" the alternative to the de%recated *in Java K, stopA B #ethod o" Threa'. RFSURF STIJLT+(6PTE5M?TIM@@U To set u% a connection between the )en'er and $eceiver ob0ects, a #ipe'0riter and #ipe'$ea'er are created. Cote that the #ipe'$ea'er in #ust be connected to the #ipe'0riter o*t via a constructor argu#ent. 6"ter that, anything that s %laced in o*t can later be e&tracted "ro# in, as i" it %assed through a %i%e *hence the na#e,. The in and o*t ob0ects are then %assed to the $eceiver and )en'er constructors, res%ectively, which treat the# as $ea'er and 0riter ob0ects o" any ty%e *that is, they are u%cast,. RFSURF STIJLT+(6PTE5M?TIM@MU The array o" 2lockable re"erences b is not initiali1ed at its %oint o" de"inition because the %i%ed strea#s cannot be set u% be"ore that de"inition takes %lace *the need "or the try block %revents this,.
///3Continuing /////////// Testing Everything /////////// "ublic class Blocking e6ten!s J0""let @ "rivate JButton start ? ne: JButton-8%tart8., sto"Peekers ? ne: JButton-8%to" Peekers8.< "rivate boolean starte! ? false< "rivate BlockableNO b< "rivate Pi"e!\riter out< "rivate Pi"e!5ea!er in< class %tartL i#"le#ents 0ctionListener @ "ublic voi! actionPerfor#e!-0ctionEvent e. @ if-4starte!. @ starte! ? true< for-int i ? '< i P b.length< iKK. bNiO.start-.<
;=3
A A A class %to"PeekersL i#"le#ents 0ctionListener @ "ublic voi! actionPerfor#e!-0ctionEvent e. @ // De#onstration of the "referre! // alternative to Threa!.sto"-.3 for-int i ? '< i P b.length< iKK. bNiO.sto"Peeker-.< A A "ublic voi! init-. @ Container c" ? getContentPane-.< c".setLayout-ne: Llo:Layout-..< out ? ne: Pi"e!\riter-.< try @ in ? ne: Pi"e!5ea!er-out.< A catch-$GE6ce"tion e. @ %yste#.err."rintln-8Pi"e!5ea!er "roble#8.< A b ? ne: BlockableNO @ ne: %lee"er(-c"., ne: %lee"er -c"., ne: %us"en!5esu#e(-c"., ne: %us"en!5esu#e -c"., ne: \ait&otify(-c"., ne: \ait&otify -c"., ne: %en!er-c", out., ne: 5eceiver-c", in. A< start.a!!0ctionListener-ne: %tartL-..< c".a!!-start.< sto"Peekers.a!!0ctionListenerne: %to"PeekersL-..< c".a!!-sto"Peekers.< A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: Blocking-., ),', ,,'.< A A ///3>
;=4
In initA B, notice the loo% that #oves through the entire array and adds the state and peeker!stat*s te&t "ields to the %age. RFSURF STIJLT+(6PTE5M?TIM@KU :hen the 2lockable threads are initially created, each one auto#atically creates and starts its own #eeker. So you ll see the #eekers running be"ore the 2lockable threads are started. This is i#%ortant, as so#e o" the #eekers will get blocked and sto% when the 2lockable threads start, and it s essential to see this to understand that %articular as%ect o" blocking. RFSURFSTIJLT+(6PTE5M?TIM@LU
Deadlock
Because threads can beco#e blocked and because ob0ects can have synchroni7e' #ethods that %revent threads "ro# accessing that ob0ect until the synchroni1ation lock is released, it s %ossible "or one thread to get stuck waiting "or another thread, which in turn waits "or another thread, etc., until the chain leads back to a thread waiting on the "irst one. /ou get a continuous loo% o" threads waiting on each other and no one can #ove. This is called deadlock. The clai# is that it doesn t ha%%en that o"ten, but when it ha%%ens to you it s "rustrating to debug. RFSURF STIJLT+(6PTE5M?TIM@?U There is no language su%%ort to hel% %revent deadlock; it s u% to you to avoid it by care"ul design. These are not co#"orting words to the %erson who s trying to debug a deadlocking %rogra#. RFSURF STIJLT+(6PTE5M?TIM@HU
;=5
Instead o" using stopA B, you should "ollow the e&a#%le in 2locking! 8ava and use a "lag to tell the thread when to ter#inate itsel" by e&iting its r*nA B #ethod. RFSURFSTIJLT+(6PTE5M?TIM@GU There are ti#es when a thread blocks9such as when it is waiting "or in%ut9and it cannot %oll a "lag as it does in 2locking!8ava. In these cases, you still shouldn t use stopA B, but instead you can use the interr*ptA B #ethod in Threa' to break out o" the blocked code=
//3 c(I3$nterru"t.Hava // The alternative a""roach to using // sto"-. :hen a threa! is blocke!. // Pa""let co!e?$nterru"t :i!th? '' height?(''Q // P/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.B< i#"ort Hava.a:t.event.B< i#"ort co#.bruceeckel.s:ing.B< class Blocke! e6ten!s Threa! @ "ublic synchroniUe! voi! run-. @ try @ :ait-.< // Blocks A catch-$nterru"te!E6ce"tion e. @ %yste#.err."rintln-8$nterru"te!8.< A %yste#.out."rintln-8E6iting run-.8.< A A "ublic class $nterru"t e6ten!s J0""let @ "rivate JButton interru"t ? ne: JButton-8$nterru"t8.< "rivate Blocke! blocke! ? ne: Blocke!-.< "ublic voi! init-. @ Container c" ? getContentPane-.< c".setLayout-ne: Llo:Layout-..< c".a!!-interru"t.< interru"t.a!!0ctionListenerne: 0ctionListener-. @ "ublic
;=7
voi! actionPerfor#e!-0ctionEvent e. @ %yste#.out."rintln-8Button "resse!8.< if-blocke! ?? null. return< Threa! re#ove ? blocke!< blocke! ? null< // to release it re#ove.interru"t-.< A A.< blocke!.start-.< A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: $nterru"t-., '', (''.< A A ///3>
The (aitA B inside 2locke'!r*nA B %roduces the blocked thread. :hen you %ress the button, the blocke' re"erence is set to n*ll so the garbage collector will clean it u%, and then the ob0ect s interr*ptA B #ethod is called. The "irst ti#e you %ress the button you ll see that the thread Auits, but a"ter that there s no thread to kill so you 0ust see that the button has been %ressed. RFSURFSTIJLT+(6PTE5M?TIM@IU The s*spen'A B and res*meA B #ethods turn out to be inherently deadlock'%rone. :hen you call s*spen'A B, the target thread sto%s but it still holds any locks that it has acAuired u% to that %oint. So no other thread can access the locked resources until the thread is resu#ed. 6ny thread that wants to resu#e the target thread and also tries to use any o" the locked resources %roduces deadlock. /ou should not use s*spen'A B and res*meA B, but instead %ut a "lag in your Threa' class to indicate whether the thread should be active or sus%ended. I" the "lag indicates that the thread is sus%ended, the thread goes into a wait using (aitA B. :hen the "lag indicates that the thread should be resu#ed the thread is restarted with notifyA B. 6n e&a#%le can be %roduced by #odi"ying -o*nterI!8ava. 6lthough the e""ect is si#ilar, you ll notice that the code organi1ation is Auite di""erent9anony#ous inner classes are used "or all o" the listeners and the Threa' is an inner class, which #akes %rogra##ing slightly #ore convenient since it eli#inates so#e o" the e&tra bookkee%ing necessary in -o*nterI!8ava= RFSURF STIJLT+(6PTE5M?TIM@2U
;=8
//3 c(I3%us"en!.Hava // The alternative a""roach to using sus"en!-. // an! resu#e-., :hich are !e"recate! in Java . // Pa""let co!e?%us"en! :i!th?)'' height?(''Q // P/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.B< i#"ort Hava.a:t.event.B< i#"ort co#.bruceeckel.s:ing.B< "ublic class %us"en! e6ten!s J0""let @ "rivate JTe6tLiel! t ? ne: JTe6tLiel!-('.< "rivate JButton sus"en! ? ne: JButton-8%us"en!8., resu#e ? ne: JButton-85esu#e8.< "rivate %us"en!able ss ? ne: %us"en!able-.< class %us"en!able e6ten!s Threa! @ "rivate int count ? '< "rivate boolean sus"en!e! ? false< "ublic %us"en!able-. @ su"er.start-.< A "ublic voi! fau6%us"en!-. @ sus"en!e! ? true< A "ublic synchroniUe! voi! fau65esu#e-. @ sus"en!e! ? false< notify-.< A "ublic voi! run-. @ :hile -true. @ try @ slee"-(''.< synchroniUe!-this. @ :hile-sus"en!e!. :ait-.< A A catch-$nterru"te!E6ce"tion e. @ %yste#.err."rintln-8$nterru"te!8.< A t.setTe6t-$nteger.to%tring-countKK..< A A
;=:
A "ublic voi! init-. @ Container c" ? getContentPane-.< c".setLayout-ne: Llo:Layout-..< c".a!!-t.< sus"en!.a!!0ctionListenerne: 0ctionListener-. @ "ublic voi! actionPerfor#e!-0ctionEvent e. @ ss.fau6%us"en!-.< A A.< c".a!!-sus"en!.< resu#e.a!!0ctionListenerne: 0ctionListener-. @ "ublic voi! actionPerfor#e!-0ctionEvent e. @ ss.fau65esu#e-.< A A.< c".a!!-resu#e.< A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: %us"en!-., )'', (''.< A A ///3>
The "lag s*spen'e' inside )*spen'able is used to turn sus%ension on and o"". To sus%end, the "lag is set to tr*e by calling fa*4)*spen'A B and this is detected inside r*nA B. The (aitA B, as described earlier in this cha%ter, #ust be synchroni7e' so that it has the ob0ect lock. In fa*4$es*meA B, the s*spen'e' "lag is set to false and notifyA B is called9since this wakes u% (aitA B inside a synchroni7e' clause the fa*4$es*meA B #ethod #ust also be synchroni7e' so that it acAuires the lock be"ore calling notifyA B *thus the lock is available "or the (aitA B to wake u% with,. I" you "ollow the style shown in this %rogra# you can avoid using s*spen'A B and res*meA B. RFSURF STIJLT+(6PTE5M?TIMM@U The 'estroyA B #ethod o" Threa' has never been i#%le#ented; it s like a s*spen'A B that cannot resu#e, so it has the sa#e deadlock issues as
;=;
riorities
The riorit) o" a thread tells the scheduler how i#%ortant this thread is. I" there are a nu#ber o" threads blocked and waiting to be run, the scheduler will run the one with the highest %riority "irst. (owever, this doesn t #ean that threads with lower %riority don t get run *that is, you can t get deadlocked because o" %riorities,. Dower %riority threads 0ust tend to run less o"ten. RFSURFSTIJLT+(6PTE5M?TIMMLU 6lthough %riorities are interesting to know about and to %lay with, in %ractice you al#ost never need to set %riorities yoursel". So "eel "ree to ski% the rest o" this section i" %riorities aren t interesting to you. RFSURF STIJLT+(6PTE5M?TIMM?U
;1=
that the counters slow down as the associated threads have their %riorities lowered=
//3 c(I3Counter,.Hava // 0!Husting the "riorities of threa!s. // Pa""let co!e?Counter, :i!th?I,' height?+''Q // P/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.B< i#"ort Hava.a:t.event.B< i#"ort co#.bruceeckel.s:ing.B< class Ticker e6ten!s Threa! @ "rivate JButton b ? ne: JButton-8Toggle8., incPriority ? ne: JButton-8u"8., !ecPriority ? ne: JButton-8!o:n8.< "rivate JTe6tLiel! t ? ne: JTe6tLiel!-('., "r ? ne: JTe6tLiel!-).< // Dis"lay "riority "rivate int count ? '< "rivate boolean runLlag ? true< "ublic Ticker -Container c. @ b.a!!0ctionListener-ne: ToggleL-..< incPriority.a!!0ctionListener-ne: Y"L-..< !ecPriority.a!!0ctionListener-ne: Do:nL-..< JPanel " ? ne: JPanel-.< ".a!!-t.< ".a!!-"r.< ".a!!-b.< ".a!!-incPriority.< ".a!!-!ecPriority.< c.a!!-".< A class ToggleL i#"le#ents 0ctionListener @ "ublic voi! actionPerfor#e!-0ctionEvent e. @ runLlag ? 4runLlag< A A class Y"L i#"le#ents 0ctionListener @ "ublic voi! actionPerfor#e!-0ctionEvent e. @
;11
int ne:Priority ? getPriority-. K (< if-ne:Priority Q Threa!.J09bP5$G5$T;. ne:Priority ? Threa!.J09bP5$G5$T;< setPriority-ne:Priority.< A A class Do:nL i#"le#ents 0ctionListener @ "ublic voi! actionPerfor#e!-0ctionEvent e. @ int ne:Priority ? getPriority-. - (< if-ne:Priority P Threa!.J$&bP5$G5$T;. ne:Priority ? Threa!.J$&bP5$G5$T;< setPriority-ne:Priority.< A A "ublic voi! run-. @ :hile -true. @ if-runLlag. @ t.setTe6t-$nteger.to%tring-countKK..< "r.setTe6t$nteger.to%tring-getPriority-...< A yiel!-.< A A A "ublic class Counter, e6ten!s J0""let @ "rivate JButton start ? ne: JButton-8%tart8., u"Ja6 ? ne: JButton-8$nc Ja6 Priority8., !o:nJa6 ? ne: JButton-8Dec Ja6 Priority8.< "rivate boolean starte! ? false< "rivate static final int %$TE ? ('< "rivate Ticker NO s ? ne: Ticker N%$TEO< "rivate JTe6tLiel! #" ? ne: JTe6tLiel!-).< "ublic voi! init-. @ Container c" ? getContentPane-.< c".setLayout-ne: Llo:Layout-..< for-int i ? '< i P s.length< iKK. sNiO ? ne: Ticker -c".< c".a!!-ne: JLabel-
;12
8J09bP5$G5$T; ? 8 K Threa!.J09bP5$G5$T;..< c".a!!-ne: JLabel-8J$&bP5$G5$T; ? 8 K Threa!.J$&bP5$G5$T;..< c".a!!-ne: JLabel-8arou" Ja6 Priority ? 8..< c".a!!-#".< c".a!!-start.< c".a!!-u"Ja6.< c".a!!-!o:nJa6.< start.a!!0ctionListener-ne: %tartL-..< u"Ja6.a!!0ctionListener-ne: Y"Ja6L-..< !o:nJa6.a!!0ctionListener-ne: Do:nJa6L-..< sho:Ja6Priority-.< // 5ecursively !is"lay "arent threa! grou"s3 Threa!arou" "arent ? sN'O.getThrea!arou"-..getParent-.< :hile-"arent 4? null. @ c".a!!-ne: Label8Parent threa!grou" #a6 "riority ? 8 K "arent.getJa6Priority-...< "arent ? "arent.getParent-.< A A "ublic voi! sho:Ja6Priority-. @ #".setTe6t-$nteger.to%tringsN'O.getThrea!arou"-..getJa6Priority-...< A class %tartL i#"le#ents 0ctionListener @ "ublic voi! actionPerfor#e!-0ctionEvent e. @ if-4starte!. @ starte! ? true< for-int i ? '< i P s.length< iKK. sNiO.start-.< A A A class Y"Ja6L i#"le#ents 0ctionListener @ "ublic voi! actionPerfor#e!-0ctionEvent e. @ int #a6" ? sN'O.getThrea!arou"-..getJa6Priority-.< if-KK#a6" Q Threa!.J09bP5$G5$T;. #a6" ? Threa!.J09bP5$G5$T;<
;13
sN'O.getThrea!arou"-..setJa6Priority-#a6".< sho:Ja6Priority-.< A A class Do:nJa6L i#"le#ents 0ctionListener @ "ublic voi! actionPerfor#e!-0ctionEvent e. @ int #a6" ? sN'O.getThrea!arou"-..getJa6Priority-.< if---#a6" P Threa!.J$&bP5$G5$T;. #a6" ? Threa!.J$&bP5$G5$T;< sN'O.getThrea!arou"-..setJa6Priority-#a6".< sho:Ja6Priority-.< A A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: Counter,-., I,', +''.< A A ///3> TickerI "ollows the "or# established earlier in this cha%ter, but there s an e&tra JTe4tFiel' "or dis%laying the %riority o" the thread and two #ore buttons "or incre#enting and decre#enting the %riority. RFSURF STIJLT+(6PTE5M?TIMMHU
6lso notice the use o" yiel'A B, which voluntarily hands control back to the scheduler. :ithout this the #ultithreading #echanis# still works, but you ll notice it runs slowly *try re#oving the call to yiel'A B to see this,. /ou could also call sleepA B, but then the rate o" counting would be controlled by the sleepA B duration instead o" the %riority. RFSURF STIJLT+(6PTE5M?TIMM3U The initA B in -o*nter@ creates an array o" ten TickerIs; their buttons and "ields are %laced on the "or# by the TickerI constructor. -o*nter@ adds buttons to start everything u% as well as incre#ent and decre#ent the #a&i#u# %riority o" the thread grou%. In addition, there are labels that dis%lay the #a&i#u# and #ini#u# %riorities %ossible "or a thread and a JTe4tFiel' to show the thread grou% s #a&i#u# %riority. *The ne&t section will describe thread grou%s., Einally, the %riorities o" the %arent thread grou%s are also dis%layed as labels. RFSURF STIJLT+(6PTE5M?TIMMGU
;14
:hen you %ress an !u%$ or !down$ button, that TickerI s %riority is "etched and incre#ented or decre#ented accordingly. RFSURF STIJLT+(6PTE5M?TIMMIU :hen you run this %rogra#, you ll notice several things. Eirst o" all, the thread grou% s de"ault %riority is "ive. Even i" you decre#ent the #a&i#u# %riority below "ive be"ore starting the threads *or be"ore creating the threads, which reAuires a code change,, each thread will have a de"ault %riority o" "ive. RFSURFSTIJLT+(6PTE5M?TIMM2U The si#%le test is to take one counter and decre#ent its %riority to one, and observe that it counts #uch slower. But now try to incre#ent it again. /ou can get it back u% to the thread grou% s %riority, but no higher. Cow decre#ent the thread grou% s %riority a cou%le o" ti#es. The thread %riorities are unchanged, but i" you try to #odi"y the# either u% or down you ll see that they ll auto#atically %o% to the %riority o" the thread grou%. 6lso, new threads will still be given a de"ault %riority, even i" that s higher than the grou% %riority. *Thus the grou% %riority is not a way to %revent new threads "ro# having higher %riorities than e&isting ones., RFSURF STIJLT+(6PTE5M?TIMK@U Einally, try to incre#ent the grou% #a&i#u# %riority. It can t be done. /ou can only reduce thread grou% #a&i#u# %riorities, not increase the#. RFSURFSTIJLT+(6PTE5M?TIMKMU
#hread grou.s
6ll threads belong to a thread grou%. This can be either the de"ault thread grou% or a grou% you e&%licitly s%eci"y when you create the thread. 6t creation, the thread is bound to a grou% and cannot change to a di""erent grou%. Each a%%lication has at least one thread that belongs to the syste# thread grou%. I" you create #ore threads without s%eci"ying a grou%, they will also belong to the syste# thread grou%. RFSURF STIJLT+(6PTE5M?TIMKKU Thread grou%s #ust also belong to other thread grou%s. The thread grou% that a new one belongs to #ust be s%eci"ied in the constructor. I" you create a thread grou% without s%eci"ying a thread grou% "or it to belong to, it will be %laced under the syste# thread grou%. Thus, all thread
;15
grou%s in your a%%lication will ulti#ately have the syste# thread grou% as the %arent. RFSURFSTIJLT+(6PTE5M?TIMKLU The reason "or the e&istence o" thread grou%s is hard to deter#ine "ro# the literature, which tends to be con"using on this sub0ect. It s o"ten cited as !security reasons.$ 6ccording to 6rnold N 8osling, @ !Threads within a thread grou% can #odi"y the other threads in the grou%, including any "arther down the hierarchy. 6 thread cannot #odi"y threads outside o" its own grou% or contained grou%s.$ It s hard to know what !#odi"y$ is su%%osed to #ean here. The "ollowing e&a#%le shows a thread in a !lea"$ subgrou% #odi"ying the %riorities o" all the threads in its tree o" thread grou%s as well as calling a #ethod "or all the threads in its tree.
//3 c(I3Test0ccess.Hava // Mo: threa!s can access other threa!s // in a "arent threa! grou". "ublic class Test0ccess @ "ublic static voi! #ain-%tringNO args. @ Threa!arou" 6 ? ne: Threa!arou"-868., y ? ne: Threa!arou"-6, 8y8., U ? ne: Threa!arou"-y, 8U8.< Threa! one ? ne: TestThrea!(-6, 8one8., t:o ? ne: TestThrea! -U, 8t:o8.< A A class TestThrea!( e6ten!s Threa! @ "rivate int i< TestThrea!(-Threa!arou" g, %tring na#e. @ su"er-g, na#e.< A voi! f-. @ iKK< // #o!ify this threa! %yste#.out."rintln-get&a#e-. K 8 f-.8.< A
@ The Java Programming (anguage, by >en 6rnold and Ja#es 8osling, 6ddison':esley M223 %% MG2.
;17
A class TestThrea! e6ten!s TestThrea!( @ TestThrea! -Threa!arou" g, %tring na#e. @ su"er-g, na#e.< start-.< A "ublic voi! run-. @ Threa!arou" g ? getThrea!arou"-..getParent-..getParent-.< g.list-.< Threa!NO g0ll ? ne: Threa!Ng.activeCount-.O< g.enu#erate-g0ll.< for-int i ? '< i P g0ll.length< iKK. @ if-g0llNiO 4? null. @ g0llNiO.setPriority-Threa!.J$&bP5$G5$T;.< --TestThrea!(.g0llNiO..f-.< A g.list-.< A A ///3>
In mainA B, several Threa'"ro*ps are created, lea"ing o"" "ro# each other= 4 has no argu#ent but its na#e *a )tring,, so it is auto#atically %laced in the !syste#$ thread grou%, while y is under 4 and 7 is under y. Cote that initiali1ation ha%%ens in te&tual order so this code is legal. RF SURFSTIJLT+(6PTE5M?TIMK?U Two threads are created and %laced in di""erent thread grou%s. TestThrea'> doesn t have a r*nA B #ethod but it does have an fA B that #odi"ies the thread and %rints so#ething so you can see it was called. TestThrea'I is a subclass o" TestThrea'> and its r*nA B is "airly elaborate. It "irst gets the thread grou% o" the current thread, then #oves u% the heritage tree by two levels using get#arentA B. *This is contrived since I %ur%osely %lace the TestThrea'I ob0ect two levels down in the hierarchy., 6t this %oint, an array o" re"erences to Threa's is created using the #ethod active-o*ntA B to ask how #any threads are in this thread grou% and all the child thread grou%s. The en*merateA B #ethod %laces re"erences to all o" these threads in the array gAll, then I si#%ly #ove through the entire array calling the fA B #ethod "or each thread, as
;18
well as #odi"ying the %riority. Thus, a thread in a !lea"$ thread grou% #odi"ies threads in %arent thread grou%s. Cote that since the "irst edition
o" this book a%%eared, the behavior o" en*merateA B a%%ears to have changed, and it will now so#eti#es %lace n*ll entries into the array, so you #ust guard against these in your code.RFSURF
STIJLT+(6PTE5M?TIMKHU The debugging #ethod listA B %rints all the in"or#ation about a thread grou% to standard out%ut and is hel%"ul when investigating thread grou% behavior. (ere s the out%ut o" the %rogra#=
Hava.lang.Threa!arou"Nna#e?6,#a6"ri?('O Threa!None,,,6O Hava.lang.Threa!arou"Nna#e?y,#a6"ri?('O Hava.lang.Threa!arou"Nna#e?U,#a6"ri?('O Threa!Nt:o,,,UO t:o f-. Hava.lang.Threa!arou"Nna#e?6,#a6"ri?('O Threa!None,,,6O Hava.lang.Threa!arou"Nna#e?y,#a6"ri?('O Hava.lang.Threa!arou"Nna#e?U,#a6"ri?('O Threa!Nt:o,(,UOHava.lang.Threa!arou" Nna#e?6,#a6"ri?('O Threa!None,,,6O Hava.lang.Threa!arou"Nna#e?y,#a6"ri?('O Hava.lang.Threa!arou"Nna#e?U,#a6"ri?('O Threa!Nt:o,,,UO one f-. t:o f-. Hava.lang.Threa!arou"Nna#e?6,#a6"ri?('O Threa!None,(,6O Hava.lang.Threa!arou"Nna#e?y,#a6"ri?('O Hava.lang.Threa!arou"Nna#e?U,#a6"ri?('O Threa!Nt:o,(,UO
Cot only does listA B %rint the class na#e o" Threa'"ro*p or Threa', but it also %rints the thread grou% na#e and its #a&i#u# %riority. Eor threads, the thread na#e is %rinted, "ollowed by the thread %riority and the grou% that it belongs to. Cote that listA B indents the threads and thread grou%s to indicate that they are children o" the unindented thread grou%. RFSURFSTIJLT+(6PTE5M?TIMK3U
;1:
/ou can see that fA B is called by the TestThrea'I r*nA B #ethod, so it s obvious that all threads in a grou% are vulnerable. (owever, you can access only the threads that branch o"" "ro# your own system thread grou% tree, and %erha%s this is what is #eant by !sa"ety.$ /ou cannot access anyone else s syste# thread grou% tree. RFSURF STIJLT+(6PTE5M?TIMKGU
//3 c(I3Threa!arou"(.Hava // Mo: threa! grou"s control "riorities // of the threa!s insi!e the#. "ublic class Threa!arou"( @ "ublic static voi! #ain-%tringNO args. @ // aet the syste# threa! D "rint its $nfo3 Threa!arou" sys ? Threa!.currentThrea!-..getThrea!arou"-.< sys.list-.< // -(. // 5e!uce the syste# threa! grou" "riority3 sys.setJa6Priority-Threa!.J09bP5$G5$T; - (.< // $ncrease the #ain threa! "riority3 Threa! curr ? Threa!.currentThrea!-.< curr.setPriority-curr.getPriority-. K (.< sys.list-.< // - . // 0tte#"t to set a ne: grou" to the #a63 Threa!arou" g( ? ne: Threa!arou"-8g(8.< g(.setJa6Priority-Threa!.J09bP5$G5$T;.< // 0tte#"t to set a ne: threa! to the #a63 Threa! t ? ne: Threa!-g(, 808.< t.setPriority-Threa!.J09bP5$G5$T;.< g(.list-.< // -). // 5e!uce g(2s #a6 "riority, then atte#"t // to increase it3 g(.setJa6Priority-Threa!.J09bP5$G5$T; - .<
;1;
g(.setJa6Priority-Threa!.J09bP5$G5$T;.< g(.list-.< // -I. // 0tte#"t to set a ne: threa! to the #a63 t ? ne: Threa!-g(, 8B8.< t.setPriority-Threa!.J09bP5$G5$T;.< g(.list-.< // -,. // Lo:er the #a6 "riority belo: the !efault // threa! "riority3 g(.setJa6Priority-Threa!.J$&bP5$G5$T; K .< // Look at a ne: threa!2s "riority before // an! after changing it3 t ? ne: Threa!-g(, 8C8.< g(.list-.< // -+. t.setPriority-t.getPriority-. -(.< g(.list-.< // -*. // Jake g a chil! Threa!grou" of g( an! // try to increase its "riority3 Threa!arou" g ? ne: Threa!arou"-g(, 8g 8.< g .list-.< // -1. g .setJa6Priority-Threa!.J09bP5$G5$T;.< g .list-.< // -C. // 0!! a bunch of ne: threa!s to g 3 for -int i ? '< i P ,< iKK. ne: Threa!-g , $nteger.to%tring-i..< // %ho: infor#ation about all threa!grou"s // an! threa!s3 sys.list-.< // -('. %yste#.out."rintln-8%tarting all threa!s38.< Threa!NO all ? ne: Threa!Nsys.activeCount-.O< sys.enu#erate-all.< for-int i ? '< i P all.length< iKK. if-allNiO 4? null DD 4allNiO.is0live-.. allNiO.start-.< // %us"en!s D %to"s all threa!s in // this grou" an! its subgrou"s3 %yste#.out."rintln-80ll threa!s starte!8.< sys.sus"en!-.< // De"recate! in Java // &ever gets here... %yste#.out."rintln-80ll threa!s sus"en!e!8.< sys.sto"-.< // De"recate! in Java %yste#.out."rintln-80ll threa!s sto""e!8.<
;2=
A A ///3>
The out%ut that "ollows has been edited to allow it to "it on the %age *the
-(. Threa!arou"Nna#e?syste#,#a6"ri?('O Threa!N#ain,,,syste#O - . Threa!arou"Nna#e?syste#,#a6"ri?CO Threa!N#ain,+,syste#O -). Threa!arou"Nna#e?g(,#a6"ri?CO Threa!N0,C,g(O -I. Threa!arou"Nna#e?g(,#a6"ri?1O Threa!N0,C,g(O -,. Threa!arou"Nna#e?g(,#a6"ri?1O Threa!N0,C,g(O Threa!NB,1,g(O -+. Threa!arou"Nna#e?g(,#a6"ri?)O Threa!N0,C,g(O Threa!NB,1,g(O Threa!NC,+,g(O -*. Threa!arou"Nna#e?g(,#a6"ri?)O Threa!N0,C,g(O Threa!NB,1,g(O Threa!NC,),g(O -1. Threa!arou"Nna#e?g ,#a6"ri?)O -C. Threa!arou"Nna#e?g ,#a6"ri?)O -('.Threa!arou"Nna#e?syste#,#a6"ri?CO Threa!N#ain,+,syste#O Threa!arou"Nna#e?g(,#a6"ri?)O Threa!N0,C,g(O Threa!NB,1,g(O Threa!NC,),g(O Threa!arou"Nna#e?g ,#a6"ri?)O Threa!N',+,g O Threa!N(,+,g O Threa!N ,+,g O Threa!N),+,g O Threa!NI,+,g O
;21
mainA B is to call the static #ethod o" Threa' called c*rrentThrea' A B. Ero# this thread, the thread grou% is %roduced and listA B is called
"or the result. The out%ut is=
- . Threa!arou"Nna#e?syste#,#a6"ri?CO Threa!N#ain,+,syste#O
The third e&ercise creates a new thread grou%, g>, which auto#atically belongs to the system thread grou% since it isn t otherwise s%eci"ied. 6 new thread A is %laced in g>. 6"ter atte#%ting to set this grou% s #a&i#u# %riority to the highest level and A s %riority to the highest level, the result is=
;22
thread grou% s #a&i#u# %riority. +hanging a thread grou% s #a&i#u# %riority doesn t a""ect e&isting threads. RFSURF STIJLT+(6PTE5M?TIMLMU The "i"th e&ercise atte#%ts to set a new thread to #a&i#u# %riority=
;23
6 si#ilar e&%eri#ent is %er"or#ed in *I, and *2,, in which a new thread grou% gI is created as a child o" g> and its #a&i#u# %riority is changed. /ou can see that it s i#%ossible "or gI s #a&i#u# to go higher than g> s=
-('.Threa!arou"Nna#e?syste#,#a6"ri?CO Threa!N#ain,+,syste#O Threa!arou"Nna#e?g(,#a6"ri?)O Threa!N0,C,g(O Threa!NB,1,g(O Threa!NC,),g(O Threa!arou"Nna#e?g ,#a6"ri?)O Threa!N',+,g O Threa!N(,+,g O Threa!N ,+,g O Threa!N),+,g O Threa!NI,+,g O
So because o" the rules o" thread grou%s, a child grou% #ust always have a #a&i#u# %riority that s less than or eAual to its %arent s #a&i#u# %riority. RFSURFSTIJLT+(6PTE5M?TIML3U The last %art o" this %rogra# de#onstrates #ethods "or an entire grou% o" threads. Eirst the %rogra# #oves through the entire tree o" threads and starts each one that hasn t been started. Eor dra#a, the system grou% is then sus%ended and "inally sto%%ed. *6lthough it s interesting to see that s*spen'A B and stopA B work on entire thread grou%s, you should kee% in #ind that these #ethods are de%recated in Java K., But when you sus%end the system grou% you also sus%end the main thread and the whole %rogra# shuts down, so it never gets to the %oint where the threads are sto%%ed. 6ctually, i" you do sto% the main thread it throws a Threa' eath e&ce%tion, so this is not a ty%ical thing to do. Since Threa'"ro*p is inherited "ro# .b8ect, which contains the (aitA B
;24
#ethod, you can also choose to sus%end the %rogra# "or any nu#ber o" seconds by calling (aitAsecon's K >DDDB. This #ust acAuire the lock inside a synchroni1ed block, o" course. RFSURF STIJLT+(6PTE5M?TIMLGU The Threa'"ro*p class also has s*spen'A B and res*meA B #ethods so you can sto% and start an entire thread grou% and all o" its threads and subgrou%s with a single co##and. *6gain, s*spen'A B and res*meA B are de%recated in Java K., RFSURFSTIJLT+(6PTE5M?TIMLIU Thread grou%s can see# a bit #ysterious at "irst, but kee% in #ind that you %robably won t be using the# directly very o"ten. RFSURF STIJLT+(6PTE5M?TIML2U
5unnable revisited
Earlier in this cha%ter, I suggested that you think care"ully be"ore #aking an a%%let or #ain Frame as an i#%le#entation o" $*nnable. )" course, i" you #ust inherit "ro# a class and you want to add threading behavior to the class, $*nnable is the correct solution. The "inal e&a#%le in this cha%ter e&%loits this by #aking a $*nnable J#anel class that %aints di""erent colors on itsel". This a%%lication is set u% to take values "ro# the co##and line to deter#ine how big the grid o" colors is and how long to sleepA B between color changes. By %laying with these values you ll discover so#e interesting and %ossibly ine&%licable "eatures o" threads=
//3 c(I3ColorBo6es.Hava // Ysing the 5unnable interface. // Pa""let co!e?ColorBo6es :i!th?,'' height?I''Q // P"ara# na#e?gri! value?8( 8Q // P"ara# na#e?"ause value?8,'8Q // P/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.B< i#"ort Hava.a:t.event.B< i#"ort co#.bruceeckel.s:ing.B< class CBo6 e6ten!s JPanel i#"le#ents 5unnable @ "rivate Threa! t<
;25
"rivate int "ause< "rivate static final ColorNO colors ? @ Color.black, Color.blue, Color.cyan, Color.!arkaray, Color.gray, Color.green, Color.lightaray, Color.#agenta, Color.orange, Color."ink, Color.re!, Color.:hite, Color.yello: A< "rivate Color cColor ? ne:Color-.< "rivate static final Color ne:Color-. @ return colorsN -int.-Jath.ran!o#-. B colors.length. O< A "ublic voi! "aintCo#"onent-ara"hics g. @ su"er."aintCo#"onent-g.< g.setColor-cColor.< Di#ension s ? get%iUe-.< g.fill5ect-', ', s.:i!th, s.height.< A "ublic CBo6-int "ause. @ this."ause ? "ause< t ? ne: Threa!-this.< t.start-.< A "ublic voi! run-. @ :hile-true. @ cColor ? ne:Color-.< re"aint-.< try @ t.slee"-"ause.< A catch-$nterru"te!E6ce"tion e. @ %yste#.err."rintln-8$nterru"te!8.< A A A A "ublic class ColorBo6es e6ten!s J0""let @ "rivate boolean is0""let ? true< "rivate int gri! ? ( <
;27
"rivate int "ause ? ,'< "ublic voi! init-. @ // aet "ara#eters fro# \eb "age3 if -is0""let. @ %tring gsiUe ? getPara#eter-8gri!8.< if-gsiUe 4? null. gri! ? $nteger."arse$nt-gsiUe.< %tring "se ? getPara#eter-8"ause8.< if-"se 4? null. "ause ? $nteger."arse$nt-"se.< A Container c" ? getContentPane-.< c".setLayout-ne: ari!Layout-gri!, gri!..< for -int i ? '< i P gri! B gri!< iKK. c".a!!-ne: CBo6-"ause..< A "ublic static voi! #ain-%tringNO args. @ ColorBo6es a""let ? ne: ColorBo6es-.< a""let.is0""let ? false< if-args.length Q '. a""let.gri! ? $nteger."arse$nt-argsN'O.< if-args.length Q (. a""let."ause ? $nteger."arse$nt-argsN(O.< Console.run-a""let, ,'', I''.< A A ///3> -olor2o4es is the usual a%%letFa%%lication with an initA B that sets u% the 84I. This sets u% the "ri'+ayo*t so that it has gri' cells in each di#ension. Then it adds the a%%ro%riate nu#ber o" -2o4 ob0ects to "ill the grid, %assing the pa*se value to each one. In mainA B you can see how pa*se and gri' have de"ault values that can be changed i" you %ass in co##and'line argu#ents, or by using a%%let %ara#eters. RFSURF STIJLT+(6PTE5M?TIM?@U -2o4 is where all the work takes %lace. This is inherited "ro# J#anel and it i#%le#ents the $*nnable inter"ace so each J#anel can also be a Threa'. 5e#e#ber that when you i#%le#ent $*nnable, you don t #ake a Threa' ob0ect, 0ust a class that has a r*nA B #ethod. Thus, you #ust e&%licitly create a Threa' ob0ect and hand the $*nnable ob0ect to
;28
the constructor, then call startA B *this ha%%ens in the constructor,. In -2o4 this thread is called t. RFSURFSTIJLT+(6PTE5M?TIM?MU Cotice the array colors, which is an enu#eration o" all the colors in class -olor. This is used in ne(-olorA B to %roduce a rando#ly selected color. The current cell color is c-olor. RFSURF STIJLT+(6PTE5M?TIM?KU
paint-omponentA B is Auite si#%le9it 0ust sets the color to c-olor and "ills the entire J#anel with that color. RFSURF
STIJLT+(6PTE5M?TIM?LU In r*nA B, you see the in"inite loo% that sets the c-olor to a new rando# color and then calls repaintA B to show it. Then the thread goes to sleep A B "or the a#ount o" ti#e s%eci"ied on the co##and line. RFSURF STIJLT+(6PTE5M?TIM??U Precisely because this design is "le&ible and threading is tied to each J#anel ele#ent, you can e&%eri#ent by #aking as #any threads as you want. *In reality, there is a restriction i#%osed by the nu#ber o" threads your JVM can co#"ortably handle., RFSURFSTIJLT+(6PTE5M?TIM?HU This %rogra# also #akes an interesting bench#ark, since it can show dra#atic %er"or#ance di""erences between one JVM threading i#%le#entation and another. RFSURFSTIJLT+(6PTE5M?TIM?3U
;2:
//3 c(I3ColorBo6es .Hava // Balancing threa! use. // Pa""let co!e?ColorBo6es :i!th?+'' height?,''Q // P"ara# na#e?gri! value?8( 8Q // P"ara# na#e?"ause value?8,'8Q // P/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.B< i#"ort Hava.a:t.event.B< i#"ort Hava.util.B< i#"ort co#.bruceeckel.s:ing.B< class CBo6 e6ten!s JPanel @ "rivate static final ColorNO colors ? @ Color.black, Color.blue, Color.cyan, Color.!arkaray, Color.gray, Color.green, Color.lightaray, Color.#agenta, Color.orange, Color."ink, Color.re!, Color.:hite, Color.yello: A< "rivate Color cColor ? ne:Color-.< "rivate static final Color ne:Color-. @ return colorsN -int.-Jath.ran!o#-. B colors.length. O< A voi! ne6tColor-. @ cColor ? ne:Color-.< re"aint-.< A "ublic voi! "aintCo#"onent-ara"hics g. @ su"er."aintCo#"onent-g.< g.setColor-cColor.< Di#ension s ? get%iUe-.< g.fill5ect-', ', s.:i!th, s.height.< A A class CBo6List e6ten!s 0rrayList i#"le#ents 5unnable @ "rivate Threa! t<
;2;
"rivate int "ause< "ublic CBo6List-int "ause. @ this."ause ? "ause< t ? ne: Threa!-this.< A "ublic voi! go-. @ t.start-.< A "ublic voi! run-. @ :hile-true. @ int i ? -int.-Jath.ran!o#-. B siUe-..< --CBo6 .get-i...ne6tColor-.< try @ t.slee"-"ause.< A catch-$nterru"te!E6ce"tion e. @ %yste#.err."rintln-8$nterru"te!8.< A A A "ublic GbHect last-. @ return get-siUe-. - (.<A A "ublic class ColorBo6es e6ten!s J0""let @ "rivate boolean is0""let ? true< "rivate int gri! ? ( < // %horter !efault "ause than ColorBo6es3 "rivate int "ause ? ,'< "rivate CBo6ListNO v< "ublic voi! init-. @ // aet "ara#eters fro# \eb "age3 if -is0""let. @ %tring gsiUe ? getPara#eter-8gri!8.< if-gsiUe 4? null. gri! ? $nteger."arse$nt-gsiUe.< %tring "se ? getPara#eter-8"ause8.< if-"se 4? null. "ause ? $nteger."arse$nt-"se.< A Container c" ? getContentPane-.< c".setLayout-ne: ari!Layout-gri!, gri!..< v ? ne: CBo6ListNgri!O< for-int i ? '< i P gri!< iKK. vNiO ? ne: CBo6List-"ause.<
;3=
for -int i ? '< i P gri! B gri!< iKK. @ vNi V gri!O.a!!-ne: CBo6 -..< c".a!!--CBo6 .vNi V gri!O.last-..< A for-int i ? '< i P gri!< iKK. vNiO.go-.< A "ublic static voi! #ain-%tringNO args. @ ColorBo6es a""let ? ne: ColorBo6es -.< a""let.is0""let ? false< if-args.length Q '. a""let.gri! ? $nteger."arse$nt-argsN'O.< if-args.length Q (. a""let."ause ? $nteger."arse$nt-argsN(O.< Console.run-a""let, ,'', I''.< A A ///3>
In -olor2o4esI an array o" -2o4+ist is created and initiali1ed to hold gri' -2o4+ists, each o" which knows how long to slee%. 6n eAual nu#ber o" -2o4I ob0ects is then added to each -2o4+ist, and each list is told to goA B, which starts its thread. RFSURF STIJLT+(6PTE5M?TIM?GU
-2o4I is si#ilar to -2o4= it %aints itsel" with a rando#ly chosen color. But that s all a -2o4I does. 6ll o" the threading has been #oved into -2o4+ist. RFSURFSTIJLT+(6PTE5M?TIM?IU
The -2o4+ist could also have inherited Threa' and had a #e#ber ob0ect o" ty%e Array+ist. That design has the advantage that the a''A B and getA B #ethods could then be given s%eci"ic argu#ent and return value ty%es instead o" generic .b8ects. *Their na#es could also be changed to so#ething shorter., (owever, the design used here see#ed at "irst glance to reAuire less code. In addition, it auto#atically retains all the other behaviors o" an Array+ist. :ith all the casting and %arentheses necessary "or getA B, this #ight not be the case as your body o" code grows. RFSURFSTIJLT+(6PTE5M?TIM?2U 6s be"ore, when you i#%le#ent $*nnable you don t get all o" the eAui%#ent that co#es with Threa', so you have to create a new Threa' and hand yoursel" to its constructor in order to have so#ething to start
;31
A B, as you can see in the -2o4+ist constructor and in goA B. The r*nA B
#ethod si#%ly chooses a rando# ele#ent nu#ber within the list and calls ne4t-olorA B "or that ele#ent to cause it to choose a new rando#ly selected color. RFSURFSTIJLT+(6PTE5M?TIMH@U 4%on running this %rogra#, you see that it does indeed run "aster and res%ond #ore Auickly *"or instance, when you interru%t it, it sto%s #ore Auickly,, and it doesn t see# to bog down as #uch at higher grid si1es. Thus, a new "actor is added into the threading eAuation= you #ust watch to see that you don t have !too #any threads$ *whatever that turns out to #ean "or your %articular %rogra# and %lat"or#9here, the slowdown in -olor2o4es a%%ears to be caused by the "act that there s only one thread that is res%onsible "or all %ainting, and it gets bogged down by too #any reAuests,. I" you have too #any threads, you #ust try to use techniAues like the one above to !balance$ the nu#ber o" threads in your %rogra#. I" you see %er"or#ance %roble#s in a #ultithreaded %rogra# you now have a nu#ber o" issues to e&a#ine= RFSURFSTIJLT+(6PTE5M?TIMHMU
(,*) 7o you have enough calls to sleepA B, yiel'A B, andFor (aitA BO (,+) 6re calls to sleepA B long enoughO (,,) 6re you running too #any threadsO (,-) (ave you tried di""erent %lat"or#s and JVMsO
Issues like this are one reason that #ultithreaded %rogra##ing is o"ten considered an art. RFSURFSTIJLT+(6PTE5M?TIMHKU
1ummar:
It is vital to learn when to use #ultithreading and when to avoid it. The #ain reason to use it is to #anage a nu#ber o" tasks whose inter#ingling will #ake #ore e""icient use o" the co#%uter *including the ability to trans%arently distribute the tasks across #ulti%le +P4s, or be #ore convenient "or the user. The classic e&a#%le o" resource balancing is using the +P4 during IF) waits. The classic e&a#%le o" user convenience is #onitoring a !sto%$ button during long downloads. RFSURF STIJLT+(6PTE5M?TIMHLU
;32
(,4) Slowdown while waiting "or shared resources (,5) 6dditional +P4 overhead reAuired to #anage threads (,6) 4nrewarded co#%le&ity, such as the silly idea o" having a se%arate
thread to u%date each ele#ent o" an array
;33
%roble#9at least in theory. *+reating #illions o" ob0ects "or an engineering "inite'ele#ent analysis, "or e&a#%le, #ight not be %ractical in Java., (owever, it see#s that there is an u%%er bound to the nu#ber o" threads you ll want to create, because at so#e %oint a large nu#ber o" threads see#s to beco#e unwieldy. This critical %oint is not in the #any thousands as it #ight be with ob0ects, but rather in the low hundreds, so#eti#es less than M@@. 6s you o"ten create only a hand"ul o" threads to solve a %roble#, this is ty%ically not #uch o" a li#it, yet in a #ore general design it beco#es a constraint. RFSURFSTIJLT+(6PTE5M?TIMHGU 6 signi"icant nonintuitive issue in threading is that, because o" thread scheduling, you can ty%ically #ake your a%%lications run $aster by inserting calls to sleepA B inside r*nA B s #ain loo%. This de"initely #akes it "eel like an art, in %articular when the longer delays see# to s%eed u% %er"or#ance. )" course, the reason this ha%%ens is that shorter delays can cause the end'o"' sleepA B scheduler interru%t to ha%%en be"ore the running thread is ready to go to slee%, "orcing the scheduler to sto% it and restart it later so it can "inish what it was doing and then go to slee%. It takes e&tra thought to reali1e how #essy things can get. RFSURF STIJLT+(6PTE5M?TIMHIU )ne thing you #ight notice #issing in this cha%ter is an ani#ation e&a#%le, which is one o" the #ost %o%ular things to do with a%%lets. (owever, a co#%lete solution *with sound, to this %roble# co#es with the Java J7> *available at >ava'sun'com, in the de#o section. In addition, we can e&%ect better ani#ation su%%ort to beco#e %art o" "uture versions o" Java, while co#%letely di""erent non'Java, non'%rogra##ing solutions to ani#ation "or the :eb are a%%earing that will %robably be su%erior to traditional a%%roaches. Eor e&%lanations about how Java ani#ation works, see Core Java 2 by (orst#ann N +ornell, Prentice' (all, M22G. Eor #ore advanced discussions o" threading, see Concurrent Programming in Java by 7oug Dea, 6ddison':esley, M22G, or Java Threads by )aks N :ong, ) 5eilly, M22G. RFSURF STIJLT+(6PTE5M?TIMH2U
/0ercises
Solutions to selected e&ercises can be "ound in the electronic docu#entThe Thinking in Java "nnotated Solution @uide, available "or a s#all "ee "ro# ,,,'0ruceEckel'com.
;34
!+4) Inherit a class "ro# Threa' and override the r*nA B #ethod.
Inside r*nA B, %rint a #essage, and then call sleepA B. 5e%eat this three ti#es, then return "ro# r*nA B. Put a start'u% #essage in the constructor and override finali7eA B to %rint a shut'down #essage. Make a se%arate thread class that calls )ystem!gcA B and )ystem!r*nFinali7ationA B inside r*nA B, %rinting a #essage as it does so. Make several thread ob0ects o" both ty%es and run the# to see what ha%%ens. RFSURF STIJLT+(6PTE5M?TIM3@U
!+6) +reate two Threa' subclasses, one with a r*nA B that starts
u% , ca%tures the re"erence o" the second Threa' ob0ect and then calls (aitA B. The other class r*nA B should ca%ture the re"erence o" the "irst Threa' ob0ect. Its r*nA B should call notifyAllA B "or the "irst thread a"ter so#e nu#ber o" seconds have %assed, so the "irst thread can %rint a #essage. RFSURF STIJLT+(6PTE5M?TIM3KU
!,!) +hange
aemons!8ava so that mainA B has a sleepA B instead o" a rea'+ineA B. E&%eri#ent with di""erent slee% ti#es to see
what ha%%ens. RFSURFSTIJLT+(6PTE5M?TIM3HU
;35
and change the rest o" the design so that it works with this new Threa''based &vent. RFSURFSTIJLT+(6PTE5M?TIM33U
!,-) Modi"y E&ercise 2 so that #ulti%le sine wave %anels are created
within the a%%lication. The nu#ber o" sine wave %anels should be controlled by (TMD tags or co##and'line %ara#eters. RFSURF STIJLT+(6PTE5M?TIM32U
;37
8et so#e in"or#ation "ro# that #achine over there and #ove it
to this #achine here, or vice versa. This is acco#%lished with basic network %rogra##ing. RFSURFSTIJLT+(6PTE5MHTIKU
+onnect to a database, which #ay live across a network. This is acco#%lished with Java %ata0ase Connectivit) *J7B+,, which is
an abstraction away "ro# the #essy, %lat"or#'s%eci"ic details o" SeD *the structured #uer) language used "or #ost database transactions,. RFSURFSTIJLT+(6PTE5MHTILU
Provide services via a :eb server. This is acco#%lished with Java s servlets and Java Server Pages *JSPs,. RFSURF
STIJLT+(6PTE5MHTI?U
;38
4se code written in other languages, running on other architectures. This is acco#%lished using the Common Ob>ect -e#uest 0roker "rchitecture *+)5B6,, which is directly
su%%orted by Java. RFSURFSTIJLT+(6PTE5MHTI3U
2etwork .rogramming
)ne o" Java s great strengths is %ainless networking. The Java network library designers have #ade it Auite si#ilar to reading and writing "iles, e&ce%t that the !"ile$ e&ists on a re#ote #achine and the re#ote #achine can decide e&actly what it wants to do about the in"or#ation you re reAuesting or sending. 6s #uch as %ossible, the underlying details o" networking have been abstracted away and taken care o" within the JVM and local #achine installation o" Java. The %rogra##ing #odel you use is that o" a "ile; in "act, you actually wra% the network connection *a !socket$, with strea# ob0ects, so you end u% using the sa#e #ethod calls as you do with all other strea#s. In addition, Java s built'in #ultithreading is e&ce%tionally handy when dealing with another
;3:
Thinking in Java
,,,'0ruceEckel'com
networking issue= handling #ulti%le connections at once. RFSURF STIJLT+(6PTE5MHTIM@U This section introduces Java s networking su%%ort using easy'to' understand e&a#%les. RFSURFSTIJLT+(6PTE5MHTIMMU
Identif:ing a machine
)" course, in order to tell one #achine "ro# another and to #ake sure that you are connected with a %articular #achine, there #ust be so#e way o" uniAuely identi"ying #achines on a network. Early networks were satis"ied to %rovide uniAue na#es "or #achines within the local network. (owever, Java works within the Internet, which reAuires a way to uniAuely identi"y a #achine "ro# all the others in the ,orld. This is acco#%lished with the IP *Internet Protocol, address which can e&ist in two "or#s!= RFSURFSTIJLT+(6PTE5MHTIMKU
(-() The "a#iliar 7CS * %omain +ame S)stem, "or#. My do#ain na#e is br*ceeckel!com, and i" I have a co#%uter called .p*s in #y do#ain, its do#ain na#e would be .p*s!br*ceeckel!com. This
is e&actly the kind o" na#e that you use when you send e#ail to %eo%le, and is o"ten incor%orated into a :orld :ide :eb address.
(-!) 6lternatively, you can use the dotted Auad$ "or#, which is "our nu#bers se%arated by dots, such as >IJ!I@@!IY!>ID.
In both cases, the IP address is re%resented internally as a LK'bit nu#ber @ *so each o" the Auad nu#bers cannot e&ceed KHH,, and you can get a s%ecial Java ob0ect to re%resent this nu#ber "ro# either o" the "or#s above by using the static InetA''ress!get2y/ameA B #ethod that s in 8ava!net. The result is an ob0ect o" ty%e InetA''ress that you can use to build a !socket,$ as you will see later. RFSURFSTIJLT+(6PTE5MHTIMLU 6s a si#%le e&a#%le o" using InetA''ress!get2y/ameA B, consider what ha%%ens i" you have a dial'u% Internet service %rovider *ISP,. Each ti#e you dial u%, you are assigned a te#%orary IP address. But while you re connected, your IP address has the sa#e validity as any other IP
@ This #eans a #a&i#u# o" 0ust over "our billion nu#bers, which is ra%idly running out. The new standard "or IP addresses will use a MKI'bit nu#ber, which should %roduce enough uniAue IP addresses "or the "oreseeable "uture.
;3;
address on the Internet. I" so#eone connects to your #achine using your IP address then they can connect to a :eb server or ETP server that you have running on your #achine. )" course, they need to know your IP address, and since a new one is assigned each ti#e you dial u%, how can you "ind out what it isO RFSURFSTIJLT+(6PTE5MHTIM?U The "ollowing %rogra# uses InetA''ress!get2y/ameA B to %roduce your IP address. To use it, you #ust know the na#e o" your co#%uter. )n :indows 2HF2I, go to !Settings,$ !+ontrol Panel,$ !Cetwork,$ and then select the !Identi"ication$ tab. !+o#%uter na#e$ is the na#e to %ut on the co##and line.
//3 c(,3\ho0#$.Hava // Lin!s out your net:ork a!!ress :hen // you2re connecte! to the $nternet. i#"ort Hava.net.B< "ublic class \ho0#$ @ "ublic static voi! #ain-%tringNO args. thro:s E6ce"tion @ if-args.length 4? (. @ %yste#.err."rintln8Ysage3 \ho0#$ Jachine&a#e8.< %yste#.e6it-(.< A $net0!!ress a ? $net0!!ress.getBy&a#e-argsN'O.< %yste#.out."rintln-a.< A A ///3>
In this case, the #achine is called !%e%%y.$ So, once I ve connected to #y ISP I run the %rogra#=
"e""y/(CC.(C'.1*.*,
;4=
Thinking in Java
,,,'0ruceEckel'com
I" I tell #y "riend this address and I have a :eb server running on #y co#%uter, he can connect to it by going to the 45D htt !//1;;'1;=':8'85 *only as long as I continue to stay connected during that session,. This can so#eti#es be a handy way to distribute in"or#ation to so#eone else, or to test out a :eb site con"iguration be"ore %osting it to a !real$ server. RFSURFSTIJLT+(6PTE5MHTIMHU
;41
Internet Protocol were aware o" this issue, and they created a s%ecial address called localhost to be the !local loo%back$ IP address "or testing without a network. The generic way to %roduce this address in Java is=
$net0!!ress.getBy&a#e-8localhost8.<
*assu#ing !localhost$ is con"igured in your #achine s !hosts$ table,, or by using its dotted Auad "or# to na#e the reserved IP nu#ber "or the loo%back=
$net0!!ress.getBy&a#e-8( *.'.'.(8.<
6ll three "or#s %roduce the sa#e result. RFSURF STIJLT+(6PTE5MHTIK@U
;42
Thinking in Java
,,,'0ruceEckel'com
knows how to connect to the #achine via its IP address, but how does it connect to a desired service *%otentially one o" #any on that #achine,O That s where the %ort nu#bers co#e in as a second level o" addressing. The idea is that i" you ask "or a %articular %ort, you re reAuesting the service that s associated with the %ort nu#ber. The ti#e o" day is a si#%le e&a#%le o" a service. Ty%ically, each service is associated with a uniAue %ort nu#ber on a given server #achine. It s u% to the client to know ahead o" ti#e which %ort nu#ber the desired service is running on. RF SURFSTIJLT+(6PTE5MHTIKKU The syste# services reserve the use o" %orts M through M@K?, so you shouldn t use those or any other %ort that you know to be in use. The "irst choice "or e&a#%les in this book will be %ort I@I@ *in #e#ory o" the venerable old I'bit Intel I@I@ chi% in #y "irst co#%uter, a +PFM #achine,. RFSURFSTIJLT+(6PTE5MHTIKLU
1ockets
The socket is the so"tware abstraction used to re%resent the !ter#inals$ o" a connection between two #achines. Eor a given connection, there s a socket on each #achine, and you can i#agine a hy%othetical !cable$ running between the two #achines with each end o" the !cable$ %lugged into a socket. )" course, the %hysical hardware and cabling between #achines is co#%letely unknown. The whole %oint o" the abstraction is that we don t have to know #ore than is necessary. RFSURF STIJLT+(6PTE5MHTIK?U In Java, you create a socket to #ake the connection to the other #achine, then you get an Inp*t)tream and .*tp*t)tream *or, with the a%%ro%riate converters, $ea'er and 0riter, "ro# the socket in order to be able to treat the connection as an IF) strea# ob0ect. There are two strea#'based socket classes= a )erver)ocket that a server uses to !listen$ "or inco#ing connections and a )ocket that a client uses in order to initiate a connection. )nce a client #akes a socket connection, the )erver)ocket returns *via the acceptA B #ethod, a corres%onding )ocket through which co##unications will take %lace on the server side. Ero# then on, you have a true )ocket to )ocket connection and you treat both ends the sa#e way because they are the sa#e. 6t this %oint, you use the #ethods getInp*t)treamA B and get.*tp*t)treamA B to
;43
%roduce the corres%onding Inp*t)tream and .*tp*t)tream ob0ects "ro# each )ocket. These #ust be wra%%ed inside bu""ers and "or#atting classes 0ust like any other strea# ob0ect described in +ha%ter MM. RFSURF STIJLT+(6PTE5MHTIKHU The use o" the ter# )erver)ocket would see# to be another e&a#%le o" a con"using na#ing sche#e in the Java libraries. /ou #ight think )erver)ocket would be better na#ed !Server+onnector$ or so#ething without the word !Socket$ in it. /ou #ight also think that )erver)ocket and )ocket should both be inherited "ro# so#e co##on base class. Indeed, the two classes do have several #ethods in co##on, but not enough to give the# a co##on base class. Instead, )erver)ocket s 0ob is to wait until so#e other #achine connects to it, then to return an actual )ocket. This is why )erver)ocket see#s to be a bit #isna#ed, since its 0ob isn t really to be a socket but instead to #ake a )ocket ob0ect when so#eone else connects to it. RFSURFSTIJLT+(6PTE5MHTIK3U (owever, the )erver)ocket does create a %hysical !server$ or listening socket on the host #achine. This socket listens "or inco#ing connections and then returns an !established$ socket *with the local and re#ote end%oints de"ined, via the acceptA B #ethod. The con"using %art is that both o" these sockets *listening and established, are associated with the sa#e server socket. The listening socket can acce%t only new connection reAuests and not data %ackets. So while )erver)ocket doesn t #ake #uch sense %rogra##atically, it does !%hysically.$ RFSURF STIJLT+(6PTE5MHTIKGU :hen you create a )erver)ocket, you give it only a %ort nu#ber. /ou don t have to give it an IP address because it s already on the #achine it re%resents. :hen you create a )ocket, however, you #ust give both the IP address and the %ort nu#ber where you re trying to connect. *(owever, the )ocket that co#es back "ro# )erver)ocket!acceptA B already contains all this in"or#ation., RFSURFSTIJLT+(6PTE5MHTIKIU
;44
Thinking in Java
,,,'0ruceEckel'com
wra%%ed in a 2*ffere'$ea'er and a #rint0riter. 6"ter that, everything it reads "ro# the 2*ffere'$ea'er it echoes to the #rint0riter until it receives the line !EC7,$ at which ti#e it closes the connection. RFSURFSTIJLT+(6PTE5MHTIK2U The client #akes the connection to the server, then creates an
.*tp*t)tream and %er"or#s the sa#e wra%%ing as in the server. Dines o" te&t are sent through the resulting #rint0riter. The client also creates an Inp*t)tream *again, with a%%ro%riate conversions and
wra%%ing, to hear what the server is saying *which, in this case, is 0ust the words echoed back,. RFSURFSTIJLT+(6PTE5MHTIL@U Both the server and client use the sa#e %ort nu#ber and the client uses the local loo%back address to connect to the server on the sa#e #achine so you don t have to test it over a network. *Eor so#e con"igurations, you #ight need to be connected to a network "or the %rogra#s to work, even i" you aren t communicating over that network., RFSURF STIJLT+(6PTE5MHTILMU (ere is the server=
//3 c(,3Jabber%erver.Hava // Wery si#"le server that Hust // echoes :hatever the client sen!s. i#"ort Hava.io.B< i#"ort Hava.net.B< "ublic class Jabber%erver @ // Choose a "ort outsi!e of the range (-(' I3 "ublic static final int PG5T ? 1'1'< "ublic static voi! #ain-%tringNO args. thro:s $GE6ce"tion @ %erver%ocket s ? ne: %erver%ocket-PG5T.< %yste#.out."rintln-8%tarte!3 8 K s.< try @ // Blocks until a connection occurs3 %ocket socket ? s.acce"t-.< try @ %yste#.out."rintln8Connection acce"te!3 8K socket.< Buffere!5ea!er in ?
;45
ne: Buffere!5ea!erne: $n"ut%trea#5ea!ersocket.get$n"ut%trea#-...< // Gut"ut is auto#atically flushe! // by Print\riter3 Print\riter out ? ne: Print\riterne: Buffere!\riterne: Gut"ut%trea#\ritersocket.getGut"ut%trea#-...,true.< :hile -true. @ %tring str ? in.rea!Line-.< if -str.e=uals-8E&D8.. break< %yste#.out."rintln-8Echoing3 8 K str.< out."rintln-str.< A // 0l:ays close the t:o sockets... A finally @ %yste#.out."rintln-8closing...8.< socket.close-.< A A finally @ s.close-.< A A A ///3>
/ou can see that the )erver)ocket 0ust needs a %ort nu#ber, not an IP address *since it s running on this #achine.,. :hen you call acceptA B, the #ethod blocks until so#e client tries to connect to it. That is, it s there waiting "or a connection, but other %rocesses can run *see +ha%ter M?,. :hen a connection is #ade, acceptA B returns with a )ocket ob0ect re%resenting that connection. RFSURFSTIJLT+(6PTE5MHTILKU The res%onsibility "or cleaning u% the sockets is cra"ted care"ully here. I" the )erver)ocket constructor "ails, the %rogra# 0ust Auits *notice we #ust assu#e that the constructor "or )erver)ocket doesn t leave any o%en network sockets lying around i" it "ails,. Eor this case, mainA B thro(s I.&4ception so a try block is not necessary. I" the )erver)ocket constructor is success"ul then all other #ethod calls #ust be guarded in a try6finally block to ensure that, no #atter how the block
;47
Thinking in Java
,,,'0ruceEckel'com
is le"t, the )erver)ocket is %ro%erly closed. RFSURF STIJLT+(6PTE5MHTILLU The sa#e logic is used "or the )ocket returned by acceptA B. I" accept A B "ails, then we #ust assu#e that the )ocket doesn t e&ist or hold any resources, so it doesn t need to be cleaned u%. I" it s success"ul, however, the "ollowing state#ents #ust be in a try6finally block so that i" they "ail the )ocket will still be cleaned u%. +are is reAuired here because sockets use i#%ortant non#e#ory resources, so you #ust be diligent in order to clean the# u% *since there is no destructor in Java to do it "or you,. RF SURFSTIJLT+(6PTE5MHTIL?U Both the )erver)ocket and the )ocket %roduced by acceptA B are %rinted to )ystem!o*t. This #eans that their to)tringA B #ethods are auto#atically called. These %roduce=
;48
:hen writing network %rogra#s you need to be care"ul about using auto#atic "lushing. Every ti#e you "lush the bu""er a %acket #ust be created and sent. In this case, that s e&actly what we want, since i" the %acket containing the line isn t sent then the handshaking back and "orth between server and client will sto%. Put another way, the end o" a line is the end o" a #essage. But in #any cases, #essages aren t deli#ited by lines so it s #uch #ore e""icient to not use auto "lushing and instead let the built'in bu""ering decide when to build and send a %acket. This way, larger %ackets can be sent and the %rocess will be "aster. RFSURF STIJLT+(6PTE5MHTILGU Cote that, like virtually all strea#s you o%en, these are bu""ered. There s an e&ercise at the end o" this cha%ter to show you what ha%%ens i" you don t bu""er the strea#s *things get slow,. RFSURF STIJLT+(6PTE5MHTILIU The in"inite (hile loo% reads lines "ro# the 2*ffere'$ea'er in and writes in"or#ation to )ystem!o*t and to the #rint0riter o*t. Cote that in and o*t could be any strea#s, they 0ust ha%%en to be connected to the network. RFSURFSTIJLT+(6PTE5MHTIL2U :hen the client sends the line consisting o" !EC7,$ the %rogra# breaks out o" the loo% and closes the )ocket. (ere s the client=
//3 c(,3JabberClient.Hava // Wery si#"le client that Hust sen!s // lines to the server an! rea!s lines // that the server sen!s. i#"ort Hava.net.B< i#"ort Hava.io.B< "ublic class JabberClient @ "ublic static voi! #ain-%tringNO args. thro:s $GE6ce"tion @ // Passing null to getBy&a#e-. "ro!uces the // s"ecial 8Local Loo"back8 $P a!!ress, for // testing on one #achine :/o a net:ork3 $net0!!ress a!!r ? $net0!!ress.getBy&a#e-null.<
;4:
Thinking in Java
,,,'0ruceEckel'com
// 0lternatively, you can use // the a!!ress or na#e3 // $net0!!ress a!!r ? // $net0!!ress.getBy&a#e-8( *.'.'.(8.< // $net0!!ress a!!r ? // $net0!!ress.getBy&a#e-8localhost8.< %yste#.out."rintln-8a!!r ? 8 K a!!r.< %ocket socket ? ne: %ocket-a!!r, Jabber%erver.PG5T.< // auar! everything in a try-finally to #ake // sure that the socket is close!3 try @ %yste#.out."rintln-8socket ? 8 K socket.< Buffere!5ea!er in ? ne: Buffere!5ea!erne: $n"ut%trea#5ea!ersocket.get$n"ut%trea#-...< // Gut"ut is auto#atically flushe! // by Print\riter3 Print\riter out ? ne: Print\riterne: Buffere!\riterne: Gut"ut%trea#\ritersocket.getGut"ut%trea#-...,true.< for-int i ? '< i P ('< i KK. @ out."rintln-8ho:!y 8 K i.< %tring str ? in.rea!Line-.< %yste#.out."rintln-str.< A out."rintln-8E&D8.< A finally @ %yste#.out."rintln-8closing...8.< socket.close-.< A A A ///3>
In mainA B you can see all three ways to %roduce the InetA''ress o" the local loo%back IP address= using n*ll, localhost, or the e&%licit reserved address >IZ!D!D!>. )" course, i" you want to connect to a #achine across a network you substitute that #achine s IP address. :hen the
;4;
localhost/( *.'.'.(
By handing get2y/ameA B a n*ll, it de"aulted to "inding the localhost, and that %roduced the s%ecial address >IZ!D!D!>. RFSURF STIJLT+(6PTE5MHTI?MU Cote that the )ocket called socket is created with both the InetA''ress and the %ort nu#ber. To understand what it #eans when you %rint one o" these )ocket ob0ects, re#e#ber that an Internet connection is deter#ined uniAuely by these "our %ieces o" data= clientHost, client#ort/*mber, serverHost, and server#ort/*mber. :hen the server co#es u%, it takes u% its assigned %ort *I@I@, on the localhost *MKG.@[email protected],. :hen the client co#es u%, it is allocated to the ne&t available %ort on its #achine, M@GG in this case, which also ha%%ens to be on the sa#e #achine *MKG.@[email protected], as the server. Cow, in order "or data to #ove between the client and server, each side has to know where to send it. There"ore, during the %rocess o" connecting to the !known$ server, the client sends a !return address$ so the server knows where to send its data. This is what you see in the e&a#%le out%ut "or the server side=
%ocketNa!!r?( *.'.'.(,"ort?('**,local"ort?1'1'O
This #eans that the server 0ust acce%ted a connection "ro# MKG.@[email protected] on %ort M@GG while listening on its local %ort *I@I@,. )n the client side= RF SURFSTIJLT+(6PTE5MHTI?KU
%ocketNa!!r?localhost/( *.'.'.(,PG5T?1'1',local"ort?('**O
which #eans that the client #ade a connection to MKG.@[email protected] on %ort I@I@ using the local %ort M@GG. RFSURFSTIJLT+(6PTE5MHTI?LU /ou ll notice that every ti#e you start u% the client anew, the local %ort nu#ber is incre#ented. It starts at M@KH *one %ast the reserved block o" %orts, and kee%s going u% until you reboot the #achine, at which %oint it starts at M@KH again. *)n 4CIZ #achines, once the u%%er li#it o" the socket range is reached, the nu#bers will wra% around to the lowest available nu#ber again., RFSURFSTIJLT+(6PTE5MHTI??U
;5=
Thinking in Java
,,,'0ruceEckel'com
)nce the )ocket ob0ect has been created, the %rocess o" turning it into a 2*ffere'$ea'er and #rint0riter is the sa#e as in the server *again, in both cases you start with a )ocket,. (ere, the client initiates the conversation by sending the string !howdy$ "ollowed by a nu#ber. Cote that the bu""er #ust again be "lushed *which ha%%ens auto#atically via the second argu#ent to the #rint0riter constructor,. I" the bu""er isn t "lushed, the whole conversation will hang because the initial !howdy$ will never get sent *the bu""er isn t "ull enough to cause the send to ha%%en auto#atically,. Each line that is sent back "ro# the server is written to )ystem!o*t to veri"y that everything is working correctly. To ter#inate the conversation, the agreed'u%on !EC7$ is sent. I" the client si#%ly hangs u%, then the server throws an e&ce%tion. RFSURF STIJLT+(6PTE5MHTI?HU /ou can see that the sa#e care is taken here to ensure that the network resources re%resented by the )ocket are %ro%erly cleaned u%, using a try6finally block. RFSURFSTIJLT+(6PTE5MHTI?3U Sockets %roduce a !dedicated$ connection that %ersists until it is e&%licitly disconnected. *The dedicated connection can still be disconnected une&%licitly i" one side, or an inter#ediary link, o" the connection crashes., This #eans the two %arties are locked in co##unication and the connection is constantly o%en. This see#s like a logical a%%roach to networking, but it %uts an e&tra load on the network. Dater in this cha%ter you ll see a di""erent a%%roach to networking, in which the connections are only te#%orary. RFSURFSTIJLT+(6PTE5MHTI?GU
;51
The basic sche#e is to #ake a single )erver)ocket in the server and call acceptA B to wait "or a new connection. :hen acceptA B returns, you take the resulting )ocket and use it to create a new thread whose 0ob is to serve that %articular client. Then you call acceptA B again to wait "or a new client. RFSURFSTIJLT+(6PTE5MHTI?2U In the "ollowing server code, you can see that it looks si#ilar to the Jabber)erver!8ava e&a#%le e&ce%t that all o" the o%erations to serve a %articular client have been #oved inside a se%arate thread class=
//3 c(,3JultiJabber%erver.Hava // 0 server that uses #ultithrea!ing // to han!le any nu#ber of clients. i#"ort Hava.io.B< i#"ort Hava.net.B< class %erveGneJabber e6ten!s Threa! @ "rivate %ocket socket< "rivate Buffere!5ea!er in< "rivate Print\riter out< "ublic %erveGneJabber-%ocket s. thro:s $GE6ce"tion @ socket ? s< in ? ne: Buffere!5ea!erne: $n"ut%trea#5ea!ersocket.get$n"ut%trea#-...< // Enable auto-flush3 out ? ne: Print\riterne: Buffere!\riterne: Gut"ut%trea#\ritersocket.getGut"ut%trea#-..., true.< // $f any of the above calls thro: an // e6ce"tion, the caller is res"onsible for // closing the socket. Gther:ise the threa! // :ill close it. start-.< // Calls run-. A "ublic voi! run-. @ try @
;52
Thinking in Java
,,,'0ruceEckel'com
:hile -true. @ %tring str ? in.rea!Line-.< if -str.e=uals-8E&D8.. break< %yste#.out."rintln-8Echoing3 8 K str.< out."rintln-str.< A %yste#.out."rintln-8closing...8.< A catch-$GE6ce"tion e. @ %yste#.err."rintln-8$G E6ce"tion8.< A finally @ try @ socket.close-.< A catch-$GE6ce"tion e. @ %yste#.err."rintln-8%ocket not close!8.< A A A A "ublic class JultiJabber%erver @ static final int PG5T ? 1'1'< "ublic static voi! #ain-%tringNO args. thro:s $GE6ce"tion @ %erver%ocket s ? ne: %erver%ocket-PG5T.< %yste#.out."rintln-8%erver %tarte!8.< try @ :hile-true. @ // Blocks until a connection occurs3 %ocket socket ? s.acce"t-.< try @ ne: %erveGneJabber-socket.< A catch-$GE6ce"tion e. @ // $f it fails, close the socket, // other:ise the threa! :ill close it3 socket.close-.< A A A finally @ s.close-.< A A
;53
A ///3>
The )erve.neJabber thread takes the )ocket ob0ect that s %roduced by acceptA B in mainA B every ti#e a new client #akes a connection. Then, as be"ore, it creates a 2*ffere'$ea'er and auto'"lushed #rint0riter ob0ect using the )ocket. Einally, it calls the s%ecial Threa' #ethod startA B, which %er"or#s thread initiali1ation and then calls r*nA B. This %er"or#s the sa#e kind o" action as in the %revious e&a#%le= reading so#ething "ro# the socket and then echoing it back until it reads the s%ecial !EC7$ signal. RFSURFSTIJLT+(6PTE5MHTIH@U The res%onsibility "or cleaning u% the socket #ust again be care"ully designed. In this case, the socket is created outside o" the )erve.neJabber so the res%onsibility can be shared. I" the )erve.neJabber constructor "ails, it will 0ust throw the e&ce%tion to the caller, who will then clean u% the thread. But i" the constructor succeeds, then the )erve.neJabber ob0ect takes over res%onsibility "or cleaning u% the thread, in its r*nA B. RFSURFSTIJLT+(6PTE5MHTIHMU Cotice the si#%licity o" the 1*ltiJabber)erver. 6s be"ore, a )erver)ocket is created and acceptA B is called to allow a new connection. But this ti#e, the return value o" acceptA B *a )ocket, is %assed to the constructor "or )erve.neJabber, which creates a new thread to handle that connection. :hen the connection is ter#inated, the thread si#%ly goes away. RFSURFSTIJLT+(6PTE5MHTIHKU I" the creation o" the )erver)ocket "ails, the e&ce%tion is again thrown through mainA B. But i" the creation succeeds, the outer try6finally guarantees its cleanu%. The inner try6catch guards only against the "ailure o" the )erve.neJabber constructor; i" the constructor succeeds, then the )erve.neJabber thread will close the associated socket. RF SURFSTIJLT+(6PTE5MHTIHLU To test that the server really does handle #ulti%le clients, the "ollowing %rogra# creates #any clients *using threads, that connect to the sa#e server. The #a&i#u# nu#ber o" threads allowed is deter#ined by the final int 1AXXTH$&A ).
;54
Thinking in Java
,,,'0ruceEckel'com
// by starting u" #ulti"le clients. i#"ort Hava.net.B< i#"ort Hava.io.B< class JabberClientThrea! e6ten!s Threa! @ "rivate %ocket socket< "rivate Buffere!5ea!er in< "rivate Print\riter out< "rivate static int counter ? '< "rivate int i! ? counterKK< "rivate static int threa!count ? '< "ublic static int threa!Count-. @ return threa!count< A "ublic JabberClientThrea!-$net0!!ress a!!r. @ %yste#.out."rintln-8Jaking client 8 K i!.< threa!countKK< try @ socket ? ne: %ocket-a!!r, JultiJabber%erver.PG5T.< A catch-$GE6ce"tion e. @ %yste#.err."rintln-8%ocket faile!8.< // $f the creation of the socket fails, // nothing nee!s to be cleane! u". A try @ in ? ne: Buffere!5ea!erne: $n"ut%trea#5ea!ersocket.get$n"ut%trea#-...< // Enable auto-flush3 out ? ne: Print\riterne: Buffere!\riterne: Gut"ut%trea#\ritersocket.getGut"ut%trea#-..., true.< start-.< A catch-$GE6ce"tion e. @ // The socket shoul! be close! on any // failures other than the socket // constructor3
;55
try @ socket.close-.< A catch-$GE6ce"tion e . @ %yste#.err."rintln-8%ocket not close!8.< A A // Gther:ise the socket :ill be close! by // the run-. #etho! of the threa!. A "ublic voi! run-. @ try @ for-int i ? '< i P ,< iKK. @ out."rintln-8Client 8 K i! K 83 8 K i.< %tring str ? in.rea!Line-.< %yste#.out."rintln-str.< A out."rintln-8E&D8.< A catch-$GE6ce"tion e. @ %yste#.err."rintln-8$G E6ce"tion8.< A finally @ // 0l:ays close it3 try @ socket.close-.< A catch-$GE6ce"tion e. @ %yste#.err."rintln-8%ocket not close!8.< A threa!count--< // En!ing this threa! A A A "ublic class JultiJabberClient @ static final int J09bTM5E0D% ? I'< "ublic static voi! #ain-%tringNO args. thro:s $GE6ce"tion, $nterru"te!E6ce"tion @ $net0!!ress a!!r ? $net0!!ress.getBy&a#e-null.< :hile-true. @ if-JabberClientThrea!.threa!Count-. P J09bTM5E0D%. ne: JabberClientThrea!-a!!r.<
;57
Thinking in Java
,,,'0ruceEckel'com
Threa!.currentThrea!-..slee"-(''.< A A A ///3>
The Jabber-lientThrea' constructor takes an InetA''ress and uses it to o%en a )ocket. /ou re %robably starting to see the %attern= the )ocket is always used to create so#e kind o" $ea'er andFor 0riter *or Inp*t)tream andFor .*tp*t)tream, ob0ect, which is the only way that the )ocket can be used. */ou can, o" course, write a class or two to auto#ate this %rocess instead o" doing all the ty%ing i" it beco#es %ain"ul., 6gain, startA B %er"or#s thread initiali1ation and calls r*nA B. (ere, #essages are sent to the server and in"or#ation "ro# the server is echoed to the screen. (owever, the thread has a li#ited li"eti#e and eventually co#%letes. Cote that the socket is cleaned u% i" the constructor "ails a"ter the socket is created but be"ore the constructor co#%letes. )therwise the res%onsibility "or calling closeA B "or the socket is relegated to the r*nA B #ethod. RFSURFSTIJLT+(6PTE5MHTIH?U The threa'co*nt kee%s track o" how #any Jabber-lientThrea' ob0ects currently e&ist. It is incre#ented as %art o" the constructor and decre#ented as r*nA B e&its *which #eans the thread is ter#inating,. In 1*ltiJabber-lient!mainA B, you can see that the nu#ber o" threads is tested, and i" there are too #any, no #ore are created. Then the #ethod slee%s. This way, so#e threads will eventually ter#inate and #ore can be created. /ou can e&%eri#ent with 1AXXTH$&A ) to see where your %articular syste# begins to have trouble with too #any connections. RF SURFSTIJLT+(6PTE5MHTIHHU
Datagrams
The e&a#%les you ve seen so "ar use the Transmission Control Protocol *T+P, also known as stream/based sockets,, which is designed "or ulti#ate reliability and guarantees that the data will get there. It allows retrans#ission o" lost data, it %rovides #ulti%le %aths through di""erent routers in case one goes down, and bytes are delivered in the order they are sent. 6ll this control and reliability co#es at a cost= T+P has a high overhead. RFSURFSTIJLT+(6PTE5MHTIH3U
;58
There s a second %rotocol, called <ser %atagram Protocol *47P,, which doesn t guarantee that the %ackets will be delivered and doesn t guarantee that they will arrive in the order they were sent. It s called an !unreliable %rotocol$ *T+P is a !reliable %rotocol$,, which sounds bad, but because it s #uch "aster it can be use"ul. There are so#e a%%lications, such as an audio signal, in which it isn t so critical i" a "ew %ackets are dro%%ed here or there but s%eed is vital. )r consider a ti#e'o"'day server, where it really doesn t #atter i" one o" the #essages is lost. 6lso, so#e a%%lications #ight be able to "ire o"" a 47P #essage to a server and can then assu#e, i" there is no res%onse in a reasonable %eriod o" ti#e, that the #essage was lost. RFSURFSTIJLT+(6PTE5MHTIHGU Ty%ically, you ll do #ost o" your direct network %rogra##ing with T+P, and only occasionally will you use 47P. There s a #ore co#%lete treat#ent o" 47P, including an e&a#%le, in the "irst edition o" this book *available on the +7 5)M bound into this book, or as a "ree download "ro# ,,,'0ruceEckel'com,. RFSURFSTIJLT+(6PTE5MHTIHIU
get0""letConte6t-..sho:Docu#ent-u.<
in which * is the U$+ ob0ect. (ere s a si#%le e&a#%le that redirects you to another :eb %age. 6lthough you re 0ust redirected to an (TMD %age, you could also redirect to the out%ut o" a +8I %rogra#. RFSURF STIJLT+(6PTE5MHTIH2U
//3 c(,3%ho:MTJL.Hava // Pa""let co!e?%ho:MTJL :i!th?('' height?,'Q // P/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.B< i#"ort Hava.a:t.event.B< i#"ort Hava.net.B< i#"ort Hava.io.B< i#"ort co#.bruceeckel.s:ing.B<
;5:
Thinking in Java
,,,'0ruceEckel'com
"ublic class %ho:MTJL e6ten!s J0""let @ JButton sen! ? ne: JButton-8ao8.< JLabel l ? ne: JLabel-.< "ublic voi! init-. @ Container c" ? getContentPane-.< c".setLayout-ne: Llo:Layout-..< sen!.a!!0ctionListener-ne: 0l-..< c".a!!-sen!.< c".a!!-l.< A class 0l i#"le#ents 0ctionListener @ "ublic voi! actionPerfor#e!-0ctionEvent ae. @ try @ // This coul! be a Ca$ "rogra# instea! of // an MTJL "age. Y5L u ? ne: Y5L-getDocu#entBase-., 8LetcherLra#e.ht#l8.< // Dis"lay the out"ut of the Y5L using // the \eb bro:ser, as an or!inary "age3 get0""letConte6t-..sho:Docu#ent-u.< A catch-E6ce"tion e. @ l.setTe6t-e.to%tring-..< A A A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: %ho:MTJL-., ('', ,'.< A A ///3>
The beauty o" the U$+ class is how #uch it shields you "ro#. /ou can connect to :eb servers without knowing #uch at all about what s going on under the covers. RFSURFSTIJLT+(6PTE5MHTI3@U
;5;
// P/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.B< i#"ort Hava.a:t.event.B< i#"ort Hava.net.B< i#"ort Hava.io.B< i#"ort co#.bruceeckel.s:ing.B< "ublic class Letcher e6ten!s J0""let @ JButton fetch$t? ne: JButton-8Letch the Data8.< JTe6tLiel! f ? ne: JTe6tLiel!-8Letcher.Hava8, '.< JTe6t0rea t ? ne: JTe6t0rea-(',I'.< "ublic voi! init-. @ Container c" ? getContentPane-.< c".setLayout-ne: Llo:Layout-..< fetch$t.a!!0ctionListener-ne: LetchL-..< c".a!!-ne: J%crollPane-t..< c".a!!-f.< c".a!!-fetch$t.< A "ublic class LetchL i#"le#ents 0ctionListener @ "ublic voi! actionPerfor#e!-0ctionEvent e. @ try @ Y5L url ? ne: Y5L-getDocu#entBase-., f.getTe6t-..< t.setTe6t-url K 8_n8.< $n"ut%trea# is ? url.o"en%trea#-.< Buffere!5ea!er in ? ne: Buffere!5ea!erne: $n"ut%trea#5ea!er-is..< %tring line< :hile --line ? in.rea!Line-.. 4? null. t.a""en!-line K 8_n8.< A catch-E6ce"tion e6. @ t.a""en!-e6.to%tring-..< A A A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: Letcher-., ,'', )''.< A A ///3>
;7=
Thinking in Java
,,,'0ruceEckel'com
The creation o" the U$+ ob0ect is si#ilar to the %revious e&a#%le9 get oc*ment2aseA B is the starting %oint as be"ore, but this ti#e the na#e o" the "ile is read "ro# the JTe4tFiel'. )nce the U$+ ob0ect is created, its )tring version is %laced in the JTe4tArea so we can see what it looks like. Then an Inp*t)tream is %rocured "ro# the U$+, which in this case will si#%ly %roduce a strea# o" the characters in the "ile. 6"ter converting to a $ea'er and bu""ering, each line is read and a%%ended to the JTe4tArea. Cote that the JTe4tArea has been %laced inside a J)croll#ane so that scrolling is handled auto#atically. RFSURF STIJLT+(6PTE5MHTI3MU
More to networking
There s actually a lot #ore to networking than can be covered in this introductory treat#ent. Java networking also %rovides "airly e&tensive su%%ort "or 45Ds, including %rotocol handlers "or di""erent ty%es o" content that can be discovered at an Internet site. /ou can "ind other Java networking "eatures "ully and care"ully described in Java +et,ork Programming by Elliotte 5usty (arold *) 5eilly, M22G,. RFSURF STIJLT+(6PTE5MHTI3KU
;71
still %ossible to #ake vendor's%eci"ic calls "ro# J7B+ so you aren t restricted "ro# doing what you #ust. RFSURFSTIJLT+(6PTE5MHTI3?U )ne %lace where %rogra##ers #ay need to use SeD ty%e na#es is in the SeD T0BLE C5E0TE state#ent when they are creating a new database table and de"ining the SeD ty%e "or each colu#n. 4n"ortunately there are signi"icant variations between SeD ty%es su%%orted by di""erent database %roducts. 7i""erent databases that su%%ort SeD ty%es with the sa#e se#antics and structure #ay give those ty%es di""erent na#es. Most #a0or databases su%%ort an SeD data ty%e "or large binary values= in )racle this ty%e is called a LG&a 50\, Sybase calls it $J0aE, In"or#i& calls it B;TE, and 7BK calls it LG&a W05CM05 LG5 B$T D0T0. There"ore, i" database %ortability is a goal you should try to use only generic SeD ty%e identi"iers. RFSURFSTIJLT+(6PTE5MHTI3HU Portability is an issue when writing "or a book where readers #ay be testing the e&a#%les with all kinds o" unknown data stores. I have tried to write these e&a#%les to be as %ortable as %ossible. /ou should also notice that the database's%eci"ic code has been isolated in order to centrali1e any changes that you #ay need to %er"or# to get the e&a#%les o%erational in your environ#ent. RFSURFSTIJLT+(6PTE5MHTI33U J7B+, like #any o" the 6PIs in Java, is designed "or si#%licity. The #ethod calls you #ake corres%ond to the logical o%erations you d think o" doing when gathering data "ro# a database= connect to the database, create a state#ent and e&ecute the Auery, and look at the result set. RF SURFSTIJLT+(6PTE5MHTI3GU To allow this %lat"or# inde%endence, J7B+ %rovides a driver manager that dyna#ically #aintains all the driver ob0ects that your database Aueries will need. So i" you have three di""erent kinds o" vendor databases to connect to, you ll need three di""erent driver ob0ects. The driver ob0ects register the#selves with the driver #anager at the ti#e o" loading, and you can "orce the loading using -lass!for/ameA B. RFSURF STIJLT+(6PTE5MHTI3IU To o%en a database, you #ust create a !database 45D$ that s%eci"ies=
;72
Thinking in Java
,,,'0ruceEckel'com
(-+) The !sub%rotocol$= the na#e o" the driver or the na#e o" a
database connectivity #echanis#. Since the design o" J7B+ was ins%ired by )7B+, the "irst sub%rotocol available is the !0dbc'odbc bridge,$ s%eci"ied by !odbc.$ RFSURFSTIJLT+(6PTE5MHTIG@U
(-,) The database identi"ier. This varies with the database driver used,
but it generally %rovides a logical na#e that is #a%%ed by the database ad#inistration so"tware to a %hysical directory where the database tables are located. Eor your database identi"ier to have any #eaning, you #ust register the na#e using your database ad#inistration so"tware. *The %rocess o" registration varies "ro# %lat"or# to %lat"or#., RFSURFSTIJLT+(6PTE5MHTIGMU 6ll this in"or#ation is co#bined into one string, the !database 45D.$ Eor e&a#%le, to connect through the )7B+ sub%rotocol to a database identi"ied as !%eo%le,$ the database 45D could be= RFSURF STIJLT+(6PTE5MHTIGKU
;73
-onnection ob0ect that you can then use to Auery and #ani%ulate the
database. RFSURFSTIJLT+(6PTE5MHTIGHU The "ollowing e&a#%le o%ens a database o" contact in"or#ation and looks "or a %erson s last na#e as given on the co##and line. It selects only the na#es o" %eo%le that have e#ail addresses, then %rints out all the ones that #atch the given last na#e=
//3 c(,3H!bc3Looku".Hava // Looks u" e#ail a!!resses in a // local !atabase using JDBC. i#"ort Hava.s=l.B< "ublic class Looku" @ "ublic static voi! #ain-%tringNO args. thro:s %/LE6ce"tion, Class&otLoun!E6ce"tion @ %tring !bYrl ? 8H!bc3o!bc3"eo"le8< %tring user ? 88< %tring "ass:or! ? 88< // Loa! the !river -registers itself. Class.for&a#e8sun.H!bc.o!bc.J!bcG!bcDriver8.< Connection c ? DriverJanager.getConnection!bYrl, user, "ass:or!.< %tate#ent s ? c.create%tate#ent-.< // %/L co!e3 5esult%et r ? s.e6ecute/uery8%ELECT L$5%T, L0%T, EJ0$L 8 K 8L5GJ "eo"le.csv "eo"le 8 K 8\ME5E 8 K 8-L0%T?28 K argsN'O K 82. 8 K 8 0&D -EJ0$L $s &ot &ull. 8 K 8G5DE5 B; L$5%T8.< :hile-r.ne6t-.. @ // Ca"italiUation !oesn2t #atter3 %yste#.out."rintlnr.get%tring-8Last8. K 8, 8 K r.get%tring-8f$5%T8. K 83 8 K r.get%tring-8EJ0$L8. .< A
;74
Thinking in Java
,,,'0ruceEckel'com
;75
)" course, this %rocess can vary radically "ro# #achine to #achine, but the %rocess I used to #ake it work under LK'bit :indows #ight give you clues to hel% you attack your own situation. RFSURF STIJLT+(6PTE5MHTII@U
Class.for&a#e-8sun.H!bc.o!bc.J!bcG!bcDriver8.<
This i#%lies a directory structure, which is deceiving. :ith this %articular installation o" J7> M.M, there was no "ile called J'bc.'bc river!class, so i" you looked at this e&a#%le and went searching "or it you d be "rustrated. )ther %ublished e&a#%les use a %seudo na#e, such as !#y7river.+lassCa#e,$ which is less than hel%"ul. In "act, the load state#ent above "or the 0dbc'odbc driver *the only one that actually co#es with the J7>, a%%ears in only a "ew %laces in the online docu#entation *in %articular, a %age labeled !J7B+')7B+ Bridge 7river$,. I" the load state#ent above doesn t work, then the na#e #ight have been changed as %art o" a Java version change, so you should hunt through the docu#entation again. RFSURFSTIJLT+(6PTE5MHTIIMU I" the load state#ent is wrong, you ll get an e&ce%tion at this %oint. To test whether your driver load state#ent is working correctly, co##ent out the code a"ter the state#ent and u% to the catch clause; i" the %rogra# throws no e&ce%tions it #eans that the driver is loading %ro%erly. RFSURF STIJLT+(6PTE5MHTIIKU
;77
Thinking in Java
,,,'0ruceEckel'com
turns out that "or the J7B+')7B+ bridge, the only %lace where it s i#%ortant to set u% your database is !Syste# 7SC,$ but you ll also want to test your con"iguration and create Aueries, and "or that you ll also need to set u% your database in !Eile 7SC.$ This will allow the Microso"t euery tool *that co#es with Microso"t )""ice, to "ind the database. Cote that other Auery tools are also available "ro# other vendors. RFSURF STIJLT+(6PTE5MHTII?U The #ost interesting database is one that you re already using. Standard )7B+ su%%orts a nu#ber o" di""erent "ile "or#ats including such venerable workhorses as 7Base. (owever, it also includes the si#%le !co##a'se%arated 6S+II$ "or#at, which virtually every data tool has the ability to write. In #y case, I 0ust took #y !%eo%le$ database that I ve been #aintaining "or years using various contact'#anage#ent tools and e&%orted it as a co##a'se%arated 6S+II "ile *these ty%ically have an e&tension o" !csv,. In the !Syste# 7SC$ section I chose !6dd,$ chose the te&t driver to handle #y co##a'se%arated 6S+II "ile, and then un' checked !use current directory$ to allow #e to s%eci"y the directory where I e&%orted the data "ile. RFSURFSTIJLT+(6PTE5MHTIIHU /ou ll notice when you do this that you don t actually s%eci"y a "ile, only a directory. That s because a database is ty%ically re%resented as a collection o" "iles under a single directory *although it could be re%resented in other "or#s as well,. Each "ile usually contains a single table, and the SeD state#ents can %roduce results that are culled "ro# #ulti%le tables in the database *this is called a >oin,. 6 database that contains only a single table *like #y !%eo%le$ database, is usually called a $lat/$ile database. Most %roble#s that go beyond the si#%le storage and retrieval o" data generally reAuire #ulti%le tables that #ust be related by 0oins to %roduce the desired results, and these are called relational databases. RFSURFSTIJLT+(6PTE5MHTII3U
Connection c ? DriverJanager.getConnection-
;78
(--) Start a new Auery and use the euery :i1ard. Select the !%eo%le$
database. *This is the eAuivalent o" o%ening the database connection using the a%%ro%riate database 45D.,
(-4) Select the !%eo%le$ table within the database. Ero# within the
table, choose the colu#ns EI5ST, D6ST, and EM6ID.
(-5) 4nder !Eilter 7ata,$ choose D6ST and select !eAuals$ with an
argu#ent o" !Eckel.$ +lick the !6nd$ radio button.
(-6) +hoose EM6ID and select !Is not Cull.$ (47) 4nder !Sort By,$ choose EI5ST.
;7:
Thinking in Java
,,,'0ruceEckel'com
The result o" this Auery will show you whether you re getting what you want. RFSURFSTIJLT+(6PTE5MHTI2@U Cow you can %ress the SeD button and without any research on your %art, u% will %o% the correct SeD code, ready "or you to cut and %aste. Eor this Auery, it looked like this=
%ELECT "eo"le.L$5%T, "eo"le.L0%T, "eo"le.EJ0$L L5GJ "eo"le.csv "eo"le \ME5E -"eo"le.L0%T?2Eckel2. 0&D -"eo"le.EJ0$L $s &ot &ull. G5DE5 B; "eo"le.L$5%T
Es%ecially with #ore co#%licated Aueries it s easy to get things wrong, but by using a Auery tool you can interactively test your Aueries and auto#atically generate the correct code. It s hard to argue the case "or doing this by hand. RFSURFSTIJLT+(6PTE5MHTI2MU
%ELECT L$5%T, L0%T, EJ0$L L5GJ "eo"le.csv "eo"le \ME5E -L0%T?2Eckel2. 0&D -EJ0$L $s &ot &ull. G5DE5 B; L$5%T
In addition, you don t want this %rogra# to be hard coded to look "or only one na#e. Instead, it should hunt "or the na#e given as the co##and' line argu#ent. Making these changes and turning the SeD state#ent into a dyna#ically'created )tring %roduces= RFSURF STIJLT+(6PTE5MHTI2LU
;7;
8\ME5E 8 K 8-L0%T?28 K argsN'O K 82. 8 K 8 0&D -EJ0$L $s &ot &ull. 8 K 8G5DE5 B; L$5%T8.<
SeD has another way to insert na#es into a Auery called stored rocedures, which is used "or s%eed. But "or #uch o" your database e&%eri#entation and "or your "irst cut, building your own Auery strings in Java is "ine. RFSURFSTIJLT+(6PTE5MHTI2?U /ou can see "ro# this e&a#%le that by using the tools currently available 9in %articular the Auery'building tool9database %rogra##ing with SeD and J7B+ can be Auite straight"orward. RFSURF STIJLT+(6PTE5MHTI2HU
//3 c(,3H!bc3WLooku".Hava // aY$ version of Looku".Hava. // Pa""let co!e?WLooku" // :i!th?,'' height? ''QP/a""letQ i#"ort Hava6.s:ing.B< i#"ort Hava.a:t.B< i#"ort Hava.a:t.event.B< i#"ort Hava6.s:ing.event.B< i#"ort Hava.s=l.B< i#"ort co#.bruceeckel.s:ing.B< "ublic class WLooku" e6ten!s J0""let @ %tring !bYrl ? 8H!bc3o!bc3"eo"le8< %tring user ? 88< %tring "ass:or! ? 88< %tate#ent s<
;8=
Thinking in Java
,,,'0ruceEckel'com
JTe6tLiel! searchLor ? ne: JTe6tLiel!- '.< JLabel co#"letion ? ne: JLabel-8 8.< JTe6t0rea results ? ne: JTe6t0rea-I', '.< "ublic voi! init-. @ searchLor.getDocu#ent-..a!!Docu#entListenerne: %earchL-..< JPanel " ? ne: JPanel-.< ".a!!-ne: Label-8Last na#e to search for38..< ".a!!-searchLor.< ".a!!-co#"letion.< Container c" ? getContentPane-.< c".a!!-", Bor!erLayout.&G5TM.< c".a!!-results, Bor!erLayout.CE&TE5.< try @ // Loa! the !river -registers itself. Class.for&a#e8sun.H!bc.o!bc.J!bcG!bcDriver8.< Connection c ? DriverJanager.getConnection!bYrl, user, "ass:or!.< s ? c.create%tate#ent-.< A catch-E6ce"tion e. @ results.setTe6t-e.to%tring-..< A A class %earchL i#"le#ents Docu#entListener @ "ublic voi! change!Y"!ate-Docu#entEvent e.@A "ublic voi! insertY"!ate-Docu#entEvent e.@ te6tWalueChange!-.< A "ublic voi! re#oveY"!ate-Docu#entEvent e.@ te6tWalueChange!-.< A A "ublic voi! te6tWalueChange!-. @ 5esult%et r< if-searchLor.getTe6t-..length-. ?? '. @ co#"letion.setTe6t-88.< results.setTe6t-88.< return< A
;81
try @ // &a#e co#"letion3 r ? s.e6ecute/uery8%ELECT L0%T L5GJ "eo"le.csv "eo"le 8 K 8\ME5E -L0%T Like 28 K searchLor.getTe6t-. K 8V2. G5DE5 B; L0%T8.< if-r.ne6t-.. co#"letion.setTe6tr.get%tring-8last8..< r ? s.e6ecute/uery8%ELECT L$5%T, L0%T, EJ0$L 8 K 8L5GJ "eo"le.csv "eo"le 8 K 8\ME5E -L0%T?28 K co#"letion.getTe6t-. K 82. 0&D -EJ0$L $s &ot &ull. 8 K 8G5DE5 B; L$5%T8.< A catch-E6ce"tion e. @ results.setTe6tsearchLor.getTe6t-. K 8_n8.< results.a""en!-e.to%tring-..< return< A results.setTe6t-88.< try @ :hile-r.ne6t-.. @ results.a""en!r.get%tring-8Last8. K 8, 8 K r.get%tring-8f$5%T8. K 83 8 K r.get%tring-8EJ0$L8. K 8_n8.< A A catch-E6ce"tion e. @ results.setTe6t-e.to%tring-..< A A "ublic static voi! #ain-%tringNO args. @ Console.run-ne: WLooku"-., ,'', ''.< A A ///3>
;82
Thinking in Java
,,,'0ruceEckel'com
Much o" the database logic is the sa#e, but you can see that a oc*ment+istener is added to listen to the JTe4tFiel' *see the 8ava4!s(ing!JTe4tFiel' entry in the Java (TMD docu#entation "ro# >ava'sun'com "or details,, so that whenever you ty%e a new character it "irst tries to do a na#e co#%letion by looking u% the last na#e in the database and using the "irst one that shows u%. *It %laces it in the completion J+abel, and uses that as the looku% te&t., This way, as soon as you ve ty%ed enough characters "or the %rogra# to uniAuely "ind the na#e you re looking "or, you can sto%. RFSURFSTIJLT+(6PTE5MHTI23U
;83
bear in #ind that your li"e will be easier i" you can either write generic Aueries and not worry Auite as #uch about %er"or#ance, or, i" you #ust tune "or %er"or#ance, know the %lat"or# you re writing "or so you don t need to write all that investigation code. RFSURF STIJLT+(6PTE5MHTI22U
de%loy#ent, "ro# htt%=FFwww.+loudsca%e.co#. /ou ll need to "ollow the instructions in the download in order to %ro%erly install and set u% +loudsca%e.RFSURFSTIJLT+(6PTE5MHTIM@MU
To kee% changes in the connection in"or#ation si#%le, the database driver, database 45D, user na#e, and %assword are %laced in a se%arate class=
//3 c(,3H!bc3C$DConnect.Hava // Database connection infor#ation for // the co##unity interests !atabase -C$D..
@ +reated by 7ave Bartlett.
;84
Thinking in Java
,,,'0ruceEckel'com
"ublic class C$DConnect @ // 0ll the infor#ation s"ecific to Clou!%ca"e3 "ublic static %tring !bDriver ? 8CGJ.clou!sca"e.core.JDBCDriver8< "ublic static %tring !bY5L ? 8H!bc3clou!sca"e3!3/!ocs/b:ork/J%a"ienDB8< "ublic static %tring user ? 88< "ublic static %tring "ass:or! ? 88< A ///3>
In this e&a#%le, there is no %assword %rotection on the database so the user na#e and %assword are e#%ty strings. :ith +loudsca%e, the
'bU$+ contains the directory %ath where the database is located, but other RFSURFSTIJLT+(6PTE5MHTIM@KU 7BMSs and J7B+ drivers will use other ways to encode this in"or#ation. This e&a#%le assu#es that the database !JSa%ien7B$ has already been created, but in order to get the e&a#%le to work you ll need to use the cvie( tool that co#es with +loudsca%e in order to create the new database, and then you #ust change the above 'bU$+ to re"lect the %ath o" the database you created.
The database consists o" a set o" tables that have a structure as shown here=
EVTMEMS MEM_ID EVT_ID MEM_ORD EVENTS EVT_ID TITLE (IE) TYPE LOC_ID PRICE DATETIME
MEMBERS MEM_ID MEM_UNAME (AK) MEM_LNAME (IE) MEM_FNAME (IE) ADDRESS CITY STATE ZIP PHONE EMAIL LOCATIONS LOC_ID NAME (IE) CONTACT ADDRESS CITY STATE ZIP PHONE DIRECTIONS
;85
!Me#bers$ contains co##unity #e#ber in"or#ation, !Events$ and !Docations$ contain in"or#ation about the activities and where they take %lace, and !Evt#e#s$ connects events and #e#bers that would like to attend that event. /ou can see that a data #e#ber in one table %roduces a key in another table. RFSURFSTIJLT+(6PTE5MHTIM@LU The "ollowing class contains the SeD strings that will create these database tables *re"er to an SeD guide "or an e&%lanation o" the SeD code,= RFSURFSTIJLT+(6PTE5MHTIM@?U
//3 c(,3H!bc3C$D%/L.Hava // %/L strings to create the tables for the C$D. "ublic class C$D%/L @ "ublic static %tringNO s=l ? @ // Create the JEJBE5% table3 8!ro" table JEJBE5%8, 8create table JEJBE5% 8 K 8-JEJb$D $&TEaE5 "ri#ary key, 8 K 8JEJbY&0JE W05CM05-( . not null uni=ue, 8K 8JEJbL&0JE W05CM05-I'., 8 K 8JEJbL&0JE W05CM05- '., 8 K 80DD5E%% W05CM05-I'., 8 K 8C$T; W05CM05- '., 8 K 8%T0TE CM05-I., 8 K 8T$P CM05-,., 8 K 8PMG&E CM05-( ., 8 K 8EJ0$L W05CM05-)'..8, 8create uni=ue in!e6 8 K 8L&0JEb$D9 on JEJBE5%-JEJbL&0JE.8, // Create the EWE&T% table 8!ro" table EWE&T%8, 8create table EWE&T% 8 K 8-EWTb$D $&TEaE5 "ri#ary key, 8 K 8EWTbT$TLE W05CM05-)'. not null, 8 K 8EWTbT;PE W05CM05- '., 8 K 8LGCb$D $&TEaE5, 8 K 8P5$CE DEC$J0L, 8 K 8D0TET$JE T$JE%T0JP.8, 8create uni=ue in!e6 8 K 8T$TLEb$D9 on EWE&T%-EWTbT$TLE.8,
;87
Thinking in Java
,,,'0ruceEckel'com
// Create the EWTJEJ% table 8!ro" table EWTJEJ%8, 8create table EWTJEJ% 8 K 8-JEJb$D $&TEaE5 not null, 8 K 8EWTb$D $&TEaE5 not null, 8 K 8JEJbG5D $&TEaE5.8, 8create uni=ue in!e6 8 K 8EWTJEJb$D9 on EWTJEJ%-JEJb$D, EWTb$D.8, // Create the LGC0T$G&% table 8!ro" table LGC0T$G&%8, 8create table LGC0T$G&% 8 K 8-LGCb$D $&TEaE5 "ri#ary key, 8 K 8LGCb&0JE W05CM05-)'. not null, 8 K 8CG&T0CT W05CM05-,'., 8 K 80DD5E%% W05CM05-I'., 8 K 8C$T; W05CM05- '., 8 K 8%T0TE W05CM05-I., 8 K 8T$P W05CM05-,., 8 K 8PMG&E CM05-( ., 8 K 8D$5ECT$G&% W05CM05-I'C+..8, 8create uni=ue in!e6 8 K 8&0JEb$D9 on LGC0T$G&%-LGCb&0JE.8, A< A ///3>
The "ollowing %rogra# uses the -I -onnect and -I )3+ in"or#ation to load the J7B+ driver, #ake a connection to the database, and then create the table structure diagra##ed above. To connect with the database, you call the static #ethod river1anager!get-onnection A B, %assing it the database 45D, the user na#e, and a %assword to get into the database. /ou get back a -onnection ob0ect that you can use to Auery and #ani%ulate the database. )nce the connection is #ade you can si#%ly %ush the SeD to the database, in this case by #arching through the -I )3+ array. (owever, the "irst ti#e this %rogra# is run, the !dro% table$ co##and will "ail, causing an e&ce%tion, which is caught, re%orted, and then ignored. The reason "or the !dro% table$ co##and is to allow easy e&%eri#entation= you can #odi"y the SeD that de"ines the tables and then rerun the %rogra#, causing the old tables to be re%laced by the new. RFSURFSTIJLT+(6PTE5MHTIM@HU
;88
In this e&a#%le, it #akes sense to let the e&ce%tions be thrown out to the console=
//3 c(,3H!bc3C$DCreateTables.Hava // Creates !atabase tables for the // co##unity interests !atabase. i#"ort Hava.s=l.B< "ublic class C$DCreateTables @ "ublic static voi! #ain-%tringNO args. thro:s %/LE6ce"tion, Class&otLoun!E6ce"tion, $llegal0ccessE6ce"tion @ // Loa! the !river -registers itself. Class.for&a#e-C$DConnect.!bDriver.< Connection c ? DriverJanager.getConnectionC$DConnect.!bY5L, C$DConnect.user, C$DConnect."ass:or!.< %tate#ent s ? c.create%tate#ent-.< for-int i ? '< i P C$D%/L.s=l.length< iKK. @ %yste#.out."rintln-C$D%/L.s=lNiO.< try @ s.e6ecuteY"!ate-C$D%/L.s=lNiO.< A catch-%/LE6ce"tion s=lE6. @ %yste#.err."rintln8Probably a 2!ro" table2 faile!8.< A A s.close-.< c.close-.< A A ///3>
Cote that all changes in the database can be controlled by changing
e4ec*teUp'ateA B will usually return the nu#ber o" rows that were a""ected by the SeD state#ent. e4ec*teUp'ateA B is #ore co##only used to e&ecute $&%E5T, YPD0TE, or DELETE state#ents that #odi"y one or #ore rows. Eor state#ents such as C5E0TE T0BLE, D5GP T0BLE, and
;8:
Thinking in Java
,,,'0ruceEckel'com
//3 c(,3H!bc3Loa!DB.Hava // Loa!s an! tests the !atabase. i#"ort Hava.s=l.B< class Test%et @ GbHectNONO !ata ? @ @ 8JEJBE5%8, ne: $nteger-(., 8!bartlett8, 8Bartlett8, 8Davi!8, 8( ) Jockingbir! Lane8, 8aettysburg8, 8P08, 8(C)( 8, 8( ).I,+.*1C'8, 8bartRyou.net8 A, @ 8JEJBE5%8, ne: $nteger- ., 8beckel8, 8Eckel8, 8Bruce8, 8( ) Gver 5ainbo: Lane8, 8Creste! Butte8, 8CG8, 81( I8, 8( ).I,+.*1C'8, 8beckelRyou.net8 A, @ 8JEJBE5%8, ne: $nteger-)., 8rcastane!a8, 8Castane!a8, 85obert8, 8( ) Do:nun!er Lane8, 8%y!ney8, 8&%\8, 8( )I,8, 8( ).I,+.*1C'8, 8rcastane!aRyou.net8 A, @ 8LGC0T$G&%8, ne: $nteger-(., 8Center for 0rts8, 8Betty \right8, 8( ) Elk 0ve.8, 8Creste! Butte8, 8CG8, 81( I8, 8( ).I,+.*1C'8, 8ao this :ay then that.8 A, @ 8LGC0T$G&%8, ne: $nteger- ., 8\itts En! Conference Center8, 8John \ittig8, 8( ) Jusic Drive8, 8Toneville8, 8P08, 8(C( )8,
;8;
8( ).I,+.*1C'8, 8ao that :ay then this.8 A, @ 8EWE&T%8, ne: $nteger-(., 8ProHect Janage#ent Jyths8, 8%oft:are Develo"#ent8, ne: $nteger-(., ne: Lloat- .,'., 8 '''-'*-(* (C3)'3''8 A, @ 8EWE&T%8, ne: $nteger- ., 8Life of the Creste! Dog8, 80rcheology8, ne: $nteger- ., ne: Lloat-'.''., 8 '''-'*-(C (C3''3''8 A, // Jatch so#e "eo"le :ith events @ 8EWTJEJ%8, ne: $nteger-(., // Dave is going to ne: $nteger-(., // the %oft:are event. ne: $nteger-'. A, @ 8EWTJEJ%8, ne: $nteger- ., // Bruce is going to ne: $nteger- ., // the 0rcheology event. ne: $nteger-'. A, @ 8EWTJEJ%8, ne: $nteger-)., // 5obert is going to ne: $nteger-(., // the %oft:are event. ne: $nteger-(. A, @ 8EWTJEJ%8, ne: $nteger-)., // ... an! ne: $nteger- ., // the 0rcheology event. ne: $nteger-(. A, A< // Yse the !efault !ata set3 "ublic Test%et-. @A // Yse a !ifferent !ata set3 "ublic Test%et-GbHectNONO !at. @ !ata ? !at< A A "ublic class Loa!DB @ %tate#ent state#ent< Connection connection< Test%et tset< "ublic Loa!DB-Test%et t. thro:s %/LE6ce"tion @
;:=
Thinking in Java
,,,'0ruceEckel'com
tset ? t< try @ // Loa! the !river -registers itself. Class.for&a#e-C$DConnect.!bDriver.< A catch-Hava.lang.Class&otLoun!E6ce"tion e. @ e."rint%tackTrace-%yste#.err.< A connection ? DriverJanager.getConnectionC$DConnect.!bY5L, C$DConnect.user, C$DConnect."ass:or!.< state#ent ? connection.create%tate#ent-.< A "ublic voi! cleanu"-. thro:s %/LE6ce"tion @ state#ent.close-.< connection.close-.< A "ublic voi! e6ecute$nsert-GbHectNO !ata. @ %tring s=l ? 8insert into 8 K !ataN'O K 8 values-8< for-int i ? (< i P !ata.length< iKK. @ if-!ataNiO instanceof %tring. s=l K? 828 K !ataNiO K 828< else s=l K? !ataNiO< if-i P !ata.length - (. s=l K? 8, 8< A s=l K? 2.2< %yste#.out."rintln-s=l.< try @ state#ent.e6ecuteY"!ate-s=l.< A catch-%/LE6ce"tion s=lE6. @ %yste#.err."rintln-8$nsert faile!.8.< :hile -s=lE6 4? null. @ %yste#.err."rintln-s=lE6.to%tring-..< s=lE6 ? s=lE6.get&e6tE6ce"tion-.< A A A "ublic voi! loa!-. @ for-int i ? '< iP tset.!ata.length< iKK.
;:1
e6ecute$nsert-tset.!ataNiO.< A // Thro: e6ce"tions out to console3 "ublic static voi! #ain-%tringNO args. thro:s %/LE6ce"tion @ Loa!DB !b ? ne: Loa!DB-ne: Test%et-..< !b.loa!-.< try @ // aet a 5esult%et fro# the loa!e! !atabase3 5esult%et rs ? !b.state#ent.e6ecute/uery8select 8 K 8e.EWTbT$TLE, #.JEJbL&0JE, #.JEJbL&0JE 8K 8fro# EWE&T% e, JEJBE5% #, EWTJEJ% e# 8 K 8:here e#.EWTb$D ? 8 K 8an! e.EWTb$D ? e#.EWTb$D 8 K 8an! #.JEJb$D ? e#.JEJb$D8.< :hile -rs.ne6t-.. %yste#.out."rintlnrs.get%tring-(. K 8 8 K rs.get%tring- . K 8, 8 K rs.get%tring-)..< A finally @ !b.cleanu"-.< A A A ///3>
The Test)et class contains a de"ault set o" data that is %roduced i" you use the de"ault constructor; however, you can also create a Test)et ob0ect using an alternate data set with the second constructor. The set o" data is held in a two'di#ensional array o" .b8ect because it can be any ty%e, including )tring or nu#erical ty%es. The e4ec*teInsertA B #ethod uses 5TTI to distinguish between )tring data *which #ust be Auoted, and non' )tring data as it builds the SeD co##and "ro# the data. 6"ter %rinting this co##and to the console, e4ec*teUp'ateA B is used to send it to the database. RFSURFSTIJLT+(6PTE5MHTIM@IU The constructor "or +oa' 2 #akes the connection, and loa'A B ste%s through the data and calls e4ec*teInsertA B "or each record. clean*pA B closes the state#ent and the connection; to guarantee that this is called, it is %laced inside a "inally clause. RFSURFSTIJLT+(6PTE5MHTIM@2U
;:2
Thinking in Java
,,,'0ruceEckel'com
)nce the database is loaded, an e4ec*te3*eryA B state#ent %roduces a sa#%le result set. Since the Auery co#bines several tables, it is an e&a#%le o" a 0oin. RFSURFSTIJLT+(6PTE5MHTIMM@U There is #ore J7B+ in"or#ation available in the electronic docu#ents that co#e as %art o" the Java distribution "ro# Sun. In addition, you can "ind #ore in the book J%0C %atabase "ccess ,ith Java *(a#ilton, +attel, and Eisher, 6ddison':esley, M22G,. )ther J7B+ books a%%ear regularly. RFSURFSTIJLT+(6PTE5MHTIMMMU
1ervlets
+lient access "ro# the Internet or cor%orate intranets is a sure way to allow #any users to access data and resources easily @. This ty%e o" access is based on clients using the :orld :ide :eb standards o" (y%erte&t Marku% Danguage *(TMD, and (y%erte&t Trans"er Protocol *(TTP,. The Servlet 6PI set abstracts a co##on solution "ra#ework "or res%onding to (TTP reAuests. RFSURFSTIJLT+(6PTE5MHTIMMKU Traditionally, the way to handle a %roble# such as allowing an Internet client to u%date a database is to create an (TMD %age with te&t "ields and a !sub#it$ button. The user ty%es the a%%ro%riate in"or#ation into the te&t "ields and %resses the !sub#it$ button. The data is sub#itted along with a 45D that tells the server what to do with the data by s%eci"ying the location o" a +o##on 8ateway Inter"ace *+8I, %rogra# that the server runs, %roviding the %rogra# with the data as it is invoked. The +8I %rogra# is ty%ically written in Perl, Python, +, +<<, or any language that can read "ro# standard in%ut and write to standard out%ut. That s all that is %rovided by the :eb server= the +8I %rogra# is invoked, and standard strea#s *or, o%tionally "or in%ut, an environ#ent variable, are used "or in%ut and out%ut. The +8I %rogra# is res%onsible "or everything else. Eirst it looks at the data and decides whether the "or#at is correct. I" not, the +8I %rogra# #ust %roduce (TMD to describe the %roble#; this %age is handed to the :eb server *via standard out%ut "ro# the +8I %rogra#,, which sends it back to the user. The user #ust usually back u% a %age and try again. I" the data is correct, the +8I %rogra# %rocesses the data in an
@ 7ave Bartlett was instru#ental in the develo%#ent o" this #aterial, and also the JSP section.
;:3
a%%ro%riate way, %erha%s adding it to a database. It #ust then %roduce an a%%ro%riate (TMD %age "or the :eb server to return to the user. RFSURF STIJLT+(6PTE5MHTIMMLU It would be ideal to go to a co#%letely Java'based solution to this %roble#9an a%%let on the client side to validate and send the data, and a servlet on the server side to receive and %rocess the data. 4n"ortunately, although a%%lets are a %roven technology with %lenty o" su%%ort, they have been %roble#atic to use on the :eb because you cannot rely on a %articular version o" Java being available on a client s :eb browser; in "act, you can t rely on a :eb browser su%%orting Java at all. In an intranet, you can reAuire that certain su%%ort be available, which allows a lot #ore "le&ibility in what you can do, but on the :eb the sa"est a%%roach is to handle all the %rocessing on the server side and deliver %lain (TMD to the client. That way, no client will be denied the use o" your site because they do not have the %ro%er so"tware installed. RFSURF STIJLT+(6PTE5MHTIMM?U Because servlets %rovide an e&cellent solution "or server'side %rogra##ing su%%ort, they are one o" the #ost %o%ular reasons "or #oving to Java. Cot only do they %rovide a "ra#ework that re%laces +8I %rogra##ing *and eli#inates a nu#ber o" thorny +8I %roble#s,, but all your code has the %lat"or# %ortability gained "ro# using Java, and you have access to all the Java 6PIs *e&ce%t, o" course, the ones that %roduce 84Is, like Swing,. RFSURFSTIJLT+(6PTE5MHTIMMHU
"ublic interface %ervlet @ "ublic voi! init-%ervletConfig config. thro:s %ervletE6ce"tion< "ublic %ervletConfig get%ervletConfig-.< "ublic voi! service-%ervlet5e=uest re=,
;:4
Thinking in Java
,,,'0ruceEckel'com
%ervlet5es"onse res. thro:s %ervletE6ce"tion, $GE6ce"tion< "ublic %tring get%ervlet$nfo-.< "ublic voi! !estroy-.< A get)ervlet-onfigA B s sole %ur%ose is to return a )ervlet-onfig ob0ect that contains initiali1ation and startu% %ara#eters "or this servlet. get)ervletInfoA B returns a string containing in"or#ation about the servlet, such as author, version, and co%yright. RFSURF STIJLT+(6PTE5MHTIMMGU
The "eneric)ervlet class is a shell i#%le#entation o" this inter"ace and is ty%ically not used. The Http)ervlet class is an e&tension o" "eneric)ervlet and is designed s%eci"ically to handle the (TTP %rotocol9 Http)ervlet is the one that you ll use #ost o" the ti#e. RF SURFSTIJLT+(6PTE5MHTIMMIU The #ost convenient attribute o" the servlet 6PI is the au&iliary ob0ects that co#e along with the (tt%Servlet class to su%%ort it. I" you look at the serviceA B #ethod in the )ervlet inter"ace, you ll see it has two %ara#eters= )ervlet$eC*est and )ervlet$esponse. :ith the Http)ervlet class these two ob0ect are e&tended "or (TTP= Http)ervlet$eC*est and Http)ervlet$esponse. (ere s a si#%le e&a#%le that shows the use o" Http)ervlet$esponse=
//3 c(,3servlets3%ervlets5ule.Hava i#"ort Hava6.servlet.B< i#"ort Hava6.servlet.htt".B< i#"ort Hava.io.B< "ublic class %ervlets5ule e6ten!s Mtt"%ervlet @ int i ? '< // %ervlet 8"ersistence8 "ublic voi! service-Mtt"%ervlet5e=uest re=, Mtt"%ervlet5es"onse res. thro:s $GE6ce"tion @ res.setContentTy"e-8te6t/ht#l8.< Print\riter out ? res.get\riter-.< out."rint-8PME0DQPT$TLEQ8.< out."rint-80 server-si!e strategy8.< out."rint-8P/T$TLEQP/ME0DQPBGD;Q8.< out."rint-8Ph(Q%ervlets 5ule4 8 K iKK.<
;:5
out."rint-8P/h(QP/BGD;Q8.< out.close-.< A A ///3> )ervlets$*le is about as si#%le as a servlet can get. The servlet is initiali1ed only once by calling its initA B #ethod, on loading the servlet
a"ter the servlet container is "irst booted u%. :hen a client #akes a reAuest to a 45D that ha%%ens to re%resent a servlet, the servlet container interce%ts this reAuest and #akes a call to the serviceA B #ethod, a"ter setting u% the Http)ervlet$eC*est and Http)ervlet$esponse ob0ects. RFSURFSTIJLT+(6PTE5MHTIMM2U The #ain res%onsibility o" the serviceA B #ethod is to interact with the (TTP reAuest that the client has sent, and to build an (TTP res%onse based on the attributes contained within the reAuest. )ervlets$*le only #ani%ulates the res%onse ob0ect without looking at what the client #ay have sent. RFSURFSTIJLT+(6PTE5MHTIMK@U 6"ter setting the content ty%e o" the res%onse *which #ust always be done be"ore the 0riter or .*tp*t)tream is %rocured,, the get0riterA B #ethod o" the res%onse ob0ect %roduces a #rint0riter ob0ect, which is used "or writing character'based res%onse data *alternatively, get.*tp*t)treamA B %roduces an .*tp*t)tream, used "or binary res%onse, which is only utili1ed in #ore s%eciali1ed solutions,. RFSURF STIJLT+(6PTE5MHTIMKMU The rest o" the %rogra# si#%ly sends (TMD back to the client *it s assu#ed you understand (TMD, so that %art is not e&%lained, as a seAuence o" )trings. (owever, notice the inclusion o" the !hit counter$ re%resented by the variable i. This is auto#atically converted to a )tring in the printA B state#ent. RFSURFSTIJLT+(6PTE5MHTIMKKU :hen you run the %rogra#, you ll notice that the value o" i is retained between reAuests to the servlet. This is an essential %ro%erty o" servlets= since only one servlet o" a %articular class is loaded into the container, and it is never unloaded *unless the servlet container is ter#inated, which is so#ething that only nor#ally ha%%ens i" you reboot the server co#%uter,, any "ields o" that servlet class e""ectively beco#e %ersistent ob0ects. This #eans that you can e""ortlessly #aintain values between
;:7
Thinking in Java
,,,'0ruceEckel'com
servlet reAuests, whereas with +8I you had to write values to disk in order to %reserve the#, which reAuired a "air a#ount o" "ooling around to get it right, and resulted in a non'cross'%lat"or# solution. RFSURF STIJLT+(6PTE5MHTIMKLU )" course, so#eti#es the :eb server, and thus the servlet container, #ust be rebooted as %art o" #aintenance or during a %ower "ailure. To avoid losing any %ersistent in"or#ation, the servlet s initA B and 'estroy A B #ethods are auto#atically called whenever the servlet is loaded or unloaded, giving you the o%%ortunity to save data during shutdown, and restore it a"ter rebooting. The servlet container calls the 'estroyA B #ethod as it is ter#inating itsel", so you always get an o%%ortunity to save valuable data as long as the server #achine is con"igured in an intelligent way. RFSURFSTIJLT+(6PTE5MHTIMK?U There s one other issue when using Http)ervlet. This class %rovides 'o"etA B and 'o#ostA B #ethods that di""erentiate between a +8I !8ET$ sub#ission "ro# the client, and a +8I !P)ST.$ 8ET and P)ST vary only in the details o" the way that they sub#it the data, which is so#ething that I %ersonally would %re"er to ignore. (owever, #ost %ublished in"or#ation that I ve seen see#s to "avor the creation o" se%arate 'o"et A B and 'o#ostA B #ethods instead o" a single generic serviceA B #ethod, which handles both cases. This "avoritis# see#s Auite co##on, but I ve never seen it e&%lained in a "ashion that leads #e to believe that it s anything #ore than inertia "ro# +8I %rogra##ers who are used to %aying attention to whether a 8ET or P)ST is being used. So in the s%irit o" !doing the si#%lest thing that could %ossibly work,$ @ I will 0ust use the serviceA B #ethod in these e&a#%les, and let it care about 8ETs vs. P)STs. (owever, kee% in #ind that I #ight have #issed so#ething and so there #ay in "act be a good reason to use 'o"etA B and 'o#ostA B instead. RFSURFSTIJLT+(6PTE5MHTIMKHU :henever a "or# is sub#itted to a servlet, the Http)ervlet$eC*est co#es %reloaded with all the "or# data, stored as key'value %airs. I" you know the na#es o" the "ields, you can 0ust use the# directly with the get#arameterA B #ethod to look u% the values. /ou can also get an &n*meration *the old "or# o" the Iterator, to the "ield na#es, as is shown in the "ollowing e&a#%le. This e&a#%le also de#onstrates how a
@ 6 %ri#ary tenet o" E&tre#e Progra##ing *ZP,. See ,,,'* rogramming'com.
;:8
single servlet can be used to %roduce the %age that contains the "or#, and to res%ond to the %age *a better solution will be seen later, with JSPs,. I" the &n*meration is e#%ty, there are no "ields; this #eans no "or# was sub#itted. In this case, the "or# is %roduced, and the sub#it button will re'call the sa#e servlet. I" "ields do e&ist, however, they are dis%layed.
//3 c(,3servlets3EchoLor#.Hava // Du#"s the na#e-value "airs of any MTJL for# i#"ort Hava6.servlet.B< i#"ort Hava6.servlet.htt".B< i#"ort Hava.io.B< i#"ort Hava.util.B< "ublic class EchoLor# e6ten!s Mtt"%ervlet @ "ublic voi! service-Mtt"%ervlet5e=uest re=, Mtt"%ervlet5es"onse res. thro:s $GE6ce"tion @ res.setContentTy"e-8te6t/ht#l8.< Print\riter out ? res.get\riter-.< Enu#eration fl!s ? re=.getPara#eter&a#es-.< if-4fl!s.hasJoreEle#ents-.. @ // &o for# sub#itte! -- create one3 out."rint-8Pht#lQ8.< out."rint-8Pfor# #etho!?_8PG%T_88 K 8 action?_8EchoLor#_8Q8.< for-int i ? '< i P ('< iKK. out."rint-8PbQLiel!8 K i K 8P/bQ 8 K 8Pin"ut ty"e?_8te6t_88K 8 siUe?_8 '_8 na#e?_8Liel!8 K i K 8_8 value?_8Walue8 K i K 8_8QPbrQ8.< out."rint-8P$&PYT T;PE?sub#it na#e?sub#it8K 8 Walue?_8%ub#it_8QP/for#QP/ht#lQ8.< A else @ out."rint-8Ph(Q;our for# containe!3P/h(Q8.< :hile-fl!s.hasJoreEle#ents-.. @ %tring fiel!? -%tring.fl!s.ne6tEle#ent-.< %tring value? re=.getPara#eter-fiel!.< out."rint-fiel! K 8 ? 8 K valueK 8PbrQ8.< A A out.close-.< A
;::
Thinking in Java
,,,'0ruceEckel'com
A ///3>
)ne drawback you ll notice here is that Java does not see# to be designed with string %rocessing in #ind9the "or#atting o" the return %age is %ain"ul because o" line breaks, esca%ing Auote #arks, and the !<$ signs necessary to build )tring ob0ects. :ith a larger (TMD %age it beco#es unreasonable to code it directly into Java. )ne solution is to kee% the %age as a se%arate te&t "ile, then o%en it and hand it to the :eb server. I" you have to %er"or# any kind o" substitution to the contents o" the %age, it s not #uch better since Java has treated string %rocessing so %oorly. In these cases you re %robably better o"" using a #ore a%%ro%riate solution *Python would be #y choice; there s a version that e#beds itsel" in Java called JPython, to generate the res%onse %age. RFSURF STIJLT+(6PTE5MHTIMK3U
//3 c(,3servlets3Threa!%ervlet.Hava i#"ort Hava6.servlet.B< i#"ort Hava6.servlet.htt".B< i#"ort Hava.io.B< "ublic class Threa!%ervlet e6ten!s Mtt"%ervlet @ int i< "ublic voi! service-Mtt"%ervlet5e=uest re=, Mtt"%ervlet5es"onse res. thro:s $GE6ce"tion @ res.setContentTy"e-8te6t/ht#l8.<
;:;
Print\riter out ? res.get\riter-.< synchroniUe!-this. @ try @ Threa!.currentThrea!-..slee"-,'''.< A catch-$nterru"te!E6ce"tion e. @ %yste#.err."rintln-8$nterru"te!8.< A A out."rint-8Ph(QLinishe! 8 K iKK K 8P/h(Q8.< out.close-.< A A ///3>
It is also %ossible to synchroni1e the entire servlet by %utting the synchroni7e' keyword in "ront o" the serviceA B #ethod. In "act, the only reason to use the synchroni7e' clause instead is i" the critical section is in an e&ecution %ath that #ight not get e&ecuted. In that case, you #ight as well avoid the overhead o" synchroni1ing every ti#e by using a synchroni7e' clause. )therwise, all the threads will have to wait anyway so you #ight as well synchroni7e the whole #ethod. RFSURF STIJLT+(6PTE5MHTIMKIU
;;=
Thinking in Java
,,,'0ruceEckel'com
6 cookie is nothing #ore than a s#all %iece o" in"or#ation sent by a :eb server to a browser. The browser stores the cookie on the local disk, and whenever another call is #ade to the 45D that the cookie is associated with, the cookie is Auietly sent along with the call, thus %roviding the desired in"or#ation back to that server *generally, %roviding so#e way that the server can be told that it s you calling,. +lients can, however, turn o"" the browser s ability to acce%t cookies. I" your site #ust track a client who has turned o"" cookies, then another #ethod o" session tracking *45D rewriting or hidden "or# "ields, #ust be incor%orated by hand, since the session tracking ca%abilities built into the servlet 6PI are designed around cookies. RFSURFSTIJLT+(6PTE5MHTIMLMU
;;1
knowledge o" %revious connections or ite#s in the sho%%ing cart. To co#%ensate "or this lack o" in"or#ation, the #echanics su%%lied by the cookie s%eci"ication allow your servlet to %er"or# session tracking. RF SURFSTIJLT+(6PTE5MHTIMLLU 6 servlet )ession ob0ect lives on the server side o" the co##unication channel; its goal is to ca%ture use"ul data about this client as the client #oves through and interacts with your :eb site. This data #ay be %ertinent "or the %resent session, such as ite#s in the sho%%ing cart, or it #ay be data such as authentication in"or#ation that was entered when the client "irst entered your :eb site, and which should not have to be reentered during a %articular set o" transactions. RFSURF STIJLT+(6PTE5MHTIML?U The )ession class o" the servlet 6PI uses the -ookie class to do its work. (owever, all the )ession ob0ect needs is so#e kind o" uniAue identi"ier stored on the client and %assed to the server. :eb sites #ay also use the other ty%es o" session tracking but these #echanis#s will be #ore di""icult to i#%le#ent as they are not enca%sulated into the servlet 6PI *that is, you #ust write the# by hand to deal with the situation when the client has disabled cookies,. RFSURFSTIJLT+(6PTE5MHTIMLHU (ere s an e&a#%le that i#%le#ents session tracking with the servlet 6PI=
//3 c(,3servlets3%essionPeek.Hava // Ysing the Mtt"%ession class. i#"ort Hava.io.B< i#"ort Hava.util.B< i#"ort Hava6.servlet.B< i#"ort Hava6.servlet.htt".B< "ublic class %essionPeek e6ten!s Mtt"%ervlet @ "ublic voi! service-Mtt"%ervlet5e=uest re=, Mtt"%ervlet5es"onse res. thro:s %ervletE6ce"tion, $GE6ce"tion @ // 5etrieve %ession GbHect before any // out"ut is sent to the client. Mtt"%ession session ? re=.get%ession-.< res.setContentTy"e-8te6t/ht#l8.< Print\riter out ? res.get\riter-.< out."rintln-8PME0DQPT$TLEQ %essionPeek 8.<
;;2
Thinking in Java
,,,'0ruceEckel'com
out."rintln-8 P/T$TLEQP/ME0DQPBGD;Q8.< out."rintln-8Ph(Q %essionPeek P/h(Q8.< // 0 si#"le hit counter for this session. $nteger ival ? -$nteger. session.get0ttribute-8sess"eek.cntr8.< if-ival??null. ival ? ne: $nteger-(.< else ival ? ne: $nteger-ival.intWalue-. K (.< session.set0ttribute-8sess"eek.cntr8, ival.< out."rintln-8;ou have hit this "age PbQ8 K ival K 8P/bQ ti#es.P"Q8.< out."rintln-8Ph Q8.< out."rintln-8%ave! %ession Data P/h Q8.< // Loo" through all !ata in the session3 Enu#eration ses&a#es ? session.get0ttribute&a#es-.< :hile-ses&a#es.hasJoreEle#ents-.. @ %tring na#e ? ses&a#es.ne6tEle#ent-..to%tring-.< GbHect value ? session.get0ttribute-na#e.< out."rintln-na#e K 8 ? 8 K value K 8PbrQ8.< A out."rintln-8Ph)Q %ession %tatistics P/h)Q8.< out."rintln-8%ession $D3 8 K session.get$!-. K 8PbrQ8.< out."rintln-8&e: %ession3 8 K session.is&e:-. K 8PbrQ8.< out."rintln-8Creation Ti#e3 8 K session.getCreationTi#e-..< out."rintln-8P$Q-8 K ne: Date-session.getCreationTi#e-.. K 8.P/$QPbrQ8.< out."rintln-8Last 0ccesse! Ti#e3 8 K session.getLast0ccesse!Ti#e-..< out."rintln-8P$Q-8 K ne: Date-session.getLast0ccesse!Ti#e-.. K 8.P/$QPbrQ8.< out."rintln-8%ession $nactive $nterval3 8 K session.getJa6$nactive$nterval-..< out."rintln-8%ession $D in 5e=uest3 8
;;3
K re=.get5e=ueste!%ession$!-. K 8PbrQ8.< out."rintln-8$s session i! fro# Cookie3 8 K re=.is5e=ueste!%ession$!Lro#Cookie-. K 8PbrQ8.< out."rintln-8$s session i! fro# Y5L3 8 K re=.is5e=ueste!%ession$!Lro#Y5L-. K 8PbrQ8.< out."rintln-8$s session i! vali!3 8 K re=.is5e=ueste!%ession$!Wali!-. K 8PbrQ8.< out."rintln-8P/BGD;Q8.< out.close-.< A "ublic %tring get%ervlet$nfo-. @ return 80 session tracking servlet8< A A ///3>
Inside the serviceA B #ethod, get)essionA B is called "or the reAuest ob0ect, which returns the )ession ob0ect associated with this reAuest. The )ession ob0ect does not travel across the network, but instead it lives on the server and is associated with a client and its reAuests. RFSURF STIJLT+(6PTE5MHTIML3U
get)essionA B co#es in two versions= no %ara#eter, as used here, and get)essionAbooleanB. get)essionAtr*eB is eAuivalent to get)ession A B. The only reason "or the boolean is to state whether you want the session ob0ect created i" it is not "ound. get)essionAtr*eB is the #ost likely call, hence get)essionA B. RFSURFSTIJLT+(6PTE5MHTIMLGU
The )ession ob0ect, i" it is not new, will give us details about the client "ro# %revious visits. I" the )ession ob0ect is new then the %rogra# will start to gather in"or#ation about this client s activities on this visit. +a%turing this client in"or#ation is done through the setAttrib*teA B and getAttrib*teA B #ethods o" the session ob0ect. RFSURF STIJLT+(6PTE5MHTIMLIU
;;4
Thinking in Java
,,,'0ruceEckel'com
The )ession ob0ect uses a si#%le na#e'value %airing "or loading in"or#ation. The na#e is a )tring, and the value can be any ob0ect derived "ro# 8ava!lang!.b8ect. )ession#eek kee%s track o" how #any ti#es the client has been back during this session. This is done with an Integer ob0ect na#ed sesspeek!cntr. I" the na#e is not "ound an Integer is created with value o" one, otherwise an Integer is created with the incre#ented value o" the %reviously held Integer. The new Integer is %laced into the )ession ob0ect. I" you use sa#e key in a setAttrib*teA B call, then the new ob0ect overwrites the old one. The incre#ented counter is used to dis%lay the nu#ber o" ti#es that the client has visited during this session. RFSURFSTIJLT+(6PTE5MHTIML2U
getAttrib*te/amesA B is related to getAttrib*teA B and setAttrib*te A B; it returns an enu#eration o" the na#es o" the ob0ects that are bound to the )ession ob0ect. 6 (hile loo% in )ession#eek shows this #ethod
in action. RFSURFSTIJLT+(6PTE5MHTIM?@U /ou #ay wonder how long a )ession ob0ect hangs around. The answer de%ends on the servlet container you are using; they usually de"ault to L@ #inutes *MI@@ seconds,, which is what you should see "ro# the )ervlet#eek call to get1a4InactiveIntervalA B. Tests see# to %roduce #i&ed results between servlet containers. So#eti#es the )ession ob0ect can hang around overnight, but I have never seen a case where the )ession ob0ect disa%%ears in less than the ti#e s%eci"ied by the inactive interval. /ou can try this by setting the inactive interval with set1a4InactiveIntervalA B to H seconds and see i" your )ession ob0ect hangs around or i" it is cleaned u% at the a%%ro%riate ti#e. This #ay be an attribute you will want to investigate while choosing a servlet container. RFSURFSTIJLT+(6PTE5MHTIM?MU
;;5
Eollow the instructions "or installing the To#cat i#%le#entation, then edit the server!4ml "ile to %oint to the location in your directory tree where your servlets will be %laced. )nce you start u% the To#cat %rogra# you can test your servlet %rogra#s. RFSURFSTIJLT+(6PTE5MHTIM?LU This has only been a brie" introduction to servlets; there are entire books on the sub0ect. (owever, this introduction should give you enough ideas to get you started. In addition, #any o" the ideas in the ne&t section are backward co#%atible with servlets. RFSURFSTIJLT+(6PTE5MHTIM??U
;;7
Thinking in Java
,,,'0ruceEckel'com
Ero# then on, as long as the JSP source "or the %age is not #odi"ied, it behaves as i" it were a static (TMD %age with associated servlets *all the (TMD code is actually generated by the servlet, however,. I" you #odi"y the source code "or the JSP, it is auto#atically reco#%iled and reloaded the ne&t ti#e that %age is reAuested. )" course, because o" all this dyna#is# you ll see a slow res%onse "or the "irst'ti#e access to a JSP. (owever, since a JSP is usually used #uch #ore than it is changed, you will nor#ally not be a""ected by this delay. RFSURF STIJLT+(6PTE5MHTIM?2U The structure o" a JSP %age is a cross between a servlet and an (TMD %age. The JSP tags begin and end with angle brackets, 0ust like (TMD tags, but the tags also include %ercent signs, so all JSP tags are denoted by
//34 c(,3Hs"3%ho:%econ!s.Hs" Pht#lQPbo!yQ PM(QThe ti#e in secon!s is3 PV? %yste#.currentTi#eJillis-./(''' VQP/M(Q P/bo!yQP/ht#lQ ///3>
In the JSP e&a#%les in this book, the "irst and last lines are not included in the actual code "ile that is e&tracted and %laced in the book s source' code tree. RFSURFSTIJLT+(6PTE5MHTIMHMU :hen the client creates a reAuest "or the JSP %age, the :eb server #ust have been con"igured to relay the reAuest to the JSP container, which then invokes the %age. 6s #entioned above, the "irst ti#e the %age is invoked, the co#%onents s%eci"ied by the %age are generated and
;;8
co#%iled by the JSP container as one or #ore servlets. In the above e&a#%le, the servlet will contain code to con"igure the Http)ervlet$esponse ob0ect, %roduce a #rint0riter ob0ect *which is always na#ed o*t,, and then turn the ti#e calculation into a )tring which is sent to o*t. 6s you can see, all this is acco#%lished with a very succinct state#ent, but the average (TMD %rogra##erF:eb designer will not have the skills to write such code. RFSURF STIJLT+(6PTE5MHTIMHKU
Im.licit ob3ects
Servlets include classes that %rovide convenient utilities, such as Http)ervlet$eC*est, Http)ervlet$esponse, )ession, etc. )b0ects o" these classes are built into the JSP s%eci"ication and auto#atically available "or use in your JSP without writing any e&tra lines o" code. The i#%licit ob0ects in a JSP are detailed in the table below.
Implicit variable reC*est .f Type A8ava4! servletB %rotocol de%endent subty%e o" Http)ervlet$eC*est %rotocol de%endent subty%e o" Http)ervlet$espons e 8sp!#age-onte4t escription The reAuest that triggers the service invocation. The res%onse to the reAuest. )cope reAuest
response
%age
page-onte 4t
session
The %age conte&t enca%sulates i#%le#entation' de%endent "eatures and %rovides convenience #ethods and na#es%ace access "or this JSP. The session ob0ect created "or the reAuesting client. See servlet Session ob0ect.
%age
session
;;:
Thinking in Java
,,,'0ruceEckel'com
application
)ervlet-onte4t
o*t
8sp!Jsp0riter
config page
)ervlet-onfig 8ava!lang!.b8ect
The servlet conte&t obtained "ro# the servlet con"iguration ob0ect *e.g., get)ervlet-onfigAB, get-onte4tA B. The ob0ect that writes into the out%ut strea#. The )ervlet-onfig "or this JSP. The instance o" this %age s i#%le#entation class %rocessing the current reAuest.
a%%
%age
%age %age
The sco%e o" each ob0ect can vary signi"icantly. Eor e&a#%le, the session ob0ect has a sco%e which e&ceeds that o" a %age, as it #any s%an several client reAuests and %ages. The application ob0ect can %rovide services to a grou% o" JSP %ages that together re%resent a :eb a%%lication.
"1 directives
7irectives are #essages to the JSP container and are denoted by the ! 9$= RFSURFSTIJLT+(6PTE5MHTIMHLU
;;;
es%ecially the i#%licit variables de"ined above, JavaBeans %ro%erties, and %ublic #ethods. RFSURFSTIJLT+(6PTE5MHTIMHHU The #ost i#%ortant directive is the %age directive. It de"ines a nu#ber o" %age de%endent attributes and co##unicates these attributes to the JSP container. These attributes include= lang*age, e4ten's, import, session, b*ffer, a*toFl*sh, isThrea')afe, info and error#age. Eor e&a#%le=
1===
Thinking in Java
,,,'0ruceEckel'com
:hite s%ace is o%tional a"ter !R^.$, !R^$, !R^\$, and be"ore !^U.$ RF SURFSTIJLT+(6PTE5MHTIMHIU 6ll these tags are based u%on ZMD; you could even say that a JSP %age can be #a%%ed to a ZMD docu#ent. The ZMD eAuivalent synta& "or the scri%ting ele#ents above would be=
//34 c(,3Hs"3Mello.Hs" PV-- This J%P co##ent :ill not a""ear in the generate! ht#l --VQ PV-- This is a J%P !irective3 --VQ PVR "age i#"ort?8Hava.util.B8 VQ PV-- These are !eclarations3 --VQ PV4 long loa!Ti#e? %yste#.currentTi#eJillis-.< Date loa!Date ? ne: Date-.< int hitCount ? '< VQ
1==1
Pht#lQPbo!yQ PV-- The ne6t several lines are the result of a J%P e6"ression inserte! in the generate! ht#l< the 2?2 in!icates a J%P e6"ression --VQ PM(QThis "age :as loa!e! at PV? loa!Date VQ P/M(Q PM(QMello, :orl!4 $t2s PV? ne: Date-. VQP/M(Q PM QMere2s an obHect3 PV? ne: GbHect-. VQP/M Q PM QThis "age has been u" PV? -%yste#.currentTi#eJillis-.-loa!Ti#e./(''' VQ secon!sP/M Q PM)QPage has been accesse! PV? KKhitCount VQ ti#es since PV? loa!Date VQP/M)Q PV-- 0 8scri"tlet8 that :rites to the server console an! to the client "age. &ote that the 2<2 is re=uire!3 --VQ PV %yste#.out."rintln-8aoo!bye8.< out."rintln-8Cheerio8.< VQ P/bo!yQP/ht#lQ ///3>
:hen you run this %rogra# you ll see that the variables loa'Time, loa' ate and hit-o*nt hold their values between hits to the %age, so they are clearly "ields and not local variables. RFSURF STIJLT+(6PTE5MHTIM3@U 6t the end o" the e&a#%le is a scri%tlet that writes !8oodbye$ to the :eb server console and !+heerio$ to the i#%licit Jsp0riter ob0ect o*t. Scri%tlets can contain any code "rag#ents that are valid Java state#ents. Scri%tlets are e&ecuted at reAuest'%rocessing ti#e. :hen all the scri%tlet "rag#ents in a given JSP are co#bined in the order they a%%ear in the JSP %age, they should yield a valid state#ent as de"ined by the Java %rogra##ing language. :hether or not they %roduce any out%ut into the o*t strea# de%ends u%on the code in the scri%tlet. /ou should be aware that scri%tlets can %roduce side e""ects by #odi"ying the ob0ects that are visible to the#. RFSURFSTIJLT+(6PTE5MHTIM3MU JSP e&%ressions can "ound inter#ingled with the (TMD in the #iddle section o" Hello!8sp. E&%ressions #ust be co#%lete Java state#ents, which are evaluated, coerced to a )tring, and sent to o*t. I" the result o"
1==2
Thinking in Java
,,,'0ruceEckel'com
//34 c(,3Hs"3Dis"layLor#Data.Hs" PV-- Letching the !ata fro# an MTJL for#. --VQ PV-- This J%P also generates the for#. --VQ PVR "age i#"ort?8Hava.util.B8 VQ Pht#lQPbo!yQ PM(QDis"layLor#DataP/M(QPM)Q PV Enu#eration fl!s ? re=uest.getPara#eter&a#es-.< if-4fl!s.hasJoreEle#ents-.. @ // &o fiel!s VQ Pfor# #etho!?8PG%T8 action?8Dis"layLor#Data.Hs"8Q PV for-int i ? '< i P ('< iKK. @ VQ Liel!PV?iVQ3 Pin"ut ty"e?8te6t8 siUe?8 '8 na#e?8Liel!PV?iVQ8 value?8WaluePV?iVQ8QPbrQ PV A VQ P$&PYT T;PE?sub#it na#e?sub#it value?8%ub#it8QP/for#Q PVA else @ :hile-fl!s.hasJoreEle#ents-.. @ %tring fiel! ? -%tring.fl!s.ne6tEle#ent-.< %tring value ? re=uest.getPara#eter-fiel!.< VQ PliQPV? fiel! VQ ? PV? value VQP/liQ PV A A VQ P/M)QP/bo!yQP/ht#lQ
1==3
///3>
The #ost interesting "eature o" this e&a#%le is that it de#onstrates how scri%tlet code can be inter#i&ed with (TMD code, even to the %oint o" generating (TMD within a Java for loo%. This is es%ecially convenient "or building any kind o" "or# where re%etitive (TMD code would otherwise be reAuired. RFSURFSTIJLT+(6PTE5MHTIM3LU
//34 c(,3Hs"3PageConte6t.Hs" PV--Wie:ing the attributes in the "ageConte6t--VQ PV-- &ote that you can inclu!e any a#ount of co!e insi!e the scri"tlet tags --VQ PVR "age i#"ort?8Hava.util.B8 VQ Pht#lQPbo!yQ %ervlet &a#e3 PV? config.get%ervlet&a#e-. VQPbrQ %ervlet container su""orts servlet version3 PV out."rint-a""lication.getJaHorWersion-. K 8.8 K a""lication.getJinorWersion-..< VQPbrQ PV session.set0ttribute-8Jy !og8, 85al"h8.< for-int sco"e ? (< sco"e P? I< sco"eKK. @ VQ PM)Q%co"e3 PV? sco"e VQ P/M)Q PV Enu#eration e ? "ageConte6t.get0ttribute&a#es$n%co"e-sco"e.< :hile-e.hasJoreEle#ents-.. @ out."rintln-8_tPliQ8 K e.ne6tEle#ent-. K 8P/liQ8.< A A VQ P/bo!yQP/ht#lQ ///3>
1==4
Thinking in Java
,,,'0ruceEckel'com
This e&a#%le also shows the use o" both e#bedded (TMD and writing to
//34 c(,3Hs"3%essionGbHect.Hs" PV--aetting an! setting session obHect values--VQ Pht#lQPbo!yQ PM(Q%ession i!3 PV? session.get$!-. VQP/M(Q PM)QPliQThis session :as create! at PV? session.getCreationTi#e-. VQP/liQP/M(Q PM)QPliQGl! Ja6$nactive$nterval ? PV? session.getJa6$nactive$nterval-. VQP/liQ PV session.setJa6$nactive$nterval-,.< VQ PliQ&e: Ja6$nactive$nterval? PV? session.getJa6$nactive$nterval-. VQP/liQ
1==5
P/M)Q PM Q$f the session obHect 8Jy !og8 is still aroun!, this value :ill be non-null3PM Q PM)QPliQ%ession value for 8Jy !og8 ? PV? session.get0ttribute-8Jy !og8. VQP/liQP/M)Q PV-- &o: a!! the session obHect 8Jy !og8 --VQ PV session.set0ttribute-8Jy !og8, ne: %tring-85al"h8..< VQ PM(QJy !og2s na#e is PV? session.get0ttribute-8Jy !og8. VQP/M(Q PV-- %ee if 8Jy !og8 :an!ers to another for# --VQ PLG5J T;PE?PG%T 0CT$G&?%essionGbHect .Hs"Q P$&PYT T;PE?sub#it na#e?sub#it Walue?8$nvali!ate8QP/LG5JQ PLG5J T;PE?PG%T 0CT$G&?%essionGbHect).Hs"Q P$&PYT T;PE?sub#it na#e?sub#it Walue?8`ee" 0roun!8QP/LG5JQ P/bo!yQP/ht#lQ ///3>
The session ob0ect is %rovided by de"ault so it is available without any e&tra coding. The calls to getI A B, get-reationTimeA B and get1a4InactiveIntervalA B are used to dis%lay in"or#ation about this session ob0ect. RFSURFSTIJLT+(6PTE5MHTIM33U :hen you "irst bring u% this session you will see a 1a4InactiveInterval o", "or e&a#%le, MI@@ seconds *L@ #inutes,. This will de%end on the way your JSPFservlet container is con"igured. The 1a4InactiveInterval is shortened to H seconds to #ake things interesting. I" you re"resh the %age be"ore the H second interval e&%ires, then you ll see=
1==7
Thinking in Java
,,,'0ruceEckel'com
the !invalidate$ button in )ession.b8ect!8sp, reads the session in"or#ation and then e&%licitly invalidates that session=
//34 c(,3Hs"3%essionGbHect .Hs" PV--The session obHect carries through--VQ Pht#lQPbo!yQ PM(Q%ession i!3 PV? session.get$!-. VQP/M(Q PM(Q%ession value for 8Jy !og8 PV? session.getWalue-8Jy !og8. VQP/M(Q PV session.invali!ate-.< VQ P/bo!yQP/ht#lQ ///3>
To e&%eri#ent with this, re"resh )ession.b8ect!8sp, then i##ediately click the !invalidate$ button to bring you to )ession.b8ectI!8sp. 6t this %oint you will still see !5al%h,$ and right away *be"ore the H'second interval has e&%ired,, re"resh )ession.b8ectI!8sp to see that the session has been "orce"ully invalidated and !5al%h$ has disa%%eared. RFSURF STIJLT+(6PTE5MHTIM3IU I" you go back to )ession.b8ect!8sp, re"resh the %age so you have a new H'second interval, then %ress the !>ee% 6round$ button, it will take you to the "ollowing %age, )ession.b8ectJ!8sp, which does C)T invalidate the session=
//34 c(,3Hs"3%essionGbHect).Hs" PV--The session obHect carries through--VQ Pht#lQPbo!yQ PM(Q%ession i!3 PV? session.get$!-. VQP/M(Q PM(Q%ession value for 8Jy !og8 PV? session.getWalue-8Jy !og8. VQP/M(Q PLG5J T;PE?PG%T 0CT$G&?%essionGbHect.Hs"Q P$&PYT T;PE?sub#it na#e?sub#it Walue?85eturn8Q P/LG5JQ P/bo!yQP/ht#lQ ///3>
Because this %age doesn t invalidate the session, !5al%h$ will hang around as long as you kee% re"reshing the %age be"ore the H second ti#e interval e&%ires. This is not unlike a !To#agotchi$ %et9as long as you %lay with
1==8
1==:
Thinking in Java
,,,'0ruceEckel'com
6"ter dis%laying the session identi"ier, each cookie in the array o" cookies that co#es in with the reC*est ob0ect is dis%layed, along with its #a&i#u# age. The #a&i#u# age is changed and dis%layed again to veri"y the new value, then a new cookie is added to the res%onse. (owever, your browser #ay see# to ignore the #a&i#u# age; it s worth %laying with this %rogra# and #odi"ying the #a&i#u# age value to see the behavior under di""erent browsers. RFSURF STIJLT+(6PTE5MHTIMGMU
"1 summar:
This section has only been a brie" coverage o" JSPs, and yet even with what was covered here *along with the Java you ve learned in the rest o" the book, and your own knowledge o" (TMD, you can begin to write so%histicated web %ages via JSPs. The JSP synta& isn t #eant to be %articularly dee% or co#%licated, so i" you understand what was %resented in this section you re ready to be %roductive with JSPs. /ou can "ind "urther in"or#ation in #ost current books on servlets, or at >ava' sun'com. RFSURFSTIJLT+(6PTE5MHTIMGKU It s es%ecially nice to have JSPs available, even i" your goal is only to %roduce servlets. /ou ll discover that i" you have a Auestion about the behavior o" a servlet "eature, it s #uch easier and "aster to write a JSP test %rogra# to answer that Auestion than it is to write a servlet. Part o" the bene"it co#es "ro# having to write less code and being able to #i& the dis%lay (TMD in with the Java code, but the leverage beco#es es%ecially obvious when you see that the JSP +ontainer handles all the reco#%ilation and reloading o" the JSP "or you whenever the source is changed. RFSURFSTIJLT+(6PTE5MHTIMGLU 6s terri"ic as JSPs are, however, it s worth kee%ing in #ind that JSP creation reAuires a higher level o" skill than 0ust %rogra##ing in Java or 0ust creating :eb %ages. In addition, debugging a broken JSP %age is not as easy as debugging a Java %rogra#, as *currently, the error #essages are #ore obscure. This should change as develo%#ent syste#s i#%rove, but we #ay also see other technologies built on to% o" Java and the :eb that are better ada%ted to the skills o" the web site designer. RFSURF STIJLT+(6PTE5MHTIMG?U
1==;
$emote interfaces
5MI #akes heavy use o" inter"aces. :hen you want to create a re#ote ob0ect, you #ask the underlying i#%le#entation by %assing around an inter"ace. Thus, when the client gets a re"erence to a re#ote ob0ect, what they really get is an inter"ace re"erence, which ha ens to connect to so#e local stub code that talks across the network. But you don t think about this, you 0ust send #essages via your inter"ace re"erence. RFSURF STIJLT+(6PTE5MHTIMG3U :hen you create a re#ote inter"ace, you #ust "ollow these guidelines=
(4() The re#ote inter"ace #ust be p*blic *it cannot have !%ackage
access,$ that is, it cannot be !"riendly$,. )therwise, a client will get an error when atte#%ting to load a re#ote ob0ect that i#%le#ents the re#ote inter"ace.
(4!) The re#ote inter"ace #ust e&tend the inter"ace 8ava!rmi! $emote. (4*) Each #ethod in the re#ote inter"ace #ust declare 8ava!rmi! $emote&4ception in its thro(s clause in addition to any
a%%lication's%eci"ic e&ce%tions.
1=1=
Thinking in Java
,,,'0ruceEckel'com
//3 c(,3r#i3PerfectTi#e$.Hava // The PerfectTi#e re#ote interface. "ackage c(,.r#i< i#"ort Hava.r#i.B< "ublic interface PerfectTi#e$ e6ten!s 5e#ote @ long getPerfectTi#e-. thro:s 5e#oteE6ce"tion< A ///3>
It looks like any other inter"ace e&ce%t that it e&tends $emote and all o" its #ethods throw $emote&4ception. 5e#e#ber that all the #ethods o" an interface and all o" its #ethods are auto#atically p*blic. RFSURF STIJLT+(6PTE5MHTIMGIU
//3 c(,3r#i3PerfectTi#e.Hava // The i#"le#entation of // the PerfectTi#e re#ote obHect. "ackage c(,.r#i< i#"ort Hava.r#i.B<
1=11
i#"ort Hava.r#i.server.B< i#"ort Hava.r#i.registry.B< i#"ort Hava.net.B< "ublic class PerfectTi#e e6ten!s Ynicast5e#oteGbHect i#"le#ents PerfectTi#e$ @ // $#"le#entation of the interface3 "ublic long getPerfectTi#e-. thro:s 5e#oteE6ce"tion @ return %yste#.currentTi#eJillis-.< A // Just i#"le#ent constructor // to thro: 5e#oteE6ce"tion3 "ublic PerfectTi#e-. thro:s 5e#oteE6ce"tion @ // su"er-.< // Calle! auto#atically A // 5egistration for 5J$ serving. Thro: // e6ce"tions out to the console. "ublic static voi! #ain-%tringNO args. thro:s E6ce"tion @ %yste#.set%ecurityJanagerne: 5J$%ecurityJanager-..< PerfectTi#e "t ? ne: PerfectTi#e-.< &a#ing.bin!8//"e""y3 '',/PerfectTi#e8, "t.< %yste#.out."rintln-85ea!y to !o ti#e8.< A A ///3>
(ere, mainA B handles all the details o" setting u% the server. :hen you re serving 5MI ob0ects, at so#e %oint in your %rogra# you #ust= RF SURFSTIJLT+(6PTE5MHTIMIMU
(4,) +reate and install a security #anager that su%%orts 5MI. The only
one available "or 5MI as %art o" the Java distribution is $1I)ec*rity1anager. RFSURFSTIJLT+(6PTE5MHTIMIKU
(4-) +reate one or #ore instances o" a re#ote ob0ect. (ere, you can see the creation o" the #erfectTime ob0ect. RFSURF
STIJLT+(6PTE5MHTIMILU
1=12
Thinking in Java
,,,'0ruceEckel'com
(44) 5egister at least one o" the re#ote ob0ects with the 5MI re#ote
ob0ect registry "or bootstra%%ing %ur%oses. )ne re#ote ob0ect can have #ethods that %roduce re"erences to other re#ote ob0ects. This allows you to set it u% so the client #ust go to the registry only once, to get the "irst re#ote ob0ect. RFSURF STIJLT+(6PTE5MHTIMI?U
start r#iregistry
to start it in the background. )n 4ni&, the co##and is=
r#iregistry D
Dike #any network %rogra#s, the rmiregistry is located at the IP address o" whatever #achine started it u%, but it #ust also be listening at a %ort. I" you invoke the rmiregistry as above, with no argu#ent, the registry s %ort will de"ault to M@22. I" you want it to be at so#e other %ort, you add an argu#ent on the co##and line to s%eci"y the %ort. Eor this e&a#%le, the %ort is located at K@@H, so the rmiregistry should be started like this under LK'bit :indows= RFSURF STIJLT+(6PTE5MHTIMI3U
start r#iregistry
or "or 4ni&=
'',
r#iregistry
'', D
The in"or#ation about the %ort #ust also be given to the bin'A B co##and, as well as the IP address o" the #achine where the registry is located. But this brings u% what can be a "rustrating %roble# i" you re e&%ecting to test 5MI %rogra#s locally the way the network %rogra#s have been tested so "ar in this cha%ter. In the J7> M.M.M release, there are a cou%le o" %roble#s= @ RFSURFSTIJLT+(6PTE5MHTIMIGU
@ Many brain cells died in agony to discover this in"or#ation.
1=13
(45) localhost does not work with 5MI. Thus, to e&%eri#ent with 5MI
on a single #achine, you #ust %rovide the na#e o" the #achine. To "ind out the na#e o" your #achine under LK'bit :indows, go to the control %anel and select !Cetwork.$ Select the !Identi"ication$ tab, and you ll see your co#%uter na#e. In #y case, I called #y co#%uter !Pe%%y.$ It a%%ears that ca%itali1ation is ignored. RF SURFSTIJLT+(6PTE5MHTIMIIU
(46) 5MI will not work unless your co#%uter has an active T+PFIP
connection, even i" all your co#%onents are 0ust talking to each other on the local #achine. This #eans that you #ust connect to your Internet service %rovider be"ore trying to run the %rogra# or you ll get so#e obscure e&ce%tion #essages. RFSURF STIJLT+(6PTE5MHTIMI2U :ith all this in #ind, the bin'A B co##and beco#es= RFSURF STIJLT+(6PTE5MHTIM2@U
&a#ing.bin!-8//"e""y/PerfectTi#e8, "t.<
/ou should be able to %er"or# local testing by leaving o"" the IP address and using only the identi"ier= RFSURFSTIJLT+(6PTE5MHTIM2KU
&a#ing.bin!-8PerfectTi#e8, "t.<
The na#e "or the service is arbitrary; it ha%%ens to be Per"ectTi#e here, 0ust like the na#e o" the class, but you could call it anything you want. The i#%ortant thing is that it s a uniAue na#e in the registry that the client knows to look "or to %rocure the re#ote ob0ect. I" the na#e is already in the registry, you ll get an Alrea'y2o*n'&4ception. To %revent this, you can always use rebin'A B instead o" bin'A B, since rebin'A B either adds a new entry or re%laces the one that s already there. RFSURFSTIJLT+(6PTE5MHTIM2LU Even though mainA B e&its, your ob0ect has been created and registered so it s ke%t alive by the registry, waiting "or a client to co#e along and reAuest it. 6s long as the rmiregistry is running and you don t call
1=14
Thinking in Java
,,,'0ruceEckel'com
Locate5egistry.create5egistry- '',.<
Dike be"ore, K@@H is the %ort nu#ber we ha%%en to be using in this e&a#%le. This is the eAuivalent o" running rmiregistry IDD@ "ro# a co##and line, but it can o"ten be #ore convenient when you re develo%ing 5MI code since it eli#inates the e&tra ste%s o" starting and sto%%ing the registry. )nce you ve e&ecuted this code, you can bin'A B using /aming as be"ore. RFSURFSTIJLT+(6PTE5MHTIM2HU
1=15
The rmic tool is %articular about %ackages and class%aths, however. #erfectTime!8ava is in the package c>@!rmi, and even i" you invoke rmic in the sa#e directory in which #erfectTime!class is located, rmic won t "ind the "ile, since it searches the class%ath. So you #ust s%eci"y the location o"" the class %ath, like so=
r#ic c(,.r#i.PerfectTi#e
/ou don t have to be in the directory containing #erfectTime!class when you e&ecute this co##and, but the results will be %laced in the current directory. RFSURFSTIJLT+(6PTE5MHTIM2IU :hen rmic runs success"ully, you ll have two new classes in the directory=
PerfectTi#eb%tub.class PerfectTi#eb%kel.class
corres%onding to the stub and skeleton. Cow you re ready to get the server and client to talk to each other. RFSURF STIJLT+(6PTE5MHTIM22U
//3 c(,3r#i3Dis"layPerfectTi#e.Hava // Yses re#ote obHect PerfectTi#e. "ackage c(,.r#i< i#"ort Hava.r#i.B< i#"ort Hava.r#i.registry.B< "ublic class Dis"layPerfectTi#e @ "ublic static voi! #ain-%tringNO args. thro:s E6ce"tion @ %yste#.set%ecurityJanagerne: 5J$%ecurityJanager-..<
1=17
Thinking in Java
,,,'0ruceEckel'com
PerfectTi#e$ t ? -PerfectTi#e$.&a#ing.looku"8//"e""y3 '',/PerfectTi#e8.< for-int i ? '< i P ('< iKK. %yste#.out."rintln-8Perfect ti#e ? 8 K t.getPerfectTi#e-..< A A ///3>
The I7 string is the sa#e as the one used to register the ob0ect with /aming, and the "irst %art re%resents the 45D and %ort nu#ber. Since you re using a 45D, you can also s%eci"y a #achine on the Internet. RF SURFSTIJLT+(6PTE5MHTIK@@U :hat co#es back "ro# /aming!look*pA B #ust be cast to the re#ote inter"ace, not to the class. I" you use the class instead, you ll get an e&ce%tion. RFSURFSTIJLT+(6PTE5MHTIK@MU /ou can see in the #ethod call
t.getPerfectTi#e-.
that once you have a re"erence to the re#ote ob0ect, %rogra##ing with it is indistinguishable "ro# %rogra##ing with a local ob0ect *with one di""erence= re#ote #ethods throw $emote&4ception,. RFSURF STIJLT+(6PTE5MHTIK@KU
CO$;A
In large, distributed a%%lications, your needs #ight not be satis"ied by the %receding a%%roaches. Eor e&a#%le, you #ight want to inter"ace with legacy data stores, or you #ight need services "ro# a server ob0ect regardless o" its %hysical location. These situations reAuire so#e "or# o" 5e#ote Procedure +all *5P+,, and %ossibly language inde%endence. This is where +)5B6 can hel%. RFSURFSTIJLT+(6PTE5MHTIK@LU +)5B6 is not a language "eature; it s an integration technology. It s a s%eci"ication that vendors can "ollow to i#%le#ent +)5B6'co#%liant integration %roducts. +)5B6 is %art o" the )M8 s e""ort to de"ine a
1=18
standard "ra#ework "or distributed, language'inde%endent ob0ect intero%erability. RFSURFSTIJLT+(6PTE5MHTIK@?U +)5B6 su%%lies the ability to #ake re#ote %rocedure calls into Java ob0ects and non'Java ob0ects, and to inter"ace with legacy syste#s in a location'trans%arent way. Java adds networking su%%ort and a nice ob0ect'oriented language "or building gra%hical and non'gra%hical a%%lications. The Java and )M8 ob0ect #odel #a% nicely to each other; "or e&a#%le, both Java and +)5B6 i#%le#ent the inter"ace conce%t and a re"erence ob0ect #odel. RFSURFSTIJLT+(6PTE5MHTIK@HU
CO$;A fundamentals
The ob0ect intero%erability s%eci"ication develo%ed by the )M8 is co##only re"erred to as the )b0ect Manage#ent 6rchitecture *)M6,. The )M6 de"ines two co#%onents= the +ore )b0ect Model and the )M6 5e"erence 6rchitecture. The +ore )b0ect Model states the basic conce%ts o" ob0ect, inter"ace, o%eration, and so on. *+)5B6 is a re"ine#ent o" the +ore )b0ect Model., The )M6 5e"erence 6rchitecture de"ines an underlying in"rastructure o" services and #echanis#s that allow ob0ects to intero%erate. The )M6 5e"erence 6rchitecture includes the )b0ect 5eAuest Broker *)5B,, )b0ect Services *also known as +)5B6 services,, and co##on "acilities. RFSURFSTIJLT+(6PTE5MHTIK@3U The )5B is the co##unication bus by which ob0ects can reAuest services "ro# other ob0ects, regardless o" their %hysical location. This #eans that what looks like a #ethod call in the client code is actually a co#%le& o%eration. Eirst, a connection with the server ob0ect #ust e&ist, and to create a connection the )5B #ust know where the server i#%le#entation code resides. )nce the connection is established, the #ethod argu#ents #ust be #arshaled, i.e. converted in a binary strea# to be sent across a network. )ther in"or#ation that #ust be sent are the server #achine na#e, the server %rocess, and the identity o" the server ob0ect inside that %rocess. Einally, this in"or#ation is sent through a low'level wire %rotocol, the in"or#ation is decoded on the server side, and the call is e&ecuted. The )5B hides all o" this co#%le&ity "ro# the %rogra##er and #akes the o%eration al#ost as si#%le as calling a #ethod on local ob0ect. RFSURFSTIJLT+(6PTE5MHTIK@GU
1=1:
Thinking in Java
,,,'0ruceEckel'com
There is no s%eci"ication "or how an )5B +ore should be i#%le#ented, but to %rovide a basic co#%atibility a#ong di""erent vendors )5Bs, the )M8 de"ines a set o" services that are accessible through standard inter"aces. RFSURFSTIJLT+(6PTE5MHTIK@IU
-.$2A I +
Module Inter"ace Method
Java
Packag e Inter"a ce Metho d
-LL
Ca#es%ace Pure abstract class Me#ber "unction
The inheritance conce%t is su%%orted as well, using the colon o%erator as in +<<. The %rogra##er writes an I7D descri%tion o" the attributes, #ethods, and inter"aces that are i#%le#ented and used by the server and clients. The I7D is then co#%iled by a vendor'%rovided I7DFJava co#%iler, which reads the I7D source and generates Java code. The I7D co#%iler is an e&tre#ely use"ul tool= it doesn t 0ust generate a Java source eAuivalent o" the I7D, it also generates the code that will be used to #arshal #ethod argu#ents and to #ake re#ote calls. This code, called the stub and skeleton code, is organi1ed in #ulti%le Java source "iles and is usually %art o" the sa#e Java %ackage. RFSURF STIJLT+(6PTE5MHTIK@2U
1=1;
An e0am.le
The code shown here will not be elaborate because di""erent )5Bs have di""erent ways to access +)5B6 services, so e&a#%les are vendor s%eci"ic. *The e&a#%le below uses JavaI7D, a "ree %roduct "ro# Sun that co#es with a light'weight )5B, a na#ing service, and an I7D'to'Java co#%iler., In addition, since Java is young and still evolving, not all +)5B6 "eatures are %resent in the various JavaF+)5B6 %roducts. RFSURF STIJLT+(6PTE5MHTIKMLU :e want to i#%le#ent a server, running on so#e #achine, that can be Aueried "or the e&act ti#e. :e also want to i#%le#ent a client that asks "or the e&act ti#e. In this case we ll be i#%le#enting both %rogra#s in
1=2=
Thinking in Java
,,,'0ruceEckel'com
Java, but we could also use two di""erent languages *which o"ten ha%%ens in real situations,. RFSURFSTIJLT+(6PTE5MHTIKM?U
//3 c(,3corba3E6actTi#e.i!l //S ;ou #ust install i!ltoHava.e6e fro# //S Hava.sun.co# an! a!Hust the settings to use //S your local C "re"rocessor in or!er to co#"ile //S This file. %ee !ocs at Hava.sun.co#. #o!ule re#oteti#e @ interface E6actTi#e @ string getTi#e-.< A< A< ///3>
This is a declaration o" the &4actTime inter"ace inside the remotetime na#es%ace. The inter"ace is #ade u% o" one single #ethod that gives back the current ti#e in string "or#at. RFSURFSTIJLT+(6PTE5MHTIKM3U
i!ltoHava re#oteti#e.i!l
This will auto#atically generate code "or both the stub and the skeleton. I'lto8ava generates a Java package na#ed a"ter the I7D #odule, remotetime, and the generated Java "iles are %ut in the remotetime subdirectory. X&4actTimeImpl2ase!8ava is the skeleton that we ll use to i#%le#ent the server ob0ect, and X&4actTime)t*b!8ava will be used "or the client. There are Java re%resentations o" the I7D inter"ace in
1=21
&4actTime!8ava and a cou%le o" other su%%ort "iles used, "or e&a#%le, to
"acilitate access to the na#ing service o%erations. RFSURF STIJLT+(6PTE5MHTIKMGU
//3 c(,3corba35e#oteTi#e%erver.Hava i#"ort re#oteti#e.B< i#"ort org.o#g.Cos&a#ing.B< i#"ort org.o#g.Cos&a#ing.&a#ingConte6tPackage.B< i#"ort org.o#g.CG5B0.B< i#"ort Hava.util.B< i#"ort Hava.te6t.B< // %erver obHect i#"le#entation class E6actTi#e%erver e6ten!s bE6actTi#e$#"lBase @ "ublic %tring getTi#e-.@ return DateLor#at. getTi#e$nstance-DateLor#at.LYLL.. for#at-ne: Date%yste#.currentTi#eJillis-...< A A // 5e#ote a""lication i#"le#entation "ublic class 5e#oteTi#e%erver @ // Thro: e6ce"tions to console3 "ublic static voi! #ain-%tringNO args. thro:s E6ce"tion @ // G5B creation an! initialiUation3 G5B orb ? G5B.init-args, null.< // Create the server obHect an! register it3 E6actTi#e%erver ti#e%erverGbH5ef ? ne: E6actTi#e%erver-.< orb.connect-ti#e%erverGbH5ef.<
1=22
Thinking in Java
,,,'0ruceEckel'com
// aet the root na#ing conte6t3 org.o#g.CG5B0.GbHect obH5ef ? orb.resolvebinitialbreferences8&a#e%ervice8.< &a#ingConte6t nc5ef ? &a#ingConte6tMel"er.narro:-obH5ef.< // 0ssign a string na#e to the // obHect reference -bin!ing.3 &a#eCo#"onent nc ? ne: &a#eCo#"onent-8E6actTi#e8, 88.< &a#eCo#"onentNO "ath ? @ nc A< nc5ef.rebin!-"ath, ti#e%erverGbH5ef.< // \ait for client re=uests3 Hava.lang.GbHect sync ? ne: Hava.lang.GbHect-.< synchroniUe!-sync.@ sync.:ait-.< A A A ///3>
6s you can see, i#%le#enting the server ob0ect is si#%le; it s a regular Java class that inherits "ro# the skeleton code generated by the I7D co#%iler. Things get a bit #ore co#%licated when it co#es to interacting with the )5B and other +)5B6 services. RFSURF STIJLT+(6PTE5MHTIKMIU
1=23
4% to this %oint, all we have is time)erver.b8$ef, an ob0ect re"erence that is known only inside the current server %rocess. The ne&t ste% will be to assign a stringi"ied na#e to this servant ob0ect; clients will use that na#e to locate the servant ob0ect. :e acco#%lish this o%eration using the Ca#ing Service. Eirst, we need an ob0ect re"erence to the Ca#ing Service; the call to resolveXinitialXreferencesA B takes the stringi"ied ob0ect re"erence o" the Ca#ing Service that is !Ca#eService,$ in JavaI7D, and returns an ob0ect re"erence. This is cast to a s%eci"ic /aming-onte4t re"erence using the narro(A B #ethod. :e can use now the na#ing services. RFSURFSTIJLT+(6PTE5MHTIKK@U To bind the servant ob0ect with a stringi"ied ob0ect re"erence, we "irst create a /ame-omponent ob0ect, initiali1ed with !E&actTi#e,$ the na#e string we want to bind to the servant ob0ect. Then, using the rebin'A B #ethod, the stringi"ied re"erence is bound to the ob0ect re"erence. :e use rebin'A B to assign a re"erence, even i" it already e&ists, whereas bin'A B raises an e&ce%tion i" the re"erence already e&ists. 6 na#e is #ade u% in +)5B6 by a seAuence o" Ca#e+onte&ts9that s why we use an array to bind the na#e to the ob0ect re"erence. RFSURF STIJLT+(6PTE5MHTIKKMU The servant ob0ect is "inally ready "or use by clients. 6t this %oint, the server %rocess enters a wait state. 6gain, this is because it is a transient servant, so its li"eti#e is con"ined to the server %rocess. JavaI7D does not currently su%%ort %ersistent ob0ects9ob0ects that survive the e&ecution o" the %rocess that creates the#. RFSURFSTIJLT+(6PTE5MHTIKKKU Cow that we have an idea o" what the server code is doing, let s look at the client code=
//3 c(,3corba35e#oteTi#eClient.Hava i#"ort re#oteti#e.B< i#"ort org.o#g.Cos&a#ing.B< i#"ort org.o#g.CG5B0.B< "ublic class 5e#oteTi#eClient @ // Thro: e6ce"tions to console3 "ublic static voi! #ain-%tringNO args. thro:s E6ce"tion @ // G5B creation an! initialiUation3
1=24
Thinking in Java
,,,'0ruceEckel'com
G5B orb ? G5B.init-args, null.< // aet the root na#ing conte6t3 org.o#g.CG5B0.GbHect obH5ef ? orb.resolvebinitialbreferences8&a#e%ervice8.< &a#ingConte6t nc5ef ? &a#ingConte6tMel"er.narro:-obH5ef.< // aet -resolve. the stringifie! obHect // reference for the ti#e server3 &a#eCo#"onent nc ? ne: &a#eCo#"onent-8E6actTi#e8, 88.< &a#eCo#"onentNO "ath ? @ nc A< E6actTi#e ti#eGbH5ef ? E6actTi#eMel"er.narro:nc5ef.resolve-"ath..< // Jake re=uests to the server obHect3 %tring e6actTi#e ? ti#eGbH5ef.getTi#e-.< %yste#.out."rintln-e6actTi#e.< A A ///3>
The "irst "ew lines do the sa#e as they do in the server %rocess= the )5B is initiali1ed and a re"erence to the na#ing service server is resolved. Ce&t, we need an ob0ect re"erence "or the servant ob0ect, so we %ass the stringi"ied ob0ect re"erence to the resolveA B #ethod, and we cast the result into an &4actTime inter"ace re"erence using the narro(A B #ethod. Einally, we call getTimeA B. RFSURF STIJLT+(6PTE5MHTIKKLU
1=25
1=27
Thinking in Java
,,,'0ruceEckel'com
%olicy "or connecting with e&ternal servers. RFSURF STIJLT+(6PTE5MHTIKK2U So#e Java )5B %roducts o""er %ro%rietary solutions to this %roble#. Eor e&a#%le, so#e i#%le#ent what is called (TTP Tunneling, while others have their s%ecial "irewall "eatures. RFSURFSTIJLT+(6PTE5MHTIKL@U This is too co#%le& a to%ic to be covered in an a%%endi&, but it is de"initely so#ething you should be aware o". RFSURF STIJLT+(6PTE5MHTIKLMU
/nter.rise "ava;eans
Su%%ose @ you need to develo% a #ulti'tiered a%%lication to view and u%date records in a database through a :eb inter"ace. /ou can write a database a%%lication using J7B+, a :eb inter"ace using JSPFservlets, and a distributed syste# using +)5B6F5MI. But what e&tra considerations
@ This section was contributed by 5obert +astaneda, with hel% "ro# 7ave Bartlett.
1=28
#ust you #ake when develo%ing a distributed ob0ect syste# rather than 0ust knowing 6PI sO (ere are the issues= RFSURF STIJLT+(6PTE5MHTIKLHU
Reusabilit!. The ideal distributed ob0ect can be e""ortlessly #oved onto another vendors a%%lication server. It would be nice i" you could resell a distributed ob0ect co#%onent without #aking s%ecial #odi"ications, or buy so#eone else s co#%onent and use it without having to reco#%ile or rewrite it. RFSURFSTIJLT+(6PTE5MHTIK?@U -vailabilit!. I" one o" the #achines in the syste# goes down, clients should auto#atically "ail'over to backu% co%ies o" the ob0ects running on other #achines. RFSURFSTIJLT+(6PTE5MHTIK?MU
These considerations, in addition the business %roble# that you set out to solve, can #ake "or a daunting develo%#ent %ro0ect. (owever, all the issues e*ce t "or your business %roble# are redundant9solutions #ust be reinvented "or every distributed business a%%lication. RFSURF STIJLT+(6PTE5MHTIK?KU
1=2:
Thinking in Java
,,,'0ruceEckel'com
Sun, along with other leading distributed ob0ect vendors, reali1ed that sooner or later every develo%#ent tea# would be reinventing these %articular solutions, so they created the Enter%rise JavaBeans s%eci"ication *EJB,. EJB describes a server'side co#%onent #odel that tackles all o" the considerations #entioned above using a standard a%%roach that allows develo%ers to create business co#%onents called EJBs that are isolated "ro# low'level !%lu#bing$ code and that "ocus solely on %roviding business logic. Because EJB s are de"ined in a standard way, they can vendor inde%endent. RFSURF STIJLT+(6PTE5MHTIK?LU
1=2;
running o" a distributed syste#. Vendors, ad#inistrators and develo%ers %lay the various roles, to allow the %artitioning o" technical and do#ain knowledge. The vendor %rovides a technically sound "ra#ework and the develo%ers create do#ain's%eci"ic co#%onents; "or e&a#%le, an !accounting$ co#%onent. The sa#e %arty can %er"or# one or #any roles. The roles de"ined in the EJB s%eci"ication are su##ari1ed in the "ollowing table=
$ole
Enter%rise Bean Provider
$esponsibility
The develo%er res%onsible "or creating reusable EJB co#%onents. These co#%onents are %ackaged into a s%ecial 0ar "ile *e0b'0ar "ile,. +reates and asse#bles a%%lications "ro# a collection o" e0b'0ar "iles. This includes writing a%%lications that utili1e the collection o" EJBs *e.g., servlets, JSP, Swing etc. etc.,. Takes the collection o" e0b'0ar "iles "ro# the 6sse#bler andFor Bean Provider and de%loys the# into a run'ti#e environ#ent= one or #ore EJB +ontainers. Provides a run'ti#e environ#ent and tools that are used to de%loy, ad#inister, and run EJB co#%onents. Manages the di""erent co#%onents and services so that they are con"igured and they interact correctly, as well as ensuring that the syste# is u% and running.
6%%lication 6sse#bler
7e%loyer
/"; com.onents
EJB co#%onents are ele#ents o" reusable business logic that adhere to strict standards and design %atterns as de"ined in the EJB s%eci"ication. This allows the co#%onents to be %ortable. It also allows other services9 such as security, caching and distributed transactions9to be %er"or#ed on behal" o" the co#%onents. 6n Enter%rise Bean Provider is res%onsible "or develo%ing EJB co#%onents. RFSURFSTIJLT+(6PTE5MHTIK?GU
1=3=
Thinking in Java
,,,'0ruceEckel'com
1=31
/nter.rise ;ean
The Enter%rise Bean is a Java class that the Enter%rise Bean Provider develo%s. It i#%le#ents an Enter%rise Bean inter"ace and %rovides the i#%le#entation o" the business #ethods that the co#%onent is to %er"or#. The class does not i#%le#ent any authori1ation, authentication, #ultithreading, or transactional code. RFSURF STIJLT+(6PTE5MHTIKHHU
>ome interface
Every Enter%rise Bean that is created #ust have an associated (o#e inter"ace. The (o#e inter"ace is used as a "actory "or your EJB. +lients use the (o#e inter"ace to "ind an instance o" your EJB or create a new instance o" your EJB. RFSURFSTIJLT+(6PTE5MHTIKH3U
1=32
Thinking in Java
,,,'0ruceEckel'com
$emote interface
The 5e#ote inter"ace is a Java Inter"ace that re"lects the #ethods o" your Enter%rise Bean that you wish to e&%ose to the outside world. The 5e#ote inter"ace %lays a si#ilar role to a +)5B6 I7D inter"ace. RFSURF STIJLT+(6PTE5MHTIKHGU
De.lo:ment descri.tor
The de%loy#ent descri%tor is an ZMD "ile that contains in"or#ation about your EJB. 4sing ZMD allows the de%loyer to easily change attributes about your EJB. The con"igurable attributes de"ined in the de%loy#ent descri%tor include=
The (o#e and 5e#ote inter"ace na#es that are reAuired by your EJB The na#e to %ublish into JC7I "or your EJBs (o#e inter"ace Transactional attributes "or each #ethod o" your EJB 6ccess +ontrol Dists "or authenticationRFSURF STIJLT+(6PTE5MHTIKHIU
/";@"ar file
The EJB'Jar "ile is a nor#al 0ava 0ar "ile that contains your EJB, (o#e and 5e#ote inter"aces, as well as the de%loy#ent descri%tor. RFSURF STIJLT+(6PTE5MHTIKH2U
/"; o.eration
)nce you have an EJB'Jar "ile containing the Bean, the (o#e and 5e#ote inter"aces, and the de%loy#ent descri%tor, you can "it all o" the %ieces together and in the %rocess understand why the (o#e and 5e#ote inter"aces are needed and how the EJB +ontainer uses the#. RFSURF STIJLT+(6PTE5MHTIK3@U The EJB +ontainer i#%le#ents the (o#e and 5e#ote inter"aces that are in the EJB'Jar "ile. 6s #entioned earlier, the (o#e inter"ace %rovides #ethods to create and "ind your EJB. This #eans that the EJB +ontainer
1=33
is res%onsible "or the li"ecycle #anage#ent o" your EJB. This level o" indirection allows "or o%ti#i1ations to occur. Eor e&a#%le, H clients #ight si#ultaneously reAuest the creation o" an EJB through a (o#e Inter"ace, and the EJB +ontainer would res%ond by creating only one EJB and sharing it between all H clients. This is achieved through the 5e#ote Inter"ace, which is also i#%le#ented by the EJB +ontainer. The i#%le#ented 5e#ote ob0ect %lays the role o" a %ro&y ob0ect to the EJB. RF SURFSTIJLT+(6PTE5MHTIK3MU 6ll calls to the EJB are [%ro&ied through the EJB +ontainer via the (o#e and 5e#ote inter"aces. This indirection is the reason why the EJB container can control security and transactional behavior. RFSURF STIJLT+(6PTE5MHTIK3KU
#:.es of /";s
The Enter%rise JavaBeans s%eci"ication de"ines di""erent ty%es o" EJBs that have di""erent characteristics and behaviors. Two categories o" EJBs have been de"ined in the s%eci"ication= Session 0eans and Entit) 0eans, and each categoriy has variations. RFSURFSTIJLT+(6PTE5MHTIK3LU
1ession ;eans
Session Beans are used to re%resent 4se'+ases or :ork"low on behal" o" a client. They re%resent o%erations on %ersistent data, but not the %ersistent data itsel". There are two ty%es o" Session Beans, Stateless and State$ul. 6ll Session Beans #ust i#%le#ent the 8ava4!e8b!)ession2ean inter"ace. The EJB +ontainer governs the li"e o" a Session Bean. RFSURF STIJLT+(6PTE5MHTIK3?U
)tateless )ession 2eans are the si#%lest ty%e o" EJB co#%onent to i#%le#ent. They do not #aintain any conversational state with clients between #ethod invocations so they are easily reusable on the server side and because they can be cached, they scale well on de#and. :hen using Stateless Session Beans, all state #ust be stored outside o" the EJB. RF SURFSTIJLT+(6PTE5MHTIK3HU )tatef*l )ession 2eans #aintain state between invocations. They have
a one'to'one logical #a%%ing to a client and can #aintain state within the#selves. The EJB +ontainer is res%onsible "or %ooling and caching o"
1=34
Thinking in Java
,,,'0ruceEckel'com
State"ul Session Beans, which is achieved through Passivation and "ctivation. I" the EJB +ontainer crashes, data "or all State"ul Session Beans could be lost. So#e high'end EJB +ontainers %rovide recovery "or State"ul Session Beans. RFSURFSTIJLT+(6PTE5MHTIK33U
/ntit: ;eans
Entity Beans are co#%onents that re%resent %ersistent data and behavior o" this data. Entity Beans can be shared a#ong #ulti%le clients, the sa#e way that data in a database can be shared. The EJB +ontainer is res%onsible "or caching Entity Beans and "or #aintaining the integrity o" the Entity Beans. The li"e o" an Entity Bean outlives the EJB +ontainer, so i" an EJB +ontainer crashes, the Entity Bean is still e&%ected to be available when the EJB +ontainer again beco#es available. RFSURF STIJLT+(6PTE5MHTIK3GU There are two ty%es o" Entity Beans= those with +ontainer Managed %ersistence and those with Bean'Managed %ersistence. RFSURF STIJLT+(6PTE5MHTIK3IU
-ontainer 1anage' #ersistence A-1#B. 6 +MP Entity Bean has its %ersistence i#%le#ented on its behal" by the EJB +ontainer. Through attributes s%eci"ied in the de%loy#ent descri%tor, the EJB +ontainer will #a% the Entity Bean s attributes to so#e %ersistent store *usually9but not always9a database,. +MP reduces the develo%#ent ti#e "or the EJB, as well as dra#atically reducing the a#ount o" code reAuired. RFSURF STIJLT+(6PTE5MHTIK32U 2ean 1anage' #ersistence A21#B. 6 BMP Entity Bean has its %ersistence i#%le#ented by the Enter%rise Bean Provider. The Enter%rise Bean Provider is res%onsible "or i#%le#enting the logic reAuired to create a new EJB, u%date so#e attributes o" the EJBS, delete an EJB and "ind an EJB "ro# %ersistent store. This usually involves writing J7B+ code to interact with a database or other %ersistent store. :ith BMP, the develo%er is in "ull control o" how the Entity Bean %ersistence is #anaged. RFSURFSTIJLT+(6PTE5MHTIKG@U
BMP also gives "le&ibility where a +MP i#%le#entation #ay not be available. Eor e&a#%le, i" you wanted to create an EJB that wra%%ed so#e
1=35
code on an e&isting #ain"ra#e syste#, you could write your %ersistence using +)5B6. RFSURFSTIJLT+(6PTE5MHTIKGMU
Develo.ing an /";
6s an e&a#%le, the !Per"ect Ti#e$ e&a#%le "ro# the %revious 5MI section will be i#%le#ented as an EJB co#%onent. The e&a#%le will be a si#%le Stateless Session Bean. RFSURFSTIJLT+(6PTE5MHTIKGKU 6s #entioned earlier, EJB co#%onents consist o" at least one class *the EJB, and two inter"aces= the 5e#ote and (o#e inter"aces. :hen you create a 5e#ote inter"ace "or an EJB , you #ust "ollow these guidelines= RFSURFSTIJLT+(6PTE5MHTIKGLU
(57) The re#ote inter"ace #ust be p*blic. (5() The re#ote inter"ace #ust e&tend the inter"ace 8ava4!e8b! &J2.b8ect. (5!) Each #ethod in the re#ote inter"ace #ust declare 8ava!rmi! $emote&4ception in its thro(s clause in addition to any
a%%lication's%eci"ic e&ce%tions.
(ere is the si#%le re#ote inter"ace "or the Per"ectTi#e EJB= //3 c(,3eHb3PerfectTi#e.Hava //S ;ou #ust install the J EE Java Enter"rise //S E!ition fro# Hava.sun.co# an! a!! H ee.Har //S to your CL0%%P0TM in or!er to co#"ile //S this file. %ee !etails at Hava.sun.co#. // 5e#ote $nterface of PerfectTi#eBean i#"ort Hava.r#i.B< i#"ort Hava6.eHb.B< "ublic interface PerfectTi#e e6ten!s EJBGbHect @ "ublic long getPerfectTi#e-. thro:s 5e#oteE6ce"tion<
1=37
Thinking in Java
,,,'0ruceEckel'com
A ///3>
The (o#e inter"ace is the "actory where the co#%onent will be created. It can de"ine create #ethods, to create instances o" EJBs, or $inder #ethods, which locate e&isting EJBs and are used "or Entity Beans only. :hen you create a (o#e inter"ace "or an EJB , you #ust "ollow these guidelines=
(5,) The (o#e inter"ace #ust e&tend the inter"ace 8ava4!e8b! &J2Home. RFSURFSTIJLT+(6PTE5MHTIKGHU (5-) Each create #ethod in the (o#e inter"ace #ust declare 8ava!rmi! $emote&4ception in its thro(s clause as well as a 8ava4!e8b! -reate&4ception. RFSURFSTIJLT+(6PTE5MHTIKG3U (54) The return value o" a create #ethod #ust be a 5e#ote Inter"ace.
RFSURFSTIJLT+(6PTE5MHTIKGGU
(55) The return value o" a $inder #ethod *Entity Beans only, #ust be a 5e#ote Inter"ace or 8ava!*til!&n*meration or 8ava!*til! -ollection. RFSURFSTIJLT+(6PTE5MHTIKGIU (56) 6ny ob0ect %assed as an argu#ent *either directly or e#bedded
within a local ob0ect, #ust be a valid 5MI'II)P data ty%e *this includes other EJB ob0ects, RFSURFSTIJLT+(6PTE5MHTIKG2U The standard na#ing convention "or (o#e inter"aces is to take the 5e#ote inter"ace na#e and a%%end !(o#e$ to the end. (ere is the (o#e inter"ace "or the Per"ectTi#e EJB= RFSURFSTIJLT+(6PTE5MHTIKI@U
//3 c(,3eHb3PerfectTi#eMo#e.Hava // Mo#e $nterface of PerfectTi#eBean. i#"ort Hava.r#i.B< i#"ort Hava6.eHb.B< "ublic interface PerfectTi#eMo#e e6ten!s EJBMo#e @ "ublic PerfectTi#e create-. thro:s CreateE6ce"tion, 5e#oteE6ce"tion< A ///3>
1=38
/ou can now i#%le#ent the business logic. :hen you create your EJB i#%le#entation class, you #ust "ollow these guidelines, *note that you should consult the EJB s%eci"ication "or a co#%lete list o" guidelines when develo%ing Enter%rise JavaBeans,= RFSURF STIJLT+(6PTE5MHTIKIMU
(67) The class #ust be p*blic. RFSURFSTIJLT+(6PTE5MHTIKIKU (6() The class #ust i#%le#ent an EJB inter"ace *either 8ava4!e8b! )ession2ean or 8ava4!e8b!&ntity2ean,. RFSURF
STIJLT+(6PTE5MHTIKILU
(6!) The class should de"ine #ethods that #a% directly to the #ethods
in the 5e#ote inter"ace. Cote that the class does not i#%le#ent the 5e#ote inter"ace; it #irrors the #ethods in the 5e#ote inter"ace but does not throw 8ava!rmi!$emote&4ception. RF SURFSTIJLT+(6PTE5MHTIKI?U
(6+) The return value and argu#ents o" all #ethods #ust be valid 5MI'
II)P data ty%es. RFSURFSTIJLT+(6PTE5MHTIKI3U
//3 c(,3eHb3PerfectTi#eBean.Hava // %i#"le %tateless %ession Bean // that returns current syste# ti#e. i#"ort Hava.r#i.B< i#"ort Hava6.eHb.B< "ublic class PerfectTi#eBean i#"le#ents %essionBean @ "rivate %essionConte6t sessionConte6t< //return current ti#e "ublic long getPerfectTi#e-. @ return %yste#.currentTi#eJillis-.< A // EJB #etho!s "ublic voi! eHbCreate-. thro:s CreateE6ce"tion @A "ublic voi! eHb5e#ove-. @A
1=3:
Thinking in Java
,,,'0ruceEckel'com
"ublic voi! eHb0ctivate-. @A "ublic voi! eHbPassivate-. @A "ublic voi! set%essionConte6t-%essionConte6t ct6. @ sessionConte6t ? ct6< A A///3>
Because this is a si#%le e&a#%le, the EJB #ethods * e8b-reateA B, e8b$emoveA B, e8bActivateA B, e8b#assivateA B , are all e#%ty. These #ethods are invoked by the EJB +ontainer and are used to control the state o" the co#%onent. The set)ession-onte4tA B #ethod %asses a 8ava4!e8b!)ession-onte4t ob0ect which contains in"or#ation about the co#%onent s conte&t, such as the current transaction and security in"or#ation. RFSURFSTIJLT+(6PTE5MHTIKIGU 6"ter we have created the Enter%rise JavaBean, we then need to create a de%loy#ent descri%tor. The de%loy#ent descri%tor is an ZMD "ile that describes the EJB co#%onent. The de%loy#ent descri%tor should be stored in a "ile called e8b68ar!4ml. RFSURFSTIJLT+(6PTE5MHTIKIIU
//34 c(,3eHb3eHb-Har.6#l P[6#l version?8(.'8 enco!ing?8C"( , 8[Q P4DGCT;PE eHb-Har PYBL$C 2-//%un Jicrosyste#s, $nc.// DTD Enter"rise JavaBeans (.(//E&2 2htt"3//Hava.sun. co#/H ee/!t!s/eHb-Harb(b(.!t!2Q PeHb-HarQ P!escri"tionQE6a#"le for Cha"ter (,P/!escri"tionQ P!is"lay-na#eQP/!is"lay-na#eQ Ps#all-iconQP/s#all-iconQ Plarge-iconQP/large-iconQ Penter"rise-beansQ PsessionQ PeHb-na#eQPerfectTi#eP/eHb-na#eQ Pho#eQPerfectTi#eMo#eP/ho#eQ Pre#oteQPerfectTi#eP/re#oteQ PeHb-classQPerfectTi#eBeanP/eHb-classQ Psession-ty"eQ%tatelessP/session-ty"eQ Ptransaction-ty"eQContainerP/transaction-ty"eQ P/sessionQ
1=3;
1=4=
Thinking in Java
,,,'0ruceEckel'com
In this e&a#%le the client %rogra# is a si#%le Java %rogra#, but you should re#e#ber that it could 0ust as easily be a servlet, a JSP or even a +)5B6 or 5MI distributed ob0ect.
//3 c(,3eHb3PerfectTi#eClient.Hava // Client "rogra# for PerfectTi#eBean "ublic class PerfectTi#eClient @ "ublic static voi! #ain-%tringNO args. thro:s E6ce"tion @ // aet a J&D$ conte6t using // the J&D$ &a#ing service3 Hava6.na#ing.Conte6t conte6t ? ne: Hava6.na#ing.$nitialConte6t-.< // Look u" the ho#e interface in the // J&D$ &a#ing service3 GbHect ref ? conte6t.looku"-8"erfectTi#e8.< // Cast the re#ote obHect to the ho#e interface3 PerfectTi#eMo#e ho#e ? -PerfectTi#eMo#e. Hava6.r#i.Portable5e#oteGbHect.narro:ref, PerfectTi#eMo#e.class.< // Create a re#ote obHect fro# the ho#e interface3 PerfectTi#e "t ? ho#e.create-.< // $nvoke getPerfectTi#e-. %yste#.out."rintln8Perfect Ti#e EJB invoke!, ti#e is3 8 K "t.getPerfectTi#e-. .< A A ///3>
The seAuence o" the e&a#%le is e&%lained in the co##ents. Cote the use o" the narro(A B #ethod to %er"or# a kind o" casting o" the ob0ect be"ore a Java cast is %er"or#ed. This is very si#ilar to what ha%%ens in +)5B6. 6lso note that the (o#e ob0ect beco#es a "actory "or #erfectTime ob0ects. RFSURFSTIJLT+(6PTE5MHTIK2HU
/"; summar:
The Enter%rise JavaBeans s%eci"ication is a dra#atic ste% "orward in the standardi1ation and si#%li"ication o" distributed ob0ect co#%uting. It is a #a0or %iece o" the Java K Enter%rise Edition *JKEE, %lat"or# and is
1=41
receiving #uch su%%ort "ro# the distributed ob0ect co##unity. Many tools are currently available or will be available in the near "uture to hel% accelerate the develo%#ent o" EJB co#%onents. RFSURF STIJLT+(6PTE5MHTIK23U This overview was only a brie" tour o" EJBs. Eor #ore in"or#ation about the EJB s%eci"ication you should see the o""icial Enter%rise JavaBeans ho#e %age at >ava'sun'com/ roducts/e>b/D where you can download the latest s%eci"ication and the JKEE re"erence i#%le#entation. These can be used to develo% and de%loy your own EJB co#%onents. RFSURF STIJLT+(6PTE5MHTIK2GU
"ini in conte0t
Traditionally, o%erating syste#s have been designed with the assu#%tion that a co#%uter will have a %rocessor, so#e #e#ory, and a disk. :hen you boot a co#%uter, the "irst thing it does is look "or a disk. I" it doesn t "ind a disk, it can t "unction as a co#%uter. Increasingly, however, co#%uters are a%%earing in a di""erent guise= as e#bedded devices that have a %rocessor, so#e #e#ory, and a network connection9but no disk. The "irst thing a cell %hone does when you boot it u%, "or e&a#%le, is look "or the tele%hone network. I" it doesn t "ind the network, it can t "unction as a cell %hone. This trend in the hardware environ#ent, "ro# disk' centric to network'centric, will a""ect how we organi1e the so"tware9and that s where Jini co#es in. RFSURFSTIJLT+(6PTE5MHTIK22U Jini is an atte#%t to rethink co#%uter architecture, given the rising i#%ortance o" the network and the %roli"eration o" %rocessors in devices that have no disk drive. These devices, which will co#e "ro# #any
@ This section was contributed by Bill Venners *www.arti#a.co#,.
1=42
Thinking in Java
,,,'0ruceEckel'com
di""erent vendors, will need to interact over a network. The network itsel" will be very dyna#ic9devices and services will be added and re#oved regularly. Jini %rovides #echanis#s to enable s#ooth adding, re#oval, and "inding o" devices and services on the network. In addition, Jini %rovides a %rogra##ing #odel that #akes it easier "or %rogra##ers to get their devices talking to each other. RFSURF STIJLT+(6PTE5MHTIL@@U Building on to% o" Java, ob0ect seriali1ation, and 5MI *which together enable ob0ects to #ove around the network "ro# virtual #achine to virtual #achine, Jini atte#%ts to e&tend the bene"its o" ob0ect'oriented %rogra##ing to the network. Instead o" reAuiring device vendors to agree on the network %rotocols through which their devices can interact, Jini enables the devices to talk to each other through inter"aces to ob0ects. RF SURFSTIJLT+(6PTE5MHTIL@MU
What is "iniA
Jini is a set o" 6PIs and network %rotocols that can hel% you build and de%loy distributed syste#s that are organi1ed as $ederations o$ services. 6 service can be anything that sits on the network and is ready to %er"or# a use"ul "unction. (ardware devices, so"tware, co##unications channels9 even hu#an users the#selves9can be services. 6 Jini'enabled disk drive, "or e&a#%le, could o""er a !storage$ service. 6 Jini'enabled %rinter could o""er a !%rinting$ service. 6 "ederation o" services, then, is a set o" services, currently available on the network, that a client *#eaning a %rogra#, service, or user, can bring together to hel% it acco#%lish so#e goal. RFSURFSTIJLT+(6PTE5MHTIL@KU To %er"or# a task, a client enlists the hel% o" services. Eor e&a#%le, a client %rogra# #ight u%load %ictures "ro# the i#age storage service in a digital ca#era, download the %ictures to a %ersistent storage service o""ered by a disk drive, and send a %age o" thu#bnail'si1ed versions o" the i#ages to the %rinting service o" a color %rinter. In this e&a#%le, the client %rogra# builds a distributed syste# consisting o" itsel", the i#age storage service, the %ersistent storage service, and the color'%rinting service. The client and services o" this distributed syste# work together to %er"or# the task= to o""load and store i#ages "ro# a digital ca#era and %rint a %age o" thu#bnails. RFSURFSTIJLT+(6PTE5MHTIL@LU
1=43
The idea behind the word $ederation is that the Jini view o" the network doesn t involve a central controlling authority. Because no one service is in charge, the set o" all services available on the network "or# a "ederation 9a grou% co#%osed o" eAual %eers. Instead o" a central authority, Jini s run'ti#e in"rastructure #erely %rovides a way "or clients and services to "ind each other *via a looku% service, which stores a directory o" currently available services,. 6"ter services locate each other, they are on their own. The client and its enlisted services %er"or# their task inde%endently o" the Jini run'ti#e in"rastructure. I" the Jini looku% service crashes, any distributed syste#s brought together via the looku% service be"ore it crashed can continue their work. Jini even includes a network %rotocol that clients can use to "ind services in the absence o" a looku% service. RF SURFSTIJLT+(6PTE5MHTIL@?U
1=44
Thinking in Java
,,,'0ruceEckel'com
%acket onto a well'known %ort. Included in the %resence announce#ent is an IP address and %ort nu#ber where the disk drive can be contacted by a looku% service. RFSURFSTIJLT+(6PTE5MHTIL@GU Dooku% services #onitor the well'known %ort "or %resence announce#ent %ackets. :hen a looku% service receives a %resence announce#ent, it o%ens and ins%ects the %acket. The %acket contains in"or#ation that enables the looku% service to deter#ine whether or not it should contact the sender o" the %acket. I" so, it contacts the sender directly by #aking a T+P connection to the IP address and %ort nu#ber e&tracted "ro# the %acket. 4sing 5MI, the looku% service sends an ob0ect, called a service registrar, across the network to the originator o" the %acket. The %ur%ose o" the service registrar ob0ect is to "acilitate "urther co##unication with the looku% service. By invoking #ethods on this ob0ect, the sender o" the announce#ent %acket can %er"or# 0oin and looku% on the looku% service. In the case o" the disk drive, the looku% service would #ake a T+P connection to the disk drive and would send it a service registrar ob0ect, through which the disk drive would then register its %ersistent storage service via the 0oin %rocess. RFSURF STIJLT+(6PTE5MHTIL@IU
1=45
"or the service, and ob0ects that give #ore in"or#ation about the service. RFSURFSTIJLT+(6PTE5MHTILM@U Service ob0ects usually i#%le#ent one or #ore inter"aces through which clients interact with the service. Eor e&a#%le, a looku% service is a Jini service, and its service ob0ect is the service registrar. The registerA B #ethod invoked by service %roviders during 0oin is declared in the )ervice$egistrar inter"ace *a #e#ber o" the net!8ini!core!look*p %ackage,, which all service registrar ob0ects i#%le#ent. +lients and service %roviders talk to the looku% service through the service registrar ob0ect by invoking #ethods declared in the )ervice$egistrar inter"ace. Dikewise, a disk drive would %rovide a service ob0ect that i#%le#ented so#e well'known storage service inter"ace. +lients would look u% and interact with the disk drive by this storage service inter"ace. RFSURF STIJLT+(6PTE5MHTILMMU
1=47
Thinking in Java
,,,'0ruceEckel'com
ob0ects. The client gets a re"erence to the #atching service ob0ects as the return value o" the look*pA B #ethod. RFSURF STIJLT+(6PTE5MHTILMLU In the general case, a client looks u% a service by Java ty%e, usually an inter"ace. Eor e&a#%le, i" a client needed to use a %rinter, it would co#%ose a service te#%late that included a -lass ob0ect "or a well'known inter"ace to %rinter services. 6ll %rinter services would i#%le#ent this well'known inter"ace. The looku% service would return a service ob0ect *or ob0ects, that i#%le#ented this inter"ace. 6ttributes can be included in the service te#%late to narrow the nu#ber o" #atches "or such a ty%e'based search. The client would use the %rinter service by invoking #ethods "ro# the well'known %rinter service inter"ace on the service ob0ect. RFSURF STIJLT+(6PTE5MHTILM?U
1=48
could co##unicate with the service via 5MI, +)5B6, 7+)M, so#e ho#e'brewed %rotocol built on to% o" sockets and strea#s, or anything else. The client si#%ly doesn t need to care about network %rotocols, because it can talk to the well'known inter"ace that the service ob0ect i#%le#ents. The service ob0ect takes care o" any necessary co##unication on the network. RFSURFSTIJLT+(6PTE5MHTILM3U
Client
Ser i!e
1=4:
Thinking in Java
,,,'0ruceEckel'com
interact. The %rocesses o" discovery, 0oin, and looku%, %rovided by the Jini run'ti#e in"rastructure, enable devices to locate each other on the network. )nce they locate each other, devices can co##unicate with each other through Java inter"aces. RFSURFSTIJLT+(6PTE5MHTILMIU
1ummar:
6long with Jini "or local device networks, this cha%ter has introduced so#e, but not all, o" the co#%onents that Sun re"ers to as JKEE= the Java 2 Enter rise Edition. The goal o" JKEE is to build create a set o" tools that allows the Java develo%er to build server'based a%%lications #uch #ore Auickly than be"ore, and in a %lat"or#'inde%endent way. It s not only di""icult and ti#e'consu#ing to build such a%%lications, but it s es%ecially hard to build the# so that they can be easily %orted to other %lat"or#s, and also to kee% the business logic se%arated "ro# the underlying details o" the i#%le#entation. JKEE %rovides a "ra#ework to assist in creating server'based a%%lications; these a%%lications are in de#and now, and that de#and a%%ears to be increasing. RFSURF STIJLT+(6PTE5MHTILM2U
/0ercises
Solutions to selected e&ercises can be "ound in the electronic docu#entThe Thinking in Java "nnotated Solution @uide, available "or a s#all "ee "ro# ,,,'0ruceEckel'com.
!-7) +reate a server that asks "or a %assword, then o%ens a "ile and
sends the "ile over the network connection. +reate a client that connects to this server, gives the a%%ro%riate %assword, then ca%tures and saves the "ile. Test the %air o" %rogra#s on your #achine using the localhost *the local loo%back IP address >IZ!D!D!> %roduced by calling InetA''ress!get2y/ame An*llB,. RFSURFSTIJLT+(6PTE5MHTILKMU
1=4;
1=5=
Thinking in Java
,,,'0ruceEckel'com
servlet container, you will need to download, install, and run To#cat "ro# >akarta'a ache'org in order to run servlets. RFSURF STIJLT+(6PTE5MHTILK2U
!47) +reate a servlet that changes the inactive interval o" a session to
H seconds by calling get1a4InactiveIntervalA B. Test to see that the session does indeed e&%ire a"ter H seconds. I" you do not have an e&isting servlet container, you will need to download, install, and run To#cat "ro# >akarta'a ache'org in order to run servlets. RFSURFSTIJLT+(6PTE5MHTILLMU
!4() +reate a JSP %age that %rints a line o" te&t using the R(MU tag.
Set the color o" this te&t rando#ly, using Java code e#bedded in the JSP %age. I" you do not have an e&isting JSP container, you will need to download, install, and run To#cat "ro# >akarta' a ache'org in order to run JSPs. RFSURF STIJLT+(6PTE5MHTILLKU
!4*) +reate a JSP with a "ield that allows the user to enter the
session e&%iration ti#e and and a second "ield that holds data that is stored in the session. The sub#it button re"reshes the %age and "etches the current e&%iration ti#e and session data and %uts the# in as de"ault values o" the a"ore#entioned "ields. I" you do not have an e&isting JSP container, you will need to download,
1=51
install, and run To#cat "ro# >akarta'a ache'org in order to run JSPs. RFSURFSTIJLT+(6PTE5MHTILL?U
1=52
Thinking in Java
,,,'0ruceEckel'com
1=53
//3 a""en!i6a3Pass5eferences.Hava // Passing references aroun!. "ublic class Pass5eferences @ static voi! f-Pass5eferences h. @ %yste#.out."rintln-8h insi!e f-.3 8 K h.< A "ublic static voi! #ain-%tringNO args. @ Pass5eferences " ? ne: Pass5eferences-.< %yste#.out."rintln-8" insi!e #ain-.3 8 K ".< f-".< A A ///3>
The #ethod to)tringA B is auto#atically invoked in the %rint state#ents, and #ass$eferences inherits directly "ro# .b8ect with no rede"inition o" to)tringA B. Thus, .b8ect s version o" to)tringA B is used, which %rints out the class o" the ob0ect "ollowed by the address where that ob0ect is located *not the re"erence, but the actual ob0ect storage,. The out%ut looks like this=
Aliasing
6liasing #eans that #ore than one re"erence is tied to the sa#e ob0ect, as in the above e&a#%le. The %roble# with aliasing occurs when so#eone
1=54
Thinking in Java
,,,'0ruceEckel'com
,rites to that ob0ect. I" the owners o" the other re"erences aren t
e&%ecting that ob0ect to change, they ll be sur%rised. This can be de#onstrated with a si#%le e&a#%le=
//3 a""en!i6a30lias(.Hava // 0liasing t:o references to one obHect. "ublic class 0lias( @ int i< 0lias(-int ii. @ i ? ii< A "ublic static voi! #ain-%tringNO args. @ 0lias( 6 ? ne: 0lias(-*.< 0lias( y ? 6< // 0ssign the reference %yste#.out."rintln-863 8 K 6.i.< %yste#.out."rintln-8y3 8 K y.i.< %yste#.out."rintln-8$ncre#enting 68.< 6.iKK< %yste#.out."rintln-863 8 K 6.i.< %yste#.out."rintln-8y3 8 K y.i.< A A ///3>
In the line=
6.iKK< y s i will be a""ected as well. This can be seen in the out%ut= 63 * y3 * $ncre#enting 6 63 1 y3 1
1=55
)ne good solution in this case is to si#%ly not do it= don t consciously alias #ore than one re"erence to an ob0ect at the sa#e sco%e. /our code will be #uch easier to understand and debug. (owever, when you re %assing a re"erence in as an argu#ent9which is the way Java is su%%osed to work9you auto#atically alias because the local re"erence that s created can #odi"y the !outside ob0ect$ *the ob0ect that was created outside the sco%e o" the #ethod,. (ere s an e&a#%le= RFSURF STIJLT6PPEC7IZ6TIHU
//3 a""en!i6a30lias .Hava // Jetho! calls i#"licitly alias their // argu#ents. "ublic class 0lias @ int i< 0lias -int ii. @ i ? ii< A static voi! f-0lias reference. @ reference.iKK< A "ublic static voi! #ain-%tringNO args. @ 0lias 6 ? ne: 0lias -*.< %yste#.out."rintln-863 8 K 6.i.< %yste#.out."rintln-8Calling f-6.8.< f-6.< %yste#.out."rintln-863 8 K 6.i.< A A ///3>
The out%ut is=
63 * Calling f-6. 63 1
The #ethod is changing its argu#ent, the outside ob0ect. :hen this kind o" situation arises, you #ust decide whether it #akes sense, whether the user e&%ects it, and whether it s going to cause %roble#s. RFSURF STIJLT6PPEC7IZ6TI3U In general, you call a #ethod in order to %roduce a return value andFor a change o" state in the ob0ect that the method is called $or. *6 #ethod is
1=57
Thinking in Java
,,,'0ruceEckel'com
how you !send a #essage$ to that ob0ect., It s #uch less co##on to call a #ethod in order to #ani%ulate its argu#ents; this is re"erred to as !calling a #ethod "or its side e$$ects.$ Thus, when you create a #ethod that #odi"ies its argu#ents the user #ust be clearly instructed and warned about the use o" that #ethod and its %otential sur%rises. Because o" the con"usion and %it"alls, it s #uch better to avoid changing the argu#ent. RFSURFSTIJLT6PPEC7IZ6TIGU I" you need to #odi"y an argu#ent during a #ethod call and you don t intend to #odi"y the outside argu#ent, then you should %rotect that argu#ent by #aking a co%y inside your #ethod. That s the sub0ect o" #uch o" this a%%endi&. RFSURFSTIJLT6PPEC7IZ6TIIU
6liasing ha%%ens auto#atically during argu#ent %assing. There are no local ob0ects, only local re"erences. 5e"erences have sco%es, ob0ects do not. )b0ect li"eti#e is never an issue in Java. There is no language su%%ort *e.g., !const$, to %revent ob0ects "ro# being
#odi"ied *that is, to %revent the negative e""ects o" aliasing,. I" you re only reading in"or#ation "ro# an ob0ect and not #odi"ying it, %assing a re"erence is the #ost e""icient "or# o" argu#ent %assing. This is nice; the de"ault way o" doing things is also the #ost e""icient. (owever, so#eti#es it s necessary to be able to treat the ob0ect as i" it were !local$ so that changes you #ake a""ect only a local co%y and do not #odi"y the outside ob0ect. Many %rogra##ing languages su%%ort the ability to
1=58
auto#atically #ake a local co%y o" the outside ob0ect, inside the #ethod @. Java does not, but it allows you to %roduce this e""ect. RFSURF STIJLT6PPEC7IZ6TI2U
ass b: value
This brings u% the ter#inology issue, which always see#s good "or an argu#ent. The ter# is !%ass by value,$ and the #eaning de%ends on how you %erceive the o%eration o" the %rogra#. The general #eaning is that you get a local co%y o" whatever you re %assing, but the real Auestion is how you think about what you re %assing. :hen it co#es to the #eaning o" !%ass by value,$ there are two "airly distinct ca#%s=
(6-) Java %asses %ri#itives by value *no argu#ent there,, but ob0ects
are %assed by re"erence. This is the world view that the re"erence is an alias "or the ob0ect, so you donJt think about %assing re"erences, but instead say !I # %assing the ob0ect.$ Since you don t get a local co%y o" the ob0ect when you %ass it into a #ethod, ob0ects are clearly not %assed by value. There a%%ears to be so#e su%%ort "or this view within Sun, since at one ti#e, one o" the !reserved but not i#%le#ented$ keywords was byval*e. * There s no knowing,
however, whether that keyword will ever see the light o" day.This will %robably never be i#%le#ented, . RFSURF
STIJLT6PPEC7IZ6TIMMU
@ In +, which generally handles s#all bits o" data, the de"ault is %ass'by'value. +<< had to "ollow this "or#, but with ob0ects %ass'by'value isn t usually the #ost e""icient way. In addition, coding classes to su%%ort %ass'by'value in +<< is a big headache.
1=5:
Thinking in Java
,,,'0ruceEckel'com
(aving given both ca#%s a good airing, and a"ter saying !It de%ends on how you think o" a re"erence,$ I will atte#%t to sideste% the issue. In the end, it isn t that i#%ortant9what is i#%ortant is that you understand that %assing a re"erence allows the caller s ob0ect to be changed une&%ectedly. RFSURFSTIJLT6PPEC7IZ6TIMKU
Cloning ob3ects
The #ost likely reason "or #aking a local co%y o" an ob0ect is i" you re going to #odi"y that ob0ect and you don t want to #odi"y the caller s ob0ect. I" you decide that you want to #ake a local co%y, you si#%ly use the cloneA B #ethod to %er"or# the o%eration. This is a #ethod that s de"ined as protecte' in the base class .b8ect, and which you #ust override as p*blic in any derived classes that you want to clone. Eor e&a#%le, the standard library class Array+ist overrides cloneA B, so we can call cloneA B "or Array+ist=
//3 a""en!i6a3Cloning.Hava // The clone-. o"eration :orks for only a fe: // ite#s in the stan!ar! Java library. i#"ort Hava.util.B< class $nt @ "rivate int i< "ublic $nt-int ii. @ i ? ii< A "ublic voi! incre#ent-. @ iKK< A "ublic %tring to%tring-. @ return $nteger.to%tring-i.< A A "ublic class Cloning @ "ublic static voi! #ain-%tringNO args. @ 0rrayList v ? ne: 0rrayList-.< for-int i ? '< i P ('< iKK . v.a!!-ne: $nt-i..< %yste#.out."rintln-8v3 8 K v.< 0rrayList v ? -0rrayList.v.clone-.< // $ncre#ent all v 2s ele#ents3 for-$terator e ? v .iterator-.<
1=5;
"ublic class Cloneit i#"le#ents Cloneable @ "ublic static voi! #ain -%tringNO args. thro:s Clone&ot%u""orte!E6ce"tion @ Cloneit a ? ne: Cloneit-.<
1=7=
Thinking in Java
,,,'0ruceEckel'com
see# to be counterintuitive to the idea that base'class #ethods are always available in derived classes. +loning in Java goes against this idea; i" you want it to e&ist "or a class, you #ust s%eci"ically add code to #ake cloning work. RFSURFSTIJLT6PPEC7IZ6TIMHU
rotected
To %revent de"ault cloneability in every class you create, the cloneA B #ethod is protecte' in the base class .b8ect. Cot only does this #ean that it s not available by de"ault to the client %rogra##er who is si#%ly using the class *not subclassing it,, but it also #eans that you cannot call cloneA B via a re"erence to the base class. *6lthough that #ight see# to be use"ul in so#e situations, such as to %oly#or%hically clone a bunch o" .b8ects., It is in e""ect a way to give you, at co#%ile'ti#e, the in"or#ation that your ob0ect is not cloneable9and oddly enough #ost classes in the standard Java library are not cloneable. Thus, i" you say=
A A (owever, this only works because mainA B is a #ethod o" -loneit and thus has %er#ission to call the protecte' base'class #ethod cloneA B. I" you call it "ro# a di""erent class, it won t co#%ile.
1=71
/ou ll %robably want to override cloneA B in any "urther derived classes, otherwise your *now p*blic, cloneA B will be used, and that #ight not do the right thing *although, since .b8ect!cloneA B #akes a co%y o" the actual ob0ect, it #ight,. The protecte' trick works only once9the "irst ti#e you inherit "ro# a class that has no cloneability and you want to #ake a class that s cloneable. In any classes inherited "ro# your class the cloneA B #ethod is available since it s not %ossible in Java to reduce the access o" a #ethod during derivation. That is, once a class is cloneable, everything derived "ro# it is cloneable unless you use %rovided #echanis#s *described later, to !turn o""$ cloning. RFSURF STIJLT6PPEC7IZ6TIMIU
interface Cloneable @A
The reason "or i#%le#enting this e#%ty interface is obviously not because you are going to u%cast to -loneable and call one o" its #ethods. The use o" interface here is considered by so#e to be a !hack$ because it s using a "eature "or so#ething other than its original intent. I#%le#enting the -loneable interface acts as a kind o" a "lag, wired into the ty%e o" the class. RFSURFSTIJLT6PPEC7IZ6TIM2U There are two reasons "or the e&istence o" the -loneable interface. Eirst, you #ight have an u%cast re"erence to a base ty%e and not know whether it s %ossible to clone that ob0ect. In this case, you can use the instanceof keyword *described in +ha%ter MK, to "ind out whether the re"erence is connected to an ob0ect that can be cloned=
1=72
Thinking in Java
,,,'0ruceEckel'com
1uccessful cloning
)nce you understand the details o" i#%le#enting the cloneA B #ethod, you re able to create classes that can be easily du%licated to %rovide a local co%y=
//3 a""en!i6a3LocalCo"y.Hava // Creating local co"ies :ith clone-.. i#"ort Hava.util.B< class JyGbHect i#"le#ents Cloneable @ int i< JyGbHect-int ii. @ i ? ii< A "ublic GbHect clone-. @ GbHect o ? null< try @ o ? su"er.clone-.< A catch-Clone&ot%u""orte!E6ce"tion e. @ %yste#.err."rintln-8JyGbHect can2t clone8.< A return o< A "ublic %tring to%tring-. @ return $nteger.to%tring-i.< A A "ublic class LocalCo"y @ static JyGbHect g-JyGbHect v. @ // Passing a reference, // #o!ifies outsi!e obHect3 v.iKK< return v< A static JyGbHect f-JyGbHect v. @ v ? -JyGbHect.v.clone-.< // Local co"y v.iKK< return v< A "ublic static voi! #ain-%tringNO args. @ JyGbHect a ? ne: JyGbHect-((.<
1=73
JyGbHect b ? g-a.< // Testing reference e=uivalence, // not obHect e=uivalence3 if-a ?? b. %yste#.out."rintln-8a ?? b8.< else %yste#.out."rintln-8a 4? b8.< %yste#.out."rintln-8a ? 8 K a.< %yste#.out."rintln-8b ? 8 K b.< JyGbHect c ? ne: JyGbHect-I*.< JyGbHect ! ? f-c.< if-c ?? !. %yste#.out."rintln-8c ?? !8.< else %yste#.out."rintln-8c 4? !8.< %yste#.out."rintln-8c ? 8 K c.< %yste#.out."rintln-8! ? 8 K !.< A A ///3>
Eirst o" all, cloneA B #ust be accessible so you #ust #ake it p*blic. Second, "or the initial %art o" your cloneA B o%eration you should call the base'class version o" cloneA B. The cloneA B that s being called here is the one that s %rede"ined inside .b8ect, and you can call it because it s protecte' and thereby accessible in derived classes. RFSURF STIJLT6PPEC7IZ6TIKMU
.b8ect!cloneA B "igures out how big the ob0ect is, creates enough
#e#ory "or a new one, and co%ies all the bits "ro# the old to the new. This is called a bit,ise co )D and is ty%ically what you d e&%ect a cloneA B #ethod to do. But be"ore .b8ect!cloneA B %er"or#s its o%erations, it "irst checks to see i" a class is -loneable9that is, whether it i#%le#ents the -loneable inter"ace. I" it doesn t, .b8ect!cloneA B throws a -lone/ot)*pporte'&4ception to indicate that you can t clone it. Thus, you ve got to surround your call to s*per!cloneA B with a try'catch block, to catch an e&ce%tion that should never ha%%en *because you ve i#%le#ented the -loneable inter"ace,. RFSURF STIJLT6PPEC7IZ6TIKKU
1=74
Thinking in Java
,,,'0ruceEckel'com
In +ocal-opy, the two #ethods gA B and fA B de#onstrate the di""erence between the two a%%roaches "or argu#ent %assing. gA B shows %assing by re"erence in which it #odi"ies the outside ob0ect and returns a re"erence to that outside ob0ect, while fA B clones the argu#ent, thereby decou%ling it and leaving the original ob0ect alone. It can then %roceed to do whatever it wants, and even to return a re"erence to this new ob0ect without any ill e""ects to the original. Cotice the so#ewhat curious'looking state#ent=
v ? -JyGbHect.v.clone-.<
This is where the local co%y is created. To %revent con"usion by such a state#ent, re#e#ber that this rather strange coding idio# is %er"ectly "easible in Java because every ob0ect identi"ier is actually a re"erence. So the re"erence v is used to cloneA B a co%y o" what it re"ers to, and this returns a re"erence to the base ty%e .b8ect *because it s de"ined that way in .b8ect!cloneA B, that #ust then be cast to the %ro%er ty%e. RFSURF STIJLT6PPEC7IZ6TIKLU In mainA B, the di""erence between the e""ects o" the two di""erent argu#ent'%assing a%%roaches in the two di""erent #ethods is tested. The out%ut is=
a a b c c !
?? b ? ( ? ( 4? ! ? I* ? I1
It s i#%ortant to notice that the eAuivalence tests in Java do not look inside the ob0ects being co#%ared to see i" their values are the sa#e. The PP and =P o%erators are si#%ly co#%aring the re$erences. I" the addresses inside the re"erences are the sa#e, the re"erences are %ointing to the sa#e ob0ect and are there"ore !eAual.$ So what the o%erators are really testing is whether the re"erences are aliased to the sa#e ob0ect. RF SURFSTIJLT6PPEC7IZ6TIK?U
1=75
classO The cloneA B #ethod in the root class is res%onsible "or creating the correct a#ount o" storage and #aking the bitwise co%y o" the bits "ro# the original ob0ect into the new ob0ect s storage. That is, it doesn t 0ust #ake storage and co%y an .b8ect9it actually "igures out the si1e o" the %recise ob0ect that s being co%ied and du%licates that. Since all this is ha%%ening "ro# the code in the cloneA B #ethod de"ined in the root class *that has no idea what s being inherited "ro# it,, you can guess that the %rocess involves 5TTI to deter#ine the actual ob0ect that s being cloned. This way, the cloneA B #ethod can create the %ro%er a#ount o" storage and do the correct bitco%y "or that ty%e. RFSURF STIJLT6PPEC7IZ6TIKHU :hatever you do, the "irst %art o" the cloning %rocess should nor#ally be a call to s*per!cloneA B. This establishes the groundwork "or the cloning o%eration by #aking an e&act du%licate. 6t this %oint you can %er"or# other o%erations necessary to co#%lete the cloning. RFSURF STIJLT6PPEC7IZ6TIK3U To know "or sure what those other o%erations are, you need to understand e&actly what .b8ect!cloneA B buys you. In %articular, does it auto#atically clone the destination o" all the re"erencesO The "ollowing e&a#%le tests this=
//3 a""en!i6a3%nake.Hava // Tests cloning to see if !estination // of references are also clone!. "ublic class %nake i#"le#ents Cloneable @ "rivate %nake ne6t< "rivate char c< // Walue of i ?? nu#ber of seg#ents %nake-int i, char 6. @ c ? 6< if---i Q '. ne6t ? ne: %nake-i, -char.-6 K (..< A voi! incre#ent-. @ cKK< if-ne6t 4? null. ne6t.incre#ent-.<
1=77
Thinking in Java
,,,'0ruceEckel'com
A "ublic %tring to%tring-. @ %tring s ? 838 K c< if-ne6t 4? null. s K? ne6t.to%tring-.< return s< A "ublic GbHect clone-. @ GbHect o ? null< try @ o ? su"er.clone-.< A catch-Clone&ot%u""orte!E6ce"tion e. @ %yste#.err."rintln-8%nake can2t clone8.< A return o< A "ublic static voi! #ain-%tringNO args. @ %nake s ? ne: %nake-,, 2a2.< %yste#.out."rintln-8s ? 8 K s.< %nake s ? -%nake.s.clone-.< %yste#.out."rintln-8s ? 8 K s .< s.incre#ent-.< %yste#.out."rintln8after s.incre#ent, s ? 8 K s .< A A ///3>
6 )nake is #ade u% o" a bunch o" seg#ents, each o" ty%e )nake. Thus, it s a singly linked list. The seg#ents are created recursively, decre#enting the "irst constructor argu#ent "or each seg#ent until 1ero is reached. To give each seg#ent a uniAue tag, the second argu#ent, a char, is incre#ented "or each recursive constructor call. RFSURF STIJLT6PPEC7IZ6TIKGU The incrementA B #ethod recursively incre#ents each tag so you can see the change, and the to)tringA B recursively %rints each tag. The out%ut is=
? 3a3c3!3e3f
1=78
This #eans that only the "irst seg#ent is du%licated by .b8ect!cloneA B, there"ore it does a shallow co%y. I" you want the whole snake to be du%licated9a dee% co%y9you #ust %er"or# the additional o%erations inside your overridden cloneA B. RFSURFSTIJLT6PPEC7IZ6TIKIU /ou ll ty%ically call s*per!cloneA B in any class derived "ro# a cloneable class to #ake sure that all o" the base'class o%erations *including .b8ect! cloneA B, take %lace. This is "ollowed by an e&%licit call to cloneA B "or every re"erence in your ob0ect; otherwise those re"erences will be aliased to those o" the original ob0ect. It s analogous to the way constructors are called9base'class constructor "irst, then the ne&t'derived constructor, and so on to the #ost'derived constructor. The di""erence is that cloneA B is not a constructor, so there s nothing to #ake it ha%%en auto#atically. /ou #ust #ake sure to do it yoursel". RFSURFSTIJLT6PPEC7IZ6TIK2U
//3 a""en!i6a3Dee"Co"y.Hava // Cloning a co#"ose! obHect. class De"th5ea!ing i#"le#ents Cloneable @ "rivate !ouble !e"th< "ublic De"th5ea!ing-!ouble !e"th. @ this.!e"th ? !e"th< A "ublic GbHect clone-. @ GbHect o ? null< try @
1=7:
Thinking in Java
,,,'0ruceEckel'com
o ? su"er.clone-.< A catch-Clone&ot%u""orte!E6ce"tion e. @ e."rint%tackTrace-%yste#.err.< A return o< A A class Te#"erature5ea!ing i#"le#ents Cloneable @ "rivate long ti#e< "rivate !ouble te#"erature< "ublic Te#"erature5ea!ing-!ouble te#"erature. @ ti#e ? %yste#.currentTi#eJillis-.< this.te#"erature ? te#"erature< A "ublic GbHect clone-. @ GbHect o ? null< try @ o ? su"er.clone-.< A catch-Clone&ot%u""orte!E6ce"tion e. @ e."rint%tackTrace-%yste#.err.< A return o< A A class Gcean5ea!ing i#"le#ents Cloneable @ "rivate De"th5ea!ing !e"th< "rivate Te#"erature5ea!ing te#"erature< "ublic Gcean5ea!ing-!ouble t!ata, !ouble !!ata.@ te#"erature ? ne: Te#"erature5ea!ing-t!ata.< !e"th ? ne: De"th5ea!ing-!!ata.< A "ublic GbHect clone-. @ Gcean5ea!ing o ? null< try @ o ? -Gcean5ea!ing.su"er.clone-.< A catch-Clone&ot%u""orte!E6ce"tion e. @ e."rint%tackTrace-%yste#.err.< A // Just clone references3
1=7;
o.!e"th ? -De"th5ea!ing.o.!e"th.clone-.< o.te#"erature ? -Te#"erature5ea!ing.o.te#"erature.clone-.< return o< // Y"casts back to GbHect A A "ublic class Dee"Co"y @ "ublic static voi! #ain-%tringNO args. @ Gcean5ea!ing rea!ing ? ne: Gcean5ea!ing-)).C, (''.,.< // &o: clone it3 Gcean5ea!ing r ? -Gcean5ea!ing.rea!ing.clone-.< A A ///3> epth$ea'ing and Temperat*re$ea'ing are Auite si#ilar; they both contain only %ri#itives. There"ore, the cloneA B #ethod can be Auite si#%le= it calls s*per!cloneA B and returns the result. Cote that the cloneA B code "or both classes is identical. RFSURF
STIJLT6PPEC7IZ6TILMU
.cean$ea'ing is co#%osed o" epth$ea'ing and Temperat*re$ea'ing ob0ects and so, to %roduce a dee% co%y, its cloneA B #ust clone the re"erences inside .cean$ea'ing. To acco#%lish this, the result o" s*per!cloneA B #ust be cast to an .cean$ea'ing ob0ect *so you can access the 'epth and temperat*re
re"erences,. RFSURFSTIJLT6PPEC7IZ6TILKU
//3 a""en!i6a30!!ingClone.Hava // ;ou #ust go through a fe: gyrations // to a!! cloning to your o:n class. i#"ort Hava.util.B< class $nt i#"le#ents Cloneable @
1=8=
Thinking in Java
,,,'0ruceEckel'com
"rivate int i< "ublic $nt -int ii. @ i ? ii< A "ublic voi! incre#ent-. @ iKK< A "ublic %tring to%tring-. @ return $nteger.to%tring-i.< A "ublic GbHect clone-. @ GbHect o ? null< try @ o ? su"er.clone-.< A catch-Clone&ot%u""orte!E6ce"tion e. @ %yste#.err."rintln-8$nt can2t clone8.< A return o< A A // Gnce it2s cloneable, inheritance // !oesn2t re#ove cloneability3 class $nt) e6ten!s $nt @ "rivate int H< // 0uto#atically !u"licate! "ublic $nt)-int i. @ su"er-i.< A A "ublic class 0!!ingClone @ "ublic static voi! #ain-%tringNO args. @ $nt 6 ? ne: $nt -('.< $nt 6 ? -$nt .6.clone-.< 6 .incre#ent-.< %yste#.out."rintln86 ? 8 K 6 K 8, 6 ? 8 K 6 .< // 0nything inherite! is also cloneable3 $nt) 6) ? ne: $nt)-*.< 6) ? -$nt).6).clone-.< 0rrayList v ? ne: 0rrayList-.< for-int i ? '< i P ('< iKK . v.a!!-ne: $nt -i..< %yste#.out."rintln-8v3 8 K v.< 0rrayList v ? -0rrayList.v.clone-.< // &o: clone each ele#ent3
1=81
for-int i ? '< i P v.siUe-.< iKK. v .set-i, --$nt .v .get-i...clone-..< // $ncre#ent all v 2s ele#ents3 for-$terator e ? v .iterator-.< e.has&e6t-.< . --$nt .e.ne6t-...incre#ent-.< // %ee if it change! v2s ele#ents3 %yste#.out."rintln-8v3 8 K v.< %yste#.out."rintln-8v 3 8 K v .< A A ///3> IntJ is inherited "ro# IntI and a new %ri#itive #e#ber int 8 is added. /ou #ight think that you d need to override cloneA B again to #ake sure 8 is co%ied, but that s not the case. :hen IntI s cloneA B is called as IntJ s cloneA B, it calls .b8ect!cloneA B, which deter#ines that it s working with an IntJ and du%licates all the bits in the IntJ. 6s long as you don t add re"erences that need to be cloned, the one call to .b8ect!cloneA B
%er"or#s all o" the necessary du%lication, regardless o" how "ar down in the hierarchy cloneA B is de"ined. RFSURFSTIJLT6PPEC7IZ6TILLU /ou can see what s necessary in order to do a dee% co%y o" an Array+ist= a"ter the Array+ist is cloned, you have to ste% through and clone each one o" the ob0ects %ointed to by the Array+ist. /ou d have to do so#ething si#ilar to this to do a dee% co%y o" a Hash1ap. RFSURF STIJLT6PPEC7IZ6TIL?U The re#ainder o" the e&a#%le shows that the cloning did ha%%en by showing that, once an ob0ect is cloned, you can change it and the original ob0ect is le"t untouched. RFSURFSTIJLT6PPEC7IZ6TILHU
//3 a""en!i6a3Co#"ete.Hava
1=82
Thinking in Java
,,,'0ruceEckel'com
i#"ort Hava.io.B< class Thing( i#"le#ents %erialiUable @A class Thing i#"le#ents %erialiUable @ Thing( o( ? ne: Thing(-.< A class Thing) i#"le#ents Cloneable @ "ublic GbHect clone-. @ GbHect o ? null< try @ o ? su"er.clone-.< A catch-Clone&ot%u""orte!E6ce"tion e. @ %yste#.err."rintln-8Thing) can2t clone8.< A return o< A A class ThingI i#"le#ents Cloneable @ Thing) o) ? ne: Thing)-.< "ublic GbHect clone-. @ ThingI o ? null< try @ o ? -ThingI.su"er.clone-.< A catch-Clone&ot%u""orte!E6ce"tion e. @ %yste#.err."rintln-8ThingI can2t clone8.< A // Clone the fiel!, too3 o.o) ? -Thing).o).clone-.< return o< A A "ublic class Co#"ete @ static final int %$TE ? ,'''< "ublic static voi! #ain-%tringNO args. thro:s E6ce"tion @ Thing NO a ? ne: Thing N%$TEO< for-int i ? '< i P a.length< iKK. aNiO ? ne: Thing -.<
1=83
ThingINO b ? ne: ThingIN%$TEO< for-int i ? '< i P b.length< iKK. bNiO ? ne: ThingI-.< long t( ? %yste#.currentTi#eJillis-.< Byte0rrayGut"ut%trea# buf ? ne: Byte0rrayGut"ut%trea#-.< GbHectGut"ut%trea# o ? ne: GbHectGut"ut%trea#-buf.< for-int i ? '< i P a.length< iKK. o.:riteGbHect-aNiO.< // &o: get co"ies3 GbHect$n"ut%trea# in ? ne: GbHect$n"ut%trea#ne: Byte0rray$n"ut%trea#buf.toByte0rray-...< Thing NO c ? ne: Thing N%$TEO< for-int i ? '< i P c.length< iKK. cNiO ? -Thing .in.rea!GbHect-.< long t ? %yste#.currentTi#eJillis-.< %yste#.out."rintln8Du"lication via serialiUation3 8 K -t - t(. K 8 Jillisecon!s8.< // &o: try cloning3 t( ? %yste#.currentTi#eJillis-.< ThingINO ! ? ne: ThingIN%$TEO< for-int i ? '< i P !.length< iKK. !NiO ? -ThingI.bNiO.clone-.< t ? %yste#.currentTi#eJillis-.< %yste#.out."rintln8Du"lication via cloning3 8 K -t - t(. K 8 Jillisecon!s8.< A A ///3> ThingI and ThingQ contain #e#ber ob0ects so that there s so#e dee% co%ying going on. It s interesting to notice that while )eriali7able classes are easy to set u%, there s #uch #ore work going on to du%licate the#. +loning involves a lot o" work to set u% the class, but the actual du%lication o" ob0ects is relatively si#%le. The results really tell the tale. (ere is the out%ut "ro# three di""erent runs=
1=84
Thinking in Java
,,,'0ruceEckel'com
Du"lication via serialiUation3 CI' Jillisecon!s Du"lication via cloning3 ,' Jillisecon!s Du"lication via serialiUation3 *(' Jillisecon!s Du"lication via cloning3 +' Jillisecon!s Du"lication via serialiUation3 **' Jillisecon!s Du"lication via cloning3 ,' Jillisecon!s
7es%ite the signi"icant ti#e di""erence between seriali1ation and cloning, you ll also notice that the seriali1ation techniAue see#s to vary #ore in its duration, while cloning tends to be #ore stable. RFSURF STIJLT6PPEC7IZ6TILGU
//3 a""en!i6a3MorrorLlick.Hava // ;ou can insert Cloneability // at any level of inheritance. i#"ort Hava.util.B< class Person @A class Mero e6ten!s Person @A class %cientist e6ten!s Person i#"le#ents Cloneable @ "ublic GbHect clone-. @ try @ return su"er.clone-.< A catch-Clone&ot%u""orte!E6ce"tion e. @ // this shoul! never ha""en3 // $t2s Cloneable alrea!y4 thro: ne: $nternalError-.< A A
1=85
A class Ja!%cientist e6ten!s %cientist @A "ublic class MorrorLlick @ "ublic static voi! #ain-%tringNO args. @ Person " ? ne: Person-.< Mero h ? ne: Mero-.< %cientist s ? ne: %cientist-.< Ja!%cientist # ? ne: Ja!%cientist-.< // " ? -Person.".clone-.< // Co#"ile error // h ? -Mero.h.clone-.< // Co#"ile error s ? -%cientist.s.clone-.< # ? -Ja!%cientist.#.clone-.< A A ///3>
Be"ore cloneability was added, the co#%iler sto%%ed you "ro# trying to clone things. :hen cloneability is added in )cientist, then )cientist and all its descendants are cloneable. RFSURFSTIJLT6PPEC7IZ6TILIU
1=87
Thinking in Java
,,,'0ruceEckel'com
straight"orward sche#e= cloneA B is now protecte' in .b8ect. /ou #ust override it and implement -loneable and deal with the e&ce%tions. RFSURFSTIJLT6PPEC7IZ6TI?MU It s worth noting that you #ust use the -loneable inter"ace onl) i" you re going to call .b8ect s cloneA B, #ethod, since that #ethod checks at run' ti#e to #ake sure that your class i#%le#ents -loneable. But "or consistency *and since -loneable is e#%ty anyway, you should i#%le#ent it. RFSURFSTIJLT6PPEC7IZ6TI?KU
Controlling cloneabilit:
/ou #ight suggest that, to re#ove cloneability, the cloneA B #ethod si#%ly be #ade private, but this won t work since you cannot take a base'class #ethod and #ake it less accessible in a derived class. So it s not that si#%le. 6nd yet, it s necessary to be able to control whether an ob0ect can be cloned. There are actually a nu#ber o" attitudes you can take to this in a class that you design=
(65) Su%%ort cloneA B. Eollow the standard %ractice o" i#%le#enting -loneable and overriding cloneA B. In the overridden cloneA B, you call s*per!cloneA B and catch all e&ce%tions *so your overridden cloneA B doesn t throw any e&ce%tions,. RFSURF
STIJLT6PPEC7IZ6TI??U
1=88
your Array+ist, so you don t know whether they can be cloned. RF SURFSTIJLT6PPEC7IZ6TI?HU
!7() Try to %revent cloning by not i#%le#enting -loneable and overriding cloneA B to throw an e&ce%tion. This is success"ul only i" any class derived "ro# this calls s*per!cloneA B in its rede"inition o" cloneA B. )therwise, a %rogra##er #ay be able to
get around it. RFSURFSTIJLT6PPEC7IZ6TI?GU
!7!) Prevent cloning by #aking your class final. I" cloneA B has not
been overridden by any o" your ancestor classes, then it can t be. I" it has, then override it again and throw -lone/ot)*pporte'&4ception. Making the class final is the only way to guarantee that cloning is %revented. In addition, when dealing with security ob0ects or other situations in which you want to control the nu#ber o" ob0ects created you should #ake all constructors private and %rovide one or #ore s%ecial #ethods "or creating ob0ects. That way, these #ethods can restrict the nu#ber o" ob0ects created and the conditions in which they re created. *6 %articular case o" this is the singleton %attern shown in Thinking in Patterns ,ith Java, downloadable at ,,,'0ruceEckel'com., RF SURFSTIJLT6PPEC7IZ6TI?IU (ere s an e&a#%le that shows the various ways cloning can be i#%le#ented and then, later in the hierarchy, !turned o""$= RFSURF STIJLT6PPEC7IZ6TI?2U
1=8:
Thinking in Java
,,,'0ruceEckel'com
// Can2t clone this because it !oesn2t // overri!e clone-.3 class Gr!inary @A // Gverri!es clone, but !oesn2t i#"le#ent // Cloneable3 class \rongClone e6ten!s Gr!inary @ "ublic GbHect clone-. thro:s Clone&ot%u""orte!E6ce"tion @ return su"er.clone-.< // Thro:s e6ce"tion A A // Does all the right things for cloning3 class $sCloneable e6ten!s Gr!inary i#"le#ents Cloneable @ "ublic GbHect clone-. thro:s Clone&ot%u""orte!E6ce"tion @ return su"er.clone-.< A A // Turn off cloning by thro:ing the e6ce"tion3 class &oJore e6ten!s $sCloneable @ "ublic GbHect clone-. thro:s Clone&ot%u""orte!E6ce"tion @ thro: ne: Clone&ot%u""orte!E6ce"tion-.< A A class TryJore e6ten!s &oJore @ "ublic GbHect clone-. thro:s Clone&ot%u""orte!E6ce"tion @ // Calls &oJore.clone-., thro:s e6ce"tion3 return su"er.clone-.< A A class BackGn e6ten!s &oJore @ "rivate BackGn !u"licate-BackGn b. @
1=8;
// %o#eho: #ake a co"y of b // an! return that co"y. This is a !u##y // co"y, Hust to #ake the "oint3 return ne: BackGn-.< A "ublic GbHect clone-. @ // Doesn2t call &oJore.clone-.3 return !u"licate-this.< A A // Can2t inherit fro# this, so can2t overri!e // the clone #etho! like in BackGn3 final class 5eally&oJore e6ten!s &oJore @A "ublic class CheckCloneable @ static Gr!inary tryToClone-Gr!inary or!. @ %tring i! ? or!.getClass-..get&a#e-.< %yste#.out."rintln-80tte#"ting 8 K i!.< Gr!inary 6 ? null< if-or! instanceof Cloneable. @ try @ %yste#.out."rintln-80tte#"ting 8 K i!.< 6 ? -Gr!inary.--$sCloneable.or!..clone-.< %yste#.out."rintln-8Clone! 8 K i!.< A catch-Clone&ot%u""orte!E6ce"tion e. @ %yste#.err."rintln-8Coul! not clone 8Ki!.< A A else @ %yste#.out."rintln8&ot instance of Cloneable8.< A return 6< A "ublic static voi! #ain-%tringNO args. @ // Y"casting3 Gr!inaryNO or! ? @ ne: $sCloneable-., ne: \rongClone-., ne: &oJore-., ne: TryJore-.,
1=:=
Thinking in Java
,,,'0ruceEckel'com
ne: BackGn-., ne: 5eally&oJore-., A< Gr!inary 6 ? ne: Gr!inary-.< // This :on2t co#"ile, since clone-. is // "rotecte! in GbHect3 //4 6 ? -Gr!inary.6.clone-.< // tryToClone-. checks first to see if // a class i#"le#ents Cloneable3 for-int i ? '< i P or!.length< iKK. tryToClone-or!NiO.< A A ///3>
The "irst class, .r'inary, re%resents the kinds o" classes we ve seen throughout this book= no su%%ort "or cloning, but as it turns out, no %revention o" cloning either. But i" you have a re"erence to an .r'inary ob0ect that #ight have been u%cast "ro# a #ore derived class, you can t tell i" it can be cloned or not. RFSURFSTIJLT6PPEC7IZ6TIH@U The class 0rong-lone shows an incorrect way to i#%le#ent cloning. It does override .b8ect!cloneA B and #akes that #ethod p*blic, but it doesn t i#%le#ent -loneable, so when s*per!cloneA B is called *which results in a call to .b8ect!cloneA B,, -lone/ot)*pporte'&4ception is thrown so the cloning doesn t work. RFSURFSTIJLT6PPEC7IZ6TIHMU In Is-loneable you can see all the right actions %er"or#ed "or cloning= cloneA B is overridden and -loneable is i#%le#ented. (owever, this cloneA B #ethod and several others that "ollow in this e&a#%le do not catch -lone/ot)*pporte'&4ception, but instead %ass it through to the caller, who #ust then %ut a try'catch block around it. In your own cloneA B #ethods you will ty%ically catch -lone/ot)*pporte'&4ception inside cloneA B rather than %assing it through. 6s you ll see, in this e&a#%le it s #ore in"or#ative to %ass the e&ce%tions through. RFSURFSTIJLT6PPEC7IZ6TIHKU +lass /o1ore atte#%ts to !turn o""$ cloning in the way that the Java designers intended= in the derived class cloneA B, you throw -lone/ot)*pporte'&4ception. The cloneA B #ethod in class Try1ore %ro%erly calls s*per!cloneA B, and this resolves to /o1ore!
1=:1
0tte#"ting $sCloneable Clone! $sCloneable 0tte#"ting &oJore Coul! not clone &oJore 0tte#"ting TryJore
1=:2
Thinking in Java
,,,'0ruceEckel'com
Coul! not clone TryJore 0tte#"ting BackGn Clone! BackGn 0tte#"ting 5eally&oJore Coul! not clone 5eally&oJore
So to su##ari1e, i" you want a class to be cloneable= RFSURF STIJLT6PPEC7IZ6TIHGU
!7*) I#%le#ent the -loneable inter"ace. !7+) )verride cloneA B. !7,) +all s*per!cloneA B inside your cloneA B. !7-) +a%ture e&ce%tions inside your cloneA B.
This will %roduce the #ost convenient e""ects. RFSURF STIJLT6PPEC7IZ6TIHIU
//3 a""en!i6a3Co"yConstructor.Hava // 0 constructor for co"ying an obHect of the sa#e // ty"e, as an atte#"t to create a local co"y. class Lruit/ualities @ "rivate int :eight< "rivate int color< "rivate int fir#ness< "rivate int ri"eness< "rivate int s#ell< // etc. Lruit/ualities-. @ // Default constructor // !o so#ething #eaningful...
1=:3
A // Gther constructors3 // ... // Co"y constructor3 Lruit/ualities-Lruit/ualities f. @ :eight ? f.:eight< color ? f.color< fir#ness ? f.fir#ness< ri"eness ? f.ri"eness< s#ell ? f.s#ell< // etc. A A class %ee! @ // Je#bers... %ee!-. @ /B Default constructor B/ A %ee!-%ee! s. @ /B Co"y constructor B/ A A class Lruit @ "rivate Lruit/ualities f=< "rivate int see!s< "rivate %ee!NO s< Lruit-Lruit/ualities =, int see!Count. @ f= ? =< see!s ? see!Count< s ? ne: %ee!Nsee!sO< for-int i ? '< i P see!s< iKK. sNiO ? ne: %ee!-.< A // Gther constructors3 // ... // Co"y constructor3 Lruit-Lruit f. @ f= ? ne: Lruit/ualities-f.f=.< see!s ? f.see!s< // Call all %ee! co"y-constructors3 for-int i ? '< i P see!s< iKK. sNiO ? ne: %ee!-f.sNiO.< // Gther co"y-construction activities...
1=:4
Thinking in Java
,,,'0ruceEckel'com
A // To allo: !erive! constructors -or other // #etho!s. to "ut in !ifferent =ualities3 "rotecte! voi! a!!/ualities-Lruit/ualities =. @ f= ? =< A "rotecte! Lruit/ualities get/ualities-. @ return f=< A A class To#ato e6ten!s Lruit @ To#ato-. @ su"er-ne: Lruit/ualities-., (''.< A To#ato-To#ato t. @ // Co"y-constructor su"er-t.< // Y"cast for base co"y-constructor // Gther co"y-construction activities... A A class Tebra/ualities e6ten!s Lruit/ualities @ "rivate int stri"e!ness< Tebra/ualities-. @ // Default constructor // !o so#ething #eaningful... A Tebra/ualities-Tebra/ualities U. @ su"er-U.< stri"e!ness ? U.stri"e!ness< A A class areenTebra e6ten!s To#ato @ areenTebra-. @ a!!/ualities-ne: Tebra/ualities-..< A areenTebra-areenTebra g. @ su"er-g.< // Calls To#ato-To#ato. // 5estore the right =ualities3 a!!/ualities-ne: Tebra/ualities-..< A
1=:5
voi! evaluate-. @ Tebra/ualities U= ? -Tebra/ualities.get/ualities-.< // Do so#ething :ith the =ualities // ... A A "ublic class Co"yConstructor @ "ublic static voi! ri"en-To#ato t. @ // Yse the 8co"y constructor83 t ? ne: To#ato-t.< %yste#.out."rintln-8$n ri"en, t is a 8 K t.getClass-..get&a#e-..< A "ublic static voi! slice-Lruit f. @ f ? ne: Lruit-f.< // M###... :ill this :ork[ %yste#.out."rintln-8$n slice, f is a 8 K f.getClass-..get&a#e-..< A "ublic static voi! #ain-%tringNO args. @ To#ato to#ato ? ne: To#ato-.< ri"en-to#ato.< // G` slice-to#ato.< // GGP%4 areenTebra g ? ne: areenTebra-.< ri"en-g.< // GGP%4 slice-g.< // GGP%4 g.evaluate-.< A A ///3>
This see#s a bit strange at "irst. Sure, "ruit has Aualities, but why not 0ust %ut data #e#bers re%resenting those Aualities directly into the Fr*it classO There are two %otential reasons. The "irst is that you #ight want to easily insert or change the Aualities. Cote that Fr*it has a protecte' a''3*alitiesA B #ethod to allow derived classes to do this. */ou #ight think the logical thing to do is to have a protecte' constructor in Fr*it that takes a Fr*it3*alities argu#ent, but constructors don t inherit so it wouldn t be available in second or greater level classes., By #aking the "ruit Aualities into a se%arate class, you have greater "le&ibility, including
1=:7
Thinking in Java
,,,'0ruceEckel'com
the ability to change the Aualities #idway through the li"eti#e o" a %articular Fr*it ob0ect. RFSURFSTIJLT6PPEC7IZ6TIH2U The second reason "or #aking Fr*it3*alities a se%arate ob0ect is in case you want to add new Aualities or to change the behavior via inheritance and %oly#or%his#. Cote that "or "reenZebra *which reall) is a ty%e o" to#ato9I ve grown the# and they re "abulous,, the constructor calls a''3*alitiesA B and %asses it a Zebra3*alities ob0ect, which is derived "ro# Fr*it3*alities so it can be attached to the Fr*it3*alities re"erence in the base class. )" course, when "reenZebra uses the Fr*it3*alities it #ust downcast it to the correct ty%e *as seen in eval*ateA B,, but it always knows that ty%e is Zebra3*alities. RFSURFSTIJLT6PPEC7IZ6TI3@U /ou ll also see that there s a )ee' class, and that Fr*it *which by de"inition carries its own seeds, @ contains an array o" )ee's. RFSURF STIJLT6PPEC7IZ6TI3MU Einally, notice that each class has a co%y constructor, and that each co%y constructor #ust take care to call the co%y constructors "or the base class and #e#ber ob0ects to %roduce a dee% co%y. The co%y constructor is tested inside the class -opy-onstr*ctor. The #ethod ripenA B takes a Tomato argu#ent and %er"or#s co%y'construction on it in order to du%licate the ob0ect=
t ? ne: To#ato-t.<
while sliceA B takes a #ore generic Fr*it ob0ect and also du%licates it=
f ? ne: Lruit-f.<
These are tested with di""erent kinds o" Fr*it in mainA B. (ere s the out%ut=
$n $n $n $n
t f t f
is is is is
a a a a
This is where the %roble# shows u%. 6"ter the co%y'construction that ha%%ens to the Tomato inside sliceA B, the result is no longer a Tomato
@ E&ce%t "or the %oor avocado, which has been reclassi"ied to si#%ly !"at.$
1=:8
ob0ect, but 0ust a Fr*it. It has lost all o" its to#ato'ness. Eurther, when you take a "reenZebra, both ripenA B and sliceA B turn it into a Tomato and a Fr*it, res%ectively. Thus, un"ortunately, the co%y constructor sche#e is no good to us in Java when atte#%ting to #ake a local co%y o" an ob0ect. RFSURFSTIJLT6PPEC7IZ6TI3KU
$ead@onl: classes
:hile the local co%y %roduced by cloneA B gives the desired results in the a%%ro%riate cases, it is an e&a#%le o" "orcing the %rogra##er *the author o" the #ethod, to be res%onsible "or %reventing the ill e""ects o" aliasing. :hat i" you re #aking a library that s so general %ur%ose and co##only used that you cannot #ake the assu#%tion that it will always be cloned in the %ro%er %lacesO )r #ore likely, what i" you ,ant to allow aliasing "or e""iciency9to %revent the needless du%lication o" ob0ects9but you don t want the negative side e""ects o" aliasingO RFSURF STIJLT6PPEC7IZ6TI3?U )ne solution is to create immutable ob>ects which belong to read'only classes. /ou can de"ine a class such that no #ethods in the class cause changes to the internal state o" the ob0ect. In such a class, aliasing has no i#%act since you can read only the internal state, so i" #any %ieces o" code are reading the sa#e ob0ect there s no %roble#. RFSURF STIJLT6PPEC7IZ6TI3HU 6s a si#%le e&a#%le o" i##utable ob0ects, Java s standard library contains !wra%%er$ classes "or all the %ri#itive ty%es. /ou #ight have
1=::
Thinking in Java
,,,'0ruceEckel'com
already discovered that, i" you want to store an int inside a container such as an Array+ist *which takes only .b8ect references,, you can wra% your int inside the standard library Integer class=
//3 a""en!i6a3$##utable$nteger.Hava // The $nteger class cannot be change!. i#"ort Hava.util.B< "ublic class $##utable$nteger @ "ublic static voi! #ain-%tringNO args. @ 0rrayList v ? ne: 0rrayList-.< for-int i ? '< i P ('< iKK. v.a!!-ne: $nteger-i..< // But ho: !o you change the int // insi!e the $nteger[ A A ///3>
The Integer class *as well as all the %ri#itive !wra%%er$ classes, i#%le#ents i##utability in a si#%le "ashion= they have no #ethods that allow you to change the ob0ect. RFSURFSTIJLT6PPEC7IZ6TI33U I" you do need an ob0ect that holds a %ri#itive ty%e that can be #odi"ied, you #ust create it yoursel". Eortunately, this is trivial=
//3 a""en!i6a3Jutable$nteger.Hava // 0 changeable :ra""er class. i#"ort Hava.util.B< class $ntWalue @ int n< $ntWalue-int 6. @ n ? 6< A "ublic %tring to%tring-. @ return $nteger.to%tring-n.< A A "ublic class Jutable$nteger @ "ublic static voi! #ain-%tringNO args. @ 0rrayList v ? ne: 0rrayList-.< for-int i ? '< i P ('< iKK. v.a!!-ne: $ntWalue-i..<
1=:;
//3 a""en!i6a3$##utable(.Hava // GbHects that cannot be #o!ifie! // are i##une to aliasing. "ublic class $##utable( @ "rivate int !ata< "ublic $##utable(-int initWal. @ !ata ? initWal< A "ublic int rea!-. @ return !ata< A "ublic boolean nonUero-. @ return !ata 4? '< A "ublic $##utable( =ua!ru"le-. @ return ne: $##utable(-!ata B I.< A static voi! f-$##utable( i(. @ $##utable( =ua! ? i(.=ua!ru"le-.< %yste#.out."rintln-8i( ? 8 K i(.rea!-..< %yste#.out."rintln-8=ua! ? 8 K =ua!.rea!-..<
1=;=
Thinking in Java
,,,'0ruceEckel'com
A "ublic static voi! #ain-%tringNO args. @ $##utable( 6 ? ne: $##utable(-I*.< %yste#.out."rintln-86 ? 8 K 6.rea!-..< f-6.< %yste#.out."rintln-86 ? 8 K 6.rea!-..< A A ///3>
6ll data is private, and you ll see that none o" the p*blic #ethods #odi"y that data. Indeed, the #ethod that does a%%ear to #odi"y an ob0ect is C*a'r*pleA B, but this creates a new Imm*table> ob0ect and leaves the original one untouched. RFSURFSTIJLT6PPEC7IZ6TI32U The #ethod fA B takes an Imm*table> ob0ect and %er"or#s various o%erations on it, and the out%ut o" mainA B de#onstrates that there is no change to 4. Thus, 4 s ob0ect could be aliased #any ti#es without har# because the Imm*table> class is designed to guarantee that ob0ects cannot be changed. RFSURFSTIJLT6PPEC7IZ6TIG@U
//3 a""en!i6a3$##utable .Hava // 0 co#"anion class for #aking // changes to i##utable obHects. class Jutable @
1=;1
"rivate int !ata< "ublic Jutable-int initWal. @ !ata ? initWal< A "ublic Jutable a!!-int 6. @ !ata K? 6< return this< A "ublic Jutable #ulti"ly-int 6. @ !ata B? 6< return this< A "ublic $##utable #ake$##utable -. @ return ne: $##utable -!ata.< A A "ublic class $##utable @ "rivate int !ata< "ublic $##utable -int initWal. @ !ata ? initWal< A "ublic int rea!-. @ return !ata< A "ublic boolean nonUero-. @ return !ata 4? '< A "ublic $##utable a!!-int 6. @ return ne: $##utable -!ata K 6.< A "ublic $##utable #ulti"ly-int 6. @ return ne: $##utable -!ata B 6.< A "ublic Jutable #akeJutable-. @ return ne: Jutable-!ata.< A "ublic static $##utable #o!ify(-$##utable y.@ $##utable val ? y.a!!-( .< val ? val.#ulti"ly-).< val ? val.a!!-((.< val ? val.#ulti"ly- .< return val< A // This "ro!uces the sa#e result3
1=;2
Thinking in Java
,,,'0ruceEckel'com
"ublic static $##utable #o!ify -$##utable y.@ Jutable # ? y.#akeJutable-.< #.a!!-( ..#ulti"ly-)..a!!-((..#ulti"ly- .< return #.#ake$##utable -.< A "ublic static voi! #ain-%tringNO args. @ $##utable i ? ne: $##utable -I*.< $##utable r( ? #o!ify(-i .< $##utable r ? #o!ify -i .< %yste#.out."rintln-8i ? 8 K i .rea!-..< %yste#.out."rintln-8r( ? 8 K r(.rea!-..< %yste#.out."rintln-8r ? 8 K r .rea!-..< A A ///3> Imm*tableI contains #ethods that, as be"ore, %reserve the i##utability o" the ob0ects by %roducing new ob0ects whenever a #odi"ication is desired. These are the a''A B and m*ltiplyA B #ethods. The co#%anion class is called 1*table, and it also has a''A B and m*ltiplyA B #ethods, but these #odi"y the 1*table ob0ect rather than #aking a new one. In addition, 1*table has a #ethod to use its data to %roduce an Imm*tableI ob0ect and vice versa. RFSURF STIJLT6PPEC7IZ6TIGLU
The two static #ethods mo'ify>A B and mo'ifyIA B show two di""erent a%%roaches to %roducing the sa#e result. In mo'ify>A B, everything is done within the Imm*tableI class and you can see that "our new Imm*tableI ob0ects are created in the %rocess. *6nd each ti#e val is reassigned, the %revious ob0ect beco#es garbage., RFSURF STIJLT6PPEC7IZ6TIG?U In the #ethod mo'ifyIA B, you can see that the "irst action is to take the Imm*tableI y and %roduce a 1*table "ro# it. *This is 0ust like calling cloneA B as you saw earlier, but this ti#e a di""erent ty%e o" ob0ect is created., Then the 1*table ob0ect is used to %er"or# a lot o" change o%erations ,ithout reAuiring the creation o" #any new ob0ects. Einally, it s turned back into an Imm*tableI. (ere, two new ob0ects are created *the 1*table and the result Imm*tableI, instead o" "our. RFSURF STIJLT6PPEC7IZ6TIGHU This a%%roach #akes sense, then, when=
1=;3
!74) /ou need i##utable ob0ects and !75) /ou o"ten need to #ake a lot o" #odi"ications or !76) It s e&%ensive to create new i##utable ob0ects.
Immutable Strings
+onsider the "ollowing code= RFSURFSTIJLT6PPEC7IZ6TIG3U
//3 a""en!i6a3%tringer.Hava "ublic class %tringer @ static %tring u"case-%tring s. @ return s.toY""erCase-.< A "ublic static voi! #ain-%tringNO args. @ %tring = ? ne: %tring-8ho:!y8.< %yste#.out."rintln-=.< // ho:!y %tring == ? u"case-=.< %yste#.out."rintln-==.< // MG\D; %yste#.out."rintln-=.< // ho:!y A A ///3>
:hen C is %assed in to *pcaseA B it s actually a co%y o" the re"erence to C. The ob0ect this re"erence is connected to stays %ut in a single %hysical location. The re"erences are co%ied as they are %assed around. RFSURF STIJLT6PPEC7IZ6TIGGU Dooking at the de"inition "or *pcaseA B, you can see that the re"erence that s %assed in has the na#e s, and it e&ists "or only as long as the body o" *pcaseA B is being e&ecuted. :hen *pcaseA B co#%letes, the local re"erence s vanishes. *pcaseA B returns the result, which is the original string with all the characters set to u%%ercase. )" course, it actually returns a re"erence to the result. But it turns out that the re"erence that it returns is "or a new ob0ect, and the original C is le"t alone. (ow does this ha%%enO RFSURFSTIJLT6PPEC7IZ6TIGIU
1=;4
Thinking in Java
,,,'0ruceEckel'com
Im.licit constants
I" you say=
1=;5
e""icient. 6 case in %oint is the o%erator GL that has been overloaded "or )tring ob0ects. )verloading #eans that it has been given an e&tra #eaning when used with a %articular class. *The [ L and [LP "or )tring are the only o%erators that are overloaded in Java, and Java does not allow the %rogra##er to overload any others, @. RFSURF STIJLT6PPEC7IZ6TIILU :hen used with )tring ob0ects, the [L allows you to concatenate )trings together=
//3 a""en!i6a3$##utable%trings.Hava
@ +<< allows the %rogra##er to overload o%erators at will. Because this can o"ten be a
co#%licated %rocess *see +ha%ter M@ o" Thinking in C++D 2nd editionD Prentice'(all, K@@@,, the Java designers dee#ed it a !bad$ "eature that shouldn t be included in Java. It wasn t so bad that they didn t end u% doing it the#selves, and ironically enough, o%erator overloading would be #uch easier to use in Java than in +<<. This can be seen in Python *see www.Python.org, which has garbage collection and straight"orward o%erator overloading.
1=;7
Thinking in Java
,,,'0ruceEckel'com
// De#onstrating %tringBuffer. "ublic class $##utable%trings @ "ublic static voi! #ain-%tringNO args. @ %tring foo ? 8foo8< %tring s ? 8abc8 K foo K 8!ef8 K $nteger.to%tring-I*.< %yste#.out."rintln-s.< // The 8e=uivalent8 using %tringBuffer3 %tringBuffer sb ? ne: %tringBuffer-8abc8.< // Creates %tring4 sb.a""en!-foo.< sb.a""en!-8!ef8.< // Creates %tring4 sb.a""en!-$nteger.to%tring-I*..< %yste#.out."rintln-sb.< A A ///3>
In the creation o" )tring s, the co#%iler is doing the rough eAuivalent o" the subseAuent code that uses sb= a )tring2*ffer is created and appen'A B is used to add new characters directly into the )tring2*ffer ob0ect *rather than #aking new co%ies each ti#e,. :hile this is #ore e""icient, it s worth noting that each ti#e you create a Auoted character string such as aabcb and a'efb, the co#%iler turns those into )tring ob0ects. So there can be #ore ob0ects created than you e&%ect, des%ite the e""iciency a""orded through )tring2*ffer. RFSURF STIJLT6PPEC7IZ6TII3U
1=;8
1etho' -onstr*ctor
Arg*ments, .verloa'ing
)verloaded= 7e"ault, )tring, )tring2*ffer, char arrays, byte arrays.
Use
+reating )tring ob0ects.
Cu#ber o" characters in the )tring. The char at a location in the )tring. +o%y chars or bytes into an e&ternal array.
to-harArrayA B
region1atchesA B
Produces a char]^ containing the characters in the )tring. 6n eAuality check on the contents o" the two )trings. 5esult is negative, 1ero, or %ositive de%ending on the le&icogra%hical ordering o" the )tring and the argu#ent. 4%%ercase and lowercase are not eAual. boolean result indicates whether the region #atches.
1=;:
Thinking in Java
,,,'0ruceEckel'com
1etho' starts0ithA B
Use boolean result indicates whether the )tring starts with the argu#ent. boolean result indicates whether the argu#ent is a su""i&. 5eturns 'M i" the argu#ent is not "ound within this )tring, otherwise returns the inde& where the argu#ent starts. lastIn'e4.fA B
searches backward "ro# end. 5eturns a new )tring ob0ect containing the s%eci"ied character set. 5eturns a new )tring ob0ect containing the original )tring s characters "ollowed by the characters in the argu#ent. 5eturns a new )tring ob0ect with the re%lace#ents #ade. 4ses the old )tring i" no #atch is "ound. 5eturns a new )tring ob0ect with the case o" all letters changed. 4ses the old )tring i" no changes need to be #ade.
s*bstringA B
concatA B
)verloaded= Starting inde&, starting inde&, and ending inde&. The )tring to concatenate
replaceA B
The old character to search "or, the new character to re%lace it with.
to+o(er-aseA B toUpper-aseA B
1=;;
1etho' trimA B
Arg*ments, .verloa'ing
Use
5eturns a new )tring ob0ect with the white s%ace re#oved "ro# each end. 4ses the old )tring i" no changes need to be #ade. 5eturns a )tring containing a character re%resentation o" the argu#ent.
val*e.fA B
)verloaded= .b8ect, char]^, char]^ and o""set and count, boolean, char, int, long, float, 'o*ble.
internA B
Produces one and only one )tring re" %er uniAue character seAuence.
/ou can see that every )tring #ethod care"ully returns a new )tring ob0ect when it s necessary to change the contents. 6lso notice that i" the contents don t need changing the #ethod will 0ust return a re"erence to the original )tring. This saves storage and overhead. (ere s the )tring2*ffer class=
Arg*ments, overloa'ing
)verloaded= de"ault, length o" bu""er to create, )tring to create "ro#.
Use
+reate a new
)tring2*ffer
ob0ect. +reates a )tring "ro# this )tring2*ffer. Cu#ber o" characters in the )tring2*ffer. 5eturns current nu#ber o" s%aces allocated.
11==
Thinking in Java
,,,'0ruceEckel'com
Arg*ments, overloa'ing
Integer indicating desired ca%acity.
Use
Makes the
)tring2*ffer hold
at least the desired nu#ber o" s%aces. Truncates or e&%ands the %revious character string. I" e&%anding, %ads with nulls. 5eturns the char at that location in the bu""er. Modi"ies the value at that location.
charAtA B set-harAtA B
get-harsA B
appen'A B
Integer indicating the location o" the desired ele#ent. Integer indicating the location o" the desired ele#ent and the new char value "or the ele#ent. The beginning and end "ro# which to co%y, the array to co%y into, an inde& into the destination array. )verloaded= .b8ect, )tring, char]^, char]^ with o""set and length, boolean, char, int, long, float, 'o*ble.
insertA B
)verloaded, each with a "irst argu#ent o" the o""set at which to start inserting= .b8ect, )tring, char]^, boolean, char, int, long, float, 'o*ble.
+o%y chars into an e&ternal array. There is no get2ytesA B as in )tring. The argu#ent is converted to a string and a%%ended to the end o" the current bu""er, increasing the bu""er i" necessary. The second argu#ent is converted to a string and inserted into the current bu""er beginning at the o""set. The bu""er is increased i" necessary.
11=1
1etho' reverseA B
Arg*ments, overloa'ing
Use
The order o" the characters in the bu""er is reversed.
The #ost co##only used #ethod is appen'A B, which is used by the co#%iler when evaluating )tring e&%ressions that contain the [L and [LP o%erators. The insertA B #ethod has a si#ilar "or#, and both #ethods %er"or# signi"icant #ani%ulations to the bu""er instead o" creating new ob0ects.
1ummar:
Because everything is a re"erence in Java, and because every ob0ect is created on the hea% and garbage'collected only when it is no longer used, the "lavor o" ob0ect #ani%ulation changes, es%ecially when %assing and returning ob0ects. Eor e&a#%le, in + or +<<, i" you wanted to initiali1e so#e %iece o" storage in a #ethod, you d %robably reAuest that the user %ass the address o" that %iece o" storage into the #ethod. )therwise you d have to worry about who was res%onsible "or destroying that storage. Thus, the inter"ace and understanding o" such #ethods is #ore co#%licated. But in Java, you never have to worry about res%onsibility or whether an ob0ect will still e&ist when it is needed, since that is always taken care o" "or you. /our can create an ob0ect at the %oint that it is needed, and no sooner, and never worry about the #echanics o" %assing around res%onsibility "or that ob0ect= you si#%ly %ass the re"erence.
11=2
Thinking in Java
,,,'0ruceEckel'com
So#eti#es the si#%li"ication that this %rovides is unnoticed, other ti#es it is staggering. RFSURFSTIJLT6PPEC7IZ6TII2U The downside to all this underlying #agic is two"old=
!(7) /ou always take the e""iciency hit "or the e&tra #e#ory
#anage#ent *although this can be Auite s#all,, and there s always a slight a#ount o" uncertainty about the ti#e so#ething can take to run *since the garbage collector can be "orced into action whenever you get low on #e#ory,. Eor #ost a%%lications, the bene"its outweigh the drawbacks, and %articularly ti#e'critical sections can be written using native #ethods *see 6%%endi& B,. RFSURFSTIJLT6PPEC7IZ6TI2@U
@ 7oug Dea, who was hel%"ul in resolving this issue, suggested this to #e, saying that he si#%ly creates a "unction called '*plicateA B "or each class.
11=3
/0ercises
Solutions to selected e&ercises can be "ound in the electronic docu#entThe Thinking in Java "nnotated Solution @uide, available "or a s#all "ee "ro# ,,,'0ruceEckel'com.
11=4
Thinking in Java
,,,'0ruceEckel'com
11=5
The Java language and its standard 6PI are rich enough to write "ull'"ledged a%%lications. But in so#e cases you #ust call non'Java code; "or e&a#%le, i" you want to access o%erating'syste#'s%eci"ic "eatures, inter"ace with s%ecial hardware devices, reuse a %ree&isting, non'Java code base, or i#%le#ent ti#e'critical sections o" code.
Inter"acing with non'Java code reAuires dedicated su%%ort in the co#%iler and in the Virtual Machine, and additional tools to #a% the Java code to the non'Java code. The standard solution "or calling non'Java code that is %rovided by JavaSo"t is called the Java +ative Inter$ace, which will be introduced in this a%%endi&. This is not an in'de%th treat#ent, and in so#e cases you re assu#ed to have %artial knowledge o" the related conce%ts and techniAues. RFSURFSTIJLT6PPEC7IZBTIMU JCI is a "airly rich %rogra##ing inter"ace that allows you to call native #ethods "ro# a Java a%%lication. It was added in Java M.M, #aintaining a certain degree o" co#%atibility with its Java M.@ eAuivalent= the native #ethod inter"ace *CMI,. CMI has design characteristics that #ake it unsuitable "or ado%tion across all virtual #achines. Eor this reason, "uture versions o" the language #ight no longer su%%ort CMI, and it will not be covered here. RFSURFSTIJLT6PPEC7IZBTIKU
11=7
+urrently, JCI is designed to inter"ace with native #ethods written only in + or +<<. 4sing JCI, your native #ethods can=
+reate, ins%ect, and u%date Java ob0ects *including arrays and )trings, +all Java #ethods +atch and throw e&ce%tions Doad classes and obtain class in"or#ation Per"or# run'ti#e ty%e checking
Thus, virtually everything you can do with classes and ob0ects in ordinary Java you can also do in native #ethods. RFSURF STIJLT6PPEC7IZBTILU
//3 a""en!i6b3%ho:Jessage.Hava "ublic class %ho:Jessage @ "rivate native voi! %ho:Jessage-%tring #sg.< static @ %yste#.loa!Library-8Jsg$#"l8.< // Linu6 hack, if you can2t get your library // "ath set in your environ#ent3 // %yste#.loa!// 8/ho#e/bruce/tiH /a""en!i6b/Jsg$#"l.so8.< A "ublic static voi! #ain-%tringNO args. @ %ho:Jessage a"" ? ne: %ho:Jessage-.< a"".%ho:Jessage-8aenerate! :ith J&$8.< A A ///3>
"
11=8
The native #ethod declaration is "ollowed by a static block that calls )ystem!loa'+ibraryA B *which you could call at any ti#e, but this style is #ore a%%ro%riate,. )ystem!loa'+ibraryA B loads a 7DD in #e#ory and links to it. The 7DD #ust be in your syste# library %ath. The "ile na#e e&tension is auto#atically added by the JVM de%ending on the %lat"or#. RFSURFSTIJLT6PPEC7IZBTIHU In the above code you can also see a call to the )ystem!loa'A B #ethod, which is co##ented out. The %ath s%eci"ied here is an absolute %ath, rather than relying on an environ#ent variable. 4sing an environ#ent variable is naturally the better and #ore %ortable solution, but i" you can t "igure that out you can co##ent out the loa'+ibraryA B call and unco##ent this one, ad0usting the %ath to your own directory. RFSURF STIJLT6PPEC7IZBTI3U
Havah eHni %ho:Jessage 8avah reads the Java class "ile and "or each native #ethod declaration it
generates a "unction %rototy%e in a + or +<< header "ile. (ere s the out%ut= the )ho(1essage!h source "ile *edited slightly to "it into this book,= RFSURFSTIJLT6PPEC7IZBTIIU
/B DG > ED$T TM$% L$LE - it is #achine generate! B/ Sinclu!e PHni.hQ /B Mea!er for class %ho:Jessage B/ Sifn!ef b$nclu!e!b%ho:Jessage S!efine b$nclu!e!b%ho:Jessage Sif!ef bbc"lus"lus e6tern 8C8 @ Sen!if /B
11=:
B Class3 %ho:Jessage B Jetho!3 %ho:Jessage B %ignature3 -LHava/lang/%tring<.W B/ J&$E9PG5T voi! J&$C0LL Javab%ho:Jessageb%ho:Jessage -J&$Env B, HobHect, Hstring.< Sif!ef bbc"lus"lus A Sen!if Sen!if
6s you can see by the Wif'ef XXcpl*spl*s %re%rocessor directive, this "ile can be co#%iled either by a + or a +<< co#%iler. The "irst Wincl*'e directive includes 8ni!h, a header "ile that, a#ong other things, de"ines the ty%es that you can see used in the rest o" the "ile. J/I&X#.$T and J/I-A++ are #acros that e&%and to #atch %lat"or#'s%eci"ic directives. J/I&nv, 8ob8ect and 8string are JCI data ty%e de"initions, which will be e&%lained shortly. RFSURFSTIJLT6PPEC7IZBTI2U
"
11=;
//3 a""en!i6b3Jsg$#"l.c"" //S Teste! :ith WCKK D BCKK. $nclu!e "ath #ust //S be a!Huste! to fin! the J&$ hea!ers. %ee //S the #akefile for this cha"ter -in the //S !o:nloa!able source co!e. for an e6a#"le. Sinclu!e PHni.hQ Sinclu!e Pst!io.hQ Sinclu!e 8%ho:Jessage.h8 e6tern 8C8 J&$E9PG5T voi! J&$C0LL Javab%ho:Jessageb%ho:Jessage-J&$EnvB env, HobHect, Hstring HJsg. @ const charB #sg?env-Qaet%tringYTLChars-HJsg,'.< "rintf-8Thinking in Java, J&$3 Vs_n8, #sg.< env-Q5elease%tringYTLChars-HJsg, #sg.< A ///3>
The argu#ents that are %assed into the native #ethod are the gateway back into Java. The "irst, o" ty%e J/I&nv, contains all the hooks that allow you to call back into the JVM. *:e ll look at this in the ne&t section., The second argu#ent has a di""erent #eaning de%ending on the ty%e o" #ethod. Eor non' static #ethods like the e&a#%le above, the second argu#ent is the eAuivalent o" the !this$ %ointer in +<< and si#ilar to this in Java= it s a re"erence to the ob0ect that called the native #ethod. Eor static #ethods, it s a re"erence to the -lass ob0ect where the #ethod is i#%le#ented. RFSURFSTIJLT6PPEC7IZBTIMKU
111=
The re#aining argu#ents re%resent the Java ob0ects %assed into the native #ethod call. Pri#itives are also %assed in this way, but they co#e in by value. RFSURFSTIJLT6PPEC7IZBTIMLU In the "ollowing sections we ll e&%lain this code by looking at the ways that you access and control the JVM "ro# inside a native #ethod. RFSURF STIJLT6PPEC7IZBTIM?U
)btaining version in"or#ation Per"or#ing class and ob0ect o%erations (andling global and local re"erences to Java ob0ects 6ccessing instance "ields and static "ields +alling instance #ethods and static #ethods
"
1111
Per"or#ing string and array o%erations 8enerating and handling Java e&ce%tions
The nu#ber o" JCI "unctions is Auite large and won t be covered here. Instead, I ll show the rationale behind the use o" these "unctions. Eor #ore detailed in"or#ation, consult your co#%iler s JCI docu#entation. RFSURFSTIJLT6PPEC7IZBTIM3U I" you take a look at the 8ni!h header "ile, you ll see that inside the Wif'ef XXcpl*spl*s %re%rocessor conditional, the J/I&nvX structure is de"ined as a class when co#%iled by a +<< co#%iler. This class contains a nu#ber o" inline "unctions that let you access the JCI "unctions with an easy and "a#iliar synta&. Eor e&a#%le, the line o" +<< code in the %receding e&a#%le=
env-Q5elease%tringYTLChars-HJsg, #sg.<
could also be called "ro# + like this= RFSURFSTIJLT6PPEC7IZBTIMGU
1112
"et)tringUTF-harsA B is one o" the #e#ber "unctions in J/I&nv. To access the JCI "unction, we use the ty%ical +<< synta& "or calling a #e#ber "unction though a %ointer. /ou use the "or# above to access all o" the JCI "unctions. RFSURFSTIJLT6PPEC7IZBTIK@U
//3 a""en!i6b3YseGbHects.Hava class JyJavaClass @ "ublic int aWalue< "ublic voi! !ivByT:o-. @ aWalue /? A
< A
"ublic class YseGbHects @ "rivate native voi! changeGbHect-JyJavaClass obH.< static @ %yste#.loa!Library-8YseGbH$#"l8.< // Linu6 hack, if you can2t get your library // "ath set in your environ#ent3 // %yste#.loa!//8/ho#e/bruce/tiH /a""en!i6b/YseGbH$#"l.so8.< A "ublic static voi! #ain-%tringNO args. @ YseGbHects a"" ? ne: YseGbHects-.<
"
1113
JyJavaClass anGbH ? ne: JyJavaClass-.< anGbH.aWalue ? < a"".changeGbHect-anGbH.< %yste#.out."rintln-8Java3 8 K anGbH.aWalue.< A A ///3>
6"ter co#%iling the code and running 8avah, you can i#%le#ent the native #ethod. In the e&a#%le below, once the "ield and #ethod I7 are obtained, they are accessed through JCI "unctions. RFSURF STIJLT6PPEC7IZBTIKKU
//3 a""en!i6b3YseGbH$#"l.c"" //S Teste! :ith WCKK D BCKK. $nclu!e "ath #ust //S be a!Huste! to fin! the J&$ hea!ers. %ee //S the #akefile for this cha"ter -in the //S !o:nloa!able source co!e. for an e6a#"le. Sinclu!e PHni.hQ e6tern 8C8 J&$E9PG5T voi! J&$C0LL JavabYseGbHectsbchangeGbHectJ&$EnvB env, HobHect, HobHect obH. @ Hclass cls ? env-QaetGbHectClass-obH.< Hfiel!$D fi! ? env-QaetLiel!$Dcls, 8aWalue8, 8$8.< H#etho!$D #i! ? env-QaetJetho!$Dcls, 8!ivByT:o8, 8-.W8.< int value ? env-Qaet$ntLiel!-obH, fi!.< "rintf-8&ative3 V!_n8, value.< env-Q%et$ntLiel!-obH, fi!, +.< env-QCallWoi!Jetho!-obH, #i!.< value ? env-Qaet$ntLiel!-obH, fi!.< "rintf-8&ative3 V!_n8, value.< A ///3>
Ignoring the !this$ eAuivalent, the +<< "unction receives a 8ob8ect, which is the native side o" the Java ob0ect re"erence we %ass "ro# the Java code. :e si#%ly read aVal*e, %rint it out, change the value, call the ob0ect s 'iv2yT(oA B #ethod, and %rint the value out again. RFSURF STIJLT6PPEC7IZBTIKLU To access a Java "ield or #ethod, you #ust "irst obtain its identi"ier using "etFiel'I A B "or "ields and "et1etho'I A B "or #ethods. These
1114
"unctions take the class ob0ect, a string containing the ele#ent na#e, and a string that gives ty%e in"or#ation= the data ty%e o" the "ield, or signature in"or#ation "or a #ethod *details can be "ound in the JCI docu#entation,. These "unctions return an identi"ier that you use to access the ele#ent. This a%%roach #ight see# convoluted, but your native #ethod has no knowledge o" the internal layout o" the Java ob0ect. Instead, it #ust access "ields and #ethods through inde&es returned by the JVM. This allows di""erent JVMs to i#%le#ent di""erent internal ob0ect layouts with no i#%act on your native #ethods. RFSURF STIJLT6PPEC7IZBTIK?U I" you run the Java %rogra#, you ll see that the ob0ect that s %assed "ro# the Java side is #ani%ulated by your native #ethod. But what e&actly is %assedO 6 %ointer or a Java re"erenceO 6nd what is the garbage collector doing during native #ethod callsO RFSURFSTIJLT6PPEC7IZBTIKHU The garbage collector continues to o%erate during native #ethod e&ecution, but it s guaranteed that your ob0ects will not be garbage' collected during a native #ethod call. To ensure this, local re$erences are created be"ore, and destroyed right a"ter, the native #ethod call. Since their li"eti#e wra%s the call, you know that the ob0ects will be valid throughout the native #ethod call. RFSURFSTIJLT6PPEC7IZBTIK3U Since these re"erences are created and subseAuently destroyed every ti#e the "unction is called, you cannot #ake local co%ies in your native #ethods, in static variables. I" you want a re"erence that lasts across "unction invocations, you need a global re"erence. 8lobal re"erences are not created by the JVM, but the %rogra##er can #ake a global re"erence out o" a local one by calling s%eci"ic JCI "unctions. :hen you create a global re"erence, you beco#e res%onsible "or the li"eti#e o" the re"erenced ob0ect. The global re"erence *and the ob0ect it re"ers to, will be in #e#ory until the %rogra##er e&%licitly "rees the re"erence with the a%%ro%riate JCI "unction. It s si#ilar to mallocA B and freeA B in +. RFSURF STIJLT6PPEC7IZBTIKGU
"
1115
Thro(A B
Throws an e&isting e&ce%tion ob0ect. 4sed in native #ethods to rethrow an e&ce%tion.
Thro(/e(A B
8enerates a new e&ce%tion ob0ect and throws it.
&4ception.cc*rre'A B
7eter#ines i" an e&ce%tion was thrown and not yet cleared.
&4ception escribeA B
Prints an e&ce%tion and the stack trace.
&4ception-learA B
+lears a %ending e&ce%tion.
Fatal&rrorA B
5aises a "atal error. 7oes not return. 6#ong these, you can t ignore &4ception.cc*rre'A B and &4ception-learA B. Most JCI "unctions can generate e&ce%tions, and there is no language "eature that you can use in %lace o" a Java try block, so you #ust call &4ception.cc*rre'A B a"ter each JCI "unction call to see i" an e&ce%tion was thrown. I" you detect an e&ce%tion, you #ay choose to handle it *and %ossibly rethrow it,. /ou #ust #ake certain, however, that the e&ce%tion is eventually cleared. This can be done in your "unction using &4ception-learA B or in so#e other "unction i" the e&ce%tion is rethrown, but it #ust be done. RFSURF STIJLT6PPEC7IZBTIK2U /ou #ust ensure that the e&ce%tion is cleared, because otherwise the results will be un%redictable i" you call a JCI "unction while an e&ce%tion is %ending. There are "ew JCI "unctions that are sa"e to call during an
1117
e&ce%tion; a#ong these, o" course, are all the e&ce%tion handling "unctions. RFSURFSTIJLT6PPEC7IZBTIL@U
"
1118
Additional information
/ou can "ind "urther introductory #aterial, including a + *rather than +<<, e&a#%le and discussion o" Microso"t issues, in 6%%endi& 6 o" the "irst edition o" this book, which can be "ound on the +7 5)M bound in with this book, or in a "ree download "ro# ,,,'0ruceEckel'com. More e&tensive in"or#ation is available at >ava'sun'com *in the search engine, select !training N tutorials$ "or keywords !native #ethods$,. +ha%ter MM o" Core Java 2, Colume II, by (orst#ann N +ornell *Prentice'(all, K@@@, gives e&cellent coverage o" native #ethods. RFSU
111:
Design
!(!) &legance al(ays pays off. In the short ter# it #ight see# like it
takes #uch longer to co#e u% with a truly grace"ul solution to a %roble#, but when it works the "irst ti#e and easily ada%ts to new situations instead o" reAuiring hours, days, or #onths o" struggle, you ll see the rewards *even i" no one can #easure the#,. Cot only does it give you a %rogra# that s easier to build and debug, but it s also easier to understand and #aintain, and that s where the "inancial value lies. This %oint can take so#e e&%erience to understand, because it can a%%ear that you re not being %roductive while you re #aking a %iece o" code elegant. 5esist the urge to hurry; it will only slow you down. RFSURF STIJLT6PPEC7IZ+TIKU
!(*) First make it (ork, then make it fast. This is true even i" you
are certain that a %iece o" code is really i#%ortant and that it will be a %rinci%al bottleneck in your syste#. 7on t do it. 8et the
111;
syste# going "irst with as si#%le a design as %ossible. Then i" it isn t going "ast enough, %ro"ile it. /ou ll al#ost always discover that !your$ bottleneck isn t the %roble#. Save your ti#e "or the really i#%ortant stu"". RFSURFSTIJLT6PPEC7IZ+TILU
!(,) )eparate the class creator from the class *ser Aclient 'rogra##erB. The class user is the !custo#er$ and doesn t need
or want to know what s going on behind the scenes o" the class. The class creator #ust be the e&%ert in class design and write the class so that it can be used by the #ost novice %rogra##er %ossible, yet still work robustly in the a%%lication. Dibrary use will be easy only i" it s trans%arent. RFSURFSTIJLT6PPEC7IZ+TIHU
!(-) 0hen yo* create a class, attempt to make yo*r names so clear that comments are *nnecessary. /our goal should be to
#ake the client %rogra##er s inter"ace conce%tually si#%le. To this end, use #ethod overloading when a%%ro%riate to create an intuitive, easy'to'use inter"ace. RFSURFSTIJLT6PPEC7IZ+TI3U
!(4) :o*r analysis an' 'esign m*st pro'*ce, at minim*m, the classes in yo*r system, their p*blic interfaces, an' their relationships to other classes, especially base classes. I"
your design #ethodology %roduces #ore than that, ask yoursel" i" all the %ieces %roduced by that #ethodology have value over the li"eti#e o" the %rogra#. I" they do not, #aintaining the# will cost you. Me#bers o" develo%#ent tea#s tend not to #aintain anything that does not contribute to their %roductivity; this is a "act o" li"e that #any design #ethods don t account "or. RFSURF STIJLT6PPEC7IZ+TIGU
!(5) A*tomate everything. :rite the test code "irst *be"ore you write
the class,, and kee% it with the class. 6uto#ate the running o" your
112=
Thinking in Java
,,,'0ruceEckel'com
tests through a #ake"ile or si#ilar tool. This way, any changes can be auto#atically veri"ied by running the test code, and you ll i##ediately discover errors. Because you know that you have the sa"ety net o" your test "ra#ework, you will be bolder about #aking swee%ing changes when you discover the need. 5e#e#ber that the greatest i#%rove#ents in languages co#e "ro# the built'in testing %rovided by ty%e checking, e&ce%tion handling, etc., but those "eatures take you only so "ar. /ou #ust go the rest o" the way in creating a robust syste# by "illing in the tests that veri"y "eatures that are s%eci"ic to your class or %rogra#. RFSURF STIJLT6PPEC7IZ+TIIU
!(6) 0rite the test co'e first Abefore yo* (rite the classB in or'er to verify that yo*r class 'esign is complete. I" you
can t write test code, you don t know what your class looks like. In addition, the act o" writing the test code will o"ten "lush out additional "eatures or constraints that you need in the class9these "eatures or constraints don t always a%%ear during analysis and design. Tests also %rovide e&a#%le code showing how your class can be used. RFSURFSTIJLT6PPEC7IZ+TI2U
!!7) All soft(are 'esign problems can be simplifie' by intro'*cing an e4tra level of concept*al in'irection' This
"unda#ental rule o" so"tware engineering @ is the basis o" abstraction, the %ri#ary "eature o" ob0ect'oriented %rogra##ing. RFSURFSTIJLT6PPEC7IZ+TIM@U
1121
it s doing too #uch and should be broken u%. +lues to suggest redesign o" a class are= M, 6 co#%licated switch state#ent= consider using %oly#or%his#. K, 6 large nu#ber o" #ethods that cover broadly di""erent ty%es o" o%erations= consider using several classes. L, 6 large nu#ber o" #e#ber variables that concern broadly di""erent characteristics= consider using several classes. RFSURF STIJLT6PPEC7IZ+TIMKU
!!*) 0atch for long arg*ment lists. Method calls then beco#e
di""icult to write, read, and #aintain. Instead, try to #ove the #ethod to a class where it is *#ore, a%%ro%riate, andFor %ass ob0ects in as argu#ents. RFSURFSTIJLT6PPEC7IZ+TIMLU
!!+)
!!,) 0atch for switch statements or chaine' if+else cla*ses. This is ty%ically an indicator o" t) e/check coding, which #eans
you are choosing what code to e&ecute based on so#e kind o" ty%e in"or#ation *the e&act ty%e #ay not be obvious at "irst,. /ou can usually re%lace this kind o" code with inheritance and %oly#or%his#; a %oly#or%hic #ethod call will %er"or# the ty%e checking "or you, and allow "or #ore reliable and easier e&tensibility. RFSURFSTIJLT6PPEC7IZ+TIMHU
!!-) From a 'esign stan'point, look for an' separate things that change from things that stay the same. That is, search
"or the ele#ents in a syste# that you #ight want to change without "orcing a redesign, then enca%sulate those ele#ents in classes. /ou can learn signi"icantly #ore about this conce%t in Thinking in Patterns ,ith Java, downloadable at ,,,'0ruceEckel'com. RF SURFSTIJLT6PPEC7IZ+TIM3U
1122
Thinking in Java
,,,'0ruceEckel'com
!!4)
on;t e4ten' f*n'amental f*nctionality by s*bclassing. I" an inter"ace ele#ent is essential to a class it should be in the base class, not added during derivation. I" you re adding #ethods by inheriting, %erha%s you should rethink the design. RFSURF STIJLT6PPEC7IZ+TIMGU
and si#%le as you need to solve the %roble# at hand, but don t try to antici%ate all the ways that your class might be used. 6s the class is used, you ll discover ways you #ust e&%and the inter"ace. (owever, once a class is in use you cannot shrink the inter"ace without disturbing client code. I" you need to add #ore #ethods, that s "ine; it won t disturb code, other than "orcing reco#%iles. But even i" new #ethods re%lace the "unctionality o" old ones, leave the e&isting inter"ace alone *you can co#bine the "unctionality in the underlying i#%le#entation i" you want,. I" you need to e&%and the inter"ace o" an e&isting #ethod by adding #ore argu#ents, create an overloaded #ethod with the new argu#ents; this way you won t disturb any e&isting calls to the e&isting #ethod. RFSURF STIJLT6PPEC7IZ+TIMIU
!!6) $ea' yo*r classes alo*' to make s*re they;re logical. 5e"er
to the relationshi% between a base class and derived class as !is'a$ and #e#ber ob0ects as !has'a.$ RFSURFSTIJLT6PPEC7IZ+TIM2U
!*7) 0hen 'eci'ing bet(een inheritance an' composition, ask if yo* nee' to *pcast to the base type. I" not, %re"er
co#%osition *#e#ber ob0ects, to inheritance. This can eli#inate the %erceived need "or #ulti%le base ty%es. I" you inherit, users will think they are su%%osed to u%cast. RFSURF STIJLT6PPEC7IZ+TIK@U
!*() Use 'ata members for variation in val*e an' metho' overri'ing for variation in behavior. That is, i" you "ind a
class that uses state variables along with #ethods that switch behavior based on those variables, you should %robably redesign it to e&%ress the di""erences in behavior within subclasses and overridden #ethods. RFSURFSTIJLT6PPEC7IZ+TIKMU
1123
$heck """.BruceEckel.com for [email protected] details and the date and location of the ne0t Hands-On Java Seminar
Based on this book Taught by Bruce Eckel Personal attention "ro# Bruce Eckel and his se#inar assistants Includes in'class %rogra##ing e&ercises Inter#ediateF6dvanced se#inars also o""ered
1124 Thinking in Java ,,,'0ruceEckel'com
!*,) -onsi'er the perspective of the client programmer an' the person maintaining the co'e. 7esign your class to be as obvious as %ossible to use. 6ntici%ate the kind o" changes that will be #ade, and design your class so that those changes will be easy.
RFSURFSTIJLT6PPEC7IZ+TIKHU
!*-) 0atch o*t for agiant ob8ect syn'rome!b This is o"ten an a""liction o" %rocedural %rogra##ers who are new to ))P and who end u% writing a %rocedural %rogra# and sticking it inside one or two giant ob0ects. :ith the e&ce%tion o" a%%lication "ra#eworks, ob0ects re%resent conce%ts in your a%%lication, not the a%%lication. RFSURFSTIJLT6PPEC7IZ+TIK3U !*4) If yo* m*st 'o something *gly, at least locali7e the *gliness insi'e a class. RFSURFSTIJLT6PPEC7IZ+TIKGU
1125
Bruce Eckels Hands-On Java Seminar Multimedia CD Its like coming to the seminar! Available at www.BruceEckel.com
)verhead slides and synchroni1ed audio voice narration "or all the lectures. Just %lay it to see and hear the lectures. +reated and narrated by Bruce Eckel. Based on the #aterial in this book.
If yo* m*st 'o something nonportable, make an abstraction for that service an' locali7e it (ithin a class. This e&tra level o"
indirection %revents the non%ortability "ro# being distributed throughout your %rogra#. *This idio# is e#bodied in the 0ridge Pattern,. RFSURFSTIJLT6PPEC7IZ+TIKIU
!*6) .b8ects sho*l' not simply hol' some 'ata. They should also have well'de"ined behaviors. *)ccasionally, !data ob0ects$ are a%%ro%riate, but only when used e&%ressly to %ackage and trans%ort a grou% o" ite#s when a generali1ed container is inna%%ro%riate., RFSURFSTIJLT6PPEC7IZ+TIK2U !+7) -hoose composition first (hen creating ne( classes from e4isting classes. /ou should only used inheritance i" it is
reAuired by your design. I" you use inheritance where co#%osition will work, your designs will beco#e needlessly co#%licated. RF SURFSTIJLT6PPEC7IZ+TIL@U
!+() Use inheritance an' metho' overri'ing to e4press 'ifferences in behavior, an' fiel's to e4press variations in state. 6n e&tre#e e&a#%le o" what not to do is inheriting
di""erent classes to re%resent colors instead o" using a !color$ "ield. RFSURFSTIJLT6PPEC7IZ+TILMU
!+!) 0atch o*t for variance. Two se#antically di""erent ob0ects #ay
have identical actions, or res%onsibilities, and there is a natural te#%tation to try to #ake one a subclass o" the other 0ust to bene"it "ro# inheritance. This is called variance, but there s no real 0usti"ication to "orce a su%erclassFsubclass relationshi% where it doesn t e&ist. 6 better solution is to create a general base class that %roduces an inter"ace "or both as derived classes9it reAuires a bit #ore s%ace, but you still bene"it "ro# inheritance, and will %robably #ake an i#%ortant discovery about the design. RFSURF STIJLT6PPEC7IZ+TILKU
1128
class in its subclass than it would be to restructure the hierarchy so your new class "its in where it should, above the old class. RFSURF STIJLT6PPEC7IZ+TILLU
!+,) 0atch o*t for aanalysis paralysis!b 5e#e#ber that you #ust usually #ove "orward in a %ro0ect be"ore you know everything, and that o"ten the best and "astest way to learn about so#e o" your unknown "actors is to go to the ne&t ste% rather than trying to "igure it out in your head. /ou can t know the solution until you have the solution. Java has built'in "irewalls; let the# work "or
you. /our #istakes in a class or set o" classes won t destroy the integrity o" the whole syste#. RFSURFSTIJLT6PPEC7IZ+TILHU
!+-) 0hen yo* think yo*;ve got a goo' analysis, 'esign, or implementation, 'o a (alkthro*gh. Bring so#eone in "ro# outside your grou%9this doesn t have to be a consultant, but can be so#eone "ro# another grou% within your co#%any. 5eviewing your work with a "resh %air o" eyes can reveal %roble#s at a stage when it s #uch easier to "i& the#, and #ore than %ays "or the ti#e and #oney !lost$ to the walkthrough %rocess. RFSURF
STIJLT6PPEC7IZ+TIL3U
Im.lementation
!+4) In general, follo( the )*n co'ing conventions. These are
available at
112:
Thinking in Java
,,,'0ruceEckel'com
"ollows these conventions as #uch as I was able,. These are used "or what constitutes arguably the largest body o" code that the largest nu#ber o" Java %rogra##ers will be e&%osed to. I" you doggedly stick to the coding style you ve always used, you will #ake it harder "or your reader. :hatever coding conventions you decide on, ensure they are consistent throughout the %ro0ect. There is a "ree tool to auto#atically re"or#at Java code at= home',tal'de/
so$t,are/solutions/>indent' RFSURFSTIJLT6PPEC7IZ+TILGU !+5) 0hatever co'ing style yo* *se, it really 'oes make a 'ifference if yo*r team Aan' even better, yo*r companyB stan'ar'i7es on it. This #eans to the %oint that everyone
considers it "air ga#e to "i& so#eone else s coding style i" it doesn t con"or#. The value o" standardi1ation is that it takes less brain cycles to %arse the code, so that you can "ocus #ore on what the code #eans. RFSURFSTIJLT6PPEC7IZ+TILIU
ThisIsA-lass/ame thisIsA1etho'.rFiel'/ame +a%itali1e all the letters o" static final %ri#itive identi"iers that
have constant initiali1ers in their de"initions. This indicates they are co#%ile'ti#e constants. #ackages are a special case9they are all lowercase letters, even "or inter#ediate words. The do#ain e&tension *co#, org, net, edu, etc., should also be lowercase. *This was a change between Java M.M and Java K., RFSURFSTIJLT6PPEC7IZ+TIL2U
!,7)
on;t create yo*r o(n a'ecorate'b private 'ata member names. This is usually seen in the "or# o" %re%ended underscores
and characters. (ungarian notation is the worst e&a#%le o" this, where you attach e&tra characters that indicate data ty%e, use, location, etc., as i" you were writing asse#bly language and the co#%iler %rovided no e&tra assistance at all. These notations are con"using, di""icult to read, and un%leasant to en"orce and
112;
#aintain. Det classes and %ackages do the na#e sco%ing "or you. RF SURFSTIJLT6PPEC7IZ+TI?@U
!,() Follo( a acanonical formb when creating a class "or general' %ur%ose use. Include de"initions "or eC*alsA B, hash-o'eA B, to)tringA B, cloneA B *i#%le#ent -loneable,, and i#%le#ent -omparable and )eriali7able. RFSURF
STIJLT6PPEC7IZ+TI?MU
!,!) Use the Java2eans aget,b aset,b an' aisb naming conventions "or #ethods that read and change private "ields,
even i" you don t think you re #aking a JavaBean at the ti#e. Cot only does it #ake it easy to use your class as a Bean, but it s a standard way to na#e these kinds o" #ethods and so will be #ore easily understood by the reader. RFSURF STIJLT6PPEC7IZ+TI?KU
!,*) For each class yo* create, consi'er incl*'ing a static 'ublic test1 2 that contains co'e to test that class. /ou don t
need to re#ove the test code to use the class in a %ro0ect, and i" you #ake any changes you can easily rerun the tests. This code also %rovides e&a#%les o" how to use your class. RFSURF STIJLT6PPEC7IZ+TI?LU
!,+) )ometimes yo* nee' to inherit in or'er to access 'rotected members of the base class. This can lead to a
%erceived need "or #ulti%le base ty%es. I" you don t need to u%cast, "irst derive a new class to %er"or# the %rotected access. Then #ake that new class a #e#ber ob0ect inside any class that needs to use it, rather than inheriting. RFSURFSTIJLT6PPEC7IZ+TI??U
!,,) Avoi' the *se of final metho's for efficiency p*rposes. 4se final only when the %rogra# is running, but not "ast enough,
and your %ro"iler has shown you that a #ethod invocation is the bottleneck. RFSURFSTIJLT6PPEC7IZ+TI?HU
!,-) If t(o classes are associate' (ith each other in some f*nctional (ay As*ch as containers an' iteratorsB, try to make one an inner class of the other. This not only
e#%hasi1es the association between the classes, but it allows the
113=
Thinking in Java
,,,'0ruceEckel'com
class na#e to be reused within a single %ackage by nesting it within another class. The Java containers library does this by de"ining an inner Iterator class inside each container class, thereby %roviding the containers with a co##on inter"ace. The other reason you ll want to use an inner class is as %art o" the private i#%le#entation. (ere, the inner class bene"icial "or i#%le#entation hiding rather than the class association and %revention o" na#es%ace %ollution noted above. RFSURF STIJLT6PPEC7IZ+TI?3U
!,4) Anytime yo* notice classes that appear to have high co*pling (ith each other, consi'er the co'ing an' maintenance improvements yo* might get by *sing inner classes. The use o" inner classes will not uncou%le the classes, but
rather #ake the cou%ling e&%licit and #ore convenient. RFSURF STIJLT6PPEC7IZ+TI?GU
!,5)
on;t fall prey to premat*re optimi7ation. This way lies #adness. In %articular, don t worry about writing *or avoiding, native #ethods, #aking so#e #ethods final, or tweaking code to be e""icient when you are "irst constructing the syste#. /our %ri#ary goal should be to %rove the design, unless the design reAuires a certain e""iciency. RFSURFSTIJLT6PPEC7IZ+TI?IU
!,6) %eep scopes as small as possible so the visibility an' lifetime of yo*r ob8ects are as small as possible. This
reduces the chance o" using an ob0ect in the wrong conte&t and hiding a di""icult'to'"ind bug. Eor e&a#%le, su%%ose you have a container and a %iece o" code that iterates through it. I" you co%y that code to use with a new container, you #ay accidentally end u% using the si1e o" the old container as the u%%er bound o" the new one. I", however, the old container is out o" sco%e, the error will be caught at co#%ile'ti#e. RFSURFSTIJLT6PPEC7IZ+TI?2U
1131
!-() For a program to be rob*st, each component m*st be rob*st. 4se all the tools %rovided by Java= access control,
e&ce%tions, ty%e checking, and so on, in each class you create. That way you can sa"ely #ove to the ne&t level o" abstraction when building your syste#. RFSURFSTIJLT6PPEC7IZ+TIHMU
!-,) Use comments liberally, an' *se the javadoc comment6 'oc*mentation synta4 to pro'*ce yo*r program
1132
Thinking in Java
,,,'0ruceEckel'com
'oc*mentation. (owever, the co##ents should add geniune #eaning to the code; co##ents that only reiterate what the code is clearly e&%ressing are annoying. Cote that the ty%ical verbose detail o" Java class and #ethod na#es reduce the need "or as #any co##ents. RFSURFSTIJLT6PPEC7IZ+TIHHU !--) Avoi' *sing amagic n*mbersb9which are nu#bers hard' wired into code. These are a night#are i" you need to change the#, since you never know i" !M@@$ #eans !the array si1e$ or !so#ething else entirely.$ Instead, create a constant with a descri%tive na#e and use the constant identi"ier throughout your %rogra#. This #akes the %rogra# easier to understand and #uch easier to #aintain. RFSURFSTIJLT6PPEC7IZ+TIH3U !-4) 0hen creating constr*ctors, consi'er e4ceptions. In the
best case, the constructor won t do anything that throws an e&ce%tion. In the ne&t'best scenario, the class will be co#%osed and inherited "ro# robust classes only, so they will need no cleanu% i" an e&ce%tion is thrown. )therwise, you #ust clean u% co#%osed classes inside a finally clause. I" a constructor #ust "ail, the a%%ro%riate action is to throw an e&ce%tion, so the caller doesn t continue blindly, thinking that the ob0ect was created correctly. RFSURFSTIJLT6PPEC7IZ+TIHGU
!-5) If yo*r class reC*ires any clean*p (hen the client programmer is finishe' (ith the ob8ect, place the clean*p co'e in a single, (ell6'efine' metho'9with a na#e like clean*pA B that clearly suggests its %ur%ose. In addition, %lace a boolean "lag in the class to indicate whether the ob0ect has been cleaned u% so that finali7eA B can check "or !the death condition$
*see +ha%ter ?,. RFSURFSTIJLT6PPEC7IZ+TIHIU
!-6) The responsibility of finali%e1 2 can only be to verify athe 'eath con'itionb of an ob8ect for 'eb*gging! *See +ha%ter
?., In s%ecial cases, it #ight be needed to release #e#ory that would not otherwise be released by the garbage collector. Since the garbage collector #ight not get called "or your ob0ect, you cannot use finali7eA B to %er"or# necessary cleanu%. Eor that you #ust create your own !cleanu%$ #ethod. In the finali7eA B #ethod "or
1133
the class, check to #ake sure that the ob0ect has been cleaned u% and throw a class derived "ro# $*ntime&4ception i" it hasn t, to indicate a %rogra##ing error. Be"ore relying on such a sche#e, ensure that finali7eA B works on your syste#. */ou #ight need to call )ystem!gcA B to ensure this behavior., RFSURF STIJLT6PPEC7IZ+TIH2U
!47) If an ob8ect m*st be cleane' *p Aother than by garbage collectionB (ithin a partic*lar scope, *se the follo(ing approach< Initiali1e the ob0ect and, i" success"ul, i##ediately enter a try block with a finally clause that %er"or#s the cleanu%.
RFSURFSTIJLT6PPEC7IZ+TI3@U
!4() 0hen overri'ing finali%e1 2 '*ring inheritance, remember to call su'er6finali%e1 2! *This is not necessary i" .b8ect is your i##ediate su%erclass., /ou should call s*per! finali7eA B as the $inal act o" your overridden finali7eA B rather
than the "irst, to ensure that base'class co#%onents are still valid i" you need the#. RFSURFSTIJLT6PPEC7IZ+TI3MU
!4!) 0hen yo* are creating a fi4e'6si7e container of ob8ects, transfer them to an array9es%ecially i" you re returning this
container "ro# a #ethod. This way you get the bene"it o" the array s co#%ile'ti#e ty%e checking, and the reci%ient o" the array #ight not need to cast the ob0ects in the array in order to use the#. Cote that the base'class o" the containers library, 8ava!*til! -ollection, has two toArrayA B #ethods to acco#%lish this. RF SURFSTIJLT6PPEC7IZ+TI3KU
!4+) Insi'e constr*ctors, 'o only (hat is necessary to set the ob8ect into the proper state. 6ctively avoid calling other #ethods *e&ce%t "or final #ethods, since those #ethods can be
1134
Thinking in Java
,,,'0ruceEckel'com
overridden by so#eone else to %roduce une&%ected results during construction. *See +ha%ter G "or details., S#aller, si#%ler constructors are less likely to throw e&ce%tions or cause %roble#s. RFSURFSTIJLT6PPEC7IZ+TI3?U
!4,) To avoi' a highly fr*strating e4perience, make s*re that there is only one *npackage' class of each name any(here in yo*r classpath. )therwise, the co#%iler can "ind
the identically'na#ed other class "irst, and re%ort error #essages that #ake no sense. I" you sus%ect that you are having a class%ath %roble#, try looking "or !class "iles with the sa#e na#es at each o" the starting %oints in your class%ath. Ideally, %ut all your classes within %ackages. RFSURFSTIJLT6PPEC7IZ+TI3HU
!44) 0atch o*t for premat*re optimi7ation. Eirst #ake it work, then #ake it "ast9but only i" you #ust, and only i" it s %roven that there is a %er"or#ance bottleneck in a %articular section o" your code. 4nless you have used a %ro"iler to discover a bottleneck, you will %robably be wasting your ti#e. The hidden cost o" %er"or#ance tweaks is that your code beco#es less understandable and #aintainable. RFSURFSTIJLT6PPEC7IZ+TI3GU !45) $emember that co'e is rea' m*ch more than it is (ritten. +lean designs #ake "or easy'to'understand %rogra#s, but co##ents, detailed e&%lanations, and e&a#%les are invaluable. They will hel% both you and everyone who co#es a"ter you. I" nothing else, the "rustration o" trying to "erret out use"ul in"or#ation "ro# the online Java docu#entation should convince you. RFSU
1135
D: $esources
1oftware
RFSTIJLT6PPEC7IZ7TI@U The J % "ro# >ava'sun'com. Even i" you choose to use a third'%arty develo%#ent environ#ent, it s always a good idea to have the J7> on hand in case you co#e u% against what #ight be a co#%iler error. The J7> is the touchstone, and i" there is a bug in it, chances are it will be well'known. RFSURFSTIJLT6PPEC7IZ7TIMU
;ooks
Thinking in Java7 8st dition. 6vailable as "ully'inde&ed, color'
synta&'highlighted (TMD on the +7 5)M bound in with this book, or as a "ree download "ro# ,,,'0ruceEckel'com. Includes older #aterial and #aterial that was not considered interesting enough to carry through to the K nd edition. RFSURFSTIJLT6PPEC7IZ7TILU
Core Java 9, by (orst#ann N +ornell, Volu#e I9Eunda#entals *Prentice'(all, M222,. Volu#e II96dvanced Eeatures, K@@@. (uge, co#%rehensive, and the "irst %lace I go when I # hunting "or answers. The book I reco##end when you ve co#%leted Thinking in Java and need to cast a bigger net. RFSURFSTIJLT6PPEC7IZ7TI?U
1137
Java in a 0utshell. - Deskto' :uick Reference7 9nd dition, by 7avid Elanagan *) 5eilly, M22G,. 6 co#%act su##ary o" the online Java docu#entation. Personally, I %re"er to browse the docs "ro# >ava'sun' com online, es%ecially since they change so o"ten. (owever, #any "olks still like %rinted docu#entation and this "its the bill; it also %rovides #ore discussion than the online docu#ents. F/GHF/GTIJ3I"PPE+%IN%II5H The Java Class 5ibraries. -n -nnotated Reference, by Patrick +han and 5osanna Dee *6ddison':esley, M22G,. :hat the online re"erence should have been= enough descri%tion to #ake it usable. )ne o" the technical reviewers "or Thinking in Java said, !I" I had only one Java book, this would be it *well, in addition to yours, o" course,.$ I # not as thrilled with it as he is. It s big, it s e&%ensive, and the Auality o" the e&a#%les doesn t satis"y #e. 0ut it s a %lace to look when you re stuck and it see#s to have #ore de%th *and sheer si1e, than Java in a +utshell. RF SURFSTIJLT6PPEC7IZ7TI3U Java 0etwork "rogra##ing, by Elliotte 5usty (arold *) 5eilly, M22G,. I didn t begin to understand Java networking until I "ound this book. I also "ind his :eb site, +a"W au Dait, to be a sti#ulating, o%inionated, and u%'to'date %ers%ective on Java develo%#ents, unencu#bered by allegiances to any vendors. (is regular u%dates kee% u% with "ast'changing news about Java. See metalab'unc'edu/>ava$a#/. RF SURFSTIJLT6PPEC7IZ7TIGU JD4C Database -ccess with Java, by (a#ilton, +attell N Eisher
*6ddison':esley, M22G,. I" you know nothing about SeD and databases, this is a nice, gentle introduction. It also contains so#e o" the details as well as an !annotated re"erence$ to the 6PI *again, what the online re"erence should have been,. The drawback, as with all books in The Java Series *!The )CD/ Books 6uthori1ed by JavaSo"t$, is that it s been whitewashed so that it says only wonder"ul things about Java9you won t "ind out about any dark corners in this series. RFSURF STIJLT6PPEC7IZ7TIIU
"
endi* %! -esources
1138
Design "atterns, by 8a##a, (el#, Johnson N Vlissides *6ddison' :esley, M22H,. The se#inal book that started the %atterns #ove#ent in %rogra##ing. RFSURFSTIJLT6PPEC7IZ7TIM@U "ractical -lgorith#s for "rogra##ers, by Binstock N 5e&
*6ddison':esley, M22H,. The algorith#s are in +, so they re "airly easy to translate into Java. Each algorith# is thoroughly e&%lained. RFSURF STIJLT6PPEC7IZ7TIMMU
Anal:sis L design
xtre#e "rogra##ing x'lained, by >ent Beck *6ddison':esley, K@@@,. I love this book. /es, I tend to take a radical a%%roach to things but IVve always "elt that there could be a #uch di""erent, #uch better %rogra# develo%#ent %rocess, and I think ZP co#es %retty darn close. The only book that has had a si#ilar i#%act on #e was Peo leBare *described below,, which talks %ri#arily about the environ#ent and dealing with cor%orate culture. E*treme Programming E* lained talks about %rogra##ing, and turns #ost things, even recent !"indings,$ on their ear. They even go so "ar as to say that %ictures are )> as long as you don t s%end too #uch ti#e on the# and are willing to throw the# away. */ou ll notice that this book does not have the !4MD sta#% o" a%%roval$ on its cover., I could see deciding whether to work "or a co#%any based solely on whether they used ZP. S#all book, s#all cha%ters, e""ortless to read, e&citing to think about. /ou start i#agining yoursel" working in such an at#os%here and it brings visions o" a whole new world. RFSURF STIJLT6PPEC7IZ7TIMKU U/5 Distilled7 9nd dition, by Martin Eowler *6ddison':esley,
K@@@,. :hen you "irst encounter 4MD, it is daunting because there are so #any diagra#s and details. 6ccording to Eowler, #ost o" this stu"" is unnecessary so he cuts through to the essentials. Eor #ost %ro0ects, you only need to know a "ew diagra##ing tools, and Eowler s goal is to co#e u% with a good design rather than worry about all the arti"acts o" getting there. 6 nice, thin, readable book; the "irst one you should get i" you need to understand 4MD. RFSURFSTIJLT6PPEC7IZ7TIMLU
113:
Java. 6n acco#%anying +7 5)M contains the Java code and a cut'down version o" 5ational 5ose. 6n e&cellent introduction to 4MD and how to use it to build a real syste#. RFSURFSTIJLT6PPEC7IZ7TIM?U
"
endi* %! -esources
113;
*oftware Creativit!, by 5obert 8lass *Prentice'(all, M22H,. This is the best book I ve seen that discusses ers ective on the whole #ethodology issue. It s a collection o" short essays and %a%ers that 8lass has written and so#eti#es acAuired *P.J. Plauger is one contributor,, re"lecting his #any years o" thinking and study on the sub0ect. They re entertaining and only long enough to say what s necessary; he doesn t ra#ble and bore you. (e s not 0ust blowing s#oke, either; there are hundreds o" re"erences to other %a%ers and studies. 6ll %rogra##ers and #anagers should read this book be"ore wading into the #ethodology #ire. RFSURF STIJLT6PPEC7IZ7TIMIU *oftware Runawa!s. /onu#ental *oftware Disasters, by 5obert 8lass *Prentice'(all, M22G,. The great thing about this book is that it brings to the "ore"ront what we don t talk about= how #any %ro0ects not only "ail, but "ail s%ectacularly. I "ind that #ost o" us still think !That can t ha%%en to #e$ *or !That can t ha%%en again$,, and I think this %uts us at a disadvantage. By kee%ing in #ind that things can always go wrong, you re in a #uch better %osition to #ake the# go right. RFSURF STIJLT6PPEC7IZ7TIM2U "eo'lewareD 9nd dition, by To# 7e#arco and Ti#othy Dister *7orset
(ouse, M222,. 6lthough they have backgrounds in so"tware develo%#ent, this book is about %ro0ects and tea#s in general. But the "ocus is on the eo le and their needs, rather than the technology and its needs. They talk about creating an environ#ent where %eo%le will be ha%%y and %roductive, rather than deciding what rules those %eo%le should "ollow to be adeAuate co#%onents o" a #achine. This latter attitude, I think, is the biggest contributor to %rogra##ers s#iling and nodding when Z/Q #ethod is ado%ted and then Auietly doing whatever they ve always done. RFSURFSTIJLT6PPEC7IZ7TIK@U
114=
:thon
5earning "!thon, by Mark Dut1 and 7avid 6scher *) 5eilly, M222,. 6
nice %rogra##er s introduction to what is ra%idly beco#ing #y "avorite language, an e&cellent co#%anion to Java. The book includes an introduction to JPython, which allows you to co#bine Java and Python in a single %rogra# *the JPython inter%reter is co#%iled to %ure Java bytecodes, so there is nothing s%ecial you need to add to acco#%lish this,. This language union %ro#ises great %ossibilities. RFSURF STIJLT6PPEC7IZ7TIKKU
Co#'uter Interfacing with "ascal & C, *Sel"'%ublished via the Eisys i#%rint, M2II. )nly available via ,,,'0ruceEckel'com,. 6n introduction to electronics "ro# back when +PFM was still king and 7)S was an u%start. I used high'level languages and o"ten the %arallel %ort o" the co#%uter to drive various electronic %ro0ects. 6da%ted "ro# #y colu#ns in the "irst and best #aga1ine I wrote "or, Micro Cornuco ia' *To %ara%hrase Darry ) Brien, long'ti#e editor o" So$t,are %evelo ment Maga?ine= the best co#%uter #aga1ine ever %ublished9they even had %lans "or building a robot in a "lower %ot., 6las, Micro + beca#e lost long be"ore the Internet a%%eared. +reating this book was an e&tre#ely satis"ying %ublishing e&%erience. RFSURFSTIJLT6PPEC7IZ7TIK?U
"
endi* %! -esources
1141
Using C++, *)sborneFMc8raw'(ill, M2I2,. )ne o" the "irst books out on +<<. This is out o" %rint and re%laced by its second edition, the rena#ed C++ Inside & Out. RFSURFSTIJLT6PPEC7IZ7TIKHU C++ Inside & Out, *)sborneFMc8raw'(ill, M22L,. 6s noted, actually the K nd edition o" Using -LL. The +<< in this book is reasonably accurate, but itVs circa M22K and Thinking in C++ is intended to re%lace it.
/ou can "ind out #ore about this book and download the source code at ,,,'0ruceEckel'com. RFSURFSTIJLT6PPEC7IZ7TIK3U
Thinking in C++7 9nd dition7 ;olu#e 8, *Prentice'(all, K@@@,. 7ownloadable "ro# ,,,'0ruceEckel'com. RFSURF
STIJLT6PPEC7IZ7TIKIU
4lack 4elt C++7 the /aster<s Collection, Bruce Eckel, editor *MNT
Books, M22?,. )ut o" %rint. 6 collection o" cha%ters by various +<< lu#inaries based on their %resentations in the +<< track at the So"tware 7evelo%#ent +on"erence, which I chaired. The cover on this book sti#ulated #e to gain control over all "uture cover designs. RFSURF STIJLT6PPEC7IZ7TIK2U
Thinking in Java7 8st dition, *Prentice'(all, M22I,. The "irst edition o" this book won the So$t,are %evelo ment Maga?ine Productivity 6ward, the Java %evelo erJs Journal Editor s +hoice 6ward, and the JavaBorld -eaderJs Choice ",ard $or best book. 7ownloadable "ro# ,,,'0ruceEckel'com. RFSU
1142
Inde0
Please note that so#e na#es will be du%licated in ca%itali1ed "or#. Eollowing Java style, the ca%itali1ed na#es re"er to Java classes, while lowercase na#es re"er to a general conce%t.
boolean g
o%erator g M@3H
]\ g MH?
6
abstract g
class g LLI
abstract keyword g LL2, 6bstract :indow Toolkit *6:T, g GM3, 6bstractButton g G3L, abstraction g LM, 6bstractSeAuentialDist g HK@, 6bstractSet g ?GI, acce%t* , g 2?L access g
%aralysis g GG
and g M@GH 6C7 g
advantages "or clientFserver syste#s g GK@, co#bined a%%lets and a%%lications g GKI, %ackaging a%%lets in a J65 "ile to o%ti#i1e loading g IKL, %lacing inside a :eb %age g GKL
6%%let g
a%%lication builder g ILM, a%%lication "ra#ework g ?@2, co#bined with 6%%let g IGM
a%%lication "ra#ework, and a%%lets g GKM, archive tag, "or (TMD and J65 "iles g IKL argu#ent g
ele#ent co#%arisons g ??G, "irst'class ob0ects g ?K?, initiali1ation g KL2, length g K?@, o" ob0ects g ?K?, o" %ri#itives g ?K?
6rrayDist g ?GK, ?I@, HMI, HKL, 6rrays class, container utility g ?L@, 6rrays.asDist* , g HLI, 6rrays.binarySearch* , g ?HK, 6rrays."ill* , g ??L, assigning ob0ects g M?M, assign#ent g M?@, associative array g ?HH, ?2?, associative arrays *Ma%s, g ?HI, auto'decre#ent o%erator g M?3, auto'incre#ent o%erator g M?3, auto#atic ty%e conversion g KIL, available* , g 3KM
B
base g
ty%es g ?M
base M3 g M3L, base I g M3? base class g KG@, KI3, LK3
1144
bitwise g
6C7 g M3M, 6C7 o%erator *N, g MHL, EZ+D4SIVE )5 Z)5 *a, g MHL, C)T h g MHL, o%erators g MHL, )5 o%erator *], g MHL
bitwise co%y g M@3?, blank "inal g L@I blocking g
errors, re%orting g K?
Boolean g MG3 Boolean g
+
+F+<<, inter"acing with g MM@G +<< g M?I
co%y constructor g M@IL, Standard +ontainer Dibrary aka STD g ?HH, strategies "or transition to g 2I, vector class, vs. array and 6rrayDist g ?KL, why it succeeds g 23
callback g ??G, H23, GLH callbacks g
and containers g ?33, and %ri#itive ty%es g MGG, "ro# "loat or double to integral, truncation g M2?, o%erators g M3M
catch g
g L2M, access g KGL, browser g KGL, class literal g 32M, 32H, creators g LG, eAuivalence, and instanceo"FisInstance* , g 322, initiali1ing #e#bers at %oint o" de"inition g KK2, inner classes and overriding g ?@@, keyword g ?@, loading g LMG, #e#ber initiali1ation g KIL, read'only classes g M@II
+lass g G33
g K2L
+ollection g ?H3, collection class g ?KK, +ollections g HL@, +ollections.enu#eration* , g HL2, +ollections."ill* , g ?HI, +ollections.reverse)rder*, g ?H@, collisions, during hashing g H@3, co#.bruceeckel.swing g GLM, co##a o%erator g M3@, MIL, +o##and Pattern g H23 co##ents g
and cloning g M@3I, and design g LHL, choosing co#%osition vs. inheritance g K2I, co#bining co#%osition N inheritance g K2M, vs. inheritance g L@?
1147
"olding g L@H, grou%s o" constant values g LGK, i#%licit constants, and String g M@2H
constrained %ro%erties g I?2 constructor g
and e&ce%tion handling g HIL, and e&ce%tions g HIK, and "inally g HI?, and overloading g K@K, argu#ents g K@@, base'class constructors and e&ce%tions g K2M, calling base'class constructors with argu#ents g K2@, calling "ro# other constructors g KMK, initiali1ation during inheritance and co#%osition g K2M, na#e g M22, return value g K@M
+onstructor g
7
dae#on threads g IGK data g
eAuivalence to class g LH
database g
via %oly#or%his# g ?2
decou%ling through %oly#or%his# g LKK, decre#ent o%erator g M?3 dee% co%y g M@3@, M@3I
and inheritance g LHK, and #istakes g KGI, o" ob0ect hierarchies g LMI, %atterns g 2K
design %atterns g KG3, destroy* , g 2@2, destructor g KMH, KMG, HGH destructor g
use case g IK
dialog bo& g I@M, dictionary g ?2?, digital signing g GK@ directory g
and %ackages g K3?, creating directories and %aths g 3@@, lister g H2H
dis%ose* , g I@M, division g M?L, do'while g MIM, 7o#ain Ca#e Syste# *7CS, g 2L2, dotted Auad g 2L2, double, literal value #arker *7, g M3?, downcast g L@?, LH3, 32K downcast g
E
early binding g ?I, LKG, editor, creating one using the Swing JTe&tPane g GGH e""iciency g
114:
elegance, in %rogra##ing g 2L, enca%sulation g KGM, Enter%rise JavaBeans *EJB, g M@KG, Enu#eration g HL2 eAuals* , g M?2, ?2L
and hashed data structures g H@L, overriding "or (ashMa% g H@M, vs. \\ g 3G@
eAuivalence g
\\ g M?I
error g
handling with e&ce%tions g HHM, recovery g H2@, standard error strea# g HHI
event g
changing the %oint o" origin o" the e&ce%tion g H3I, creating your own g HHG, design issues g HIG, Error class g HG@, E&ce%tion class g HG@, e&ce%tion handler g HH3, handler g HHK, handling g K2?, losing an e&ce%tion, %it"all g HGI, restrictions g HG2, s%eci"ication g H3K, ter#ination vs. resu#%tion g HHG, Throwable g H3?, throwing an e&ce%tion g HHL
e&ce%tional condition g HHK e&ce%tions g
%rogra# g LLM
E&ternali1able g 3??
"ail "ast containers g HL?, "alse g MH@, Eeature7escri%tor g I?2, Eield, "or re"lection g G@H, "ields, initiali1ing "ields in inter"aces g LGH, EIE) g ?I2 "ile g
class g H2H
"ile dialogs g I@3, Eile Trans"er Protocol *ETP, g GK3, EileIn%ut5eader g 3K@, Eilena#eEilter g 3GI, EileCotEoundE&ce%tion g HI3, Eile5eader g HI?, Eile:riter g 3KK, "illInStackTrace* , g H33, Eilter5eader g 3M? "inal g L3L
and %rivate g LMM, argu#ent g H22, classes g LMK, data g L@H, keyword g L@H, #ethod g LKG, #ethods g LM@, LHK, static %ri#itives g L@G, with ob0ect re"erences g L@H
"inali1e* , g KMH, HIG "inali1e* , g
8
garbage collection g KMH, L?H
and native #ethod e&ecution g MMMH, "orcing "inali1ation g K2G, how the collector works g KKL, order o" ob0ect recla#ation g K2G, setting re"erences to null to allow cleanu% g ?MK
generator g ?H2, generator ob0ect, to "ill arrays and containers g ?LM, get* ,, 6rrayDist g ?33, ?GK, get* ,, (ashMa% g ?2I, getBeanIn"o* , g ILH, getBytes* , g 3KM, get+lass* , g H3?, G@M, get+onstructor* , g G33, get+onstructors* , g G@G, get+ontentPane* , g GKK, get+ontents* , g IKK, getEventSet7escri%tors* , g IL2, getEloat* , g 23H, getIn%utStrea#* , g 2?L, getInt* , g 23H, getInter"aces* , g G@K, getMethod7escri%tors* , g IL2, getMethods* , g G@G, getModel* , g IM?, getCa#e* , g G@L, IL2, get)ut%utStrea#* , g 2?L, getPriority* , g 2M@, getPro%erty7escri%tors* , g IL2, getPro%ertyTy%e* , g IL2, get5eadMethod* , g IL2,
115=
getSelectedValues* , g GIK, getState* , g G2?, getString* , g 23H, getSu%erclass* , g G@L, getTrans"er7ata* , g IKK, getTrans"er7ataElavors* , g IKK, get:riteMethod* , g IL2, 8lass, 5obert g MM?@, glue, in Bo&Dayout g G?H goto g
ob0ect develo%#ent g II (
hardware devices, inter"acing with g MM@3, has'a g L2, has'a relationshi%, co#%osition g L@@, hash code g ?2?, H@H, hash "unction g H@H hash+ode* , g ?2@, ?2?
and hashed data structures g H@L, issues when writing g H@2, overriding "or (ashMa% g H@M
hashing g H@L
I
IF) g
co#%ression library g 3L@, in%ut g 3@K, library g H2?, %i%ed strea#s g 3K3, ty%ical IF) con"igurations g 3MG
Icon g G33, I7D g M@M2, idlto0ava g M@KM, i"'else state#ent g MH2, MGI, IllegalMonitorStateE&ce%tion g I22, I#ageIcon g G33, i##utable ob0ects g M@II i#%le#entation g L3
String g G@G
inheritance g ?@, KG@, KIM, KI3, LKK
and "inal g LML, class inheritance diagra#s g L@L, diagra# g H@, "ro# an abstract class g LL2, "ro# inner classes g L22, vs co#%osition g 33G
and class loading g LMH, base class g KI2, initiali1ing with the constructor g M22, o" #ethod variables g KKI, with inheritance g LM3
inline #ethod calls g LM@, inner class g LI@, IL@ inner class g
and Swing g GH@, and u%casting g LIK, hidden re"erence to the ob0ect o" the enclosing class g L2L, identi"iers and .class "iles g ?@K, in #ethods N sco%es g LI?, nesting within any arbitrary sco%e g LI3, re"erring to the outer class ob0ect g L23
In%utStrea# g 2?G, In%utStrea#5eader g 3MK, 2?G, insertCodeInto* , g IM? instance g
%arseInt* , g I@3
Integer wra%%er class g K?K inter"ace g
and i#%le#entation, se%aration g KGK, and inheritance g LGM, +loneable inter"ace used as a "lag g M@3K, de"ining the class g 2?, i#%le#entation, se%aration o" g LI, keyword g L3L, %rivate, as nested inter"aces g LG2, u%casting to an inter"ace g L3G, vs. abstract g L32
Inter"ace 7e"inition Danguage *I7D, g M@M2, inter"acing with hardware devices g MM@3, internationali1ation, in IF) library g 3MK Internet g
relationshi%, inheritance g L@@, relationshi%, inheritance N u%casting g L@K, vs. is'like'a relationshi%s g ?H
is'like'a g LHH, is7ae#on* , g IGK, is7ataElavorSu%%orted* , g IKK, isInstance g 32G, isInter"ace * , g G@L, iteration, in %rogra# develo%#ent g I2, iterator g ?GK, Iterator g ?GK, ?I@, HMI, iterator* , g ?I@
J
Jacobsen, Ivar g MML2, J6%%let g G?@, J65 g I?G J65 g
1152
and %ointers g M@HL, and set'to% bo&es g MHL, ca%itali1ation style source' code checking tool g 3GM, containers library g ?HH, %ublic Java se#inars g MM, versions g KL
Java M.M g
>
keyboard navigation, and Swing g GM2, keySet* , g HK2, >oenig, 6ndrew g MMKM
D
label g MI3, labeled break g MI3, labeled continue g MI3, late binding g ?2 layout g
linked list g ?HH, DinkedDist g ?I2, HKL, Dist g ?KL, ?HH, ?I?, GIK Dist g
M
#ain* , g KIG, #aintenance, %rogra# g 2@, #anage#ent obstacles g M@@, #ani"est "ile, "or J65 "iles g 3LH, #a% g ?2?, Ma% g ?KL, ?HH, ?2?, HK3, Ma%.Entry g H@L, #ark* , g 3M3, Math. rando#* , g ?2G Math.rando#* , g
adding #ore #ethods to a design g KGI, aliasing during #ethod calls g M?K, looku% tool g GHL, #ethod call binding g LKG, overloading g K@M, %oly#or%hic #ethod call g LKK, %rotected #ethods g L@M, recursive g ?G3, static g KM?
Method g IL2 Method g
1154
#ulticast g I?H
dedicated connection g 2HM, identi"ying #achines g 2L2, serving #ulti%le clients g 2HM, testing %rogra#s without a network g 2?M
new o%erator g KMH
re"lection g G@L
ne&t* ,, Iterator g ?GL, ne&tToken* , g 3G2 no'arg g
constructors g K@L
non'Java code, calling g MM@3, Corth, BorderDayout g G?M C)T g
)
ob0ect g LK
creation g M22, eAuivalence g M?I, "ive stages o" ob0ect design g IG, inter"ace to g L?, lock, "or #ultithreading g II@, %rocess o" creation g KLH, seriali1ation g 3LG
)b0ect g ?KL
clone* , g M@3H, hash+ode* , g ?2?, standard root class, de"ault inheritance "ro# g KI3, wait* , and noti"y* , #ethods g I22
ob0ect'oriented g
basic characteristics g LK
o%erator g
*]], g MH@
order g
distinguishing overloaded #ethods g K@L, lack o" na#e hiding during inheritance g K2G, on return values g K@2, o%erator overloading "or String g M@2H
overriding g
access, and "riendly g K3H, and a%%lets g GKG, creating uniAue %ackage na#es g KH3
%aint+o#%onent* , g G2G, I@H, %air %rogra##ing g 2H, %ara#eter, a%%let g GKH, %ara#eteri1ed ty%e g ?GM %ass g
1157
%ointer g
and constructors g L?K, behavior o" %oly#or%hic #ethods inside constructors g L?2
%ort g 2?K, %ortability in +, +<< and Java g M3H, %osition, absolute, when laying out Swing co#%onents g G??, %rereAuisites, "or this book g L@ %ri#itive g
co#%arison g M?2, data ty%es, and use with o%erators g M33, dealing with the i##utability o" %ri#itive wra%%er classes g M@II, "inal g L@H, initiali1ation o" class data #e#bers g KKI, wra%%ers g ?22
%ri#itive ty%es g MM@, %rintIn"o* , g G@L, %rinting arrays g ?LK, %rintStackTrace* , g H3?, H33, Print:riter g 3KK, 3KL, 2?G %riority g
thread g 2M@
%rivate g LI, KHK, K3?, K3I, L@@, II@ %rivate g
inner class g I3H, inner classes g ?ML, #ethod overriding g LLG, #ethods g LHK
%roble# s%ace g LM, L@K, %rocess, and threading g IH3 %rogra##ing g
substitution g ?H
%ure inheritance, vs. e&tension g LH?, %ure substitution g LHH, %ushBack* , g 3G2, %ut* ,, (ashMa% g ?2I, Python g I3
e
Aueue g ?HH, ?I2
5
567 *5a%id 6%%lication 7evelo%#ent, g G@?, radio button g GG2, 5ando#6ccessEile g 3MH, 3KK, ra%id %rototy%ing g 2K, re'throwing an e&ce%tion g H33, reachable ob0ects and garbage collection g HML, read+har* , g 3KL, read7ouble* , g 3K?, 5eader g 3MK, 3ML, 2@M, 2?G, readE&ternal* , g 3??, reading "ro# standard in%ut g 3K3, readDine* , g HIG, 3KK, 3KL, 3KG read)b0ect* , g 3L2
eAuivalence vs ob0ect eAuivalence g M?I, "inding e&act ty%e o" a base re"erence g 3II, re"erence eAuivalence vs. ob0ect eAuivalence g M@3H
5e"erence, "ro# 0ava.lang.re" g HML, re"lection g G@?, GHL, ILH re"lection g
an array g ?KI
reusability g L2 reuse g II
and cloning g M@33, di""erence between 5TTI and re"lection g G@3, using the +lass ob0ect g G@M
5u#baugh, Ja#es g MML2, run'ti#e binding g LKG run'ti#e ty%e identi"ication g
115:
*5TTI, g LHG, #isuse g GMM, sha%e e&a#%le g 3IH, when to use it g GMM
runEinali1ers)nE&it* , g L?I, 5unnable g 2KH 5unnable g
inter"ace g I3G
5unti#eE&ce%tion g ?KL, HGM, rvalue g M?@
S
scenario g IM, scheduling g IL sco%e g
use case g 2@
searching an array g ?HK, seek* , g 3MH, 3KH, sending a #essage g L?, se%arating business logic "ro# 4I logic g IK3, Seriali1able g 3??, 3?2, 33K, I?? seriali1ation g
and ob0ect storage g 3HH, controlling the %rocess o" seriali1ation g 3??, 5MI argu#ents g M@MH, to %er"or# dee% co%ying g M@GK
server g 2?M servlet g 2IL
#ultithreading g 2I2
session g
develo%#ent #ethodology g GG
So"tware 7evelo%#ent +on"erence g M@, solution s%ace g LM
sorting g ??G
and "inal g L@H, block g KL3, clause g 32@, construction clause g KL3, initiali1ation g LMG, inner classes g L2L, keyword g KM?
sto%* , g
concatenation with o%erator < g M3@, i##utability g M@2?, inde&)"* , g H2G, le&icogra%hic vs. al%habetic sorting g ?HM, #ethods g M@2G, o%erator < g ?32, )%erator < g M3@, o%erator < and <\ overloading g KIG, toString * , g ?3I
StringBu""er g
#ethods g MM@@
String5eader g 3KM, StringSelection g IKK, StringTokeni1er g 33I, struts, in Bo&Dayout g G?H, stub, 5MI g M@MH, style o" creating classes g KGK, subob0ect g KI2, K2I substitution g
%rinci%le g ?H
subtraction g M?L su%er g K2@
and inheritance g I2@, and wait* , N noti"y* , g I2I, containers g HLL, deciding what #ethods to synchroni1e g I2@, e""iciency g IIH, static g II@, synchroni1ed block g II?
syste# cli%board g IM2, syste# s%eci"ication g I@, Syste#.arrayco%y* , g ???, Syste#.err g HHI, Syste#.gc* , g KK@, Syste#.in g 3K@, Syste#.runEinali1ation* , g KK@
117=
T
table g IM? te#%late g
in +<< g ?GM
testing g
co#bined with #ain class g I3H, interru%t* , g 2@3, order o" e&ecution o" threads g I3K, %ro%erly sus%ending N resu#ing g 2@G, run* , g I3@, sharing li#ited resources g IG?, slee%* , g I2K, start* , g I3M, sto%%ing g 2@3, thread grou% g 2MH, thread grou%, de"ault %riority g 2MH, threads and e""iciency g IH2, when they can be sus%ended g IG2
throw keyword g HH?, Throwable g H3I, throwing an e&ce%tion g HH?, ti#e'critical code sections g MM@3, to6rray* , g HK2, Tokeni1ing g 33?, To#cat, standard servlet container g 22H, tool ti%s g G32, TooManyDistenersE&ce%tion g I?H, toString* , g KIL, ?G?, HMI training g 22
4
4MD g I3 4MD g
indicating co#%osition g L2
unary g
#inus *', g M?H, o%erator g MHL, o%erators g M?H, %lus *<, g M?H
unicast g I?H, 4nicast5e#ote)b0ect g M@MM, 4nicode g 3MK, 4ni"ied Modeling Danguage *4MD, g L3, MMLI, unit testing g KIG, un#odi"iable, #aking a +ollection or Ma% un#odi"iable g HLK, unsu%%orted #ethods, in the Java K containers g HLH, u%casting g H@, L@K, LKL, 3I3 u%casting g
iteration g I2
4ser 7atagra# Protocol *47P, g 2HI user inter"ace g IL
de"ining a variable g MIK, variable argu#ent lists *unknown Auantity and ty%e o" argu#ents, g K??
Vector g HKL, HLI, H?@, versioning, seriali1ation g 3HH, visibility, %ackage visibility, *"riendly, g LIK visual g
%rogra##ing g ILM :
wait* , g I2I, :aldro%, M. Mitchell g MM?@ weak g
dis%laying a :eb %age "ro# within an a%%let g 2HI, sa"ety, and a%%let restrictions g GM2
web o" ob0ects g 3L2, M@3@, while g MI@, widening conversion g M3K, wild'card g GI, :indow6da%ter g GLM, window+losing* , g GLM, I@M, windowed a%%lications g GKG, :indows E&%lorer, running Java %rogra#s "ro# g GLK, writeBytes* , g 3KL, write7ouble* , g 3K?, writeE&ternal* , g 3?? write)b0ect* , g 3L2
/
yield* , g I2L
Q
1ero e&tension g MH?, Qi%Entry g 3L?
1172
/nd@Cser &icense Agreement for Microsoft 1oftware IM O$#A2#@$/AD CA$/<C&&G: #his Microsoft /nd@Cser &icense Agreement 8B/C&AB9 is a legal agreement between :ou 8either an individual or a single entit:9 and Microsoft Cor.oration for the Microsoft software .roduct included in this .ackageH which includes com.uter software and ma: include associated mediaH .rinted materialsH and BonlineB or electronic documentation 8B1O<#WA$/ $ODCC#B9) #he 1O<#WA$/ $ODCC# also includes an: u.dates and su..lements to the original 1O<#WA$/ $ODCC# .rovided to :ou b: Microsoft) ;: installingH co.:ingH downloadingH accessing or otherwise using the 1O<#WA$/ $ODCC#H :ou agree to be bound b: the terms of this /C&A) If :ou do not agree to the terms of this /C&AH do not installH co.:H or otherwise use the 1O<#WA$/ $ODCC#) 1O<#WA$/ $ODCC# &IC/21/ #he 1O<#WA$/ $ODCC# is .rotected b: co.:right laws and international co.:right treatiesH as well as other intellectual .ro.ert: laws and treaties) #he 1O<#WA$/ $ODCC# is licensedH not sold) () '$A2# O< &IC/21/) #his /C&A grants :ou the following rights: ()( &icense 'rant) Microsoft grants to :ou as an individualH a .ersonal none0clusive license to make and use co.ies of the 1O<#WA$/ $ODCC# for the sole .ur.oses of evaluating and learning how to use the 1O<#WA$/ $ODCC#H as ma: be instructed in accom.an:ing .ublications or documentation) Gou ma: install the software on an unlimited number of com.uters .rovided that :ou are the onl: individual using the 1O<#WA$/ $ODCC#) ()! Academic Cse) Gou must be a BRualified /ducational CserB to use the 1O<#WA$/ $ODCC# in the manner described in this section) #o determine whether :ou are a Rualified /ducational CserH .lease contact the Microsoft 1ales Information CenterDOne Microsoft Wa:D$edmondH WA 657,!@-*66 or the Microsoft subsidiar: serving :our countr:) If :ou are a Rualified /ducational CserH :ou ma: either: 8i9 e0ercise the rights granted in 1ection ()(H O$ 8ii9 if :ou intend to use the 1O<#WA$/ $ODCC# solel: for instructional .ur.oses in connection with a class or other educational .rogramH this /C&A grants :ou the following alternative license models: 8A9 er Com.uter Model) <or ever: valid license :ou have ac%uired for the 1O<#WA$/ $ODCC#H :ou ma: install a single co.: of the 1O<#WA$/
$ODCC# on a single com.uter for access and use b: an unlimited number of student end users at :our educational institutionH .rovided that all such end users com.l: with all other terms of this /C&AH O$ 8;9 er &icense Model) If :ou have multi.le licenses for the 1O<#WA$/ $ODCC#H then at an: time :ou ma: have as man: co.ies of the 1O<#WA$/ $ODCC# in use as :ou have licensesH .rovided that such use is limited to student or facult: end users at :our educational institution and .rovided that all such end users com.l: with all other terms of this /C&A) <or .ur.oses of this subsectionH the 1O<#WA$/ $ODCC# is Bin useB on a com.uter when it is loaded into the tem.orar: memor: 8i)e)H $AM9 or installed into the .ermanent memor: 8e)g)H hard diskH CD $OMH or other storage device9 of that com.uterH e0ce.t that a co.: installed on a network server for the sole .ur.ose of distribution to other com.uters is not Bin useB) If the antici.ated number of users of the 1O<#WA$/ $ODCC# will e0ceed the number of a..licable licensesH then :ou must have a reasonable mechanism or .rocess in .lace to ensure that the number of .ersons using the 1O<#WA$/ $ODCC# concurrentl: does not e0ceed the number of licenses) !) D/1C$I #IO2 O< O#>/$ $I'>#1 A2D &IMI#A#IO21) T &imitations on $everse /ngineeringH Decom.ilationH and Disassembl:) Gou ma: not reverse engineerH decom.ileH or disassemble the 1O<#WA$/ $ODCC#H e0ce.t and onl: to the e0tent that such activit: is e0.ressl: .ermitted b: a..licable law notwithstanding this limitation) T 1e.aration of Com.onents) #he 1O<#WA$/ $ODCC# is licensed as a single .roduct) Its com.onent .arts ma: not be se.arated for use on more than one com.uter) T $ental) Gou ma: not rentH lease or lend the 1O<#WA$/ $ODCC#) T #rademarks) #his /C&A does not grant :ou an: rights in connection with an: trademarks or service marks of Microsoft) T 1oftware #ransfer) #he initial user of the 1O<#WA$/ $ODCC# ma: make a one@time .ermanent transfer of this /C&A and 1O<#WA$/ $ODCC# onl: directl: to an end user) #his transfer must include all of the 1O<#WA$/ $ODCC# 8including all com.onent .artsH the media and .rinted materialsH an: u.gradesH this /C&AH andH if a..licableH the Certificate of Authenticit:9) 1uch transfer ma: not be b: wa: of consignment or an: other indirect transfer) #he transferee of such one@time transfer must agree to com.l: with the terms of this /C&AH including the obligation not to further transfer this /C&A and 1O<#WA$/ $ODCC#) T 2o 1u..ort) Microsoft shall have no obligation to .rovide an: .roduct su..ort for the 1O<#WA$/ $ODCC#) T #ermination) Without .re3udice to an: other rightsH Microsoft ma: terminate this /C&A if :ou fail to com.l: with the terms and conditions of this /C&A) In
such eventH :ou must destro: all co.ies of the 1O<#WA$/ $ODCC# and all of its com.onent .arts) *) CO G$I'>#) All title and intellectual .ro.ert: rights in and to the 1O<#WA$/ $ODCC# 8including but not limited to an: imagesH .hotogra.hsH animationsH videoH audioH musicH te0tH and Ba..letsB incor.orated into the 1O<#WA$/ $ODCC#9H the accom.an:ing .rinted materialsH and an: co.ies of the 1O<#WA$/ $ODCC# are owned b: Microsoft or its su..liers) All title and intellectual .ro.ert: rights in and to the content which ma: be accessed through use of the 1O<#WA$/ $ODCC# is the .ro.ert: of the res.ective content owner and ma: be .rotected b: a..licable co.:right or other intellectual .ro.ert: laws and treaties) #his /C&A grants :ou no rights to use such content) All rights not e0.ressl: granted are reserved b: Microsoft) +) ;ACUC CO G) After installation of one co.: of the 1O<#WA$/ $ODCC# .ursuant to this /C&AH :ou ma: kee. the original media on which the 1O<#WA$/ $ODCC# was .rovided b: Microsoft solel: for backu. or archival .ur.oses) If the original media is re%uired to use the 1O<#WA$/ $ODCC# on the COM C#/$H :ou ma: make one co.: of the 1O<#WA$/ $ODCC# solel: for backu. or archival .ur.oses) /0ce.t as e0.ressl: .rovided in this /C&AH :ou ma: not otherwise make co.ies of the 1O<#WA$/ $ODCC# or the .rinted materials accom.an:ing the 1O<#WA$/ $ODCC#) ,) C)1) 'O=/$2M/2# $/1#$IC#/D $I'>#1) #he 1O<#WA$/ $ODCC# and documentation are .rovided with $/1#$IC#/D $I'>#1) CseH du.licationH or disclosure b: the 'overnment is sub3ect to restrictions as set forth in sub.aragra.h 8c98(98ii9 of the $ights in #echnical Data and Com.uter 1oftware clause at D<A$1 !,!)!!4@47(* or sub.aragra.hs 8c98(9 and 8!9 of the Commercial Com.uter 1oftware@$estricted $ights at +5 C<$ ,!)!!4@(6H as a..licable) Manufacturer is Microsoft Cor.orationDOne Microsoft Wa:D $edmondH WA 657,!@-*66) -) /E O$# $/1#$IC#IO21) Gou agree that :ou will not e0.ort or [email protected] the 1O<#WA$/ $ODCC#H an: .art thereofH or an: .rocess or service that is the direct .roduct of the 1O<#WA$/ $ODCC# 8the foregoing collectivel: referred to as the B$estricted Com.onentsB9H to an: countr:H .ersonH entit: or end user sub3ect to C)1) e0.ort restrictions) Gou s.ecificall: agree not to e0.ort or re@ e0.ort an: of the $estricted Com.onents 8i9 to an: countr: to which the C)1) has embargoed or restricted the e0.ort of goods or servicesH which currentl: includeH but are not necessaril: limited to CubaH IranH Ira%H &ib:aH 2orth UoreaH 1udan and 1:riaH or to an: national of an: such countr:H wherever locatedH who intends to transmit or trans.ort the $estricted Com.onents back to such countr:M 8ii9 to an: end@user who :ou know or have reason to know will utili?e the $estricted Com.onents in the designH develo.ment or .roduction of nuclearH chemical or biological wea.onsM or 8iii9 to an: end@user who has been
.rohibited from .artici.ating in C)1) e0.ort transactions b: an: federal agenc: of the C)1) government) Gou warrant and re.resent that neither the ;EA nor an: other C)1) federal agenc: has sus.endedH revokedH or denied :our e0.ort .rivileges) 4) 2O#/ O2 "A=A 1C O$#) #>/ 1O<#WA$/ $ODCC# MAG CO2#AI2 1C O$# <O$ $O'$AM1 W$I##/2 I2 "A=A) "A=A #/C>2O&O'G I1 2O# <AC&# #O&/$A2# A2D I1 2O# D/1I'2/DH MA2C<AC#C$/DH O$ I2#/2D/D <O$ C1/ O$ $/1A&/ A1 O2@&I2/ CO2#$O& /RCI M/2# I2 >AQA$DOC1 /2=I$O2M/2#1 $/RCI$I2' <AI&@1A</ /$<O$MA2C/H 1CC> A1 I2 #>/ O /$A#IO2 O< 2CC&/A$ <ACI&I#I/1H AI$C$A<# 2A=I'A#IO2 O$ COMMC2ICA#IO2 1G1#/M1H AI$ #$A<<IC CO2#$O&H DI$/C# &I</ 1C O$# MAC>I2/1H O$ W/A O21 1G1#/M1H I2 W>IC> #>/ <AI&C$/ O< "A=A #/C>2O&O'G COC&D &/AD DI$/C#&G #O D/A#>H /$1O2A& I2"C$GH O$ 1/=/$/ >G1ICA& O$ /2=I$O2M/2#A& DAMA'/) MI1C/&&A2/OC1 If :ou ac%uired this .roduct in the Cnited 1tatesH this /C&A is governed b: the laws of the 1tate of Washington) If :ou ac%uired this .roduct in CanadaH this /C&A is governed b: the laws of the rovince of OntarioH Canada) /ach of the .arties hereto irrevocabl: attorns to the 3urisdiction of the courts of the rovince of Ontario and further agrees to commence an: litigation which ma: arise hereunder in the courts located in the "udicial District of GorkH rovince of Ontario) If this .roduct was ac%uired outside the Cnited 1tatesH then local law ma: a..l:) 1hould :ou have an: %uestions concerning this /C&AH or if :ou desire to contact Microsoft for an: reasonH .lease contact MicrosoftH or write: Microsoft 1ales Information CenterDOne Microsoft Wa:D $edmondH WA 657,!@-*66) &IMI#/D WA$$A2#G &IMI#/D WA$$A2#G) Microsoft warrants that 8a9 the 1O<#WA$/ $ODCC# will .erform substantiall: in accordance with the accom.an:ing written materials for a .eriod of ninet: 8679 da:s from the date of recei.tH and 8b9 an: 1u..ort 1ervices .rovided b: Microsoft shall be substantiall: as described in a..licable written materials .rovided to :ou b: MicrosoftH and Microsoft su..ort engineers will make commerciall: reasonable efforts to solve an: .roblem) #o the e0tent allowed b: a..licable lawH im.lied warranties on the 1O<#WA$/ $ODCC#H if an:H are limited to ninet: 8679 da:s) 1ome statesD3urisdictions do
not allow limitations on duration of an im.lied warrant:H so the above limitation ma: not a..l: to :ou) CC1#OM/$ $/M/DI/1) MicrosoftVs and its su..liersV entire liabilit: and :our e0clusive remed: shall beH at MicrosoftVs o.tionH either 8a9 return of the .rice .aidH if an:H or 8b9 re.air or re.lacement of the 1O<#WA$/ $ODCC# that does not meet MicrosoftVs &imited Warrant: and that is returned to Microsoft with a co.: of :our recei.t) #his &imited Warrant: is void if failure of the 1O<#WA$/ $ODCC# has resulted from accidentH abuseH or misa..lication) An: re.lacement 1O<#WA$/ $ODCC# will be warranted for the remainder of the original warrant: .eriod or thirt: 8*79 da:sH whichever is longer) Outside the Cnited 1tatesH neither these remedies nor an: .roduct su..ort services offered b: Microsoft are available without .roof of .urchase from an authori?ed international source) 2O O#>/$ WA$$A2#I/1) #O #>/ MAEIMCM /E#/2# /$MI##/D ;G A &ICA;&/ &AWH MIC$O1O<# A2D I#1 1C &I/$1 DI1C&AIM A&& O#>/$ WA$$A2#I/1 A2D CO2DI#IO21H /I#>/$ /E $/11 O$ IM &I/DH I2C&CDI2'H ;C# 2O# &IMI#/D #OH IM &I/D WA$$A2#I/1 O$ CO2DI#IO21 O< M/$C>A2#A;I&I#GH <I#2/11 <O$ A A$#ICC&A$ C$ O1/H #I#&/ A2D 2O2@ I2<$I2'/M/2#H WI#> $/'A$D #O #>/ 1O<#WA$/ $ODCC#H A2D #>/ $O=I1IO2 O< O$ <AI&C$/ #O $O=ID/ 1C O$# 1/$=IC/1) #>I1 &IMI#/D WA$$A2#G 'I=/1 GOC 1 /CI<IC &/'A& $I'>#1) GOC MAG >A=/ O#>/$1H W>IC> =A$G <$OM 1#A#/D"C$I1DIC#IO2 #O 1#A#/D"C$I1DIC#IO2) &IMI#A#IO2 O< &IA;I&I#G) #O #>/ MAEIMCM /E#/2# /$MI##/D ;G A &ICA;&/ &AWH I2 2O /=/2# 1>A&& MIC$O1O<# O$ I#1 1C &I/$1 ;/ &IA;&/ <O$ A2G 1 /CIA&H I2CID/2#A&H I2DI$/C#H O$ CO21/RC/2#IA& DAMA'/1 W>A#1O/=/$ 8I2C&CDI2'H WI#>OC# &IMI#A#IO2H DAMA'/1 <O$ &O11 O< ;C1I2/11 $O<I#1H ;C1I2/11 I2#/$$C #IO2H &O11 O< ;C1I2/11 I2<O$MA#IO2H O$ A2G O#>/$ /CC2IA$G &O119 A$I1I2' OC# O< #>/ C1/ O< O$ I2A;I&I#G #O C1/ #>/ 1O<#WA$/ $ODCC# O$ #>/ <AI&C$/ #O $O=ID/ 1C O$# 1/$=IC/1H /=/2 I< MIC$O1O<# >A1 ;//2 AD=I1/D O< #>/ O11I;I&I#G O< 1CC> DAMA'/1) I2 A2G CA1/H MIC$O1O<#V1 /2#I$/ &IA;I&I#G C2D/$ A2G $O=I1IO2 O< #>I1 /C&A 1>A&& ;/ &IMI#/D #O #>/ '$/A#/$ O< #>/ AMOC2# AC#CA&&G AID ;G GOC <O$ #>/ 1O<#WA$/ $ODCC# O$ C)1)W,)77M $O=ID/DH >OW/=/$H I< GOC >A=/ /2#/$/D I2#O A MIC$O1O<# 1C O$# 1/$=IC/1 A'$//M/2#H MIC$O1O<#V1 /2#I$/ &IA;I&I#G $/'A$DI2' 1C O$# 1/$=IC/1 1>A&& ;/ 'O=/$2/D ;G #>/ #/$M1 O< #>A# A'$//M/2#) ;/CAC1/ 1OM/ 1#A#/1D"C$I1DIC#IO21 DO 2O# A&&OW #>/ /EC&C1IO2 O$ &IMI#A#IO2 O< &IA;I&I#GH #>/ A;O=/ &IMI#A#IO2 MAG 2O# A &G #O GOC) 7+6, art 2o) -+*,5
&IC/21/ A'$//M/2# <O$ Mind=iewH Inc)Vs #hinking in C: <oundations for "ava L CFF CD $OM b: Chuck Allison #his CD is .rovided together with the book B#hinking in "avaH !nd edition)B $/AD #>I1 A'$//M/2# ;/<O$/ C1I2' #>I1 B#hinking in C: <oundations for CFF L "avaB 8>ereafter called BCDB9) ;G C1I2' #>/ CD GOC A'$// #O ;/ ;OC2D ;G #>/ #/$M1 A2D CO2DI#IO21 O< #>I1 A'$//M/2#) I< GOC DO 2O# A'$// #O #>/ #/$M1 A2D CO2DI#IO21 O< #>I1 A'$//M/2#H IMM/DIA#/&G $/#C$2 #>/ C2C1/D CD <O$ A <C&& $/<C2D O< MO2I/1 AIDH I< A2G) X!777 Mind=iewH Inc) All rights reserved) rinted in the C)1) 1O<#WA$/ $/RCI$/M/2#1 #he .ur.ose of this CD is to .rovide the ContentH not the associated software necessar: to view the Content) #he Content of this CD is in >#M& for viewing with Microsoft Internet /0.lorer + or newerH and uses Microsoft 1ound Codecs available in MicrosoftVs Windows Media la:er for Windows) It is :our res.onsibilit: to correctl: install the a..ro.riate Microsoft software for :our s:stem) #he te0tH imagesH and other media included on this CD 8BContentB9 and their com.ilation are licensed to :ou sub3ect to the terms and conditions of this Agreement b: Mind=iewH Inc)H having a .lace of business at ,*+* =alle =istaH &a MesaH CA 6(6+() Gour rights to use other .rograms and materials included on the CD are also governed b: se.arate agreements distributed with those .rograms and materials on the CD 8the BOther AgreementsB9) In the event of an: inconsistenc: between this Agreement and the Other AgreementsH this Agreement shall govern) ;: using this CDH :ou agree to be bound b: the terms and conditions of this Agreement) Mind=iewH Inc) owns title to the Content and to all intellectual .ro.ert: rights thereinH e0ce.t insofar as it contains materials that are .ro.rietar: to [email protected]: su..liers) All rights in the Content e0ce.t those e0.ressl: granted to :ou in this Agreement are reserved to Mind=iewH Inc) and such su..liers as their res.ective interests ma: a..ear) () &IMI#/D &IC/21/ Mind=iewH Inc) grants :ou a limitedH none0clusiveH nontransferable license to use the Content on a single dedicated com.uter 8e0cluding network servers9) #his Agreement and :our rights hereunder shall automaticall: terminate if :ou fail to com.l: with an: .rovisions of this Agreement or an: of the Other
Agreements) C.on such terminationH :ou agree to destro: the CD and all co.ies of the CDH whether lawful or notH that are in :our .ossession or under :our control) !) ADDI#IO2A& $/1#$IC#IO21 a) Gou shall not 8and shall not .ermit other .ersons or entities to9 directl: or indirectl:H b: electronic or other meansH re.roduce 8e0ce.t for archival .ur.oses as .ermitted b: law9H .ublishH distributeH rentH leaseH sellH sublicenseH assignH or otherwise transfer the Content or an: .art thereof) b) Gou shall not 8and shall not .ermit other .ersons or entities to9 use the Content or an: .art thereof for an: commercial .ur.ose or mergeH modif:H create derivative works ofH or translate the Content) c) Gou shall not 8and shall not .ermit other .ersons or entities to9 obscure Mind=iewVs or its su..liers co.:rightH trademarkH or other .ro.rietar: notices or legends from an: .ortion of the Content or an: related materials) *) /$MI11IO21 a) /0ce.t as noted in the Contents of the CDH :ou must treat this software 3ust like a book) >oweverH :ou ma: co.: it onto a com.uter to be used and :ou ma: make archival co.ies of the software for the sole .ur.ose of backing u. the software and .rotecting :our investment from loss) ;: sa:ingH B3ust like a bookHB Mind=iewH Inc) meansH for e0am.leH that this software ma: be used b: an: number of .eo.le and ma: be freel: moved from one com.uter location to anotherH so long as there is no .ossibilit: of its being used at one location or on one com.uter while it is being used at another) "ust as a book cannot be read b: two different .eo.le in two different .laces at the same timeH neither can the software be used b: two different .eo.le in two different .laces at the same time) b) Gou ma: show or demonstrate the un@modified Content in a live .resentationH live seminarH or live .erformance as long as :ou attribute all material of the Content to Mind=iewH Inc) c) Other .ermissions and grants of rights for use of the CD must be obtained directl: from Mind=iewH Inc) at htt.:DDwww)Mind=iew)net) 8;ulk co.ies of the CD ma: also be .urchased at this site)9 DI1C&AIM/$ O< WA$$A2#G #he Content and CD are .rovided BA1 I1B without warrant: of an: kindH either e0.ress or im.liedH includingH without limitationH an: warrant: of
merchantabilit: and fitness for a .articular .ur.ose) #he entire risk as to the results and .erformance of the CD and Content is assumed b: :ou) Mind=iewH Inc) and its su..liers assume no res.onsibilit: for defects in the CDH the accurac: of the ContentH or omissions in the CD or the Content) Mind=iewH Inc) and its su..liers do not warrantH guaranteeH or make an: re.resentations regarding the useH or the results of the useH of the .roduct in terms of correctnessH accurac:H reliabilit:H currentnessH or otherwiseH or that the Content will meet :our needsH or that o.eration of the CD will be uninterru.ted or error@freeH or that an: defects in the CD or Content will be corrected) Mind=iewH Inc) and its su..liers shall not be liable for an: lossH damagesH or costs arising from the use of the CD or the inter.retation of the Content) 1ome states do not allow e0clusion or limitation of im.lied warranties or limitation of liabilit: for incidental or conse%uential damagesH so all of the above limitations or e0clusions ma: not a..l: to :ou) In no event shall Mind=iewH Inc) or its su..liersV total liabilit: to :ou for all damagesH lossesH and causes of action 8whether in contractH tortH or otherwise9 e0ceed the amount .aid b: :ou for the CD) Mind=iewH Inc)H and rentice@>allH Inc) s.ecificall: disclaim the im.lied warrantees of merchantabilit: and fitness for a .articular .ur.ose) 2o oral or written information or advice given b: Mind=iewH Inc)H rentice@>allH Inc)H their dealersH distributorsH agents or em.lo:ees shall create a warrantee) Gou ma: have other rightsH which var: from state to state) 2either Mind=iewH Inc)H ;ruce /ckelH Chuck AllisonH rentice@>allH nor an:one else who has been involved in the creationH .roduction or deliver: of the .roduct shall be liable for an: directH indirectH conse%uentialH or incidental damages 8including damages for loss of business .rofitsH business interru.tionH loss of business informationH and the like9 arising out of the use of or inabilit: to use the .roduct even if Mind=iewH Inc)H has been advised of the .ossibilit: of such damages) ;ecause some states do not allow the e0clusion or limitation of liabilit: for conse%uential or incidental damagesH the above limitation ma: not a..l: to :ou) #his CD is .rovided as a su..lement to the book B#hinking in "ava !nd edition)B #he sole res.onsibilit: of rentice@>all will be to .rovide a re.lacement CD in the event that the one that came with the book is defective) #his re.lacement warrantee shall be in effect for a .eriod of si0t: da:s from the .urchase date) Mind=iewH Inc) does not bear an: additional res.onsibilit: for the CD) 2O #/C>2ICA& 1C O$# I1 $O=ID/D WI#> #>I1 CD $OM #he following are trademarks of their res.ective com.anies in the C)1) and ma: be .rotected as trademarks in other countries: 1un and the 1un &ogoH
1un Micros:stemsH "avaH all "ava@based names and logos and the "ava Coffee Cu. are trademarks of 1un Micros:stemsM Internet /0.lorerH the Windows Media la:erH DO1H Windows 6,H and Windows 2# are trademarks of Microsoft)
M. Install the #ost recent version o" Microso"t s Internet E&%lorer. Because o" the "eatures %rovided on the +7, it will C)T work with Cetsca%e Cavigator. The Internet &4plorer soft(are for 0in'o(s ?X5/T is incl*'e' on the - ! K. Install Microso"t s Bindo,s Media Pla)er. The 1e'ia #layer soft(are for 0in'o(s ?X5/T is incl*'e' on the - ! /ou can also go to http<55(((!microsoft! com5(in'o(s5me'iaplayer and "ollow the instructions or links there to download and install the Media Player "or your %articular %lat"or#. L. 6t this %oint you should be able to %lay the lectures on the +7. 4sing the Internet E&%lorer :eb browser, o%en the "ile Install!html that you ll "ind on the +7. This will introduce you to the +7 and %rovide "urther instructions about the use o" the +7.